@nozomiishii/pm 0.1.8 → 0.2.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/README.ja.md CHANGED
@@ -68,9 +68,6 @@ Commands:
68
68
  ls List project names
69
69
  logo Display the pm logo
70
70
  uninstall Uninstall pm from your system
71
- create-workspace Generate a .code-workspace file
72
- --name <name> Workspace name (outputs <name>.code-workspace)
73
- --tag <name> Include only projects with this tag (repeatable)
74
71
 
75
72
  Options:
76
73
  --config <path> Path to projects.json (or PM_CONFIG)
@@ -116,43 +113,6 @@ pm ls
116
113
 
117
114
  ![pm ls](demo/pm-ls.gif)
118
115
 
119
- ### pm create-workspace
120
-
121
- `--tag` で指定したタグのプロジェクトを `.code-workspace` ファイルにまとめます。
122
-
123
- ```sh
124
- pm create-workspace --name <name> --tag <tag>
125
- ```
126
-
127
- たとえば `projects.json` に以下のプロジェクトがある場合:
128
-
129
- ```json
130
- [
131
- { "name": "dotfiles", "rootPath": "~/Code/nozomiishii/dotfiles", "tags": ["personal"] },
132
- { "name": "portfolio", "rootPath": "~/Code/nozomiishii/portfolio", "tags": ["personal"] },
133
- { "name": "fzf", "rootPath": "~/Code/junegunn/fzf", "tags": ["oss"] }
134
- ]
135
- ```
136
-
137
- 次のコマンドを実行することで
138
-
139
- ```sh
140
- pm create-workspace --name my-workspace --tag personal
141
- ```
142
-
143
- `my-workspace.code-workspace` が生成されます:
144
-
145
- ```json
146
- {
147
- "folders": [
148
- { "name": "dotfiles", "path": "../nozomiishii/dotfiles" },
149
- { "name": "portfolio", "path": "../nozomiishii/portfolio" }
150
- ]
151
- }
152
- ```
153
-
154
- `--tag` は複数指定でき、すべてのタグを持つプロジェクトだけが含まれます。
155
-
156
116
  ## Configuration
157
117
 
158
118
  インストーラーが `.zshrc` を自動で設定しますが、手動でセットアップする場合は以下を追加してください。
package/README.md CHANGED
@@ -68,9 +68,6 @@ Commands:
68
68
  ls List project names
69
69
  logo Display the pm logo
70
70
  uninstall Uninstall pm from your system
71
- create-workspace Generate a .code-workspace file
72
- --name <name> Workspace name (outputs <name>.code-workspace)
73
- --tag <name> Include only projects with this tag (repeatable)
74
71
 
75
72
  Options:
76
73
  --config <path> Path to projects.json (or PM_CONFIG)
@@ -116,43 +113,6 @@ pm ls
116
113
 
117
114
  ![pm ls](demo/pm-ls.gif)
118
115
 
119
- ### pm create-workspace
120
-
121
- Bundles projects matching a `--tag` into a `.code-workspace` file.
122
-
123
- ```sh
124
- pm create-workspace --name <name> --tag <tag>
125
- ```
126
-
127
- For example, given the following `projects.json`:
128
-
129
- ```json
130
- [
131
- { "name": "dotfiles", "rootPath": "~/Code/nozomiishii/dotfiles", "tags": ["personal"] },
132
- { "name": "portfolio", "rootPath": "~/Code/nozomiishii/portfolio", "tags": ["personal"] },
133
- { "name": "fzf", "rootPath": "~/Code/junegunn/fzf", "tags": ["oss"] }
134
- ]
135
- ```
136
-
137
- Running the following command:
138
-
139
- ```sh
140
- pm create-workspace --name my-workspace --tag personal
141
- ```
142
-
143
- Generates `my-workspace.code-workspace`:
144
-
145
- ```json
146
- {
147
- "folders": [
148
- { "name": "dotfiles", "path": "../nozomiishii/dotfiles" },
149
- { "name": "portfolio", "path": "../nozomiishii/portfolio" }
150
- ]
151
- }
152
- ```
153
-
154
- `--tag` can be specified multiple times — only projects matching all tags are included.
155
-
156
116
  ## Configuration
157
117
 
158
118
  The installer configures `.zshrc` automatically. For manual setup, add the following:
package/dist/cli.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { existsSync } from "node:fs";
5
- import { readFile as readFile2, writeFile } from "node:fs/promises";
6
- import path3 from "node:path";
5
+ import { readFile } from "node:fs/promises";
6
+ import path2 from "node:path";
7
7
  import { spawn } from "node:child_process";
8
8
 
9
9
  // src/filter-projects.ts
@@ -53,37 +53,6 @@ function findProject(projects, query) {
53
53
  return matches[0];
54
54
  }
55
55
 
