@punkcode/cli 0.1.17 → 0.1.18

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.
@@ -10,10 +10,10 @@ import {
10
10
  signIn,
11
11
  usePunkStore,
12
12
  version
13
- } from "./chunk-5W6T4TEF.js";
13
+ } from "./chunk-NW32U73H.js";
14
14
 
15
15
  // src/ui/App.tsx
16
- import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
16
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
17
17
 
18
18
  // src/ui/LoginDialog.tsx
19
19
  import { useState, useEffect, useCallback } from "react";
@@ -208,7 +208,7 @@ function PasswordInput({ onSubmit }) {
208
208
  }
209
209
 
210
210
  // src/ui/Dashboard.tsx
211
- import { useState as useState2, useEffect as useEffect2 } from "react";
211
+ import { useState as useState2, useEffect as useEffect2, useRef } from "react";
212
212
  import { Box as Box2, Text as Text2, useApp, useInput as useInput2, useStdout } from "ink";
213
213
  import { Badge } from "@inkjs/ui";
214
214
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -238,18 +238,44 @@ function Dashboard({ store, connection, overlay }) {
238
238
  const server = usePunkStore(store, (s) => s.server);
239
239
  const connectedAt = usePunkStore(store, (s) => s.connectedAt);
240
240
  const auth = usePunkStore(store, (s) => s.auth);
241
+ const sessionProjects = usePunkStore(store, (s) => s.sessionProjects);
242
+ const [focusMode, setFocusMode] = useState2(false);
243
+ const [focusedSessionIdx, setFocusedSessionIdx] = useState2(0);
244
+ const knownSessionIds = Object.keys(sessionProjects);
245
+ const focusedSessionId = focusMode ? knownSessionIds[focusedSessionIdx] : null;
246
+ const hasMultipleSessions = knownSessionIds.length > 1;
247
+ const filteredActivity = focusedSessionId ? activityLog.filter((e) => e.sessionId === focusedSessionId) : activityLog;
241
248
  const [now, setNow] = useState2(Date.now());
242
249
  useEffect2(() => {
243
250
  const timer = setInterval(() => setNow(Date.now()), 1e3);
244
251
  return () => clearInterval(timer);
245
252
  }, []);
253
+ const [selectedIdx, setSelectedIdx] = useState2(-1);
254
+ const [userScrolled, setUserScrolled] = useState2(false);
255
+ const prevLogLength = useRef(filteredActivity.length);
256
+ useEffect2(() => {
257
+ if (filteredActivity.length > prevLogLength.current && !userScrolled) {
258
+ setSelectedIdx(filteredActivity.length - 1);
259
+ }
260
+ prevLogLength.current = filteredActivity.length;
261
+ }, [filteredActivity.length, userScrolled]);
262
+ useEffect2(() => {
263
+ setSelectedIdx(filteredActivity.length - 1);
264
+ setUserScrolled(false);
265
+ }, [focusedSessionId]);
266
+ const [detailEntry, setDetailEntry] = useState2(null);
267
+ const effectiveIdx = selectedIdx === -1 ? filteredActivity.length - 1 : selectedIdx;
246
268
  useInput2((input, key) => {
247
269
  if (input === "q" || input === "c" && key.ctrl) {
248
270
  connection?.disconnect();
249
271
  exit();
250
272
  }
251
273
  if (input === "r") connection?.reconnect();
252
- if (input === "c" && !key.ctrl) store.getState().clearActivity();
274
+ if (input === "c" && !key.ctrl) {
275
+ store.getState().clearActivity();
276
+ setSelectedIdx(-1);
277
+ setUserScrolled(false);
278
+ }
253
279
  if (input === "l") {
254
280
  connection?.disconnect();
255
281
  clearAuth();
@@ -258,6 +284,35 @@ function Dashboard({ store, connection, overlay }) {
258
284
  store.getState().addActivity({ icon: "\u25CF", message: "Logged out" });
259
285
  store.getState().setScreen("login");
260
286
  }
287
+ if (input === "g" && knownSessionIds.length > 0) {
288
+ setFocusMode((f) => !f);
289
+ setFocusedSessionIdx(0);
290
+ }
291
+ if (focusMode && key.leftArrow) {
292
+ setFocusedSessionIdx((i) => (i - 1 + knownSessionIds.length) % knownSessionIds.length);
293
+ }
294
+ if (focusMode && key.rightArrow) {
295
+ setFocusedSessionIdx((i) => (i + 1) % knownSessionIds.length);
296
+ }
297
+ if (key.return && !detailEntry && effectiveIdx >= 0 && effectiveIdx < filteredActivity.length) {
298
+ setDetailEntry(filteredActivity[effectiveIdx]);
299
+ }
300
+ if ((key.escape || key.return) && detailEntry) {
301
+ setDetailEntry(null);
302
+ }
303
+ if (!detailEntry && key.upArrow && filteredActivity.length > 0) {
304
+ setUserScrolled(true);
305
+ setSelectedIdx((prev) => Math.max(0, (prev === -1 ? filteredActivity.length - 1 : prev) - 1));
306
+ }
307
+ if (!detailEntry && key.downArrow && filteredActivity.length > 0) {
308
+ const next = selectedIdx + 1;
309
+ if (next >= filteredActivity.length - 1) {
310
+ setUserScrolled(false);
311
+ setSelectedIdx(filteredActivity.length - 1);
312
+ } else {
313
+ setSelectedIdx(next);
314
+ }
315
+ }
261
316
  });
262
317
  const sessionList = Object.values(sessions);
263
318
  const uptime = connectedAt ? formatDuration(now - connectedAt) : "-";
@@ -266,8 +321,14 @@ function Dashboard({ store, connection, overlay }) {
266
321
  const headerHeight = 8;
267
322
  const sessionHeight = Math.max(sessionList.length, 1) + 5;
268
323
  const footerHeight = 1;
269
- const activityHeight = Math.max(termHeight - headerHeight - sessionHeight - footerHeight - 4, 4);
270
- const visibleActivity = activityLog.slice(-activityHeight);
324
+ const visibleCount = Math.max(termHeight - headerHeight - sessionHeight - footerHeight - 4, 4);
325
+ const tabBarHeight = focusMode ? 1 : 0;
326
+ const adjustedVisibleCount = visibleCount - tabBarHeight;
327
+ let viewStart = Math.max(0, filteredActivity.length - adjustedVisibleCount);
328
+ if (effectiveIdx < viewStart) viewStart = effectiveIdx;
329
+ if (effectiveIdx >= viewStart + adjustedVisibleCount) viewStart = effectiveIdx - adjustedVisibleCount + 1;
330
+ viewStart = Math.max(0, viewStart);
331
+ const visibleActivity = filteredActivity.slice(viewStart, viewStart + adjustedVisibleCount);
271
332
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: termWidth, height: termHeight, children: [
272
333
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", justifyContent: "space-between", width: termWidth - 2, paddingX: 1, children: [
273
334
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
@@ -330,15 +391,19 @@ function Dashboard({ store, connection, overlay }) {
330
391
  ] }),
331
392
  /* @__PURE__ */ jsxs2(Box2, { children: [
332
393
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "<c> ".padEnd(10) }),
333
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Clear Log" })
394
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Clear Activity" })
395
+ ] }),
396
+ /* @__PURE__ */ jsxs2(Box2, { children: [
397
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "<g> ".padEnd(10) }),
398
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Group Activity" })
334
399
  ] }),
