@ree-auz/nook 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +421 -2
- package/bin/nk.mjs +4 -0
- package/docs/setup-hooks.md +107 -0
- package/integrations/linear/README.md +84 -0
- package/integrations/linear/coding-tools.json +7 -0
- package/integrations/linear/open-issue.mjs +147 -0
- package/package.json +32 -4
- package/skills/nook/SKILL.md +71 -0
- package/src/agents.mjs +92 -0
- package/src/backup.mjs +74 -0
- package/src/ci.mjs +378 -0
- package/src/cli.mjs +151 -0
- package/src/commands/check-hooks.mjs +128 -0
- package/src/commands/clean.mjs +175 -0
- package/src/commands/doctor.mjs +100 -0
- package/src/commands/forget.mjs +57 -0
- package/src/commands/hooks.mjs +34 -0
- package/src/commands/init.mjs +154 -0
- package/src/commands/ls.mjs +107 -0
- package/src/commands/rm.mjs +190 -0
- package/src/commands/workspace.mjs +163 -0
- package/src/commands/write-hooks.mjs +185 -0
- package/src/compose-plan.mjs +228 -0
- package/src/compose.mjs +123 -0
- package/src/config.mjs +115 -0
- package/src/context.mjs +189 -0
- package/src/errors.mjs +8 -0
- package/src/forge.mjs +75 -0
- package/src/generate-hooks.mjs +367 -0
- package/src/git.mjs +86 -0
- package/src/home.mjs +48 -0
- package/src/hooks.mjs +135 -0
- package/src/names.mjs +65 -0
- package/src/occupancy-windows.ps1 +59 -0
- package/src/occupancy.mjs +131 -0
- package/src/ports.mjs +89 -0
- package/src/prompt.mjs +100 -0
- package/src/shared.mjs +97 -0
- package/src/status.mjs +30 -0
- package/src/tools.mjs +23 -0
- package/src/ui.mjs +60 -0
package/src/status.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { exists } from "./home.mjs";
|
|
2
|
+
import { gitTry, refExists } from "./git.mjs";
|
|
3
|
+
|
|
4
|
+
/** Uncommitted changes, or null when the folder is missing or not readable. */
|
|
5
|
+
export function changeCount(path) {
|
|
6
|
+
if (!exists(path)) return null;
|
|
7
|
+
const status = gitTry(["status", "--porcelain", "--untracked-files=normal"], { cwd: path });
|
|
8
|
+
if (!status.ok) return null;
|
|
9
|
+
return status.out ? status.out.split(/\r?\n/).length : 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Commits the branch has that `base` lacks (ahead), and the reverse (behind). */
|
|
13
|
+
export function aheadBehind(repo, branch, base) {
|
|
14
|
+
if (!refExists(repo, `refs/heads/${branch}`)) return null;
|
|
15
|
+
const result = gitTry(["rev-list", "--left-right", "--count", `${base}...refs/heads/${branch}`], { cwd: repo });
|
|
16
|
+
if (!result.ok) return null;
|
|
17
|
+
const [behind, ahead] = result.out.split(/\s+/).map(Number);
|
|
18
|
+
return { ahead, behind };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function branchTip(repo, branch) {
|
|
22
|
+
const result = gitTry(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], { cwd: repo });
|
|
23
|
+
return result.ok ? result.out : null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** True when `commit` is `other` or one of its ancestors (false when either is unknown). */
|
|
27
|
+
export function contains(repo, other, commit) {
|
|
28
|
+
if (commit === other) return true;
|
|
29
|
+
return gitTry(["merge-base", "--is-ancestor", commit, other], { cwd: repo }).ok;
|
|
30
|
+
}
|
package/src/tools.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import spawn from "cross-spawn";
|
|
2
|
+
import { which } from "./agents.mjs";
|
|
3
|
+
|
|
4
|
+
function run(command, args) {
|
|
5
|
+
const result = spawn.sync(command, args, { encoding: "utf8", timeout: 15000, windowsHide: true });
|
|
6
|
+
return { ok: !result.error && result.status === 0, out: `${result.stdout ?? ""}${result.stderr ?? ""}`.trim() };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** gh and docker are optional helpers; this only reports their state. */
|
|
10
|
+
export function toolStatus(env = process.env) {
|
|
11
|
+
const status = {};
|
|
12
|
+
const gh = which("gh", env);
|
|
13
|
+
status.gh = !gh ? "not installed" : run(gh, ["auth", "status"]).ok ? "logged in" : "not logged in";
|
|
14
|
+
const docker = which("docker", env);
|
|
15
|
+
status.docker = !docker ? "not installed" : run(docker, ["info", "--format", "{{.ServerVersion}}"]).ok ? "running" : "not running";
|
|
16
|
+
return status;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function gitVersion() {
|
|
20
|
+
const result = run("git", ["--version"]);
|
|
21
|
+
const match = /(\d+)\.(\d+)/.exec(result.out);
|
|
22
|
+
return result.ok && match ? { text: result.out, major: Number(match[1]), minor: Number(match[2]) } : null;
|
|
23
|
+
}
|
package/src/ui.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line prefixes in the style of worktrunk: ◎ a step that runs now, ✓ done,
|
|
3
|
+
* ▲ needs attention, ✗ failed, ○ information, ┃ an item under the line above,
|
|
4
|
+
* ? a question.
|
|
5
|
+
* Colors only on a terminal, and never when NO_COLOR is set (no-color.org).
|
|
6
|
+
*/
|
|
7
|
+
const UNICODE = { step: "◎", ok: "✓", warn: "▲", fail: "✗", info: "○", item: "┃", ask: "?" };
|
|
8
|
+
// Older Windows consoles show ✓ and ✗ as "?"; √ and × exist in their code pages
|
|
9
|
+
// (the same fallbacks as the figures package).
|
|
10
|
+
const FALLBACK = { ...UNICODE, ok: "√", fail: "×" };
|
|
11
|
+
const COLORS = { step: 36, ok: 32, warn: 33, fail: 31, info: 2, item: 2, ask: 35 };
|
|
12
|
+
|
|
13
|
+
/** The checks of the is-unicode-supported package, plus Warp. */
|
|
14
|
+
export function unicodeSupported(env = process.env, platform = process.platform) {
|
|
15
|
+
if (platform !== "win32") return env.TERM !== "linux";
|
|
16
|
+
return (
|
|
17
|
+
Boolean(env.WT_SESSION) ||
|
|
18
|
+
Boolean(env.TERMINUS_SUBLIME) ||
|
|
19
|
+
env.ConEmuTask === "{cmd::Cmder}" ||
|
|
20
|
+
["Terminus-Sublime", "vscode", "WarpTerminal"].includes(env.TERM_PROGRAM) ||
|
|
21
|
+
["xterm-256color", "alacritty", "rxvt-unicode", "rxvt-unicode-256color"].includes(env.TERM) ||
|
|
22
|
+
env.TERMINAL_EMULATOR === "JetBrains-JediTerm"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SYMBOLS = unicodeSupported() ? UNICODE : FALLBACK;
|
|
27
|
+
|
|
28
|
+
export function useColor(stream, env = process.env) {
|
|
29
|
+
return Boolean(stream?.isTTY) && !("NO_COLOR" in env) && env.TERM !== "dumb";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function line(kind, text, color = false) {
|
|
33
|
+
const symbol = SYMBOLS[kind];
|
|
34
|
+
const mark = color ? `\x1b[${COLORS[kind]}m${symbol}\x1b[0m` : symbol;
|
|
35
|
+
return kind === "item" ? ` ${mark} ${text}` : `${mark} ${text}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Indents another program's output by two columns, under the text of the line
|
|
40
|
+
* above it. Docker Compose starts its lines with one space; that space goes.
|
|
41
|
+
* Returns a function that takes chunks and returns them indented.
|
|
42
|
+
*/
|
|
43
|
+
export function indenter(width = 2) {
|
|
44
|
+
const pad = " ".repeat(width);
|
|
45
|
+
let state = "start"; // start of a line, after one leading space, or inside it
|
|
46
|
+
return (chunk) => {
|
|
47
|
+
let out = "";
|
|
48
|
+
for (const char of String(chunk)) {
|
|
49
|
+
const newline = char === "\n" || char === "\r";
|
|
50
|
+
if (state === "mid") out += char;
|
|
51
|
+
else if (newline) out += char;
|
|
52
|
+
else if (state === "start" && char === " ") {
|
|
53
|
+
state = "space";
|
|
54
|
+
continue;
|
|
55
|
+
} else out += pad + (state === "space" && char === " " ? " " : char);
|
|
56
|
+
state = newline ? "start" : "mid";
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
};
|
|
60
|
+
}
|