@navbook/cli 0.1.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.
- package/LICENSE +9 -0
- package/README.md +165 -0
- package/dist/cli/commands/complete.d.ts +9 -0
- package/dist/cli/commands/complete.js +72 -0
- package/dist/cli/commands/complete.js.map +1 -0
- package/dist/cli/commands/compose.d.ts +27 -0
- package/dist/cli/commands/compose.js +44 -0
- package/dist/cli/commands/compose.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +127 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/entity.d.ts +55 -0
- package/dist/cli/commands/entity.js +209 -0
- package/dist/cli/commands/entity.js.map +1 -0
- package/dist/cli/commands/init.d.ts +11 -0
- package/dist/cli/commands/init.js +39 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install.d.ts +17 -0
- package/dist/cli/commands/install.js +137 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/issue.d.ts +12 -0
- package/dist/cli/commands/issue.js +42 -0
- package/dist/cli/commands/issue.js.map +1 -0
- package/dist/cli/commands/pr.d.ts +64 -0
- package/dist/cli/commands/pr.js +466 -0
- package/dist/cli/commands/pr.js.map +1 -0
- package/dist/cli/commit-flow.d.ts +27 -0
- package/dist/cli/commit-flow.js +47 -0
- package/dist/cli/commit-flow.js.map +1 -0
- package/dist/cli/context.d.ts +39 -0
- package/dist/cli/context.js +93 -0
- package/dist/cli/context.js.map +1 -0
- package/dist/cli/editor.d.ts +23 -0
- package/dist/cli/editor.js +67 -0
- package/dist/cli/editor.js.map +1 -0
- package/dist/cli/errors.d.ts +17 -0
- package/dist/cli/errors.js +23 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/history-checks.d.ts +21 -0
- package/dist/cli/history-checks.js +134 -0
- package/dist/cli/history-checks.js.map +1 -0
- package/dist/cli/install/completions.d.ts +19 -0
- package/dist/cli/install/completions.js +94 -0
- package/dist/cli/install/completions.js.map +1 -0
- package/dist/cli/install/hook.d.ts +20 -0
- package/dist/cli/install/hook.js +78 -0
- package/dist/cli/install/hook.js.map +1 -0
- package/dist/cli/main.d.ts +14 -0
- package/dist/cli/main.js +88 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +23 -0
- package/dist/cli/program.js +204 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/prompt.d.ts +22 -0
- package/dist/cli/prompt.js +51 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/render/colors.d.ts +13 -0
- package/dist/cli/render/colors.js +19 -0
- package/dist/cli/render/colors.js.map +1 -0
- package/dist/cli/render/detail.d.ts +10 -0
- package/dist/cli/render/detail.js +105 -0
- package/dist/cli/render/detail.js.map +1 -0
- package/dist/cli/render/table.d.ts +19 -0
- package/dist/cli/render/table.js +58 -0
- package/dist/cli/render/table.js.map +1 -0
- package/dist/cli/resolve.d.ts +17 -0
- package/dist/cli/resolve.js +68 -0
- package/dist/cli/resolve.js.map +1 -0
- package/dist/cli/workspace.d.ts +52 -0
- package/dist/cli/workspace.js +178 -0
- package/dist/cli/workspace.js.map +1 -0
- package/dist/core/comments.d.ts +31 -0
- package/dist/core/comments.js +80 -0
- package/dist/core/comments.js.map +1 -0
- package/dist/core/files.d.ts +88 -0
- package/dist/core/files.js +441 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/frontmatter.d.ts +63 -0
- package/dist/core/frontmatter.js +149 -0
- package/dist/core/frontmatter.js.map +1 -0
- package/dist/core/id.d.ts +46 -0
- package/dist/core/id.js +66 -0
- package/dist/core/id.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +20 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/json.d.ts +18 -0
- package/dist/core/json.js +51 -0
- package/dist/core/json.js.map +1 -0
- package/dist/core/ops.d.ts +92 -0
- package/dist/core/ops.js +173 -0
- package/dist/core/ops.js.map +1 -0
- package/dist/core/person.d.ts +20 -0
- package/dist/core/person.js +50 -0
- package/dist/core/person.js.map +1 -0
- package/dist/core/query.d.ts +30 -0
- package/dist/core/query.js +106 -0
- package/dist/core/query.js.map +1 -0
- package/dist/core/refs.d.ts +12 -0
- package/dist/core/refs.js +36 -0
- package/dist/core/refs.js.map +1 -0
- package/dist/core/slug.d.ts +22 -0
- package/dist/core/slug.js +40 -0
- package/dist/core/slug.js.map +1 -0
- package/dist/core/time.d.ts +14 -0
- package/dist/core/time.js +37 -0
- package/dist/core/time.js.map +1 -0
- package/dist/core/tree.d.ts +94 -0
- package/dist/core/tree.js +237 -0
- package/dist/core/tree.js.map +1 -0
- package/dist/core/validate.d.ts +55 -0
- package/dist/core/validate.js +312 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/git/config.d.ts +12 -0
- package/dist/git/config.js +27 -0
- package/dist/git/config.js.map +1 -0
- package/dist/git/exec.d.ts +35 -0
- package/dist/git/exec.js +58 -0
- package/dist/git/exec.js.map +1 -0
- package/dist/git/history.d.ts +35 -0
- package/dist/git/history.js +82 -0
- package/dist/git/history.js.map +1 -0
- package/dist/git/index-ops.d.ts +20 -0
- package/dist/git/index-ops.js +45 -0
- package/dist/git/index-ops.js.map +1 -0
- package/dist/git/merge.d.ts +27 -0
- package/dist/git/merge.js +57 -0
- package/dist/git/merge.js.map +1 -0
- package/dist/git/refscan.d.ts +32 -0
- package/dist/git/refscan.js +82 -0
- package/dist/git/refscan.js.map +1 -0
- package/dist/git/repo.d.ts +45 -0
- package/dist/git/repo.js +95 -0
- package/dist/git/repo.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Navbook contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Navbook
|
|
2
|
+
|
|
3
|
+
_A lightweight software project manager that lives inside your git repo._
|
|
4
|
+
|
|
5
|
+
Navbook stores every issue and pull request as plaintext files inside the
|
|
6
|
+
repository, on the same branch and history as the code they describe. There is
|
|
7
|
+
no server, no database, and no hidden ref namespace. If you can clone the
|
|
8
|
+
repository, you have the whole tracker.
|
|
9
|
+
|
|
10
|
+
This is meant to replace your code forge's issues with a portable,
|
|
11
|
+
decentralised, offline-first solution. Is GitHub down? No big deal — you'll push
|
|
12
|
+
your comment to `origin` whenever it's available again.
|
|
13
|
+
|
|
14
|
+
```console
|
|
15
|
+
$ nav issue open "Login times out on slow connections" --label bug -m "Aborts after 5 s on 3G."
|
|
16
|
+
Created .navbook/issues/open/bqlybac0-login-timeout/ (#bqlybac0)
|
|
17
|
+
|
|
18
|
+
$ nav issue list
|
|
19
|
+
ID STATUS TITLE LABELS
|
|
20
|
+
#bqlybac0 open Login times out on slow connections bug
|
|
21
|
+
|
|
22
|
+
$ nav issue close bqly --resolution fixed --commit
|
|
23
|
+
Closed #bqlybac0 .navbook/issues/closed/bqlybac0-login-timeout/
|
|
24
|
+
Committed docs(issue): close #bqlybac0
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That last command moved a directory and made a commit. On the branch that fixes
|
|
28
|
+
the bug, the fix and the close travel together — merging the branch merges both.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Requires Node 24 or newer and a working `git`.
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install -g @navbook/cli # or: npx @navbook/cli <command>
|
|
36
|
+
cd your-repo
|
|
37
|
+
nav init
|
|
38
|
+
nav install # git alias, merge config, pre-commit hook, completions
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`nav install` prints every change it is about to make and asks before making
|
|
42
|
+
it, `apt`-style. `-y` skips the question; `nav uninstall` removes exactly what
|
|
43
|
+
it added.
|
|
44
|
+
|
|
45
|
+
The one setting worth knowing about is `merge.directoryRenames=true`, which
|
|
46
|
+
`nav install` offers. Without it, the most common concurrent pair in Navbook — a
|
|
47
|
+
comment racing a close — is placed correctly by git but still reported as a
|
|
48
|
+
conflict to confirm. With it, that merge is clean.
|
|
49
|
+
|
|
50
|
+
## What it looks like on disk
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
.navbook/
|
|
54
|
+
├── issues/
|
|
55
|
+
│ ├── open/
|
|
56
|
+
│ │ └── bqlybac0-login-timeout/
|
|
57
|
+
│ │ ├── issue.md
|
|
58
|
+
│ │ └── comments/
|
|
59
|
+
│ │ └── 2026-08-03T141207Z-t5kr1gq6.md
|
|
60
|
+
│ └── closed/
|
|
61
|
+
└── prs/
|
|
62
|
+
├── open/
|
|
63
|
+
├── merged/
|
|
64
|
+
└── closed/
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
An issue is a Markdown file with YAML frontmatter. Its status is which directory
|
|
68
|
+
it sits in. A comment is one file, which is why two people commenting at once
|
|
69
|
+
can never conflict. Every forge file browser, every editor, `ls` and `cat` are
|
|
70
|
+
complete Navbook clients for reading.
|
|
71
|
+
|
|
72
|
+
**The files are the product.** The `nav` CLI mints IDs, renders listings and
|
|
73
|
+
validates the tree, but nothing requires it: creating, commenting on, closing
|
|
74
|
+
and reviewing with a text editor and `git` is a first-class, supported workflow.
|
|
75
|
+
No operation exists that only the tool can perform correctly.
|
|
76
|
+
|
|
77
|
+
## Commands
|
|
78
|
+
|
|
79
|
+
Everything is noun-verb, with one verb vocabulary shared by both entity kinds.
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
nav {issue|pr} {open|list|show|edit|comment|close|reopen}
|
|
83
|
+
nav pr {update|review|merge}
|
|
84
|
+
nav {init|id|doctor|install|uninstall}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
IDs accept any unambiguous prefix of four characters or more, so `bqly` is
|
|
88
|
+
usually enough. A full directory name works too.
|
|
89
|
+
|
|
90
|
+
| Command | What it does |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `nav issue open <title>` | File an issue. `-m TEXT`, or `$EDITOR` opens on the new file. |
|
|
93
|
+
| `nav issue list [query]` | Filtered table; `--json` for one JSON object per line. |
|
|
94
|
+
| `nav issue close <id> [--resolution R]` | Move it to `closed/`. |
|
|
95
|
+
| `nav pr open [--target BRANCH]` | Open a PR from the current branch, pinning the exact head and merge base under review. |
|
|
96
|
+
| `nav pr review <id> --approve` | Record a verdict bound to a specific revision. |
|
|
97
|
+
| `nav pr list --all-refs` | Find PRs on branches you have fetched but not checked out. |
|
|
98
|
+
| `nav pr merge <id>` | Merge into the checked-out target, archiving the discussion into its history. |
|
|
99
|
+
| `nav doctor [--fix]` | Check the tree against the specification. |
|
|
100
|
+
|
|
101
|
+
`--commit` on any mutating command wraps the change in a well-formed
|
|
102
|
+
Conventional Commits `docs` commit (`docs(issue): close #bqlybac0`,
|
|
103
|
+
`docs(pr): merge #dk3mp2x9`). Without it, changes are left staged for your own
|
|
104
|
+
commit.
|
|
105
|
+
|
|
106
|
+
### Query syntax
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
nav issue list status:closed label:bug assignee:example.com "timeout"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`status:`, `label:`, `assignee:`, `author:`, `milestone:`, and bare words that
|
|
113
|
+
match the title, description or any comment body. Terms AND together; the
|
|
114
|
+
default query is `status:open`.
|
|
115
|
+
|
|
116
|
+
## Why the design is what it is
|
|
117
|
+
|
|
118
|
+
Three properties drive everything else:
|
|
119
|
+
|
|
120
|
+
- **Browsable.** The tracker renders on any forge with no plugin, because it is
|
|
121
|
+
just Markdown in human-named directories.
|
|
122
|
+
- **Same history as the code.** `git log`, `git blame` and `git bisect` work on
|
|
123
|
+
tracker state exactly as they do on code. A release tag captures what the
|
|
124
|
+
tracker said at that moment.
|
|
125
|
+
- **No coordination.** IDs are 8 random characters, not sequential numbers —
|
|
126
|
+
the single most repeated mistake in this problem space. Two people can file
|
|
127
|
+
issues offline, on different branches, and never collide.
|
|
128
|
+
|
|
129
|
+
Pull requests live on the branch they propose to merge, so opening one needs no
|
|
130
|
+
server and works offline. Merging carries the whole discussion into the target
|
|
131
|
+
branch's permanent history. Approvals are bound to the exact revision they
|
|
132
|
+
judged, so a force-push can never inherit a stale approval.
|
|
133
|
+
|
|
134
|
+
## Platforms
|
|
135
|
+
|
|
136
|
+
Developed and tested on Linux and macOS. Windows is not guaranteed; use
|
|
137
|
+
[Git Bash](https://gitforwindows.org/) or WSL, where Navbook works because both
|
|
138
|
+
provide the POSIX shell the hooks and completions expect.
|
|
139
|
+
|
|
140
|
+
## Documentation
|
|
141
|
+
|
|
142
|
+
The [specification](doc/spec/README.md) is the normative definition of the file
|
|
143
|
+
format and the reference for anyone writing another implementation. Start with
|
|
144
|
+
[01-functionality.md](doc/spec/01-functionality.md) for what Navbook does, or
|
|
145
|
+
[02-data-model.md](doc/spec/02-data-model.md) for the exact file format.
|
|
146
|
+
|
|
147
|
+
## Contributing
|
|
148
|
+
|
|
149
|
+
Navbook tracks its own development in `.navbook/` — run `nav issue list` in a
|
|
150
|
+
clone to see what is open.
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
npm install
|
|
154
|
+
npm test # unit, CLI and conformance suites
|
|
155
|
+
npm run check # lint and type-check
|
|
156
|
+
npm run bench # the performance budget, on its own machine
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The [conformance fixtures](doc/spec/fixtures/README.md) are golden repositories
|
|
160
|
+
that any implementation must pass; they run against `$NAV_BIN`, so the same
|
|
161
|
+
suite validates the planned Rust rewrite.
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nav __complete` — the completion backend the shell scripts call.
|
|
3
|
+
*
|
|
4
|
+
* Given the words typed so far (without the leading `nav`), it prints one
|
|
5
|
+
* candidate per line. Keeping the logic here rather than in three shell
|
|
6
|
+
* dialects is what makes ID and slug completion possible at all.
|
|
7
|
+
*/
|
|
8
|
+
import type { Ctx } from "../context.ts";
|
|
9
|
+
export declare function cmdComplete(ctx: Ctx, words: string[]): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nav __complete` — the completion backend the shell scripts call.
|
|
3
|
+
*
|
|
4
|
+
* Given the words typed so far (without the leading `nav`), it prints one
|
|
5
|
+
* candidate per line. Keeping the logic here rather than in three shell
|
|
6
|
+
* dialects is what makes ID and slug completion possible at all.
|
|
7
|
+
*/
|
|
8
|
+
import { allEntities } from "../../core/tree.js";
|
|
9
|
+
import { loadRepo } from "../workspace.js";
|
|
10
|
+
const ROOT_COMMANDS = ["issue", "pr", "init", "id", "doctor", "install", "uninstall", "help"];
|
|
11
|
+
const SHARED_VERBS = ["open", "list", "show", "edit", "comment", "close", "reopen"];
|
|
12
|
+
const PR_VERBS = [...SHARED_VERBS, "update", "review", "merge"];
|
|
13
|
+
const QUERY_KEYS = ["status:", "label:", "assignee:", "author:", "milestone:"];
|
|
14
|
+
export function cmdComplete(ctx, words) {
|
|
15
|
+
for (const candidate of completionsFor(ctx, words))
|
|
16
|
+
ctx.stdout.write(`${candidate}\n`);
|
|
17
|
+
}
|
|
18
|
+
function completionsFor(ctx, words) {
|
|
19
|
+
const [noun, verb] = words;
|
|
20
|
+
if (noun === undefined)
|
|
21
|
+
return ROOT_COMMANDS;
|
|
22
|
+
if (noun !== "issue" && noun !== "pr") {
|
|
23
|
+
return words.length === 1 ? ROOT_COMMANDS : [];
|
|
24
|
+
}
|
|
25
|
+
const kind = noun === "issue" ? "issue" : "pr";
|
|
26
|
+
const verbs = kind === "issue" ? SHARED_VERBS : PR_VERBS;
|
|
27
|
+
if (verb === undefined)
|
|
28
|
+
return verbs;
|
|
29
|
+
if (!verbs.includes(verb))
|
|
30
|
+
return [];
|
|
31
|
+
if (verb === "list")
|
|
32
|
+
return [...QUERY_KEYS, ...labels(ctx)];
|
|
33
|
+
if (verb === "open")
|
|
34
|
+
return [];
|
|
35
|
+
// Every other verb takes an ID as its first argument.
|
|
36
|
+
return words.length === 2 ? entityCandidates(ctx, kind) : [];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Bare IDs and full directory names, so a user can complete either the short
|
|
40
|
+
* form they would type or the readable name they would recognize.
|
|
41
|
+
*/
|
|
42
|
+
function entityCandidates(ctx, kind) {
|
|
43
|
+
try {
|
|
44
|
+
const repo = loadRepo(ctx, { includeComments: false });
|
|
45
|
+
return allEntities(repo)
|
|
46
|
+
.filter((entity) => entity.kind === kind)
|
|
47
|
+
.flatMap((entity) => [entity.id, entity.dirName])
|
|
48
|
+
.sort();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function labels(ctx) {
|
|
55
|
+
try {
|
|
56
|
+
const repo = loadRepo(ctx, { includeComments: false });
|
|
57
|
+
const found = new Set();
|
|
58
|
+
for (const entity of allEntities(repo)) {
|
|
59
|
+
const values = entity.fm.labels;
|
|
60
|
+
if (!Array.isArray(values))
|
|
61
|
+
continue;
|
|
62
|
+
for (const value of values)
|
|
63
|
+
if (typeof value === "string")
|
|
64
|
+
found.add(`label:${value}`);
|
|
65
|
+
}
|
|
66
|
+
return [...found].sort();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=complete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../src/cli/commands/complete.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producing the text of a new Navbook file, from `-m` or from `$EDITOR`.
|
|
3
|
+
*
|
|
4
|
+
* Both paths end in the same place: a complete file that has been parsed and
|
|
5
|
+
* validated before anything is written into `.navbook/`. The editor buffer is
|
|
6
|
+
* the whole file — frontmatter included — so an author can set the title,
|
|
7
|
+
* labels and body in one pass, and an abort leaves nothing behind.
|
|
8
|
+
*/
|
|
9
|
+
import { type ParsedFile, type Problem } from "../../core/files.ts";
|
|
10
|
+
import type { Ctx } from "../context.ts";
|
|
11
|
+
export interface ComposeOptions {
|
|
12
|
+
/** Text supplied with `-m`; when absent the editor is opened. */
|
|
13
|
+
message?: string;
|
|
14
|
+
/** Name of the scratch buffer inside the git directory. */
|
|
15
|
+
bufferName: string;
|
|
16
|
+
/** Render the complete file from a body. */
|
|
17
|
+
render: (body: string) => string;
|
|
18
|
+
/** Schema check applied to the finished file. */
|
|
19
|
+
validate: (parsed: ParsedFile) => Problem[];
|
|
20
|
+
/** Noun used in error messages, e.g. "issue" or "comment". */
|
|
21
|
+
noun: string;
|
|
22
|
+
}
|
|
23
|
+
export interface Composed {
|
|
24
|
+
content: string;
|
|
25
|
+
parsed: ParsedFile;
|
|
26
|
+
}
|
|
27
|
+
export declare function composeFile(ctx: Ctx, opts: ComposeOptions): Composed;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producing the text of a new Navbook file, from `-m` or from `$EDITOR`.
|
|
3
|
+
*
|
|
4
|
+
* Both paths end in the same place: a complete file that has been parsed and
|
|
5
|
+
* validated before anything is written into `.navbook/`. The editor buffer is
|
|
6
|
+
* the whole file — frontmatter included — so an author can set the title,
|
|
7
|
+
* labels and body in one pass, and an abort leaves nothing behind.
|
|
8
|
+
*/
|
|
9
|
+
import { parseFile } from "../../core/files.js";
|
|
10
|
+
import { editBuffer } from "../editor.js";
|
|
11
|
+
import { fail } from "../errors.js";
|
|
12
|
+
export function composeFile(ctx, opts) {
|
|
13
|
+
if (opts.message !== undefined) {
|
|
14
|
+
if (opts.message.trim() === "")
|
|
15
|
+
fail(`empty ${opts.noun} text; aborting`);
|
|
16
|
+
return check(opts, opts.render(opts.message));
|
|
17
|
+
}
|
|
18
|
+
const edited = editBuffer(ctx, opts.bufferName, opts.render(""));
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = parseFile(edited);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
fail(`aborting: ${error instanceof Error ? error.message : String(error)}`);
|
|
25
|
+
}
|
|
26
|
+
if (parsed.body.trim() === "")
|
|
27
|
+
fail(`aborting ${opts.noun} due to empty body`);
|
|
28
|
+
return check(opts, edited);
|
|
29
|
+
}
|
|
30
|
+
function check(opts, content) {
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = parseFile(content);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
fail(`aborting: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
}
|
|
38
|
+
const problems = opts.validate(parsed);
|
|
39
|
+
if (problems.length > 0) {
|
|
40
|
+
fail(`the ${opts.noun} is not valid and was not created`, problems.map((problem) => ` ${problem.message}`));
|
|
41
|
+
}
|
|
42
|
+
return { content, parsed };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../src/cli/commands/compose.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAiC,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAoBpC,MAAM,UAAU,WAAW,CAAC,GAAQ,EAAE,IAAoB;IACxD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,iBAAiB,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,aAAa,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,oBAAoB,CAAC,CAAC;IAC/E,OAAO,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,IAAoB,EAAE,OAAe;IAClD,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,aAAa,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,CACF,OAAO,IAAI,CAAC,IAAI,mCAAmC,EACnD,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAClD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nav doctor` — spec 04 §4.3.
|
|
3
|
+
*
|
|
4
|
+
* Doctor enforces the specification, not a house style: hand edits that are
|
|
5
|
+
* unusual but valid must pass. Errors (exit 2) are format violations; warnings
|
|
6
|
+
* (exit 0) are things worth a look that may be perfectly deliberate.
|
|
7
|
+
*/
|
|
8
|
+
import type { Ctx } from "../context.ts";
|
|
9
|
+
export interface DoctorOptions {
|
|
10
|
+
staged?: boolean;
|
|
11
|
+
fix?: boolean;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function cmdDoctor(ctx: Ctx, opts: DoctorOptions): void;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nav doctor` — spec 04 §4.3.
|
|
3
|
+
*
|
|
4
|
+
* Doctor enforces the specification, not a house style: hand edits that are
|
|
5
|
+
* unusual but valid must pass. Errors (exit 2) are format violations; warnings
|
|
6
|
+
* (exit 0) are things worth a look that may be perfectly deliberate.
|
|
7
|
+
*/
|
|
8
|
+
import { NAVBOOK_ROOT } from "../../core/json.js";
|
|
9
|
+
import { parseTree } from "../../core/tree.js";
|
|
10
|
+
import { hasErrors, sortDiagnostics, validateRepo } from "../../core/validate.js";
|
|
11
|
+
import { git, gitMaybe, splitNul } from "../../git/exec.js";
|
|
12
|
+
import { stagedContent, stagedPaths } from "../../git/index-ops.js";
|
|
13
|
+
import { NavError } from "../errors.js";
|
|
14
|
+
import { runHistoryChecks } from "../history-checks.js";
|
|
15
|
+
import { applyOps, loadRepo, repoPath, requireNavbook } from "../workspace.js";
|
|
16
|
+
export function cmdDoctor(ctx, opts) {
|
|
17
|
+
requireNavbook(ctx);
|
|
18
|
+
const repo = opts.staged ? stagedRepo(ctx) : loadRepo(ctx);
|
|
19
|
+
const diagnostics = sortDiagnostics([
|
|
20
|
+
...validateRepo(repo, { commitMessages: recentCommitMessages(ctx, opts) }),
|
|
21
|
+
// History-dependent checks are skipped for --staged: the commit being made
|
|
22
|
+
// does not exist yet, so there is nothing for them to read.
|
|
23
|
+
...(opts.staged ? [] : runHistoryChecks(ctx, repo)),
|
|
24
|
+
]);
|
|
25
|
+
const applied = opts.fix ? applyFixes(ctx, diagnostics) : [];
|
|
26
|
+
const remaining = opts.fix ? diagnostics.filter((d) => !d.fix) : diagnostics;
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
for (const diagnostic of remaining) {
|
|
29
|
+
ctx.stdout.write(`${JSON.stringify(toJson(diagnostic))}\n`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
report(ctx, remaining, applied);
|
|
34
|
+
}
|
|
35
|
+
if (hasErrors(remaining)) {
|
|
36
|
+
throw new NavError(`${countErrors(remaining)} format violation(s) found`, { exitCode: 2 });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function toJson(diagnostic) {
|
|
40
|
+
return {
|
|
41
|
+
check: diagnostic.check,
|
|
42
|
+
level: diagnostic.level,
|
|
43
|
+
path: diagnostic.path === "" ? "" : `${NAVBOOK_ROOT}/${diagnostic.path}`,
|
|
44
|
+
message: diagnostic.message,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function report(ctx, diagnostics, applied) {
|
|
48
|
+
const c = ctx.colors;
|
|
49
|
+
for (const line of applied)
|
|
50
|
+
ctx.stdout.write(`${c.green("fixed")} ${line}\n`);
|
|
51
|
+
for (const diagnostic of diagnostics) {
|
|
52
|
+
const level = diagnostic.level === "error" ? c.red("error") : c.yellow("warning");
|
|
53
|
+
const where = diagnostic.path === "" ? "" : `${NAVBOOK_ROOT}/${diagnostic.path}: `;
|
|
54
|
+
ctx.stdout.write(`${level} ${c.dim(diagnostic.check)} ${where}${diagnostic.message}\n`);
|
|
55
|
+
}
|
|
56
|
+
const errors = countErrors(diagnostics);
|
|
57
|
+
const warnings = diagnostics.length - errors;
|
|
58
|
+
if (errors === 0 && warnings === 0) {
|
|
59
|
+
ctx.stdout.write(applied.length > 0 ? "No problems remain.\n" : "No problems found.\n");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
ctx.stdout.write(`${plural(errors, "error")}, ${plural(warnings, "warning")}\n`);
|
|
63
|
+
}
|
|
64
|
+
function plural(count, noun) {
|
|
65
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
66
|
+
}
|
|
67
|
+
function countErrors(diagnostics) {
|
|
68
|
+
return diagnostics.filter((d) => d.level === "error").length;
|
|
69
|
+
}
|
|
70
|
+
/** Apply every mechanical repair a diagnostic offers, reporting each one. */
|
|
71
|
+
function applyFixes(ctx, diagnostics) {
|
|
72
|
+
const applied = [];
|
|
73
|
+
for (const diagnostic of diagnostics) {
|
|
74
|
+
if (!diagnostic.fix || diagnostic.fix.length === 0)
|
|
75
|
+
continue;
|
|
76
|
+
applyOps(ctx, diagnostic.fix);
|
|
77
|
+
for (const op of diagnostic.fix)
|
|
78
|
+
applied.push(describeFix(op));
|
|
79
|
+
}
|
|
80
|
+
return applied;
|
|
81
|
+
}
|
|
82
|
+
function describeFix(op) {
|
|
83
|
+
return op.op === "move"
|
|
84
|
+
? `moved ${repoPath(op.from)} to ${repoPath(op.to)}`
|
|
85
|
+
: `wrote ${repoPath(op.path)}`;
|
|
86
|
+
}
|
|
87
|
+
/** Build the repository model from what is staged rather than the working tree. */
|
|
88
|
+
function stagedRepo(ctx) {
|
|
89
|
+
const prefix = `${NAVBOOK_ROOT}/`;
|
|
90
|
+
const paths = allIndexedNavPaths(ctx).filter((path) => path.startsWith(prefix));
|
|
91
|
+
const files = new Map();
|
|
92
|
+
for (const path of paths) {
|
|
93
|
+
const content = stagedContent(ctx.repoRoot, path);
|
|
94
|
+
if (content !== null)
|
|
95
|
+
files.set(path.slice(prefix.length), content);
|
|
96
|
+
}
|
|
97
|
+
return parseTree(files);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Every `.navbook/` path in the index. The pre-commit hook needs the whole
|
|
101
|
+
* indexed tree, not only the changed paths: checks like ID uniqueness and
|
|
102
|
+
* reply-to resolution are properties of the tree the commit will create.
|
|
103
|
+
*/
|
|
104
|
+
function allIndexedNavPaths(ctx) {
|
|
105
|
+
const listed = splitNul(git(["ls-files", "--cached", "-z", "--", NAVBOOK_ROOT], { cwd: ctx.repoRoot }));
|
|
106
|
+
return listed.length > 0 ? listed : stagedPaths(ctx.repoRoot);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Commit messages scanned for dangling trailers (check D8).
|
|
110
|
+
*
|
|
111
|
+
* Bounded to recent history: a trailer naming an entity that is not in this
|
|
112
|
+
* tree is worth knowing about while the work is current, but the whole history
|
|
113
|
+
* of a long-lived repository would produce standing noise for entities that
|
|
114
|
+
* were legitimately archived or that live on a branch nobody has fetched.
|
|
115
|
+
*/
|
|
116
|
+
const TRAILER_SCAN_DEPTH = 100;
|
|
117
|
+
function recentCommitMessages(ctx, opts) {
|
|
118
|
+
if (opts.staged)
|
|
119
|
+
return [];
|
|
120
|
+
const output = gitMaybe(["log", "--format=%B%x00", "-n", String(TRAILER_SCAN_DEPTH)], {
|
|
121
|
+
cwd: ctx.repoRoot,
|
|
122
|
+
});
|
|
123
|
+
if (output === null)
|
|
124
|
+
return [];
|
|
125
|
+
return output.split("\0").filter((message) => message.trim() !== "");
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verbs issues and pull requests share — spec 04 §4.3.
|
|
3
|
+
*
|
|
4
|
+
* One implementation serves both nouns; the entity kind only selects which
|
|
5
|
+
* collection is searched, which file name is edited, and which words appear in
|
|
6
|
+
* the report.
|
|
7
|
+
*/
|
|
8
|
+
import { type NewCommentInput } from "../../core/files.ts";
|
|
9
|
+
import { type CloseInput, type Plan } from "../../core/ops.ts";
|
|
10
|
+
import { type Query } from "../../core/query.ts";
|
|
11
|
+
import type { EntityKind, EntityRecord, Repo } from "../../core/tree.ts";
|
|
12
|
+
import type { Ctx } from "../context.ts";
|
|
13
|
+
export interface GlobalFlags {
|
|
14
|
+
json?: boolean;
|
|
15
|
+
commit?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Author string for the current git identity. */
|
|
18
|
+
export declare function currentAuthor(ctx: Ctx): string;
|
|
19
|
+
/** Entities of one kind from a parsed repository. */
|
|
20
|
+
export declare function selectEntities(repo: Repo, kind: EntityKind): EntityRecord[];
|
|
21
|
+
/** Newest first, with a stable tie-break on ID. */
|
|
22
|
+
export declare function sortEntities(entities: readonly EntityRecord[]): EntityRecord[];
|
|
23
|
+
export interface ExtraColumn {
|
|
24
|
+
header: string;
|
|
25
|
+
value: (entity: EntityRecord) => string;
|
|
26
|
+
}
|
|
27
|
+
export interface ListOptions extends GlobalFlags {
|
|
28
|
+
/** Columns appended by PR-specific listings. */
|
|
29
|
+
extraColumns?: ExtraColumn[];
|
|
30
|
+
/** Pre-collected entities, used by `nav pr list --all-refs`. */
|
|
31
|
+
entities?: EntityRecord[];
|
|
32
|
+
/** Extra JSON keys per entity, keyed by entity identity. */
|
|
33
|
+
jsonExtra?: (entity: EntityRecord) => Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export declare function cmdList(ctx: Ctx, kind: EntityKind, terms: string[], opts: ListOptions): void;
|
|
36
|
+
/** The query a listing will run, for callers that need it before loading. */
|
|
37
|
+
export declare function parseListQuery(terms: string[], kind: EntityKind): Query;
|
|
38
|
+
export declare function cmdShow(ctx: Ctx, kind: EntityKind, prefix: string, opts: GlobalFlags): void;
|
|
39
|
+
export declare function cmdEdit(ctx: Ctx, kind: EntityKind, prefix: string, opts: GlobalFlags): void;
|
|
40
|
+
export interface CommentOptions extends GlobalFlags {
|
|
41
|
+
message?: string;
|
|
42
|
+
replyTo?: string;
|
|
43
|
+
/** Review fields, supplied by `nav pr review`. */
|
|
44
|
+
review?: Pick<NewCommentInput, "verdict" | "revision" | "file" | "line">;
|
|
45
|
+
}
|
|
46
|
+
export declare function cmdComment(ctx: Ctx, kind: EntityKind, prefix: string, opts: CommentOptions): void;
|
|
47
|
+
export interface CloseOptions extends GlobalFlags, CloseInput {
|
|
48
|
+
}
|
|
49
|
+
export declare function cmdClose(ctx: Ctx, kind: EntityKind, prefix: string, opts: CloseOptions): void;
|
|
50
|
+
export declare function cmdReopen(ctx: Ctx, kind: EntityKind, prefix: string, opts: GlobalFlags): void;
|
|
51
|
+
/**
|
|
52
|
+
* Build a plan that rewrites an entity file, turning a malformed-frontmatter
|
|
53
|
+
* failure into an operational error that names the file and the way out.
|
|
54
|
+
*/
|
|
55
|
+
export declare function rewritePlan(entity: EntityRecord, build: () => Plan): Plan;
|