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.
@@ -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(async (slug: string, options: { json?: boolean; full?: boolean }) => {
43
- const config = await readConfig();
44
- const projects = listProjects(config);
45
- const matches = findBySlug(projects, slug);
46
-
47
- if (matches.length === 0) {
48
- process.stderr.write(`No project found for slug "${slug}".\n`);
49
- process.exitCode = 1;
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
- const items: SelectEntry<(typeof matches)[number]>[] = matches.map(
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
- const selected = await promptSelect(items, { title: `Select ${slug}` });
75
- if (!selected) return;
76
- project = selected.value;
77
- }
78
-
79
- if (options.json) {
80
- process.stdout.write(JSON.stringify(project, null, 2));
81
- process.stdout.write("\n");
82
- return;
83
- }
84
-
85
- const description =
86
- project.user?.description ?? project.auto.description ?? "—";
87
- // Compute git status live
88
- const hasGit = await isInsideGitRepo(project.path);
89
- const dirty = hasGit ? await getDirtyStatus(project.path) : undefined;
90
-
91
- if (process.stdin.isTTY) {
92
- const readme = options.full
93
- ? await readReadmeContent(project.path, { full: true })
94
- : null;
95
- const markdown = readme ?? description;
96
-
97
- const view = (
98
- <Box flexDirection="column" width="100%">
99
- <Box
100
- width="100%"
101
- borderStyle="single"
102
- borderColor="green"
103
- paddingX={1}
104
- paddingY={1}
105
- marginBottom={1}
106
- >
107
- <Text color="green" bold>
108
- {project.slug}
109
- </Text>
110
- <Text color="cyan">{project.path}</Text>
111
- </Box>
112
- <Box
113
- borderStyle="round"
114
- borderColor="cyan"
115
- padding={1}
116
- flexDirection="column"
117
- marginBottom={1}
118
- >
119
- <Box marginBottom={1}>
120
- <Text bold color="magenta">
121
- Details
122
- </Text>
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 flexDirection="column">
125
- <MetaRow label="Root" value={project.rootName} />
126
- <MetaRow label="Root path" value={project.root} />
127
- <MetaRow
128
- label="Git"
129
- value={hasGit ? "yes" : "no"}
130
- valueColor={hasGit ? "green" : "yellow"}
131
- />
132
- <MetaRow
133
- label="README"
134
- value={project.hasReadme ? "yes" : "no"}
135
- valueColor={project.hasReadme ? "green" : "yellow"}
136
- />
137
- <MetaRow
138
- label="Started"
139
- value={formatDate(project.auto.startedAt)}
140
- />
141
- <MetaRow
142
- label="Last modified"
143
- value={formatDate(project.auto.lastModifiedAt)}
144
- />
145
- <MetaRow
146
- label="Last indexed"
147
- value={formatDate(project.auto.lastIndexedAt)}
148
- />
149
- <MetaRow
150
- label="Dirty"
151
- value={dirty === undefined ? "unknown" : dirty ? "yes" : "no"}
152
- valueColor={
153
- dirty === undefined ? "yellow" : dirty ? "red" : "green"
154
- }
155
- />
156
- {project.user?.tags?.length ? (
157
- <Box>
158
- <Text bold color="gray">{`Tags: `}</Text>
159
- <Text color="magenta">{project.user.tags.join(", ")}</Text>
160
- </Box>
161
- ) : null}
162
- {project.user?.onEnter ? (
163
- <Box>
164
- <Text bold color="gray">{`On enter: `}</Text>
165
- <Text color="blue">{project.user.onEnter}</Text>
166
- </Box>
167
- ) : null}
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
- </Box>
170
- <Box
171
- borderStyle="round"
172
- borderColor="magenta"
173
- padding={1}
174
- flexDirection="column"
175
- >
176
- <Box marginBottom={1}>
177
- <Text bold color="magenta">
178
- Description
179
- </Text>
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
- <Markdown>{markdown}</Markdown>
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
- </Box>
184
- );
205
+ );
185
206
 
186
- const { unmount } = render(view, { stdout: process.stdout });
187
- await new Promise((resolve) => setTimeout(resolve, 0));
188
- unmount();
189
- return;
190
- }
191
-
192
- process.stdout.write(`${chalk.bold(project.slug)}\n`);
193
- process.stdout.write(`${chalk.dim(project.path)}\n\n`);
194
-
195
- process.stdout.write(`${chalk.bold("Root:")} ${project.rootName}\n`);
196
- process.stdout.write(`${chalk.bold("Root path:")} ${project.root}\n`);
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("Tags:")} ${project.user.tags.join(", ")}\n`,
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
- if (project.user?.onEnter) {
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("On enter:")} ${project.user.onEnter}\n`,
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
  }