@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 +0 -40
- package/README.md +0 -40
- package/dist/cli.js +21 -81
- package/package.json +5 -1
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
|

|
|
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
|

|
|
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
|
|
6
|
-
import
|
|
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
|
|
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
|
|
127
|
+
return path2.join(home, "Library/Application Support/Code/User/globalStorage/alefragnani.project-manager/projects.json");
|
|
155
128
|
case "win32":
|
|
156
|
-
return
|
|
129
|
+
return path2.join(process.env.APPDATA ?? "", "Code/User/globalStorage/alefragnani.project-manager/projects.json");
|
|
157
130
|
default:
|
|
158
|
-
return
|
|
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", "
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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": {
|