335
400
  /* @__PURE__ */ jsxs2(Box2, { children: [
336
401
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "<l> ".padEnd(10) }),
337
402
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Logout" })
338
403
  ] }),
339
404
  /* @__PURE__ */ jsxs2(Box2, { children: [
340
- /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "<ctrl-c>".padEnd(10) }),
341
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Force Quit" })
405
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "<enter> ".padEnd(10) }),
406
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Activity Details" })
342
407
  ] })
343
408
  ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
344
409
  /* @__PURE__ */ jsxs2(Text2, { children: [
@@ -350,8 +415,14 @@ function Dashboard({ store, connection, overlay }) {
350
415
  /* @__PURE__ */ jsxs2(Text2, { children: [
351
416
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "c" }),
352
417
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " clear " }),
418
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "g" }),
419
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " group" })
420
+ ] }),
421
+ /* @__PURE__ */ jsxs2(Text2, { children: [
353
422
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "l" }),
354
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " logout" })
423
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " logout " }),
424
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "enter" }),
425
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " details" })
355
426
  ] })
356
427
  ] }) }),
357
428
  termWidth >= 120 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", alignItems: "flex-end", justifyContent: "center", children: LOGO.map((line, i) => /* @__PURE__ */ jsx2(Text2, { color: theme.logo, children: line }, i)) })
