@punkcode/cli 0.1.20 → 0.1.22

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,7 +10,7 @@ import {
10
10
  signIn,
11
11
  usePunkStore,
12
12
  version
13
- } from "./chunk-LYCIVKB3.js";
13
+ } from "./chunk-4FFAG2HK.js";
14
14
 
15
15
  // src/ui/App.tsx
16
16
  import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
@@ -221,7 +221,7 @@ function PasswordInput({ onSubmit }) {
221
221
  }
222
222
 
223
223
  // src/ui/Dashboard.tsx
224
- import { useState as useState2, useEffect as useEffect2, useRef } from "react";
224
+ import { useState as useState2, useEffect as useEffect2, useRef, useMemo } from "react";
225
225
  import { Box as Box2, Text as Text2, useApp, useInput as useInput2, useStdout } from "ink";
226
226
  import { Badge } from "@inkjs/ui";
227
227
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -239,6 +239,7 @@ var LOGO = [
239
239
  "\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557",
240
240
  "\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
241
241
  ];
242
+ var LOGO_JSX = LOGO.map((line, i) => /* @__PURE__ */ jsx2(Text2, { color: theme.logo, children: line }, i));
242
243
  function Dashboard({ store, connection, overlay }) {
243
244
  const { exit } = useApp();
244
245
  const { stdout } = useStdout();
@@ -250,20 +251,17 @@ function Dashboard({ store, connection, overlay }) {
250
251
  const sessions = usePunkStore(store, (s) => s.sessions);
251
252
  const activityLog = usePunkStore(store, (s) => s.activityLog);
252
253
  const server = usePunkStore(store, (s) => s.server);
253
- const connectedAt = usePunkStore(store, (s) => s.connectedAt);
254
254
  const auth = usePunkStore(store, (s) => s.auth);
255
255
  const sessionProjects = usePunkStore(store, (s) => s.sessionProjects);
256
256
  const [focusMode, setFocusMode] = useState2(false);
257
257
  const [focusedSessionIdx, setFocusedSessionIdx] = useState2(0);
258
- const knownSessionIds = Object.keys(sessionProjects);
258
+ const knownSessionIds = useMemo(() => Object.keys(sessionProjects), [sessionProjects]);
259
259
  const focusedSessionId = focusMode ? knownSessionIds[focusedSessionIdx] : null;
260
260
  const hasMultipleSessions = knownSessionIds.length > 1;
261
- const filteredActivity = focusedSessionId ? activityLog.filter((e) => e.sessionId === focusedSessionId) : activityLog;
262
- const [now, setNow] = useState2(Date.now());
263
- useEffect2(() => {
264
- const timer = setInterval(() => setNow(Date.now()), 1e3);
265
- return () => clearInterval(timer);
266
- }, []);
261
+ const filteredActivity = useMemo(
262
+ () => focusedSessionId ? activityLog.filter((e) => e.sessionId === focusedSessionId) : activityLog,
263
+ [focusedSessionId, activityLog]
264
+ );
267
265
  const [selectedIdx, setSelectedIdx] = useState2(-1);
268
266
  const [userScrolled, setUserScrolled] = useState2(false);
269
267
  const prevLogLength = useRef(filteredActivity.length);
@@ -284,6 +282,8 @@ function Dashboard({ store, connection, overlay }) {
284
282
  connection?.disconnect();
285
283
  exit();
286
284
  }
285
+ });
286
+ useInput2((input, key) => {
287
287
  if (input === "r") connection?.reconnect();
288
288
  if (input === "c" && !key.ctrl) {
289
289
  store.getState().clearActivity();
@@ -327,9 +327,8 @@ function Dashboard({ store, connection, overlay }) {
327
327
  setSelectedIdx(next);
328
328
  }
329
329
  }
330
- });
330
+ }, { isActive: !overlay });
331
331
  const sessionList = Object.values(sessions);
332
- const uptime = connectedAt ? formatDuration(now - connectedAt) : "-";
333
332
  const boxWidth = termWidth - 2;
334
333
  const col = getColumns(termWidth);
335
334
  const headerHeight = 8;
@@ -354,7 +353,7 @@ function Dashboard({ store, connection, overlay }) {
354
353
  /* @__PURE__ */ jsx2(Text2, { children: stripProtocol(server) })
355
354
  ] })
356
355
  ] }),
