bet-cli 0.2.0 → 0.3.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/README.md +5 -0
- package/dist/commands/edit.js +48 -0
- package/dist/commands/info.js +6 -3
- package/dist/commands/update.js +12 -6
- package/dist/lib/config.js +9 -0
- package/dist/lib/editor.js +97 -0
- package/dist/lib/git.js +14 -8
- package/dist/lib/help.js +7 -3
- package/dist/main.js +16 -14
- package/package.json +1 -1
- package/src/commands/edit.ts +56 -0
- package/src/commands/info.tsx +200 -175
- package/src/commands/update.ts +203 -149
- package/src/lib/config.ts +17 -1
- package/src/lib/editor.ts +131 -0
- package/src/lib/git.ts +20 -10
- package/src/lib/help.ts +15 -15
- package/src/lib/types.ts +2 -0
- package/src/main.ts +3 -1
- package/tests/config.test.ts +71 -0
- package/tests/editor.test.ts +167 -0
package/src/commands/info.tsx
CHANGED
|
@@ -39,194 +39,219 @@ export function registerInfo(program: Command): void {
|
|
|
39
39
|
.description("Show project details")
|
|
40
40
|
.option("--json", "Print JSON output")
|
|
41
41
|
.option("--full", "Show full README content")
|
|
42
|
-
.action(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let project = matches[0];
|
|
54
|
-
|
|
55
|
-
if (matches.length > 1) {
|
|
56
|
-
if (!process.stdin.isTTY) {
|
|
57
|
-
process.stderr.write(`Slug "${slug}" is ambiguous. Matches:\n`);
|
|
58
|
-
for (const item of matches) {
|
|
59
|
-
process.stderr.write(` ${projectLabel(item)} ${item.path}\n`);
|
|
60
|
-
}
|
|
42
|
+
.action(
|
|
43
|
+
async (slug: string, options: { json?: boolean; full?: boolean }) => {
|
|
44
|
+
const config = await readConfig();
|
|
45
|
+
const projects = listProjects(config);
|
|
46
|
+
const matches = findBySlug(projects, slug);
|
|
47
|
+
|
|
48
|
+
if (matches.length === 0) {
|
|
49
|
+
process.stderr.write(`No project found for slug "${slug}".\n`);
|
|
61
50
|
process.exitCode = 1;
|
|
62
51
|
return;
|
|
63
52
|
}
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
(item) => ({
|
|
67
|
-
label: projectLabel(item),
|
|
68
|
-
hint: item.path,
|
|
69
|
-
value: item,
|
|
70
|
-
type: "item",
|
|
71
|
-
}),
|
|
72
|
-
);
|
|
54
|
+
let project = matches[0];
|
|
73
55
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
56
|
+
if (matches.length > 1) {
|
|
57
|
+
if (!process.stdin.isTTY) {
|
|
58
|
+
process.stderr.write(`Slug "${slug}" is ambiguous. Matches:\n`);
|
|
59
|
+
for (const item of matches) {
|
|
60
|
+
process.stderr.write(` ${projectLabel(item)} ${item.path}\n`);
|
|
61
|
+
}
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const items: SelectEntry<(typeof matches)[number]>[] = matches.map(
|
|
67
|
+
(item) => ({
|
|
68
|
+
label: projectLabel(item),
|
|
69
|
+
hint: item.path,
|
|
70
|
+
value: item,
|
|
71
|
+
type: "item",
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const selected = await promptSelect(items, {
|
|
76
|
+
title: `Select ${slug}`,
|
|
77
|
+
});
|
|
78
|
+
if (!selected) return;
|
|
79
|
+
project = selected.value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (options.json) {
|
|
83
|
+
process.stdout.write(JSON.stringify(project, null, 2));
|
|
84
|
+
process.stdout.write("\n");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const description =
|
|
89
|
+
project.user?.description ?? project.auto.description ?? "—";
|
|
90
|
+
// Compute git status live
|
|
91
|
+
const hasGit = await isInsideGitRepo(project.path);
|
|
92
|
+
const dirty = hasGit ? await getDirtyStatus(project.path) : undefined;
|
|
93
|
+
|
|
94
|
+
if (process.stdin.isTTY) {
|
|
95
|
+
const readme = options.full
|
|
96
|
+
? await readReadmeContent(project.path, { full: true })
|
|
97
|
+
: null;
|
|
98
|
+
const markdown = readme ?? description;
|
|
99
|
+
|
|
100
|
+
const view = (
|
|
101
|
+
<Box flexDirection="column" width="100%">
|
|
102
|
+
<Box
|
|
103
|
+
width="100%"
|
|
104
|
+
borderStyle="single"
|
|
105
|
+
borderColor="green"
|
|
106
|
+
paddingX={1}
|
|
107
|
+
paddingY={1}
|
|
108
|
+
marginBottom={1}
|
|
109
|
+
flexDirection="column"
|
|
110
|
+
>
|
|
111
|
+
<Box width="100%" paddingBottom={1}>
|
|
112
|
+
<Text color="green" bold>
|
|
113
|
+
{project.slug}
|
|
114
|
+
</Text>
|
|
115
|
+
</Box>
|
|
116
|
+
<Box width="100%">
|
|
117
|
+
<Text color="cyan">{project.path}</Text>
|
|
118
|
+
</Box>
|
|
123
119
|
</Box>
|
|
124
|
-
<Box
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
120
|
+
<Box
|
|
121
|
+
borderStyle="round"
|
|
122
|
+
borderColor="cyan"
|
|
123
|
+
padding={1}
|
|
124
|
+
flexDirection="column"
|
|
125
|
+
marginBottom={1}
|
|
126
|
+
>
|
|
127
|
+
<Box marginBottom={1}>
|
|
128
|
+
<Text bold color="magenta">
|
|
129
|
+
Details
|
|
130
|
+
</Text>
|
|
131
|
+
</Box>
|
|
132
|
+
<Box flexDirection="column">
|
|
133
|
+
<MetaRow
|
|
134
|
+
label="Git"
|
|
135
|
+
value={hasGit ? "yes" : "no"}
|
|
136
|
+
valueColor={hasGit ? "green" : "yellow"}
|
|
137
|
+
/>
|
|
138
|
+
<MetaRow
|
|
139
|
+
label="Git dirty"
|
|
140
|
+
value={
|
|
141
|
+
dirty === undefined ? "unknown" : dirty ? "yes" : "no"
|
|
142
|
+
}
|
|
143
|
+
valueColor={
|
|
144
|
+
dirty === undefined ? "yellow" : dirty ? "red" : "green"
|
|
145
|
+
}
|
|
146
|
+
/>
|
|
147
|
+
<MetaRow
|
|
148
|
+
label="README"
|
|
149
|
+
value={project.hasReadme ? "yes" : "no"}
|
|
150
|
+
valueColor={project.hasReadme ? "green" : "yellow"}
|
|
151
|
+
/>
|
|
152
|
+
<MetaRow
|
|
153
|
+
label="Started"
|
|
154
|
+
value={formatDate(project.auto.startedAt)}
|
|
155
|
+
/>
|
|
156
|
+
<MetaRow
|
|
157
|
+
label="Last modified"
|
|
158
|
+
value={formatDate(project.auto.lastModifiedAt)}
|
|
159
|
+
/>
|
|
160
|
+
<MetaRow
|
|
161
|
+
label="Last indexed"
|
|
162
|
+
value={formatDate(project.auto.lastIndexedAt)}
|
|
163
|
+
/>
|
|
164
|
+
|
|
165
|
+
<MetaRow label="Root" value={project.rootName} />
|
|
166
|
+
<MetaRow label="Root path" value={project.root} />
|
|
167
|
+
{project.user?.tags?.length ? (
|
|
168
|
+
<Box>
|
|
169
|
+
<Text bold color="gray">{`Tags: `}</Text>
|
|
170
|
+
<Text color="magenta">
|
|
171
|
+
{project.user.tags.join(", ")}
|
|
172
|
+
</Text>
|
|
173
|
+
</Box>
|
|
174
|
+
) : null}
|
|
175
|
+
{project.user?.onEnter ? (
|
|
176
|
+
<Box>
|
|
177
|
+
<Text bold color="gray">{`On enter: `}</Text>
|
|
178
|
+
<Text color="blue">{project.user.onEnter}</Text>
|
|
179
|
+
</Box>
|
|
180
|
+
) : null}
|
|
181
|
+
</Box>
|
|
168
182
|
</Box>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
</
|
|
183
|
+
<Box
|
|
184
|
+
borderStyle="round"
|
|
185
|
+
borderColor="magenta"
|
|
186
|
+
padding={1}
|
|
187
|
+
flexDirection="column"
|
|
188
|
+
>
|
|
189
|
+
<Box marginBottom={1}>
|
|
190
|
+
<Text bold color="magenta">
|
|
191
|
+
Description
|
|
192
|
+
</Text>
|
|
193
|
+
</Box>
|
|
194
|
+
<Markdown>{markdown}</Markdown>
|
|
180
195
|
</Box>
|
|
181
|
-
|
|
196
|
+
{!options.full && project.hasReadme ? (
|
|
197
|
+
<Box marginTop={1}>
|
|
198
|
+
<Text color="yellow">
|
|
199
|
+
Tip: Run <Text bold>bet info {project.slug} --full</Text> to
|
|
200
|
+
read the full README.
|
|
201
|
+
</Text>
|
|
202
|
+
</Box>
|
|
203
|
+
) : null}
|
|
182
204
|
</Box>
|
|
183
|
-
|
|
184
|
-
);
|
|
205
|
+
);
|
|
185
206
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
process.stdout.write(`${chalk.bold("Git:")} ${hasGit ? "yes" : "no"}\n`);
|
|
198
|
-
process.stdout.write(
|
|
199
|
-
`${chalk.bold("README:")} ${project.hasReadme ? "yes" : "no"}\n\n`,
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
const descToShow =
|
|
203
|
-
options.full && project.hasReadme
|
|
204
|
-
? (await readReadmeContent(project.path, { full: true })) ?? description
|
|
205
|
-
: description;
|
|
206
|
-
process.stdout.write(`${chalk.bold("Description:")} ${descToShow}\n`);
|
|
207
|
-
process.stdout.write(
|
|
208
|
-
`${chalk.bold("Started:")} ${formatDate(project.auto.startedAt)}\n`,
|
|
209
|
-
);
|
|
210
|
-
process.stdout.write(
|
|
211
|
-
`${chalk.bold("Last modified:")} ${formatDate(project.auto.lastModifiedAt)}\n`,
|
|
212
|
-
);
|
|
213
|
-
process.stdout.write(
|
|
214
|
-
`${chalk.bold("Last indexed:")} ${formatDate(project.auto.lastIndexedAt)}\n`,
|
|
215
|
-
);
|
|
216
|
-
process.stdout.write(
|
|
217
|
-
`${chalk.bold("Dirty:")} ${dirty === undefined ? "unknown" : dirty ? "yes" : "no"}\n`,
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
if (project.user?.tags?.length) {
|
|
207
|
+
const { unmount } = render(view, { stdout: process.stdout });
|
|
208
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
209
|
+
unmount();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
process.stdout.write(`${chalk.bold(project.slug)}\n`);
|
|
214
|
+
process.stdout.write(`${chalk.dim(project.path)}\n\n`);
|
|
215
|
+
|
|
216
|
+
process.stdout.write(`${chalk.bold("Root:")} ${project.rootName}\n`);
|
|
217
|
+
process.stdout.write(`${chalk.bold("Root path:")} ${project.root}\n`);
|
|
221
218
|
process.stdout.write(
|
|
222
|
-
`${chalk.bold("
|
|
219
|
+
`${chalk.bold("Git:")} ${hasGit ? "yes" : "no"}\n`,
|
|
220
|
+
);
|
|
221
|
+
process.stdout.write(
|
|
222
|
+
`${chalk.bold("README:")} ${project.hasReadme ? "yes" : "no"}\n\n`,
|
|
223
223
|
);
|
|
224
|
-
}
|
|
225
224
|
|
|
226
|
-
|
|
225
|
+
const descToShow =
|
|
226
|
+
options.full && project.hasReadme
|
|
227
|
+
? ((await readReadmeContent(project.path, { full: true })) ??
|
|
228
|
+
description)
|
|
229
|
+
: description;
|
|
230
|
+
process.stdout.write(`${chalk.bold("Description:")} ${descToShow}\n`);
|
|
231
|
+
process.stdout.write(
|
|
232
|
+
`${chalk.bold("Started:")} ${formatDate(project.auto.startedAt)}\n`,
|
|
233
|
+
);
|
|
227
234
|
process.stdout.write(
|
|
228
|
-
`${chalk.bold("
|
|
235
|
+
`${chalk.bold("Last modified:")} ${formatDate(project.auto.lastModifiedAt)}\n`,
|
|
229
236
|
);
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
process.stdout.write(
|
|
238
|
+
`${chalk.bold("Last indexed:")} ${formatDate(project.auto.lastIndexedAt)}\n`,
|
|
239
|
+
);
|
|
240
|
+
process.stdout.write(
|
|
241
|
+
`${chalk.bold("Dirty:")} ${dirty === undefined ? "unknown" : dirty ? "yes" : "no"}\n`,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
if (project.user?.tags?.length) {
|
|
245
|
+
process.stdout.write(
|
|
246
|
+
`${chalk.bold("Tags:")} ${project.user.tags.join(", ")}\n`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (project.user?.onEnter) {
|
|
251
|
+
process.stdout.write(
|
|
252
|
+
`${chalk.bold("On enter:")} ${project.user.onEnter}\n`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
);
|
|
232
257
|
}
|