clairo 0.2.0 → 0.4.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/dist/cli.js +266 -337
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
import meow from "meow";
|
|
5
5
|
|
|
6
6
|
// src/app.tsx
|
|
7
|
-
import { useState as
|
|
8
|
-
import { Box as Box13, useApp, useInput as
|
|
7
|
+
import { useState as useState8 } from "react";
|
|
8
|
+
import { Box as Box13, useApp, useInput as useInput10 } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/components/github/GitHubView.tsx
|
|
11
|
-
import {
|
|
11
|
+
import { exec as exec3 } from "child_process";
|
|
12
|
+
import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
|
|
12
13
|
import { TitledBox as TitledBox4 } from "@mishieck/ink-titled-box";
|
|
13
|
-
import { Box as Box5, Text as Text5, useInput as
|
|
14
|
+
import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
|
|
14
15
|
|
|
15
16
|
// src/lib/config/index.ts
|
|
16
17
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -127,8 +128,6 @@ function getCurrentBranch() {
|
|
|
127
128
|
|
|
128
129
|
// src/lib/github/index.ts
|
|
129
130
|
import { exec } from "child_process";
|
|
130
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
131
|
-
import { join as join2 } from "path";
|
|
132
131
|
import { promisify } from "util";
|
|
133
132
|
var execAsync = promisify(exec);
|
|
134
133
|
async function isGhInstalled() {
|
|
@@ -241,177 +240,124 @@ async function getPRDetails(prNumber, repo) {
|
|
|
241
240
|
};
|
|
242
241
|
}
|
|
243
242
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
243
|
+
|
|
244
|
+
// src/components/github/PRDetailsBox.tsx
|
|
245
|
+
import { useRef } from "react";
|
|
246
|
+
import open from "open";
|
|
247
|
+
import { TitledBox } from "@mishieck/ink-titled-box";
|
|
248
|
+
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
249
|
+
import { ScrollView } from "ink-scroll-view";
|
|
250
|
+
|
|
251
|
+
// src/components/ui/Markdown.tsx
|
|
252
|
+
import { Box, Text } from "ink";
|
|
253
|
+
import Link from "ink-link";
|
|
254
|
+
import { marked } from "marked";
|
|
255
|
+
import Table from "cli-table3";
|
|
256
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
257
|
+
function Markdown({ children }) {
|
|
258
|
+
const tokens = marked.lexer(children);
|
|
259
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: tokens.map((token, idx) => /* @__PURE__ */ jsx(TokenRenderer, { token }, idx)) });
|
|
260
|
+
}
|
|
261
|
+
function TokenRenderer({ token }) {
|
|
262
|
+
var _a, _b;
|
|
263
|
+
switch (token.type) {
|
|
264
|
+
case "heading":
|
|
265
|
+
return /* @__PURE__ */ jsx(Box, { marginTop: token.depth === 1 ? 0 : 1, children: /* @__PURE__ */ jsx(Text, { bold: true, underline: token.depth === 1, children: renderInline(token.tokens) }) });
|
|
266
|
+
case "paragraph": {
|
|
267
|
+
const hasLinks = (_a = token.tokens) == null ? void 0 : _a.some((t) => {
|
|
268
|
+
var _a2;
|
|
269
|
+
return t.type === "link" || t.type === "strong" && "tokens" in t && ((_a2 = t.tokens) == null ? void 0 : _a2.some((st) => st.type === "link"));
|
|
270
|
+
});
|
|
271
|
+
if (hasLinks) {
|
|
272
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", flexWrap: "wrap", children: renderInline(token.tokens) });
|
|
259
273
|
}
|
|
274
|
+
return /* @__PURE__ */ jsx(Text, { children: renderInline(token.tokens) });
|
|
260
275
|
}
|
|
276
|
+
case "code":
|
|
277
|
+
return /* @__PURE__ */ jsx(Box, { marginY: 1, paddingX: 1, borderStyle: "single", borderColor: "gray", children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: token.text }) });
|
|
278
|
+
case "blockquote":
|
|
279
|
+
return /* @__PURE__ */ jsxs(Box, { marginLeft: 2, children: [
|
|
280
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "\u2502 " }),
|
|
281
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: (_b = token.tokens) == null ? void 0 : _b.map((t, idx) => /* @__PURE__ */ jsx(TokenRenderer, { token: t }, idx)) })
|
|
282
|
+
] });
|
|
283
|
+
case "list":
|
|
284
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: token.items.map((item, idx) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
285
|
+
/* @__PURE__ */ jsx(Text, { children: token.ordered ? `${idx + 1}. ` : "\u2022 " }),
|
|
286
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: item.tokens.map((t, i) => /* @__PURE__ */ jsx(TokenRenderer, { token: t }, i)) })
|
|
287
|
+
] }, idx)) });
|
|
288
|
+
case "table":
|
|
289
|
+
return /* @__PURE__ */ jsx(TableRenderer, { token });
|
|
290
|
+
case "hr":
|
|
291
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(40) });
|
|
292
|
+
case "space":
|
|
293
|
+
return null;
|
|
294
|
+
default:
|
|
295
|
+
if ("text" in token && typeof token.text === "string") {
|
|
296
|
+
return /* @__PURE__ */ jsx(Text, { children: token.text });
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
261
299
|
}
|
|
262
|
-
return null;
|
|
263
300
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
if (!await isGhAuthenticated()) {
|
|
273
|
-
return {
|
|
274
|
-
success: false,
|
|
275
|
-
error: "Not authenticated. Run 'gh auth login'",
|
|
276
|
-
errorType: "not_authenticated"
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
try {
|
|
280
|
-
const baseArg = baseBranch ? `--base "${baseBranch}"` : "";
|
|
281
|
-
const fields = "number,title,state,author,createdAt,isDraft";
|
|
282
|
-
const escapedTitle = title.replace(/"/g, '\\"');
|
|
283
|
-
const escapedBody = body.replace(/"/g, '\\"');
|
|
284
|
-
const { stdout } = await execAsync(
|
|
285
|
-
`gh pr create --title "${escapedTitle}" --body "${escapedBody}" ${baseArg} --repo "${repo}" --json ${fields}`
|
|
286
|
-
);
|
|
287
|
-
const pr = JSON.parse(stdout);
|
|
288
|
-
return { success: true, data: pr };
|
|
289
|
-
} catch (err) {
|
|
290
|
-
const message = err instanceof Error ? err.message : "Failed to create PR";
|
|
291
|
-
return {
|
|
292
|
-
success: false,
|
|
293
|
-
error: message,
|
|
294
|
-
errorType: "api_error"
|
|
295
|
-
};
|
|
301
|
+
function TableRenderer({ token }) {
|
|
302
|
+
const table = new Table({
|
|
303
|
+
head: token.header.map((cell) => renderInlineToString(cell.tokens)),
|
|
304
|
+
style: { head: ["cyan"], border: ["gray"] }
|
|
305
|
+
});
|
|
306
|
+
for (const row of token.rows) {
|
|
307
|
+
table.push(row.map((cell) => renderInlineToString(cell.tokens)));
|
|
296
308
|
}
|
|
309
|
+
return /* @__PURE__ */ jsx(Text, { children: table.toString() });
|
|
297
310
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
311
|
+
function renderInline(tokens) {
|
|
312
|
+
if (!tokens) return null;
|
|
313
|
+
return tokens.map((token, idx) => {
|
|
314
|
+
switch (token.type) {
|
|
315
|
+
case "text":
|
|
316
|
+
return /* @__PURE__ */ jsx(Text, { children: token.text }, idx);
|
|
317
|
+
case "strong":
|
|
318
|
+
return /* @__PURE__ */ jsx(Text, { bold: true, children: renderInline(token.tokens) }, idx);
|
|
319
|
+
case "em":
|
|
320
|
+
return /* @__PURE__ */ jsx(Text, { italic: true, children: renderInline(token.tokens) }, idx);
|
|
321
|
+
case "codespan":
|
|
322
|
+
return /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
323
|
+
"`",
|
|
324
|
+
token.text,
|
|
325
|
+
"`"
|
|
326
|
+
] }, idx);
|
|
327
|
+
case "link":
|
|
328
|
+
return /* @__PURE__ */ jsx(Link, { url: token.href, children: /* @__PURE__ */ jsx(Text, { color: "blue", children: renderInlineToString(token.tokens) }) }, idx);
|
|
329
|
+
case "image":
|
|
330
|
+
return /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
|
|
331
|
+
"[Image: ",
|
|
332
|
+
token.text || token.href,
|
|
333
|
+
"]"
|
|
334
|
+
] }, idx);
|
|
335
|
+
case "br":
|
|
336
|
+
return /* @__PURE__ */ jsx(Text, { children: "\n" }, idx);
|
|
337
|
+
case "del":
|
|
338
|
+
return /* @__PURE__ */ jsx(Text, { strikethrough: true, children: renderInline(token.tokens) }, idx);
|
|
339
|
+
default:
|
|
340
|
+
if ("text" in token && typeof token.text === "string") {
|
|
341
|
+
return /* @__PURE__ */ jsx(Text, { children: token.text }, idx);
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
327
344
|
}
|
|
328
|
-
}
|
|
345
|
+
});
|
|
329
346
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (key.escape) {
|
|
342
|
-
onCancel();
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (key.upArrow || input === "k") {
|
|
346
|
-
setSelectedItem((prev) => {
|
|
347
|
-
const idx = items.indexOf(prev);
|
|
348
|
-
return items[Math.max(0, idx - 1)];
|
|
349
|
-
});
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (key.downArrow || input === "j") {
|
|
353
|
-
setSelectedItem((prev) => {
|
|
354
|
-
const idx = items.indexOf(prev);
|
|
355
|
-
return items[Math.min(items.length - 1, idx + 1)];
|
|
356
|
-
});
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
if (key.return) {
|
|
360
|
-
if (selectedItem === "title") {
|
|
361
|
-
const newTitle = openInEditor(title, "PR_TITLE.txt");
|
|
362
|
-
if (newTitle !== null) {
|
|
363
|
-
setTitle(newTitle.split("\n")[0].trim());
|
|
364
|
-
}
|
|
365
|
-
} else if (selectedItem === "body") {
|
|
366
|
-
const newBody = openInEditor(body, "PR_DESCRIPTION.md");
|
|
367
|
-
if (newBody !== null) {
|
|
368
|
-
setBody(newBody);
|
|
369
|
-
}
|
|
370
|
-
} else if (selectedItem === "submit") {
|
|
371
|
-
if (title.trim()) {
|
|
372
|
-
onSubmit(title.trim(), body);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
|
-
{ isActive: !loading }
|
|
378
|
-
);
|
|
379
|
-
const renderItem = (item, label, value) => {
|
|
380
|
-
const isSelected = selectedItem === item;
|
|
381
|
-
const prefix = isSelected ? "> " : " ";
|
|
382
|
-
const color = isSelected ? "yellow" : void 0;
|
|
383
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
384
|
-
/* @__PURE__ */ jsxs(Text, { color, bold: isSelected, children: [
|
|
385
|
-
prefix,
|
|
386
|
-
label
|
|
387
|
-
] }),
|
|
388
|
-
value !== void 0 && /* @__PURE__ */ jsx(Box, { marginLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: value || "(empty - press Enter to edit)" }) })
|
|
389
|
-
] });
|
|
390
|
-
};
|
|
391
|
-
const truncatedBody = body ? body.split("\n").slice(0, 2).join(" ").slice(0, 60) + (body.length > 60 ? "..." : "") : "";
|
|
392
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 1, children: [
|
|
393
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Create Pull Request" }),
|
|
394
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Up/Down to select, Enter to edit, Esc to cancel" }),
|
|
395
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
396
|
-
error && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: error }) }),
|
|
397
|
-
renderItem("title", "Title", title),
|
|
398
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
399
|
-
renderItem("body", "Description", truncatedBody),
|
|
400
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
401
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: selectedItem === "submit" ? "green" : void 0, bold: selectedItem === "submit", children: [
|
|
402
|
-
selectedItem === "submit" ? "> " : " ",
|
|
403
|
-
title.trim() ? "[Submit PR]" : "[Enter title first]"
|
|
404
|
-
] }) }),
|
|
405
|
-
loading && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Creating PR..." }) })
|
|
406
|
-
] });
|
|
347
|
+
function renderInlineToString(tokens) {
|
|
348
|
+
if (!tokens) return "";
|
|
349
|
+
return tokens.map((token) => {
|
|
350
|
+
if ("text" in token && typeof token.text === "string") {
|
|
351
|
+
return token.text;
|
|
352
|
+
}
|
|
353
|
+
if ("tokens" in token && Array.isArray(token.tokens)) {
|
|
354
|
+
return renderInlineToString(token.tokens);
|
|
355
|
+
}
|
|
356
|
+
return "";
|
|
357
|
+
}).join("");
|
|
407
358
|
}
|
|
408
359
|
|
|
409
360
|
// src/components/github/PRDetailsBox.tsx
|
|
410
|
-
import { useRef } from "react";
|
|
411
|
-
import open from "open";
|
|
412
|
-
import { TitledBox } from "@mishieck/ink-titled-box";
|
|
413
|
-
import { Box as Box2, Text as Text2, useInput as useInput2 } from "ink";
|
|
414
|
-
import { ScrollView } from "ink-scroll-view";
|
|
415
361
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
416
362
|
function getCheckColor(check) {
|
|
417
363
|
const conclusion = check.conclusion ?? check.state;
|
|
@@ -450,7 +396,7 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
450
396
|
return { text: pr.mergeable ?? "UNKNOWN", color: "yellow" };
|
|
451
397
|
};
|
|
452
398
|
const mergeDisplay = getMergeDisplay();
|
|
453
|
-
|
|
399
|
+
useInput(
|
|
454
400
|
(input, key) => {
|
|
455
401
|
var _a2, _b2;
|
|
456
402
|
if (key.upArrow || input === "k") {
|
|
@@ -466,7 +412,7 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
466
412
|
},
|
|
467
413
|
{ isActive: isFocused }
|
|
468
414
|
);
|
|
469
|
-
return /* @__PURE__ */ jsx2(TitledBox, { borderStyle: "round", titles: [displayTitle], borderColor, flexGrow:
|
|
415
|
+
return /* @__PURE__ */ jsx2(TitledBox, { borderStyle: "round", titles: [displayTitle], borderColor, flexGrow: 1, children: /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx2(ScrollView, { ref: scrollRef, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
470
416
|
loading && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Loading details..." }),
|
|
471
417
|
error && /* @__PURE__ */ jsx2(Text2, { color: "red", children: error }),
|
|
472
418
|
!loading && !error && !pr && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Select a PR to view details" }),
|
|
@@ -518,16 +464,16 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
518
464
|
] }),
|
|
519
465
|
pr.body && /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
520
466
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Description:" }),
|
|
521
|
-
/* @__PURE__ */ jsx2(
|
|
467
|
+
/* @__PURE__ */ jsx2(Markdown, { children: pr.body })
|
|
522
468
|
] })
|
|
523
469
|
] })
|
|
524
470
|
] }) }) }) });
|
|
525
471
|
}
|
|
526
472
|
|
|
527
473
|
// src/components/github/PullRequestsBox.tsx
|
|
528
|
-
import { useEffect, useState
|
|
474
|
+
import { useEffect, useState } from "react";
|
|
529
475
|
import { TitledBox as TitledBox2 } from "@mishieck/ink-titled-box";
|
|
530
|
-
import { Box as Box3, Text as Text3, useInput as
|
|
476
|
+
import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
|
|
531
477
|
|
|
532
478
|
// src/lib/clipboard.ts
|
|
533
479
|
import { exec as exec2 } from "child_process";
|
|
@@ -563,13 +509,13 @@ function PullRequestsBox({
|
|
|
563
509
|
repoSlug,
|
|
564
510
|
isFocused
|
|
565
511
|
}) {
|
|
566
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
512
|
+
const [highlightedIndex, setHighlightedIndex] = useState(0);
|
|
567
513
|
const totalItems = prs.length + 1;
|
|
568
514
|
useEffect(() => {
|
|
569
515
|
const idx = prs.findIndex((p) => p.number === (selectedPR == null ? void 0 : selectedPR.number));
|
|
570
516
|
if (idx >= 0) setHighlightedIndex(idx);
|
|
571
517
|
}, [selectedPR, prs]);
|
|
572
|
-
|
|
518
|
+
useInput2(
|
|
573
519
|
(input, key) => {
|
|
574
520
|
if (!isFocused) return;
|
|
575
521
|
if (key.upArrow || input === "k") {
|
|
@@ -623,17 +569,17 @@ function PullRequestsBox({
|
|
|
623
569
|
}
|
|
624
570
|
|
|
625
571
|
// src/components/github/RemotesBox.tsx
|
|
626
|
-
import { useEffect as useEffect2, useState as
|
|
572
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
627
573
|
import { TitledBox as TitledBox3 } from "@mishieck/ink-titled-box";
|
|
628
|
-
import { Box as Box4, Text as Text4, useInput as
|
|
574
|
+
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
629
575
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
630
576
|
function RemotesBox({ remotes, selectedRemote, onSelect, loading, error, isFocused }) {
|
|
631
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
577
|
+
const [highlightedIndex, setHighlightedIndex] = useState2(0);
|
|
632
578
|
useEffect2(() => {
|
|
633
579
|
const idx = remotes.findIndex((r) => r.name === selectedRemote);
|
|
634
580
|
if (idx >= 0) setHighlightedIndex(idx);
|
|
635
581
|
}, [selectedRemote, remotes]);
|
|
636
|
-
|
|
582
|
+
useInput3(
|
|
637
583
|
(input, key) => {
|
|
638
584
|
if (!isFocused || remotes.length === 0) return;
|
|
639
585
|
if (key.upArrow || input === "k") {
|
|
@@ -671,37 +617,25 @@ function RemotesBox({ remotes, selectedRemote, onSelect, loading, error, isFocus
|
|
|
671
617
|
|
|
672
618
|
// src/components/github/GitHubView.tsx
|
|
673
619
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
674
|
-
function GitHubView({ isFocused,
|
|
675
|
-
const [isRepo, setIsRepo] =
|
|
676
|
-
const [repoPath, setRepoPath] =
|
|
677
|
-
const [remotes, setRemotes] =
|
|
678
|
-
const [currentBranch, setCurrentBranch] =
|
|
679
|
-
const [currentRepoSlug, setCurrentRepoSlug] =
|
|
680
|
-
const [selectedRemote, setSelectedRemote] =
|
|
681
|
-
const [selectedPR, setSelectedPR] =
|
|
682
|
-
const [prs, setPrs] =
|
|
683
|
-
const [prDetails, setPrDetails] =
|
|
684
|
-
const [loading, setLoading] =
|
|
620
|
+
function GitHubView({ isFocused, onKeybindingsChange }) {
|
|
621
|
+
const [isRepo, setIsRepo] = useState3(null);
|
|
622
|
+
const [repoPath, setRepoPath] = useState3(null);
|
|
623
|
+
const [remotes, setRemotes] = useState3([]);
|
|
624
|
+
const [currentBranch, setCurrentBranch] = useState3(null);
|
|
625
|
+
const [currentRepoSlug, setCurrentRepoSlug] = useState3(null);
|
|
626
|
+
const [selectedRemote, setSelectedRemote] = useState3(null);
|
|
627
|
+
const [selectedPR, setSelectedPR] = useState3(null);
|
|
628
|
+
const [prs, setPrs] = useState3([]);
|
|
629
|
+
const [prDetails, setPrDetails] = useState3(null);
|
|
630
|
+
const [loading, setLoading] = useState3({
|
|
685
631
|
remotes: true,
|
|
686
632
|
prs: false,
|
|
687
|
-
details: false
|
|
688
|
-
createPR: false
|
|
633
|
+
details: false
|
|
689
634
|
});
|
|
690
|
-
const [errors, setErrors] =
|
|
691
|
-
const [
|
|
692
|
-
const [prTemplate, setPrTemplate] = useState4(null);
|
|
693
|
-
const [focusedBox, setFocusedBox] = useState4("remotes");
|
|
635
|
+
const [errors, setErrors] = useState3({});
|
|
636
|
+
const [focusedBox, setFocusedBox] = useState3("remotes");
|
|
694
637
|
useEffect3(() => {
|
|
695
638
|
if (!isFocused) {
|
|
696
|
-
setShowCreatePR(false);
|
|
697
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
698
|
-
}
|
|
699
|
-
}, [isFocused]);
|
|
700
|
-
useEffect3(() => {
|
|
701
|
-
onModalChange == null ? void 0 : onModalChange(showCreatePR);
|
|
702
|
-
}, [showCreatePR, onModalChange]);
|
|
703
|
-
useEffect3(() => {
|
|
704
|
-
if (!isFocused || showCreatePR) {
|
|
705
639
|
onKeybindingsChange == null ? void 0 : onKeybindingsChange([]);
|
|
706
640
|
return;
|
|
707
641
|
}
|
|
@@ -710,13 +644,15 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
710
644
|
bindings.push({ key: "Enter", label: "Select Remote" });
|
|
711
645
|
} else if (focusedBox === "prs") {
|
|
712
646
|
bindings.push({ key: "n", label: "New PR", color: "green" });
|
|
647
|
+
bindings.push({ key: "r", label: "Refresh" });
|
|
713
648
|
bindings.push({ key: "o", label: "Open", color: "green" });
|
|
714
649
|
bindings.push({ key: "y", label: "Copy Link" });
|
|
715
650
|
} else if (focusedBox === "details") {
|
|
651
|
+
bindings.push({ key: "r", label: "Refresh" });
|
|
716
652
|
bindings.push({ key: "o", label: "Open", color: "green" });
|
|
717
653
|
}
|
|
718
654
|
onKeybindingsChange == null ? void 0 : onKeybindingsChange(bindings);
|
|
719
|
-
}, [isFocused, focusedBox,
|
|
655
|
+
}, [isFocused, focusedBox, onKeybindingsChange]);
|
|
720
656
|
useEffect3(() => {
|
|
721
657
|
const gitRepoCheck = isGitRepo();
|
|
722
658
|
setIsRepo(gitRepoCheck);
|
|
@@ -728,8 +664,6 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
728
664
|
const rootResult = getRepoRoot();
|
|
729
665
|
if (rootResult.success) {
|
|
730
666
|
setRepoPath(rootResult.data);
|
|
731
|
-
const template = getPRTemplate(rootResult.data);
|
|
732
|
-
setPrTemplate(template);
|
|
733
667
|
}
|
|
734
668
|
const branchResult = getCurrentBranch();
|
|
735
669
|
if (branchResult.success) {
|
|
@@ -746,6 +680,43 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
746
680
|
}
|
|
747
681
|
setLoading((prev) => ({ ...prev, remotes: false }));
|
|
748
682
|
}, []);
|
|
683
|
+
const refreshPRs = useCallback(async () => {
|
|
684
|
+
if (!currentBranch || !currentRepoSlug) return;
|
|
685
|
+
setLoading((prev) => ({ ...prev, prs: true }));
|
|
686
|
+
try {
|
|
687
|
+
const result = await listPRsForBranch(currentBranch, currentRepoSlug);
|
|
688
|
+
if (result.success) {
|
|
689
|
+
setPrs(result.data);
|
|
690
|
+
if (result.data.length > 0) {
|
|
691
|
+
setSelectedPR((prev) => prev ?? result.data[0]);
|
|
692
|
+
}
|
|
693
|
+
setErrors((prev) => ({ ...prev, prs: void 0 }));
|
|
694
|
+
} else {
|
|
695
|
+
setErrors((prev) => ({ ...prev, prs: result.error }));
|
|
696
|
+
}
|
|
697
|
+
} catch (err) {
|
|
698
|
+
setErrors((prev) => ({ ...prev, prs: String(err) }));
|
|
699
|
+
} finally {
|
|
700
|
+
setLoading((prev) => ({ ...prev, prs: false }));
|
|
701
|
+
}
|
|
702
|
+
}, [currentBranch, currentRepoSlug]);
|
|
703
|
+
const refreshDetails = useCallback(async () => {
|
|
704
|
+
if (!selectedPR || !currentRepoSlug) return;
|
|
705
|
+
setLoading((prev) => ({ ...prev, details: true }));
|
|
706
|
+
try {
|
|
707
|
+
const result = await getPRDetails(selectedPR.number, currentRepoSlug);
|
|
708
|
+
if (result.success) {
|
|
709
|
+
setPrDetails(result.data);
|
|
710
|
+
setErrors((prev) => ({ ...prev, details: void 0 }));
|
|
711
|
+
} else {
|
|
712
|
+
setErrors((prev) => ({ ...prev, details: result.error }));
|
|
713
|
+
}
|
|
714
|
+
} catch (err) {
|
|
715
|
+
setErrors((prev) => ({ ...prev, details: String(err) }));
|
|
716
|
+
} finally {
|
|
717
|
+
setLoading((prev) => ({ ...prev, details: false }));
|
|
718
|
+
}
|
|
719
|
+
}, [selectedPR, currentRepoSlug]);
|
|
749
720
|
useEffect3(() => {
|
|
750
721
|
if (!selectedRemote || !currentBranch) return;
|
|
751
722
|
const remote = remotes.find((r) => r.name === selectedRemote);
|
|
@@ -753,52 +724,21 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
753
724
|
const repo = getRepoFromRemote(remote.url);
|
|
754
725
|
if (!repo) return;
|
|
755
726
|
setCurrentRepoSlug(repo);
|
|
756
|
-
setLoading((prev) => ({ ...prev, prs: true }));
|
|
757
727
|
setPrs([]);
|
|
758
728
|
setSelectedPR(null);
|
|
759
|
-
const fetchPRs = async () => {
|
|
760
|
-
try {
|
|
761
|
-
const result = await listPRsForBranch(currentBranch, repo);
|
|
762
|
-
if (result.success) {
|
|
763
|
-
setPrs(result.data);
|
|
764
|
-
if (result.data.length > 0) {
|
|
765
|
-
setSelectedPR(result.data[0]);
|
|
766
|
-
}
|
|
767
|
-
setErrors((prev) => ({ ...prev, prs: void 0 }));
|
|
768
|
-
} else {
|
|
769
|
-
setErrors((prev) => ({ ...prev, prs: result.error }));
|
|
770
|
-
}
|
|
771
|
-
} catch (err) {
|
|
772
|
-
setErrors((prev) => ({ ...prev, prs: String(err) }));
|
|
773
|
-
} finally {
|
|
774
|
-
setLoading((prev) => ({ ...prev, prs: false }));
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
fetchPRs();
|
|
778
729
|
}, [selectedRemote, currentBranch, remotes]);
|
|
730
|
+
useEffect3(() => {
|
|
731
|
+
if (currentRepoSlug && currentBranch) {
|
|
732
|
+
refreshPRs();
|
|
733
|
+
}
|
|
734
|
+
}, [currentRepoSlug, currentBranch, refreshPRs]);
|
|
779
735
|
useEffect3(() => {
|
|
780
736
|
if (!selectedPR || !currentRepoSlug) {
|
|
781
737
|
setPrDetails(null);
|
|
782
738
|
return;
|
|
783
739
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
try {
|
|
787
|
-
const result = await getPRDetails(selectedPR.number, currentRepoSlug);
|
|
788
|
-
if (result.success) {
|
|
789
|
-
setPrDetails(result.data);
|
|
790
|
-
setErrors((prev) => ({ ...prev, details: void 0 }));
|
|
791
|
-
} else {
|
|
792
|
-
setErrors((prev) => ({ ...prev, details: result.error }));
|
|
793
|
-
}
|
|
794
|
-
} catch (err) {
|
|
795
|
-
setErrors((prev) => ({ ...prev, details: String(err) }));
|
|
796
|
-
} finally {
|
|
797
|
-
setLoading((prev) => ({ ...prev, details: false }));
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
fetchDetails();
|
|
801
|
-
}, [selectedPR, currentRepoSlug]);
|
|
740
|
+
refreshDetails();
|
|
741
|
+
}, [selectedPR, currentRepoSlug, refreshDetails]);
|
|
802
742
|
const handleRemoteSelect = useCallback(
|
|
803
743
|
(remoteName) => {
|
|
804
744
|
setSelectedRemote(remoteName);
|
|
@@ -812,51 +752,21 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
812
752
|
setSelectedPR(pr);
|
|
813
753
|
}, []);
|
|
814
754
|
const handleCreatePR = useCallback(() => {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const handleCreatePRSubmit = useCallback(
|
|
819
|
-
async (title, body) => {
|
|
820
|
-
if (!currentRepoSlug) return;
|
|
821
|
-
setLoading((prev) => ({ ...prev, createPR: true }));
|
|
822
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
823
|
-
try {
|
|
824
|
-
const result = await createPR(currentRepoSlug, title, body);
|
|
825
|
-
if (result.success) {
|
|
826
|
-
setShowCreatePR(false);
|
|
827
|
-
if (currentBranch) {
|
|
828
|
-
const prsResult = await listPRsForBranch(currentBranch, currentRepoSlug);
|
|
829
|
-
if (prsResult.success) {
|
|
830
|
-
setPrs(prsResult.data);
|
|
831
|
-
const newPR = prsResult.data.find((p) => p.number === result.data.number);
|
|
832
|
-
if (newPR) {
|
|
833
|
-
setSelectedPR(newPR);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
} else {
|
|
838
|
-
setErrors((prev) => ({ ...prev, createPR: result.error }));
|
|
839
|
-
}
|
|
840
|
-
} catch (err) {
|
|
841
|
-
setErrors((prev) => ({ ...prev, createPR: String(err) }));
|
|
842
|
-
} finally {
|
|
843
|
-
setLoading((prev) => ({ ...prev, createPR: false }));
|
|
844
|
-
}
|
|
845
|
-
},
|
|
846
|
-
[currentRepoSlug, currentBranch]
|
|
847
|
-
);
|
|
848
|
-
const handleCreatePRCancel = useCallback(() => {
|
|
849
|
-
setShowCreatePR(false);
|
|
850
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
755
|
+
exec3("gh pr create --web", () => {
|
|
756
|
+
process.stdout.emit("resize");
|
|
757
|
+
});
|
|
851
758
|
}, []);
|
|
852
|
-
|
|
759
|
+
useInput4(
|
|
853
760
|
(input) => {
|
|
854
|
-
if (showCreatePR) return;
|
|
855
761
|
if (input === "1") setFocusedBox("remotes");
|
|
856
762
|
if (input === "2") setFocusedBox("prs");
|
|
857
763
|
if (input === "3") setFocusedBox("details");
|
|
764
|
+
if (input === "r") {
|
|
765
|
+
if (focusedBox === "prs") refreshPRs();
|
|
766
|
+
if (focusedBox === "details") refreshDetails();
|
|
767
|
+
}
|
|
858
768
|
},
|
|
859
|
-
{ isActive: isFocused
|
|
769
|
+
{ isActive: isFocused }
|
|
860
770
|
);
|
|
861
771
|
if (isRepo === false) {
|
|
862
772
|
return /* @__PURE__ */ jsx5(TitledBox4, { borderStyle: "round", titles: ["Error"], flexGrow: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "red", children: "Current directory is not a git repository" }) });
|
|
@@ -870,7 +780,7 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
870
780
|
onSelect: handleRemoteSelect,
|
|
871
781
|
loading: loading.remotes,
|
|
872
782
|
error: errors.remotes,
|
|
873
|
-
isFocused: isFocused &&
|
|
783
|
+
isFocused: isFocused && focusedBox === "remotes"
|
|
874
784
|
}
|
|
875
785
|
),
|
|
876
786
|
/* @__PURE__ */ jsx5(
|
|
@@ -884,17 +794,7 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
884
794
|
error: errors.prs,
|
|
885
795
|
branch: currentBranch,
|
|
886
796
|
repoSlug: currentRepoSlug,
|
|
887
|
-
isFocused: isFocused &&
|
|
888
|
-
}
|
|
889
|
-
),
|
|
890
|
-
showCreatePR && /* @__PURE__ */ jsx5(
|
|
891
|
-
CreatePRModal,
|
|
892
|
-
{
|
|
893
|
-
template: prTemplate,
|
|
894
|
-
onSubmit: handleCreatePRSubmit,
|
|
895
|
-
onCancel: handleCreatePRCancel,
|
|
896
|
-
loading: loading.createPR,
|
|
897
|
-
error: errors.createPR
|
|
797
|
+
isFocused: isFocused && focusedBox === "prs"
|
|
898
798
|
}
|
|
899
799
|
),
|
|
900
800
|
/* @__PURE__ */ jsx5(
|
|
@@ -903,17 +803,17 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
903
803
|
pr: prDetails,
|
|
904
804
|
loading: loading.details,
|
|
905
805
|
error: errors.details,
|
|
906
|
-
isFocused: isFocused &&
|
|
806
|
+
isFocused: isFocused && focusedBox === "details"
|
|
907
807
|
}
|
|
908
808
|
)
|
|
909
809
|
] });
|
|
910
810
|
}
|
|
911
811
|
|
|
912
812
|
// src/components/jira/JiraView.tsx
|
|
913
|
-
import { useCallback as useCallback2, useEffect as useEffect5, useState as
|
|
813
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useState as useState7 } from "react";
|
|
914
814
|
import open2 from "open";
|
|
915
815
|
import { TitledBox as TitledBox5 } from "@mishieck/ink-titled-box";
|
|
916
|
-
import { Box as Box11, Text as Text11, useInput as
|
|
816
|
+
import { Box as Box11, Text as Text11, useInput as useInput9 } from "ink";
|
|
917
817
|
|
|
918
818
|
// src/lib/jira/parser.ts
|
|
919
819
|
var TICKET_KEY_PATTERN = /^[A-Z][A-Z0-9]+-\d+$/;
|
|
@@ -1139,15 +1039,15 @@ async function applyTransition(auth, ticketKey, transitionId) {
|
|
|
1139
1039
|
}
|
|
1140
1040
|
|
|
1141
1041
|
// src/components/jira/ChangeStatusModal.tsx
|
|
1142
|
-
import { useEffect as useEffect4, useState as
|
|
1143
|
-
import { Box as Box6, Text as Text6, useInput as
|
|
1042
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
1043
|
+
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
1144
1044
|
import SelectInput from "ink-select-input";
|
|
1145
1045
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1146
1046
|
function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onCancel }) {
|
|
1147
|
-
const [transitions, setTransitions] =
|
|
1148
|
-
const [loading, setLoading] =
|
|
1149
|
-
const [applying, setApplying] =
|
|
1150
|
-
const [error, setError] =
|
|
1047
|
+
const [transitions, setTransitions] = useState4([]);
|
|
1048
|
+
const [loading, setLoading] = useState4(true);
|
|
1049
|
+
const [applying, setApplying] = useState4(false);
|
|
1050
|
+
const [error, setError] = useState4(null);
|
|
1151
1051
|
useEffect4(() => {
|
|
1152
1052
|
const fetchTransitions = async () => {
|
|
1153
1053
|
const siteUrl = getJiraSiteUrl(repoPath);
|
|
@@ -1189,7 +1089,7 @@ function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onC
|
|
|
1189
1089
|
setApplying(false);
|
|
1190
1090
|
}
|
|
1191
1091
|
};
|
|
1192
|
-
|
|
1092
|
+
useInput5(
|
|
1193
1093
|
(_input, key) => {
|
|
1194
1094
|
if (key.escape && !applying) {
|
|
1195
1095
|
onCancel();
|
|
@@ -1217,8 +1117,38 @@ function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onC
|
|
|
1217
1117
|
}
|
|
1218
1118
|
|
|
1219
1119
|
// src/components/jira/ConfigureJiraSiteModal.tsx
|
|
1220
|
-
import { useState as
|
|
1221
|
-
import { Box as Box7, Text as Text7, useInput as
|
|
1120
|
+
import { useState as useState5 } from "react";
|
|
1121
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
1122
|
+
|
|
1123
|
+
// src/lib/editor.ts
|
|
1124
|
+
import { spawnSync } from "child_process";
|
|
1125
|
+
import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1126
|
+
import { tmpdir } from "os";
|
|
1127
|
+
import { join as join2 } from "path";
|
|
1128
|
+
function openInEditor(content, filename) {
|
|
1129
|
+
const editor = process.env.VISUAL || process.env.EDITOR || "vi";
|
|
1130
|
+
const tempDir = mkdtempSync(join2(tmpdir(), "clairo-"));
|
|
1131
|
+
const tempFile = join2(tempDir, filename);
|
|
1132
|
+
try {
|
|
1133
|
+
writeFileSync2(tempFile, content);
|
|
1134
|
+
const result = spawnSync(editor, [tempFile], {
|
|
1135
|
+
stdio: "inherit"
|
|
1136
|
+
});
|
|
1137
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1138
|
+
process.stdout.emit("resize");
|
|
1139
|
+
if (result.status !== 0) {
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
return readFileSync2(tempFile, "utf-8");
|
|
1143
|
+
} finally {
|
|
1144
|
+
try {
|
|
1145
|
+
rmSync(tempDir, { recursive: true });
|
|
1146
|
+
} catch {
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// src/components/jira/ConfigureJiraSiteModal.tsx
|
|
1222
1152
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1223
1153
|
function ConfigureJiraSiteModal({
|
|
1224
1154
|
initialSiteUrl,
|
|
@@ -1228,13 +1158,13 @@ function ConfigureJiraSiteModal({
|
|
|
1228
1158
|
loading,
|
|
1229
1159
|
error
|
|
1230
1160
|
}) {
|
|
1231
|
-
const [siteUrl, setSiteUrl] =
|
|
1232
|
-
const [email, setEmail] =
|
|
1233
|
-
const [apiToken, setApiToken] =
|
|
1234
|
-
const [selectedItem, setSelectedItem] =
|
|
1161
|
+
const [siteUrl, setSiteUrl] = useState5(initialSiteUrl ?? "");
|
|
1162
|
+
const [email, setEmail] = useState5(initialEmail ?? "");
|
|
1163
|
+
const [apiToken, setApiToken] = useState5("");
|
|
1164
|
+
const [selectedItem, setSelectedItem] = useState5("siteUrl");
|
|
1235
1165
|
const items = ["siteUrl", "email", "apiToken", "submit"];
|
|
1236
1166
|
const canSubmit = siteUrl.trim() && email.trim() && apiToken.trim();
|
|
1237
|
-
|
|
1167
|
+
useInput6(
|
|
1238
1168
|
(input, key) => {
|
|
1239
1169
|
if (loading) return;
|
|
1240
1170
|
if (key.escape) {
|
|
@@ -1312,14 +1242,14 @@ function ConfigureJiraSiteModal({
|
|
|
1312
1242
|
}
|
|
1313
1243
|
|
|
1314
1244
|
// src/components/jira/LinkTicketModal.tsx
|
|
1315
|
-
import { useState as
|
|
1316
|
-
import { Box as Box9, Text as Text9, useInput as
|
|
1245
|
+
import { useState as useState6 } from "react";
|
|
1246
|
+
import { Box as Box9, Text as Text9, useInput as useInput8 } from "ink";
|
|
1317
1247
|
|
|
1318
1248
|
// src/components/ui/TextInput.tsx
|
|
1319
|
-
import { Box as Box8, Text as Text8, useInput as
|
|
1249
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
1320
1250
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1321
1251
|
function TextInput({ value, onChange, placeholder, isActive, mask }) {
|
|
1322
|
-
|
|
1252
|
+
useInput7(
|
|
1323
1253
|
(input, key) => {
|
|
1324
1254
|
if (key.backspace || key.delete) {
|
|
1325
1255
|
if (value.length > 0) {
|
|
@@ -1347,9 +1277,9 @@ function TextInput({ value, onChange, placeholder, isActive, mask }) {
|
|
|
1347
1277
|
// src/components/jira/LinkTicketModal.tsx
|
|
1348
1278
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1349
1279
|
function LinkTicketModal({ onSubmit, onCancel, loading, error }) {
|
|
1350
|
-
const [ticketInput, setTicketInput] =
|
|
1280
|
+
const [ticketInput, setTicketInput] = useState6("");
|
|
1351
1281
|
const canSubmit = ticketInput.trim().length > 0;
|
|
1352
|
-
|
|
1282
|
+
useInput8(
|
|
1353
1283
|
(_input, key) => {
|
|
1354
1284
|
if (loading) return;
|
|
1355
1285
|
if (key.escape) {
|
|
@@ -1406,17 +1336,17 @@ function TicketItem({ ticketKey, summary, status, isHighlighted, isSelected }) {
|
|
|
1406
1336
|
// src/components/jira/JiraView.tsx
|
|
1407
1337
|
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1408
1338
|
function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
1409
|
-
const [repoPath, setRepoPath] =
|
|
1410
|
-
const [currentBranch, setCurrentBranch] =
|
|
1411
|
-
const [isRepo, setIsRepo] =
|
|
1412
|
-
const [jiraState, setJiraState] =
|
|
1413
|
-
const [tickets, setTickets] =
|
|
1414
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
1415
|
-
const [showConfigureModal, setShowConfigureModal] =
|
|
1416
|
-
const [showLinkModal, setShowLinkModal] =
|
|
1417
|
-
const [showStatusModal, setShowStatusModal] =
|
|
1418
|
-
const [loading, setLoading] =
|
|
1419
|
-
const [errors, setErrors] =
|
|
1339
|
+
const [repoPath, setRepoPath] = useState7(null);
|
|
1340
|
+
const [currentBranch, setCurrentBranch] = useState7(null);
|
|
1341
|
+
const [isRepo, setIsRepo] = useState7(null);
|
|
1342
|
+
const [jiraState, setJiraState] = useState7("not_configured");
|
|
1343
|
+
const [tickets, setTickets] = useState7([]);
|
|
1344
|
+
const [highlightedIndex, setHighlightedIndex] = useState7(0);
|
|
1345
|
+
const [showConfigureModal, setShowConfigureModal] = useState7(false);
|
|
1346
|
+
const [showLinkModal, setShowLinkModal] = useState7(false);
|
|
1347
|
+
const [showStatusModal, setShowStatusModal] = useState7(false);
|
|
1348
|
+
const [loading, setLoading] = useState7({ configure: false, link: false });
|
|
1349
|
+
const [errors, setErrors] = useState7({});
|
|
1420
1350
|
useEffect5(() => {
|
|
1421
1351
|
if (!isFocused) {
|
|
1422
1352
|
setShowConfigureModal(false);
|
|
@@ -1579,7 +1509,7 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1579
1509
|
});
|
|
1580
1510
|
}
|
|
1581
1511
|
}, [repoPath, tickets, highlightedIndex]);
|
|
1582
|
-
|
|
1512
|
+
useInput9(
|
|
1583
1513
|
(input, key) => {
|
|
1584
1514
|
if (showConfigureModal || showLinkModal || showStatusModal) return;
|
|
1585
1515
|
if (input === "c" && jiraState === "not_configured") {
|
|
@@ -1711,10 +1641,10 @@ function KeybindingsBar({ contextBindings = [], modalOpen = false }) {
|
|
|
1711
1641
|
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1712
1642
|
function App() {
|
|
1713
1643
|
const { exit } = useApp();
|
|
1714
|
-
const [focusedView, setFocusedView] =
|
|
1715
|
-
const [modalOpen, setModalOpen] =
|
|
1716
|
-
const [contextBindings, setContextBindings] =
|
|
1717
|
-
|
|
1644
|
+
const [focusedView, setFocusedView] = useState8("github");
|
|
1645
|
+
const [modalOpen, setModalOpen] = useState8(false);
|
|
1646
|
+
const [contextBindings, setContextBindings] = useState8([]);
|
|
1647
|
+
useInput10(
|
|
1718
1648
|
(input, key) => {
|
|
1719
1649
|
if (key.ctrl && input === "c") {
|
|
1720
1650
|
exit();
|
|
@@ -1733,7 +1663,6 @@ function App() {
|
|
|
1733
1663
|
GitHubView,
|
|
1734
1664
|
{
|
|
1735
1665
|
isFocused: focusedView === "github",
|
|
1736
|
-
onModalChange: setModalOpen,
|
|
1737
1666
|
onKeybindingsChange: focusedView === "github" ? setContextBindings : void 0
|
|
1738
1667
|
}
|
|
1739
1668
|
),
|
|
@@ -1754,7 +1683,7 @@ import { render as inkRender } from "ink";
|
|
|
1754
1683
|
|
|
1755
1684
|
// src/lib/Screen.tsx
|
|
1756
1685
|
import { Box as Box14, useStdout } from "ink";
|
|
1757
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useState as
|
|
1686
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useState as useState9 } from "react";
|
|
1758
1687
|
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1759
1688
|
function Screen({ children }) {
|
|
1760
1689
|
const { stdout } = useStdout();
|
|
@@ -1762,7 +1691,7 @@ function Screen({ children }) {
|
|
|
1762
1691
|
() => ({ height: stdout.rows, width: stdout.columns }),
|
|
1763
1692
|
[stdout]
|
|
1764
1693
|
);
|
|
1765
|
-
const [size, setSize] =
|
|
1694
|
+
const [size, setSize] = useState9(getSize);
|
|
1766
1695
|
useEffect6(() => {
|
|
1767
1696
|
const onResize = () => setSize(getSize());
|
|
1768
1697
|
stdout.on("resize", onResize);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clairo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,9 +22,12 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
25
|
+
"cli-table3": "^0.6.5",
|
|
25
26
|
"ink": "^6.6.0",
|
|
27
|
+
"ink-link": "^5.0.0",
|
|
26
28
|
"ink-scroll-view": "^0.3.5",
|
|
27
29
|
"ink-select-input": "^6.2.0",
|
|
30
|
+
"marked": "^17.0.1",
|
|
28
31
|
"meow": "^11.0.0",
|
|
29
32
|
"open": "^11.0.0",
|
|
30
33
|
"react": "^19.2.4"
|