357
- 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)) })
356
+ termWidth >= 120 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", alignItems: "flex-end", justifyContent: "center", children: LOGO_JSX })
358
357
  ] })
359
358
  ) : (
360
359
  /* Full header when connected */
@@ -372,10 +371,6 @@ function Dashboard({ store, connection, overlay }) {
372
371
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Status: ".padEnd(12) }),
373
372
  /* @__PURE__ */ jsx2(StatusIndicator, { status: connectionStatus, error: connectionError })
374
373
  ] }),
375
- /* @__PURE__ */ jsxs2(Box2, { children: [
376
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Uptime: ".padEnd(12) }),
377
- /* @__PURE__ */ jsx2(Text2, { children: uptime })
378
- ] }),
379
374
  deviceInfo && /* @__PURE__ */ jsxs2(Box2, { children: [
380
375
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Device: ".padEnd(12) }),
381
376
  /* @__PURE__ */ jsx2(Text2, { children: deviceInfo.name })
@@ -445,7 +440,7 @@ function Dashboard({ store, connection, overlay }) {
445
440
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " details" })
446
441
  ] })
447
442
  ] }) }),
448
- 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)) })
443
+ termWidth >= 120 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", alignItems: "flex-end", justifyContent: "center", children: LOGO_JSX })
449
444
  ] })
450
445
  ),
451
446
  !overlay && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginX: 1, marginTop: 1, children: [
@@ -464,13 +459,13 @@ function Dashboard({ store, connection, overlay }) {
464
459
  "ID".padEnd(col.id),
465
460
  "PROJECT".padEnd(col.project),
466
461
  "STATUS".padEnd(col.status),
467
- "STARTED".padEnd(col.started),
462
+ "RUNNING".padEnd(col.started),
468
463
  col.showExtras ? "MODEL".padEnd(col.model) + "EFFORT" : ""
469
464
  ] }) }),
470
465
  sessionList.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
471
466
  "\u25CB",
472
467
  " Waiting for sessions from the Punk app..."
473
- ] }) : sessionList.map((session) => /* @__PURE__ */ jsx2(SessionRow, { session, now, col }, session.requestId))
468
+ ] }) : sessionList.map((session) => /* @__PURE__ */ jsx2(SessionRow, { session, col }, session.requestId))
474
469
  ]
475
470
  }
476
471
  )
@@ -631,10 +626,17 @@ function StatusIndicator({ status, error }) {
631
626
  " Disconnected"
632
627
  ] });
633
628
  }