@@ -384,7 +455,10 @@ function Dashboard({ store, connection, overlay }) {
384
455
  )
385
456
  ] }),
386
457
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginX: 1, flexGrow: 1, children: [
387
- buildTopBorderJsx(overlay ? "Login" : "Activity", boxWidth),
458
+ buildTopBorderJsx(
459
+ overlay ? "Login" : focusMode && focusedSessionId ? `Activity: ${sessionProjects[focusedSessionId]?.project ?? focusedSessionId.slice(0, 8)}` : filteredActivity.length > adjustedVisibleCount ? `Activity (${effectiveIdx + 1}/${filteredActivity.length})` : "Activity",
460
+ boxWidth
461
+ ),
388
462
  /* @__PURE__ */ jsx2(
389
463
  Box2,
390
464
  {
@@ -396,23 +470,117 @@ function Dashboard({ store, connection, overlay }) {
396
470
  flexGrow: 1,
397
471
  alignItems: overlay ? "center" : void 0,
398
472
  justifyContent: overlay ? "center" : void 0,
399
- children: overlay ?? (visibleActivity.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Waiting for events..." }) : visibleActivity.map((entry, i) => /* @__PURE__ */ jsx2(ActivityRow, { entry, termWidth }, `${entry.timestamp}-${i}`)))
473
+ children: overlay ?? (detailEntry ? (
474
+ /* Detail view */
475
+ /* @__PURE__ */ jsx2(DetailView, { entry: detailEntry, sessionProjects })
476
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
477
+ focusMode && knownSessionIds.length > 0 && /* @__PURE__ */ jsxs2(Box2, { marginBottom: 1, gap: 1, children: [
478
+ knownSessionIds.map((sid, i) => {
479
+ const sp = sessionProjects[sid];
480
+ const isFocused = i === focusedSessionIdx;
481
+ return /* @__PURE__ */ jsx2(Text2, { children: isFocused ? /* @__PURE__ */ jsxs2(Text2, { bold: true, children: [
482
+ "[",
483
+ sp?.project ?? sid.slice(0, 8),
484
+ ":",
485
+ sid.slice(0, 8),
486
+ "]"
487
+ ] }) : /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
488
+ " ",
489
+ sp?.project ?? sid.slice(0, 8),
490
+ ":",
491
+ sid.slice(0, 8),
492
+ " "
493
+ ] }) }, sid);
494
+ }),
495
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
496
+ " ",
497
+ "\u2190",
498
+ "/",
499
+ "\u2192",
500
+ " switch g all"
501
+ ] })
502
+ ] }),
503
+ visibleActivity.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Waiting for events..." }) : visibleActivity.map((entry, i) => /* @__PURE__ */ jsx2(
504
+ ActivityRow,
505
+ {
506
+ entry,
507
+ termWidth,
508
+ isSelected: viewStart + i === effectiveIdx,
509
+ sessionProjects: hasMultipleSessions && !focusMode ? sessionProjects : void 0
510
+ },
511
+ `${entry.timestamp}-${i}`
512
+ ))
513
+ ] }))
400
514
  }
401
515
  )
402
516
  ] }),
