@ree-auz/nook 0.1.0 → 0.1.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.
Files changed (42) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +422 -410
  3. package/bin/nk.mjs +3 -3
  4. package/docs/setup-hooks.md +107 -107
  5. package/integrations/linear/README.md +94 -84
  6. package/integrations/linear/coding-tools.json +7 -7
  7. package/integrations/linear/open-issue.mjs +193 -147
  8. package/package.json +34 -34
  9. package/skills/nook/SKILL.md +71 -71
  10. package/src/agents.mjs +92 -92
  11. package/src/backup.mjs +74 -74
  12. package/src/ci.mjs +378 -378
  13. package/src/cli.mjs +151 -151
  14. package/src/commands/check-hooks.mjs +128 -128
  15. package/src/commands/clean.mjs +175 -175
  16. package/src/commands/doctor.mjs +100 -91
  17. package/src/commands/forget.mjs +57 -57
  18. package/src/commands/hooks.mjs +34 -27
  19. package/src/commands/init.mjs +154 -154
  20. package/src/commands/ls.mjs +107 -107
  21. package/src/commands/rm.mjs +190 -190
  22. package/src/commands/workspace.mjs +163 -163
  23. package/src/commands/write-hooks.mjs +185 -185
  24. package/src/compose-plan.mjs +228 -228
  25. package/src/compose.mjs +123 -123
  26. package/src/config.mjs +115 -115
  27. package/src/context.mjs +189 -189
  28. package/src/errors.mjs +8 -8
  29. package/src/forge.mjs +75 -75
  30. package/src/generate-hooks.mjs +367 -367
  31. package/src/git.mjs +86 -86
  32. package/src/home.mjs +48 -48
  33. package/src/hooks.mjs +135 -135
  34. package/src/names.mjs +65 -65
  35. package/src/occupancy-windows.ps1 +59 -59
  36. package/src/occupancy.mjs +131 -131
  37. package/src/ports.mjs +89 -45
  38. package/src/prompt.mjs +100 -100
  39. package/src/shared.mjs +97 -97
  40. package/src/status.mjs +30 -30
  41. package/src/tools.mjs +23 -23
  42. package/src/ui.mjs +60 -60
