pair-mode 0.2.0 → 0.2.1

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 CHANGED
@@ -1,3 +1,5 @@
1
+ <img src="https://raw.githubusercontent.com/oFrusch/pair-mode/main/docs/images/duck.png" alt="The pair-mode duck" width="120" align="right">
2
+
1
3
  # pair mode
2
4
 
3
5
  #### For when your agent needs a rubber ducky.
Binary file
Binary file
package/dist/cli.js CHANGED
@@ -7361,7 +7361,7 @@ var require_dist = __commonJS({
7361
7361
  });
7362
7362
 
7363
7363
  // src/cli/index.ts
7364
- import { readFileSync as readFileSync7 } from "node:fs";
7364
+ import { readFileSync as readFileSync8 } from "node:fs";
7365
7365
  import { join as join13, resolve as resolve2 } from "node:path";
7366
7366
 
7367
7367
  // src/cli/setup/setup.ts
@@ -12156,6 +12156,7 @@ function runTui(options, io, abort) {
12156
12156
  var TITLE = "pair-mode watch";
12157
12157
  var HINT = "waiting for an edit \xB7 q quits";
12158
12158
  var LABEL_WIDTH = 10;
12159
+ var DUCK = [" __", " <(o )___", " ( ._> /", " `---'"];
12159
12160
  function line(label, value, truecolor) {
12160
12161
  return fg(theme.fold, truecolor) + label.padEnd(LABEL_WIDTH) + RESET + value;
12161
12162
  }
@@ -12167,9 +12168,12 @@ function queueText(waiting) {
12167
12168
  }
12168
12169
  function renderIdle(status, width, truecolor) {
12169
12170
  const heading = bg(theme.chrome, truecolor) + fg(theme.statusText, truecolor) + TITLE.padEnd(width).slice(0, width) + RESET;
12171
+ const duck = DUCK.map((row) => fg(theme.chrome, truecolor) + row + RESET);
12170
12172
  return [
12171
12173
  heading,
12172
12174
  "",
12175
+ ...duck,
12176
+ "",
12173
12177
  line("session", status.directory, truecolor),
12174
12178
  line("socket", status.socketPath, truecolor),
12175
12179
  line("clients", plural(status.clients, "client"), truecolor),
@@ -12597,6 +12601,8 @@ function runConfig(args, path) {
12597
12601
  // src/web/server.ts
12598
12602
  import { createServer as createServer2 } from "node:http";
12599
12603
  import { randomBytes as randomBytes4 } from "node:crypto";
12604
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
12605
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
12600
12606
 
12601
12607
  // src/web/client/bundle.ts
12602
12608
  var CLIENT_BUNDLE = `"use strict";
@@ -12946,7 +12952,8 @@ header {
12946
12952
  }
12947
12953
 
12948
12954
  header .seg { padding: 6px 13px; white-space: nowrap; }
12949
- header .mode { background: var(--amber); color: ${theme.statusText}; font-weight: 700; letter-spacing: 0.1em; }
12955
+ header .mode { display: flex; align-items: center; gap: 7px; color: var(--amber); font-weight: 700; letter-spacing: 0.1em; }
12956
+ header .mark { border-radius: 4px; }
12950
12957
  header .path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--muted); }
12951
12958
  header .plus { color: var(--add-bar); }
12952
12959
  header .minus { color: var(--del-bar); }
@@ -13170,7 +13177,15 @@ textarea {
13170
13177
 
13171
13178
  .hint { color: var(--dim); font-size: 11px; }
13172
13179
 
13173
- #idle { padding: 64px 24px; color: var(--dim); text-align: center; }
13180
+ #idle { padding: 72px 24px; color: var(--dim); text-align: center; }
13181
+ #idle img { border-radius: 14px; opacity: 0.75; animation: bob 3.2s ease-in-out infinite; }
13182
+ #idle p { margin: 16px 0 0; }
13183
+
13184
+ @keyframes bob { 50% { transform: translateY(-6px); } }
13185
+
13186
+ @media (prefers-reduced-motion: reduce) {
13187
+ #idle img { animation: none; }
13188
+ }
13174
13189
 
13175
13190
  @media (max-width: 900px) {
13176
13191
  main { flex-wrap: wrap; }
@@ -13181,6 +13196,7 @@ textarea {
13181
13196
  `;
13182
13197
  var WIRING = String.raw`
13183
13198
  const C = PairClient;
13199
+ const assets = document.body.dataset.assets ?? "";
13184
13200
  const token = location.pathname.split("/")[2];
13185
13201
  const main = document.querySelector("main");
13186
13202
  const diff = document.getElementById("diff");
@@ -13291,7 +13307,8 @@ function renderMargin() {
13291
13307
 
13292
13308
  function render() {
13293
13309
  if (review === null) {
13294
- diff.innerHTML = '<div id="idle">waiting for an edit</div>';
13310
+ diff.innerHTML =
13311
+ '<div id="idle"><img src="' + assets + '/duck.png" alt="" width="88" height="88"><p>waiting for an edit</p></div>';
13295
13312
  pathLabel.textContent = "no review open";
13296
13313
  plusLabel.textContent = "";
13297
13314
  minusLabel.textContent = "";
@@ -13563,18 +13580,19 @@ ${WIRING}`);
13563
13580
  function pressed(layout, wanted) {
13564
13581
  return layout === wanted ? "true" : "false";
13565
13582
  }
13566
- function renderPage(layout = "split") {
13583
+ function renderPage(layout = "split", assetBase = "") {
13567
13584
  return `<!doctype html>
13568
13585
  <html lang="en">
13569
13586
  <head>
13570
13587
  <meta charset="utf-8">
13571
13588
  <meta name="viewport" content="width=device-width, initial-scale=1">
13589
+ <link rel="icon" type="image/png" href="${assetBase}/favicon.png">
13572
13590
  <title>pair mode</title>
13573
13591
  <style>${STYLE}</style>
13574
13592
  </head>
13575
- <body data-layout="${layout}">
13593
+ <body data-layout="${layout}" data-assets="${assetBase}">
13576
13594
  <header>
13577
- <span class="seg mode">PAIR</span>
13595
+ <span class="seg mode"><img class="mark" src="${assetBase}/duck.png" alt="" width="18" height="18">pair</span>
13578
13596
  <span class="seg path" id="path">no review open</span>
13579
13597
  <span class="seg plus" id="plus"></span>
13580
13598
  <span class="seg minus" id="minus"></span>
@@ -13647,6 +13665,15 @@ function webNotesToQuestions(review, notes) {
13647
13665
  var HOST = "127.0.0.1";
13648
13666
  var TOKEN_BYTES = 16;
13649
13667
  var MAX_BODY_BYTES = 1e6;
13668
+ function readAsset(name) {
13669
+ const bundled = fileURLToPath4(new URL(`../assets/${name}`, import.meta.url));
13670
+ const source = fileURLToPath4(new URL(`../../assets/${name}`, import.meta.url));
13671
+ return readFileSync7(existsSync10(bundled) ? bundled : source);
13672
+ }
13673
+ var IMAGES = {
13674
+ "favicon.png": readAsset("favicon.png"),
13675
+ "duck.png": readAsset("duck.png")
13676
+ };
13650
13677
  var NOT_FOUND = 404;
13651
13678
  var OK = 200;
13652
13679
  var BAD_REQUEST = 400;
@@ -13778,7 +13805,13 @@ data: ${data}
13778
13805
  const url = request.url ?? "";
13779
13806
  if (url === base && request.method === "GET") {
13780
13807
  response.writeHead(OK, { "content-type": "text/html; charset=utf-8" });
13781
- response.end(renderPage(options.layout));
13808
+ response.end(renderPage(options.layout, base));
13809
+ return;
13810
+ }
13811
+ const image = url.startsWith(`${base}/`) ? IMAGES[url.slice(base.length + 1)] : void 0;
13812
+ if (image !== void 0 && request.method === "GET") {
13813
+ response.writeHead(OK, { "content-type": "image/png" });
13814
+ response.end(image);
13782
13815
  return;
13783
13816
  }
13784
13817
  if (url === `${base}/events` && request.method === "GET") {
@@ -13947,7 +13980,7 @@ Commands:
13947
13980
  function readVersion() {
13948
13981
  const pkgPath = join13(installRoot(), "package.json");
13949
13982
  try {
13950
- const raw = JSON.parse(readFileSync7(pkgPath, "utf-8"));
13983
+ const raw = JSON.parse(readFileSync8(pkgPath, "utf-8"));
13951
13984
  if (isRecord(raw) && typeof raw["version"] === "string") {
13952
13985
  return raw["version"];
13953
13986
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-mode",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Annotate a coding agent's proposed edits line by line, in your terminal.",
5
5
  "keywords": [
6
6
  "ai",