403
517
  /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, justifyContent: "space-between", width: termWidth - 2, children: [
518
+ /* @__PURE__ */ jsx2(Box2, { gap: 2, children: detailEntry ? /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsxs2(Text2, { children: [
519
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "esc" }),
520
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " close" })
521
+ ] }) }) : overlay ? /* @__PURE__ */ jsxs2(Fragment, { children: [
522
+ /* @__PURE__ */ jsxs2(Text2, { children: [
523
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "e" }),
524
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " email" })
525
+ ] }),
526
+ /* @__PURE__ */ jsxs2(Text2, { children: [
527
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "q" }),
528
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " quit" })
529
+ ] })
530
+ ] }) : focusMode ? /* @__PURE__ */ jsxs2(Fragment, { children: [
531
+ /* @__PURE__ */ jsxs2(Text2, { children: [
532
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "\u2190\u2192" }),
533
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " switch" })
534
+ ] }),
535
+ /* @__PURE__ */ jsxs2(Text2, { children: [
536
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "g" }),
537
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " all" })
538
+ ] }),
539
+ /* @__PURE__ */ jsxs2(Text2, { children: [
540
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "\u2191\u2193" }),
541
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " scroll" })
542
+ ] }),
543
+ /* @__PURE__ */ jsxs2(Text2, { children: [
544
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "enter" }),
545
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " details" })
546
+ ] }),
547
+ /* @__PURE__ */ jsxs2(Text2, { children: [
548
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "q" }),
549
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " quit" })
550
+ ] })
551
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
552
+ /* @__PURE__ */ jsxs2(Text2, { children: [
553
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "\u2191\u2193" }),
554
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " scroll" })
555
+ ] }),
556
+ /* @__PURE__ */ jsxs2(Text2, { children: [
557
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "enter" }),
558
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " details" })
559
+ ] }),
560
+ /* @__PURE__ */ jsxs2(Text2, { children: [
561
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "g" }),
562
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " group" })
563
+ ] }),
564
+ /* @__PURE__ */ jsxs2(Text2, { children: [
565
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "c" }),
566
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " clear" })
567
+ ] }),
568
+ /* @__PURE__ */ jsxs2(Text2, { children: [
569
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "r" }),
570
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " reconnect" })
571
+ ] }),
572
+ /* @__PURE__ */ jsxs2(Text2, { children: [
573
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "l" }),
574
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " logout" })
575
+ ] }),
576
+ /* @__PURE__ */ jsxs2(Text2, { children: [
577
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: "q" }),
578
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " quit" })
579
+ ] })
580
+ ] }) }),
404
581
  /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
405
582
  "punk v",
406
583
  version
407
- ] }),
408
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
409
- sessionList.length,
410
- " session",
411
- sessionList.length !== 1 ? "s" : "",
412
- " ",
413
- "\xB7",
414
- " ",
415
- stripProtocol(server)
416
584
  ] })
417
585
  ] })
418
586
  ] });
@@ -457,7 +625,54 @@ function SessionRow({ session, now, col }) {
457
625
  col.showExtras && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: session.effort ?? "" })
458
626
  ] });
459
627
  }