56
- // src/create-workspace/build-folders.ts
57
- import path2 from "node:path";
58
- function buildFolders(projects, opts) {
59
- const filtered = filterProjects(projects, opts.tags);
60
- const folders = [];
61
- for (const p of filtered) {
62
- const absolute = path2.resolve(expandHome(p.rootPath));
63
- let rel = path2.relative(opts.workspaceDir, absolute);
64
- if (!rel || rel === "") {
65
- rel = ".";
66
- }
67
- const relPosix = rel.split(path2.sep).join("/");
68
- const name = stripEmojiLabel(p.name) || path2.basename(absolute);
69
- folders.push({ name, path: relPosix });
70
- }
71
- return folders;
72
- }
73
-
74
- // src/create-workspace/load-existing-workspace.ts
75
- import { readFile } from "node:fs/promises";
76
- async function loadExistingWorkspace(workspacePath) {
77
- try {
78
- const raw = await readFile(workspacePath, "utf8");
79
- const parsed = JSON.parse(raw);
80
- const { folders: _f, ...rest } = parsed;
81
- return rest;
82
- } catch {
83
- return {};
84
- }
85
- }
86
-
87
56
  // src/logo/logo-color.ascii
88
57
  var logo_color_default = `\x1B[38;2;120;180;255m zzzzzzzzzzzzzzzzzzzzzzzzzz\x1B[0m
89
58
  \x1B[38;2;100;160;245m zzzzzzzzzzzzzzzzzzzzzzzzzz\x1B[0m
@@ -99,7 +68,7 @@ var logo_color_default = `\x1B[38;2;120;180;255m zzzzzzzzzzzzzzzzzzzzzzzzzz\x1B[
99
68
  // package.json
100
69
  var package_default = {
101
70
  name: "@nozomiishii/pm",
102
- version: "0.1.8",
71
+ version: "0.2.1",
103
72
  description: "Project manager CLI — jump to projects via fzf",
104
73
  type: "module",
105
74
  homepage: "https://github.com/nozomiishii/pm#readme",
@@ -122,6 +91,7 @@ var package_default = {
122
91
  scripts: {
123
92
  build: "bun build --compile src/cli.ts --outfile dist/pm",
124
93
  prepublishOnly: "bun build src/cli.ts --outfile dist/cli.js --target=node --banner '#!/usr/bin/env node'",
94
+ prepare: "lefthook install --force",
125
95
  typecheck: "tsc --noEmit",
126
96
  dev: "bun run src/cli.ts",
127
97
  demo: 'docker run --rm -v "$(pwd)":/vhs pm-vhs',
@@ -133,7 +103,10 @@ var package_default = {
133
103
  test: "vitest run"
134
104
  },
135
105
  devDependencies: {
106
+ "@nozomiishii/commitlint-config": "1.0.1",
107
+ "@nozomiishii/lefthook-config": "1.0.1",
136
108
  "@types/node": "25.6.0",
109
+ lefthook: "2.1.6",
137
110
  vitest: "4.1.5"
138
111
  },
139
112
  publishConfig: {
@@ -151,11 +124,11 @@ function defaultConfigPath() {
151
124
  const home = process.env.HOME ?? "";
152
125
  switch (process.platform) {
153
126
  case "darwin":
154
- return path3.join(home, "Library/Application Support/Code/User/globalStorage/alefragnani.project-manager/projects.json");
127
+ return path2.join(home, "Library/Application Support/Code/User/globalStorage/alefragnani.project-manager/projects.json");
155
128
  case "win32":
156
- return path3.join(process.env.APPDATA ?? "", "Code/User/globalStorage/alefragnani.project-manager/projects.json");
129
+ return path2.join(process.env.APPDATA ?? "", "Code/User/globalStorage/alefragnani.project-manager/projects.json");
157
130
  default:
158
- return path3.join(home, ".config/Code/User/globalStorage/alefragnani.project-manager/projects.json");
131
+ return path2.join(home, ".config/Code/User/globalStorage/alefragnani.project-manager/projects.json");
159
132
  }
160
133
  }
161
134
  function usage() {
@@ -166,9 +139,6 @@ Commands:
166
139
  ls List project names
167
140
  logo Display the pm logo
168
141
  uninstall Uninstall pm from your system
169
- create-workspace Generate a .code-workspace file
170
- --name <name> Workspace name (outputs <name>.code-workspace)
171
- --tag <name> Include only projects with this tag (repeatable)
172
142
 
173
143
  Options:
174
144
  --config <path> Path to projects.json (or PM_CONFIG)
@@ -180,7 +150,7 @@ Running \`pm\` without a command opens the fzf picker.`);
180
150
  function printLogo() {
181
151
  console.log(logo_color_default);
182
152
  }
183
- var SUBCOMMANDS = new Set(["cd", "ls", "create-workspace", "logo", "uninstall"]);
153
+ var SUBCOMMANDS = new Set(["cd", "ls", "logo", "uninstall"]);
184
154
  function parseArgs(argv) {
185
155
  let config = process.env.PM_CONFIG ?? defaultConfigPath();
186
156
  let help = false;
@@ -203,33 +173,25 @@ function parseArgs(argv) {
203
173
  }
204
174
  return { config, help, version, subcommand, rest };
205
175
  }
206
- function parseCreateWorkspaceArgs(rest) {
207
- let workspaceName = "";
208
- const tags = [];
209
- for (let i = 0;i < rest.length; i++) {
210
- const arg = rest[i];
211
- if (arg === "--name") {
212
- workspaceName = rest[++i] ?? "";
213
- } else if (arg === "--tag") {
214
- tags.push(rest[++i] ?? "");
215
- }
216
- }
217
- return { workspaceName, tags };
218
- }
219
176
  function plainLabel(name) {
220
177
  return stripEmojiLabel(name) || name;
221
178
  }
222
179
  function fzfSelect(projects) {
223
180
  return new Promise((resolve, reject) => {
224
- const labels = projects.map((p) => plainLabel(p.name));
225
- const proc = spawn("fzf", [], {
181
+ const lines = projects.map((p) => `${plainLabel(p.name)} ${expandHome(p.rootPath)}`);
182
+ const proc = spawn("fzf", [
183
+ "--delimiter=\t",
184
+ "--with-nth=1",
185
+ "--preview",
186
+ "bat --color=always --style=header,grid --line-range :80 {2}/README.* 2>/dev/null || echo 'No README found'"
187
+ ], {
226
188
  stdio: ["pipe", "pipe", "inherit"]
227
189
  });
228
190
  let stdout = "";
229
191
  proc.stdout.on("data", (d) => {
230
192
  stdout += d.toString();
231
193
  });
232
- proc.stdin.write(labels.join(`
194
+ proc.stdin.write(lines.join(`
233
195
  `) + `
234
196
  `);
235
197
  proc.stdin.end();
@@ -239,7 +201,7 @@ function fzfSelect(projects) {
239
201
  return;
240
202
  }
241
203
  const selected = stdout.trim();
242
- const idx = labels.indexOf(selected);
204
+ const idx = lines.indexOf(selected);
243
205
  resolve(idx >= 0 ? projects[idx] : undefined);
244
206
  });
245
207
  proc.on("error", (err) => {
@@ -252,23 +214,6 @@ function fzfSelect(projects) {
252
214
  });
253
215
  });
254
216
  }
255
- function resolveCliPath(p) {
256
- return path3.isAbsolute(p) ? path3.normalize(p) : path3.resolve(process.cwd(), p);
257
- }
258
- async function createWorkspace(projects, args) {
259
- if (!args.workspaceName) {
260
- console.error("Error: --name is required with create-workspace.");
261
- process.exit(1);
262
- }
263
- const workspacePath = resolveCliPath(`${args.workspaceName}.code-workspace`);
264
- const workspaceDir = path3.dirname(path3.resolve(workspacePath));
265
- const folders = buildFolders(projects, { tags: args.tags, workspaceDir });
266
- const preserved = await loadExistingWorkspace(workspacePath);
267
- const out = { ...preserved, folders };
268
- await writeFile(workspacePath, JSON.stringify(out, null, 2) + `
269
- `, "utf8");
270
- console.log(`Wrote ${workspacePath} (${folders.length} folders)`);
271
- }
272
217
  async function jumpToProject(projects, name) {
273
218
  let target;
274
219
  if (name) {
@@ -317,14 +262,9 @@ async function main() {
317
262
  console.error(`File not found: ${filePath}`);
318
263
  process.exit(1);
319
264
  }
320
- const raw = await readFile2(filePath, "utf-8");
265
+ const raw = await readFile(filePath, "utf-8");
321
266
  const allProjects = JSON.parse(raw);
322
267
  switch (args.subcommand) {
323
- case "create-workspace": {
324
- const cwArgs = parseCreateWorkspaceArgs(args.rest);
325
- await createWorkspace(allProjects, cwArgs);
326
- break;
327
- }
328
268
  case "ls": {
329
269
  const projects = filterProjects(allProjects, []);
330
270
  for (const p of projects) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nozomiishii/pm",
3
- "version": "0.1.8",
3
+ "version": "0.2.1",
4
4
  "description": "Project manager CLI — jump to projects via fzf",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/nozomiishii/pm#readme",
@@ -23,6 +23,7 @@
23
23
  "scripts": {
24
24
  "build": "bun build --compile src/cli.ts --outfile dist/pm",
25
25
  "prepublishOnly": "bun build src/cli.ts --outfile dist/cli.js --target=node --banner '#!/usr/bin/env node'",
26
+ "prepare": "lefthook install --force",
26
27
  "typecheck": "tsc --noEmit",
27
28
  "dev": "bun run src/cli.ts",
28
29
  "demo": "docker run --rm -v \"$(pwd)\":/vhs pm-vhs",
@@ -34,7 +35,10 @@
34
35
  "test": "vitest run"
35
36
  },
36
37
  "devDependencies": {
38
+ "@nozomiishii/commitlint-config": "1.0.1",
39
+ "@nozomiishii/lefthook-config": "1.0.1",
37
40
  "@types/node": "25.6.0",
41
+ "lefthook": "2.1.6",
38
42
  "vitest": "4.1.5"
39
43
  },
40
44
  "publishConfig": {