package/bin/nk.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { main } from "../src/cli.mjs";
3
-
4
- process.exitCode = await main(process.argv.slice(2));
2
+ import { main } from "../src/cli.mjs";
3
+
4
+ process.exitCode = await main(process.argv.slice(2));
@@ -1,107 +1,107 @@
1
- # Writing hooks
2
-
3
- `nk hooks write` turns the repository's CI and Compose file into hooks
4
- without AI; the README shows what it takes from each and what it leaves out.
5
- This page is for the parts it cannot translate, and for repositories without
6
- either: what a person or an agent writing hooks by hand has to follow.
7
-
8
- `nk hooks write <agent>` writes the hooks the same way, then starts the agent
9
- in the folder you ran it in (usually the main checkout) with a
10
- prompt that lists what nk generated, what it could not translate, the CI and
11
- setup files, and the shared files with their empty keys (never their values).
12
- The agent finishes the hooks and runs `nk hooks test` until it passes; it
13
- leaves the changes uncommitted for you to review. If a repository's rules keep
14
- agents out of the main checkout, create a workspace first (`nk -b hooks`) and
15
- run the command inside it.
16
-
17
- When you edit a generated hook, delete its first line (`// Generated by nk
18
- hooks write ...`), so `nk hooks write` will not replace it.
19
-
20
- ## Rules for the hooks
21
-
22
- - One `.mjs` file per moment works on Windows, macOS and Linux. Use
23
- `node:child_process` and stop at the first failing command with a non-zero
24
- exit code, so nk does not start an agent on a broken workspace.
25
- - Hooks run inside the workspace with these variables: `NOOK_WORKSPACE`
26
- (name), `NOOK_PATH` (folder), `NOOK_REPO` (main checkout), `NOOK_SHARED`
27
- (shared folder) and `NOOK_PORT` (first of ten ports for this workspace).
28
- - `create` runs once, after shared files such as `.env` are copied. `open`
29
- runs every time the workspace is opened, so it must be safe to run again.
30
- `remove` runs before the folder is deleted; when it fails nothing is deleted.
31
- - `remove` undoes everything `create` did outside the folder: containers,
32
- volumes, networks, built images, databases created in a shared server.
33
- `nk rm` also stops programs in the folder and, as a safety net, removes
34
- Compose projects started in it; do not rely on that.
35
- - Never touch the main checkout or its services: do not read or copy its
36
- `.env`, and do not stop or remove its containers.
37
- - Servers and containers use ports from `NOOK_PORT` to `NOOK_PORT + 9`.
38
- - Do not print secrets. Do not run `docker compose config`: it prints every
39
- value from `.env`.
40
-
41
- ## Examples
42
-
43
- A small helper the examples share:
44
-
45
- ```js
46
- import { spawnSync } from "node:child_process";
47
-
48
- function run(command, ...args) {
49
- // shell: true lets Windows find pnpm.cmd and npm.cmd.
50
- const result = spawnSync([command, ...args].join(" "), { stdio: "inherit", shell: true });
51
- if (result.status !== 0) process.exit(result.status ?? 1);
52
- }
53
- ```
54
-
55
- ### Node (pnpm, npm, yarn, bun)
56
-
57
- Install with the package manager whose lockfile the repository has:
58
- `pnpm-lock.yaml` → `pnpm install`, `package-lock.json` → `npm ci`,
59
- `yarn.lock` → `yarn install`, `bun.lock` → `bun install`.
60
-
61
- ```js
62
- // .nook/create.mjs
63
- run("pnpm", "install");
64
- ```
65
-
66
- ### Python (uv)
67
-
68
- A virtual environment holds absolute paths and cannot be copied from the main
69
- checkout; create it again:
70
-
71
- ```js
72
- // .nook/create.mjs
73
- run("uv", "sync");
74
- ```
75
-
76
- ### Docker Compose
77
-
78
- Give each workspace its own Compose project, so its containers, volumes and
79
- networks never mix with the main checkout's. Compose's own rule for a project
80
- name is lowercase letters, digits, `_` and `-`.
81
-
82
- ```js
83
- // .nook/create.mjs
84
- const project = process.env.NOOK_WORKSPACE.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
85
- const port = Number(process.env.NOOK_PORT);
86
- process.env.DB_PORT = String(port); // whatever the compose file reads
87
- run("docker", "compose", "--project-name", project, "up", "-d", "--wait");
88
- ```
89
-
90
- Write the project name and ports into the workspace `.env` as well
91
- (`COMPOSE_PROJECT_NAME=...`), so a plain `docker compose` typed in the
92
- workspace later finds the same project.
93
-
94
- ```js
95
- // .nook/open.mjs: start the containers again after a restart
96
- run("docker", "compose", "start");
97
- ```
98
-
99
- ```js
100
- // .nook/remove.mjs: everything the project created, volumes and built images too
101
- const project = process.env.NOOK_WORKSPACE.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
102
- run("docker", "compose", "--project-name", project, "down", "--volumes", "--rmi", "local", "--remove-orphans");
103
- ```
104
-
105
- A fuller setup with a database per workspace also refuses the production
106
- project name in every hook, so a mistyped name can never start or stop the
107
- main checkout's services.
1
+ # Writing hooks
2
+
3
+ `nk hooks write` turns the repository's CI and Compose file into hooks
4
+ without AI; the README shows what it takes from each and what it leaves out.
5
+ This page is for the parts it cannot translate, and for repositories without
6
+ either: what a person or an agent writing hooks by hand has to follow.
7
+
8
+ `nk hooks write <agent>` writes the hooks the same way, then starts the agent
9
+ in the folder you ran it in (usually the main checkout) with a
10
+ prompt that lists what nk generated, what it could not translate, the CI and
11
+ setup files, and the shared files with their empty keys (never their values).
12
+ The agent finishes the hooks and runs `nk hooks test` until it passes; it
13
+ leaves the changes uncommitted for you to review. If a repository's rules keep
14
+ agents out of the main checkout, create a workspace first (`nk -b hooks`) and
15
+ run the command inside it.
16
+
17
+ When you edit a generated hook, delete its first line (`// Generated by nk
18
+ hooks write ...`), so `nk hooks write` will not replace it.
19
+
20
+ ## Rules for the hooks
21
+
22
+ - One `.mjs` file per moment works on Windows, macOS and Linux. Use
23
+ `node:child_process` and stop at the first failing command with a non-zero
24
+ exit code, so nk does not start an agent on a broken workspace.
25
+ - Hooks run inside the workspace with these variables: `NOOK_WORKSPACE`
26
+ (name), `NOOK_PATH` (folder), `NOOK_REPO` (main checkout), `NOOK_SHARED`
27
+ (shared folder) and `NOOK_PORT` (first of ten ports for this workspace).
28
+ - `create` runs once, after shared files such as `.env` are copied. `open`
29
+ runs every time the workspace is opened, so it must be safe to run again.
30
+ `remove` runs before the folder is deleted; when it fails nothing is deleted.
31
+ - `remove` undoes everything `create` did outside the folder: containers,
32
+ volumes, networks, built images, databases created in a shared server.
33
+ `nk rm` also stops programs in the folder and, as a safety net, removes
34
+ Compose projects started in it; do not rely on that.
35
+ - Never touch the main checkout or its services: do not read or copy its
36
+ `.env`, and do not stop or remove its containers.
37
+ - Servers and containers use ports from `NOOK_PORT` to `NOOK_PORT + 9`.
38
+ - Do not print secrets. Do not run `docker compose config`: it prints every
39
+ value from `.env`.
40
+
41
+ ## Examples
42
+
43
+ A small helper the examples share:
44
+
45
+ ```js
46
+ import { spawnSync } from "node:child_process";
47
+
48
+ function run(command, ...args) {
49
+ // shell: true lets Windows find pnpm.cmd and npm.cmd.
50
+ const result = spawnSync([command, ...args].join(" "), { stdio: "inherit", shell: true });
51
+ if (result.status !== 0) process.exit(result.status ?? 1);
52
+ }
53
+ ```
54
+
55
+ ### Node (pnpm, npm, yarn, bun)
56
+
57
+ Install with the package manager whose lockfile the repository has:
58
+ `pnpm-lock.yaml` → `pnpm install`, `package-lock.json` → `npm ci`,
59
+ `yarn.lock` → `yarn install`, `bun.lock` → `bun install`.
60
+
61
+ ```js
62
+ // .nook/create.mjs
63
+ run("pnpm", "install");
64
+ ```
65
+
66
+ ### Python (uv)
67
+
68
+ A virtual environment holds absolute paths and cannot be copied from the main
69
+ checkout; create it again:
70
+
71
+ ```js
72
+ // .nook/create.mjs
73
+ run("uv", "sync");
74
+ ```
75
+
76
+ ### Docker Compose
77
+
78
+ Give each workspace its own Compose project, so its containers, volumes and
79
+ networks never mix with the main checkout's. Compose's own rule for a project
80
+ name is lowercase letters, digits, `_` and `-`.
81
+
82
+ ```js
83
+ // .nook/create.mjs
84
+ const project = process.env.NOOK_WORKSPACE.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
85
+ const port = Number(process.env.NOOK_PORT);
86
+ process.env.DB_PORT = String(port); // whatever the compose file reads
87
+ run("docker", "compose", "--project-name", project, "up", "-d", "--wait");
88
+ ```
89
+
90
+ Write the project name and ports into the workspace `.env` as well
91
+ (`COMPOSE_PROJECT_NAME=...`), so a plain `docker compose` typed in the
92
+ workspace later finds the same project.
93
+
94
+ ```js
95
+ // .nook/open.mjs: start the containers again after a restart
96
+ run("docker", "compose", "start");
97
+ ```
98
+
99
+ ```js
100
+ // .nook/remove.mjs: everything the project created, volumes and built images too
101
+ const project = process.env.NOOK_WORKSPACE.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
102
+ run("docker", "compose", "--project-name", project, "down", "--volumes", "--rmi", "local", "--remove-orphans");
103
+ ```
104
+
105
+ A fuller setup with a database per workspace also refuses the production
106
+ project name in every hook, so a mistyped name can never start or stop the
107
+ main checkout's services.
@@ -1,84 +1,94 @@
1
- # Open Linear issues in Nook
2
-
3
- Linear's **Work on issue → Custom script** can run a local command for an
4
- issue. With the files here, one click creates a Nook workspace on the
5
- issue's branch (running the repository's hooks) and starts your agent in it
6
- with Linear's prompt, in the terminal Linear opens for the script. Nook
7
- itself knows nothing about Linear: this folder only connects the two.
8
-
9
- Tested on Windows. `--terminal` (Windows Terminal or Warp) is Windows only.
10
-
11
- ## Set up once
12
-
13
- 1. Install Nook and run `nk init` in each repository you work on.
14
- 2. In Linear, open **Settings → Code & reviews → Configure coding tools** and
15
- enable **Custom script**.
16
- 3. Put this in `~/.linear/coding-tools.json` (on Windows,
17
- `C:\Users\<you>\.linear\coding-tools.json`). If Linear already wrote a
18
- starter file there, replace its `openIssue` block with this one:
19
-
20
- ```json
21
- {
22
- "openIssue": {
23
- "path": "C:\\Program Files\\nodejs\\node.exe",
24
- "args": ["<nook folder>\\integrations\\linear\\open-issue.mjs", "--agent", "codex"],
25
- "env": ["LINEAR_ISSUE_IDENTIFIER", "LINEAR_ISSUE_BRANCH_NAME", "LINEAR_PROMPT", "LINEAR_WORK_DIR"]
26
- }
27
- }
28
- ```
29
-
30
- - `path` is the absolute path of Node (`where node` prints it). With a
31
- version manager, use a path that stays put: for fnm,
32
- `%APPDATA%\fnm\aliases\default\node.exe` written out in full (it follows
33
- `fnm default`), not the temporary `fnm_multishells` folder. The script
34
- puts that Node's folder first on PATH, so global npm commands such as
35
- `codex` and `pnpm` are found even though Linear starts without your
36
- shell setup.
37
- - `<nook folder>` is where Nook is installed: the cloned folder, or
38
- `npm root -g` + `\@ree-auz\nook`.
39
- - `--agent` is the agent to start: `codex` (the default), `claude` or any
40
- command `nk -b <name> <agent>` accepts.
41
- - Linear runs the script in a terminal of its own (on Windows, Windows
42
- Terminal; the terminal choice in Linear's settings is macOS only). To
43
- work in Warp instead, add `"--terminal", "warp"` to `args`: the script
44
- opens a tab in Warp and closes Linear's window.
45
- - To let each issue pick its agent, label issues from one label group
46
- (say `Agent › Codex`, `Agent › Claude`) and add `"--agent-label", "Agent"`
47
- to `args`. Linear's prompt lists the issue's labels, and the script starts
48
- the agent named by that group's label (lowercased, spaces as `-`), or the
49
- `--agent` one when the issue has none.
50
- - `env` is an allowlist: Linear only passes the variables listed here.
51
-
52
- ## Use
53
-
54
- On an issue, choose **Work on issue → Custom script**. The first time, Linear
55
- asks you to **Choose a directory**: pick the repository's main checkout (the
56
- folder where you ran `nk init`). Nook uses it only to know which repository
57
- the issue belongs to; nothing runs there.
58
-
59
- The terminal runs `nk -b <issue branch> <agent> -y -p <Linear's prompt>` in
60
- that folder (`-y` keeps the converted workspace name without asking).
61
- Choosing the same issue again reopens its workspace and starts the agent
62
- without the prompt.
63
-
64
- Linear's GitHub integration moves the issue along as the branch and its pull
65
- request change, because the branch name holds the issue identifier. After the
66
- pull request is merged, `nk clean` removes the workspace.
67
-
68
- ## How it works
69
-
70
- - Linear opens a terminal, runs `open-issue.mjs` in it and passes the issue
71
- through the `LINEAR_*` variables.
72
- - By default the script runs `nk` right there, with the same Node.
73
- - With `--terminal`, the prompt is long Markdown with quotes and semicolons,
74
- so the script writes it to a temporary file and opens a tab in the chosen
75
- folder that runs the same script again: Windows Terminal with
76
- `wt.exe -w 0 new-tab -d <folder>`; Warp, whose `warp://` links cannot run a
77
- command, through a
78
- [tab config](https://docs.warp.dev/terminal/windows/tab-configs/) written to
79
- `%APPDATA%\warp\Warp\data\tab_configs\` and opened with
80
- `warp://tab_config/<name>` (the tab deletes it when it starts). A
81
- minimized Warp window stays minimized. It then
82
- closes the window Linear opened.
83
- - `nk` runs with the same Node, never through `cmd.exe`, which would cut a
84
- multi-line prompt at its first line break.
1
+ # Open Linear issues in Nook
2
+
3
+ Linear's **Work on issue → Custom script** can run a local command for an
4
+ issue. With the files here, one click creates a Nook workspace on the
5
+ issue's branch (running the repository's hooks) and starts your agent in it
6
+ with Linear's prompt, in the terminal Linear opens for the script. Nook
7
+ itself knows nothing about Linear: this folder only connects the two.
8
+
9
+ Tested on Windows. `--terminal wt` and `--terminal warp` are Windows only.
10
+
11
+ ## Set up once
12
+
13
+ 1. Install Nook and run `nk init` in each repository you work on.
14
+ 2. In Linear, open **Settings → Code & reviews → Configure coding tools** and
15
+ enable **Custom script**.
16
+ 3. Put this in `~/.linear/coding-tools.json` (on Windows,
17
+ `C:\Users\<you>\.linear\coding-tools.json`). If Linear already wrote a
18
+ starter file there, replace its `openIssue` block with this one:
19
+
20
+ ```json
21
+ {
22
+ "openIssue": {
23
+ "path": "C:\\Program Files\\nodejs\\node.exe",
24
+ "args": ["<nook folder>\\integrations\\linear\\open-issue.mjs", "--agent", "codex"],
25
+ "env": ["LINEAR_ISSUE_IDENTIFIER", "LINEAR_ISSUE_BRANCH_NAME", "LINEAR_PROMPT", "LINEAR_WORK_DIR"]
26
+ }
27
+ }
28
+ ```
29
+
30
+ - `path` is the absolute path of Node (`where node` prints it). With a
31
+ version manager, use a path that stays put: for fnm,
32
+ `%APPDATA%\fnm\aliases\default\node.exe` written out in full (it follows
33
+ `fnm default`), not the temporary `fnm_multishells` folder. The script
34
+ puts that Node's folder first on PATH, so global npm commands such as
35
+ `codex` and `pnpm` are found even though Linear starts without your
36
+ shell setup.
37
+ - `<nook folder>` is where Nook is installed: the cloned folder, or
38
+ `npm root -g` + `\@ree-auz\nook`.
39
+ - `--agent` is the agent to start: `codex` (the default), `claude` or any
40
+ command `nk -b <name> <agent>` accepts.
41
+ - Linear runs the script in a terminal of its own (on Windows, Windows
42
+ Terminal; the terminal choice in Linear's settings is macOS only). To
43
+ work in Warp instead, add `"--terminal", "warp"` to `args`: the script
44
+ opens a tab in Warp and closes Linear's window.
45
+ - To keep agents in [Orca](https://www.onorca.dev) (its accounts and
46
+ sessions), add `"--terminal", "orca"`: Nook creates the workspace and
47
+ runs its hooks in Linear's window, then
48
+ `orca agent launch --agent <agent> --worktree path:<workspace> --prompt <Linear's prompt> --focus`
49
+ starts the agent in Orca. Orca shows worktrees it did not create, and
50
+ `nk rm` / `nk clean` still remove them with their containers and
51
+ volumes. Orca's command-line tool must be installed; if Linear cannot
52
+ find it on PATH, add `"--orca", "<full path to orca>"`. Linear's window
53
+ closes when Orca has the agent, and stays open with the error otherwise.
54
+ - To let each issue pick its agent, label issues from one label group
55
+ (say `Agent › Codex`, `Agent › Claude`) and add `"--agent-label", "Agent"`
56
+ to `args`. Linear's prompt lists the issue's labels, and the script starts
57
+ the agent named by that group's label (lowercased, spaces as `-`), or the
58
+ `--agent` one when the issue has none.
59
+ - `env` is an allowlist: Linear only passes the variables listed here.
60
+
61
+ ## Use
62
+
63
+ On an issue, choose **Work on issue → Custom script**. The first time, Linear
64
+ asks you to **Choose a directory**: pick the repository's main checkout (the
65
+ folder where you ran `nk init`). Nook uses it only to know which repository
66
+ the issue belongs to; nothing runs there.
67
+
68
+ The terminal runs `nk -b <issue branch> <agent> -y -p <Linear's prompt>` in
69
+ that folder (`-y` keeps the converted workspace name without asking).
70
+ Choosing the same issue again reopens its workspace and starts the agent
71
+ without the prompt (with `--terminal orca`, a new agent session in Orca;
72
+ earlier sessions stay in Orca's list).
73
+
74
+ Linear's GitHub integration moves the issue along as the branch and its pull
75
+ request change, because the branch name holds the issue identifier. After the
76
+ pull request is merged, `nk clean` removes the workspace.
77
+
78
+ ## How it works
79
+
80
+ - Linear opens a terminal, runs `open-issue.mjs` in it and passes the issue
81
+ through the `LINEAR_*` variables.
82
+ - By default the script runs `nk` right there, with the same Node.
83
+ - With `--terminal`, the prompt is long Markdown with quotes and semicolons,
84
+ so the script writes it to a temporary file and opens a tab in the chosen
85
+ folder that runs the same script again: Windows Terminal with
86
+ `wt.exe -w 0 new-tab -d <folder>`; Warp, whose `warp://` links cannot run a
87
+ command, through a
88
+ [tab config](https://docs.warp.dev/terminal/windows/tab-configs/) written to
89
+ `%APPDATA%\warp\Warp\data\tab_configs\` and opened with
90
+ `warp://tab_config/<name>` (the tab deletes it when it starts). A
91
+ minimized Warp window stays minimized. It then
92
+ closes the window Linear opened.
93
+ - `nk` runs with the same Node, never through `cmd.exe`, which would cut a
94
+ multi-line prompt at its first line break.
@@ -1,7 +1,7 @@
1
- {
2
- "openIssue": {
3
- "path": "C:\\Program Files\\nodejs\\node.exe",
4
- "args": ["C:\\Users\\you\\AppData\\Roaming\\npm\\node_modules\\@ree-auz\\nook\\integrations\\linear\\open-issue.mjs", "--agent", "codex"],
5
- "env": ["LINEAR_ISSUE_IDENTIFIER", "LINEAR_ISSUE_BRANCH_NAME", "LINEAR_PROMPT", "LINEAR_WORK_DIR"]
6
- }
7
- }
1
+ {
2
+ "openIssue": {
3
+ "path": "C:\\Program Files\\nodejs\\node.exe",
4
+ "args": ["C:\\Users\\you\\AppData\\Roaming\\npm\\node_modules\\@ree-auz\\nook\\integrations\\linear\\open-issue.mjs", "--agent", "codex"],
5
+ "env": ["LINEAR_ISSUE_IDENTIFIER", "LINEAR_ISSUE_BRANCH_NAME", "LINEAR_PROMPT", "LINEAR_WORK_DIR"]
6
+ }
7
+ }