460
- function ActivityRow({ entry, termWidth }) {
628
+ function DetailView({ entry, sessionProjects }) {
629
+ const time = new Date(entry.timestamp).toLocaleTimeString("en-US", {
630
+ hour12: false,
631
+ hour: "2-digit",
632
+ minute: "2-digit",
633
+ second: "2-digit"
634
+ });
635
+ const date = new Date(entry.timestamp).toLocaleDateString("en-US", {
636
+ year: "numeric",
637
+ month: "short",
638
+ day: "numeric"
639
+ });
640
+ const sp = entry.sessionId ? sessionProjects[entry.sessionId] : null;
641
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingY: 1, children: [
642
+ /* @__PURE__ */ jsx2(Box2, { gap: 1, children: /* @__PURE__ */ jsxs2(Text2, { bold: true, children: [
643
+ entry.icon,
644
+ " ",
645
+ entry.message
646
+ ] }) }),
647
+ /* @__PURE__ */ jsx2(Text2, { children: " " }),
648
+ /* @__PURE__ */ jsxs2(Box2, { children: [
649
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Time: ".padEnd(12) }),
650
+ /* @__PURE__ */ jsxs2(Text2, { children: [
651
+ date,
652
+ " ",
653
+ time
654
+ ] })
655
+ ] }),
656
+ entry.sessionId && /* @__PURE__ */ jsxs2(Box2, { children: [
657
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Session: ".padEnd(12) }),
658
+ /* @__PURE__ */ jsx2(Text2, { children: entry.sessionId })
659
+ ] }),
660
+ sp && /* @__PURE__ */ jsxs2(Box2, { children: [
661
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Project: ".padEnd(12) }),
662
+ /* @__PURE__ */ jsx2(Text2, { children: sp.project })
663
+ ] }),
664
+ entry.data && Object.entries(entry.data).map(([key, value]) => {
665
+ if (value == null) return null;
666
+ const strValue = typeof value === "string" ? value : JSON.stringify(value);
667
+ if (!strValue) return null;
668
+ return /* @__PURE__ */ jsxs2(Box2, { children: [
669
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: (key + ":").padEnd(12) }),
670
+ /* @__PURE__ */ jsx2(Text2, { children: strValue })
671
+ ] }, key);
672
+ })
673
+ ] });
674
+ }
675
+ function ActivityRow({ entry, termWidth, isSelected, sessionProjects }) {
461
676
  const time = new Date(entry.timestamp).toLocaleTimeString("en-US", {
462
677
  hour12: false,
463
678
  hour: "2-digit",
@@ -467,21 +682,25 @@ function ActivityRow({ entry, termWidth }) {
467
682
  const iconColor = entry.icon === "\u2713" ? theme.success : entry.icon === "\u2717" ? theme.error : entry.icon === "\u25B6" ? theme.primary : entry.icon === "\u27F3" ? theme.warning : "white";
468
683
  const sessionStr = entry.sessionId ? entry.sessionId.slice(0, 8) : "";
469
684
  const detailStr = entry.detail ?? "";
685
+ const marker = isSelected ? "\u25B8 " : " ";
686
+ const sp = sessionProjects && entry.sessionId ? sessionProjects[entry.sessionId] : null;
470
687
  return /* @__PURE__ */ jsxs2(Box2, { children: [
471
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
688
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? theme.primary : void 0, bold: isSelected, children: marker }),
689
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: !isSelected, children: [
472
690
  time,
473
691
  " "
474
692
  ] }),
693
+ sp && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: `${sp.project.slice(0, 8)}:${sessionStr}`.padEnd(18) }),
475
694
  /* @__PURE__ */ jsxs2(Text2, { color: iconColor, bold: true, children: [
476
695
  entry.icon,
477
696
  " "
478
697
  ] }),
479
- /* @__PURE__ */ jsx2(Text2, { children: entry.message }),
480
- termWidth >= 80 && sessionStr && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
698
+ /* @__PURE__ */ jsx2(Text2, { bold: isSelected, children: entry.message }),
699
+ !sp && termWidth >= 80 && sessionStr && /* @__PURE__ */ jsxs2(Text2, { dimColor: !isSelected, children: [
481
700
  " ",
482
701
  sessionStr
483
702
  ] }),
484
- termWidth >= 80 && detailStr && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
703
+ termWidth >= 80 && detailStr && /* @__PURE__ */ jsxs2(Text2, { dimColor: !isSelected, children: [
485
704
  " ",
486
705
  detailStr
487
706
  ] })
@@ -528,7 +747,7 @@ function App({ server, idToken, options }) {
528
747
  }
529
748
  return s;
530
749
  });
531
- const connectionRef = useRef(null);
750
+ const connectionRef = useRef2(null);
532
751
  const screen = usePunkStore(store, (s) => s.screen);