634
- function SessionRow({ session, now, col }) {
629
+ function SessionRow({ session, col }) {
630
+ const [elapsed, setElapsed] = useState2(Date.now() - session.startedAt);
631
+ useEffect2(() => {
632
+ const timer = setInterval(() => {
633
+ setElapsed(Date.now() - session.startedAt);
634
+ }, 1e3);
635
+ return () => clearInterval(timer);
636
+ }, [session.startedAt]);
635
637
  const id = session.requestId.slice(0, col.id - 2);
636
638
  const project = session.workingDirectory ? session.workingDirectory.split("/").pop() ?? "" : "";
637
- const started = formatDuration(now - session.startedAt);
639
+ const started = formatDuration(elapsed);
638
640
  return /* @__PURE__ */ jsxs2(Box2, { children: [
639
641
  /* @__PURE__ */ jsxs2(Text2, { children: [
640
642
  id.padEnd(col.id),
@@ -751,7 +753,7 @@ function formatDuration(ms) {
751
753
  const seconds = Math.floor(ms / 1e3);
752
754
  if (seconds < 60) return `${seconds}s`;
753
755
  const minutes = Math.floor(seconds / 60);
754
- if (minutes < 60) return `${minutes}m ${seconds % 60}s`;
756
+ if (minutes < 60) return `${minutes}m`;
755
757
  const hours = Math.floor(minutes / 60);
756
758
  return `${hours}h ${minutes % 60}m`;
757
759
  }
@@ -794,6 +796,15 @@ function App({ server, idToken, options }) {
794
796
  connectionRef.current?.disconnect();
795
797
  };
796
798
  }, []);
799
+ useEffect3(() => {
800
+ const onSigcont = () => {
801
+ connectionRef.current?.reconnect();
802
+ };
803
+ process.on("SIGCONT", onSigcont);
804
+ return () => {
805
+ process.removeListener("SIGCONT", onSigcont);
806
+ };
807
+ }, []);
797
808
  const loginOverlay = screen === "login" ? /* @__PURE__ */ jsx3(LoginDialog, { store, server }) : void 0;
798
809
  return /* @__PURE__ */ jsx3(
799
810
  Dashboard,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var version = "0.1.20";
4
+ var version = "0.1.22";
5
5
 
6
6
  // src/lib/auth.ts
7
7
  import fs from "fs";
@@ -1175,7 +1175,6 @@ var PunkConnection = class {
1175
1175
  }
1176
1176
  }, 50 * 60 * 1e3);
1177
1177
  this.attachSocketHandlers();
1178
- this.attachSignalHandlers();
1179
1178
  }
1180
1179
  disconnect() {
1181
1180
  this.cleanup();
@@ -1273,18 +1272,6 @@ var PunkConnection = class {
1273
1272
  this.resolvePermission(msg.requestId, msg.toolUseId, msg.allow, msg.answers, msg.feedback, msg.permissionMode);
1274
1273
  });
1275
1274
  }
1276
- attachSignalHandlers() {
1277
- const onShutdown = () => {
1278
- this.store.getState().addActivity({ icon: "\u25CF", message: "Shutting down..." });
1279
- this.cleanup();
1280
- process.exit(0);
1281
- };
1282
- process.on("SIGINT", onShutdown);
1283
- process.on("SIGTERM", onShutdown);
1284
- process.on("SIGCONT", () => {
1285
- this.reconnect();
1286
- });
1287
- }
1288
1275
  send(event, msg) {
1289
1276
  if (!this.socket.connected) return;
1290
1277
  this.socket.emit(event, msg);
@@ -1592,9 +1579,11 @@ var createPunkStore = (server) => createStore((set) => ({
1592
1579
  return { sessions: { ...s.sessions, [id]: { ...existing, ...updates } } };
1593
1580
  }),
1594
1581
  removeSession: (id) => set((s) => {
1595
- const rest = { ...s.sessions };
1596
- delete rest[id];
1597
- return { sessions: rest };
1582
+ const sessions = { ...s.sessions };
1583
+ delete sessions[id];
1584
+ const sessionProjects = { ...s.sessionProjects };
1585
+ delete sessionProjects[id];
1586
+ return { sessions, sessionProjects };
1598
1587
  }),
1599
1588
  addActivity: (entry) => set((s) => ({
1600
1589
  activityLog: [
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  refreshIdToken,
9
9
  signIn,
10
10
  version
11
- } from "./chunk-LYCIVKB3.js";
11
+ } from "./chunk-4FFAG2HK.js";
12
12
 
13
13
  // src/cli.ts
14
14
  import { program } from "commander";
@@ -128,23 +128,32 @@ async function runHeadless(server, idToken, options) {
128
128
  }
129
129
  }
130
130
  });
131
- new PunkConnection(server, idToken, options, store);
131
+ const connection = new PunkConnection(server, idToken, options, store);
132
+ const shutdown = () => {
133
+ connection.disconnect();
134
+ process.exit(0);
135
+ };
136
+ process.on("SIGINT", shutdown);
137
+ process.on("SIGTERM", shutdown);
132
138
  await new Promise(() => {
133
139
  });
134
140
  }
135
141
  async function runTui(server, options) {
136
142
  const { render } = await import("ink");
137
143
  const { createElement } = await import("react");
138
- const { App } = await import("./App-VFRKDZOG.js");
144
+ const { App } = await import("./App-RF23NIE6.js");
139
145
  const idToken = options.token ? options.token : void 0;
140
146
  process.stdout.write("\x1B[?1049h");
141
147
  process.stdout.write("\x1B[H");
142
- const { waitUntilExit } = render(
148
+ const { waitUntilExit, unmount } = render(
143
149
  createElement(App, { server, idToken, options })
144
150
  );
151
+ const onSigterm = () => unmount();
152
+ process.once("SIGTERM", onSigterm);
145
153
  try {
146
154
  await waitUntilExit();
147
155
  } finally {
156
+ process.removeListener("SIGTERM", onSigterm);
148
157
  process.stdout.write("\x1B[?1049l");
149
158
  }
150
159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@punkcode/cli",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Control Claude Code from your phone",
5
5
  "type": "module",
6
6
  "bin": {