533
752
  useEffect3(() => {
534
753
  if (screen !== "connecting") return;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var version = "0.1.17";
4
+ var version = "0.1.18";
5
5
 
6
6
  // src/lib/auth.ts
7
7
  import fs from "fs";
@@ -1292,6 +1292,8 @@ var PunkConnection = class {
1292
1292
  handlePrompt(msg) {
1293
1293
  const { id, prompt, sessionId, workingDirectory, images, options } = msg;
1294
1294
  const { store } = this;
1295
+ const projectName = workingDirectory ? path3.basename(workingDirectory) : id.slice(0, 8);
1296
+ store.getState().registerSession(id, projectName);
1295
1297
  store.getState().addSession(id, {
1296
1298
  requestId: id,
1297
1299
  prompt,
@@ -1305,7 +1307,8 @@ var PunkConnection = class {
1305
1307
  icon: "\u25B6",
1306
1308
  message: "Session started",
1307
1309
  sessionId: id,
1308
- detail: workingDirectory ? path3.basename(workingDirectory) : void 0
1310
+ detail: workingDirectory ? path3.basename(workingDirectory) : void 0,
1311
+ data: { prompt: prompt.slice(0, 500), workingDirectory, model: options?.model, effort: options?.effort }
1309
1312
  });
1310
1313
  const handle = runClaude(
1311
1314
  { prompt, sessionId, workingDirectory, images, options },
@@ -1324,10 +1327,12 @@ var PunkConnection = class {
1324
1327
  },
1325
1328
  onToolUse: (toolId, name, input, parentToolUseId) => {
1326
1329
  this.send("response", { type: "tool_use", id: toolId, name, input, requestId: id, parent_tool_use_id: parentToolUseId ?? null });
1330
+ const inputStr = typeof input === "string" ? input : JSON.stringify(input);
1327
1331
  store.getState().addActivity({
1328
1332
  icon: "\u25B6",
1329
1333
  message: `Tool: ${name}`,
1330
- sessionId: id
1334
+ sessionId: id,
1335
+ data: { toolName: name, input: inputStr?.slice(0, 500) }
1331
1336
  });
1332
1337
  },
1333
1338
  onToolResult: (toolUseId, content, isError) => {
@@ -1343,13 +1348,14 @@ var PunkConnection = class {
1343
1348
  this.send("response", { type: "error", message, requestId: id });
1344
1349
  this.activeSessions.delete(id);
1345
1350
  store.getState().updateSession(id, { status: "error" });
1346
- store.getState().addActivity({ icon: "\u2717", message: `Error: ${message}`, sessionId: id });
1351
+ store.getState().addActivity({ icon: "\u2717", message: `Error: ${message}`, sessionId: id, data: { error: message } });
1347
1352
  },
1348
1353
  onPermissionRequest: (req) => {
1349
1354
  store.getState().addActivity({
1350
1355
  icon: "\u25CF",
1351
1356
  message: `Permission: ${req.toolName}`,
1352
- sessionId: id
1357
+ sessionId: id,
1358
+ data: { toolName: req.toolName, input: JSON.stringify(req.input).slice(0, 500), reason: req.reason, blockedPath: req.blockedPath }
1353
1359
  });
1354
1360
  this.socket.emit("permission-request", {
1355
1361
  requestId: id,
@@ -1557,7 +1563,8 @@ function fitToPayloadLimit(messages) {
1557
1563
 
1558
1564
  // src/ui/store.ts
1559
1565
  import { createStore, useStore } from "zustand";
1560
- var MAX_ACTIVITY_ENTRIES = 100;
1566
+ var MAX_ACTIVITY_ENTRIES = 500;
1567
+ var SESSION_COLORS = ["magenta", "blue", "magentaBright", "blueBright", "white", "gray"];
1561
1568
  var createPunkStore = (server) => createStore((set) => ({
1562
1569
  // Initial state
1563
1570
  screen: "login",
@@ -1569,6 +1576,7 @@ var createPunkStore = (server) => createStore((set) => ({
1569
1576
  connectedAt: null,
1570
1577
  sessions: {},
1571
1578
  activityLog: [],
1579
+ sessionProjects: {},
1572
1580
  // Actions
1573
1581
  setScreen: (screen) => set({ screen }),
1574
1582
  setAuth: (auth) => set({ auth }),
@@ -1594,7 +1602,17 @@ var createPunkStore = (server) => createStore((set) => ({
1594
1602
  { ...entry, timestamp: Date.now() }
1595
1603
  ]
1596
1604
  })),
1597
- clearActivity: () => set({ activityLog: [] })
1605
+ clearActivity: () => set({ activityLog: [] }),
1606
+ registerSession: (id, project) => set((s) => {
1607
+ if (s.sessionProjects[id]) return s;
1608
+ const colorIdx = Object.keys(s.sessionProjects).length % SESSION_COLORS.length;
1609
+ return {
1610
+ sessionProjects: {
1611
+ ...s.sessionProjects,
1612
+ [id]: { project, color: SESSION_COLORS[colorIdx] }
1613
+ }
1614
+ };
1615
+ })
1598
1616
  }));
1599
1617
  function usePunkStore(store, selector) {
1600
1618
  return useStore(store, selector);
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  refreshIdToken,
9
9
  signIn,
10
10
  version
11
- } from "./chunk-5W6T4TEF.js";
11
+ } from "./chunk-NW32U73H.js";
12
12
 
13
13
  // src/cli.ts
14
14
  import { program } from "commander";
@@ -135,7 +135,7 @@ async function runHeadless(server, idToken, options) {
135
135
  async function runTui(server, options) {
136
136
  const { render } = await import("ink");
137
137
  const { createElement } = await import("react");
138
- const { App } = await import("./App-K3LI5C6C.js");
138
+ const { App } = await import("./App-GTPBJCS2.js");
139
139
  const idToken = options.token ? options.token : void 0;
140
140
  process.stdout.write("\x1B[?1049h");
141
141
  process.stdout.write("\x1B[H");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@punkcode/cli",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "Control Claude Code from your phone",
5
5
  "type": "module",
6
6
  "bin": {