@say8425/cc-statusline 3.1.0 → 3.2.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/index.js CHANGED
@@ -19,41 +19,29 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
19
  // src/diff-server/config.ts
20
20
  import { homedir } from "os";
21
21
  import { join } from "path";
22
- function resolveDiffPort(env = process.env) {
22
+ var DEFAULT_DIFF_PORT = 49573, resolveDiffPort = (env = process.env) => {
23
23
  const raw = env.CC_STATUSLINE_DIFF_PORT;
24
24
  if (!raw)
25
25
  return DEFAULT_DIFF_PORT;
26
26
  const n = Number.parseInt(raw, 10);
27
27
  return Number.isInteger(n) && n > 0 && n < 65536 ? n : DEFAULT_DIFF_PORT;
28
- }
29
- function isDiffViewerDisabled(env = process.env) {
30
- return env.CC_STATUSLINE_DIFF_DISABLE === "1";
31
- }
32
- function getCacheDir(env = process.env) {
28
+ }, isDiffViewerDisabled = (env = process.env) => env.CC_STATUSLINE_DIFF_DISABLE === "1", getCacheDir = (env = process.env) => {
33
29
  const base = env.XDG_CACHE_HOME || join(env.HOME || homedir(), ".cache");
34
30
  return join(base, "cc-statusline");
35
- }
36
- var DEFAULT_DIFF_PORT = 49573;
31
+ };
37
32
  var init_config = () => {};
38
33
 
39
34
  // src/diff-server/token.ts
40
35
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
41
36
  import { join as join2 } from "path";
42
- function getTokenPath(env = process.env) {
43
- return join2(getCacheDir(env), "diff-server.token");
44
- }
45
- function generateToken() {
46
- return crypto.randomUUID().replaceAll("-", "");
47
- }
48
- function readTokenSync(env = process.env) {
37
+ var getTokenPath = (env = process.env) => join2(getCacheDir(env), "diff-server.token"), generateToken = () => crypto.randomUUID().replaceAll("-", ""), readTokenSync = (env = process.env) => {
49
38
  try {
50
39
  const value = readFileSync(getTokenPath(env), "utf8").trim();
51
40
  return value || null;
52
41
  } catch {
53
42
  return null;
54
43
  }
55
- }
56
- function ensureToken(env = process.env) {
44
+ }, ensureToken = (env = process.env) => {
57
45
  const existing = readTokenSync(env);
58
46
  if (existing)
59
47
  return existing;
@@ -61,36 +49,49 @@ function ensureToken(env = process.env) {
61
49
  mkdirSync(getCacheDir(env), { recursive: true, mode: 448 });
62
50
  writeFileSync(getTokenPath(env), token, { mode: 384 });
63
51
  return token;
64
- }
52
+ };
65
53
  var init_token = __esm(() => {
66
54
  init_config();
67
55
  });
68
56
 
57
+ // src/diff-server/mapLimit.ts
58
+ var mapWithLimit = async (items, limit, fn) => {
59
+ const results = [];
60
+ let next = 0;
61
+ const worker = async () => {
62
+ while (next < items.length) {
63
+ const index = next;
64
+ next += 1;
65
+ results[index] = await fn(items[index], index);
66
+ }
67
+ };
68
+ const workers = Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, () => worker());
69
+ await Promise.all(workers);
70
+ return results;
71
+ };
72
+
69
73
  // src/diff-server/diff.ts
70
74
  import { readFileSync as readFileSync2 } from "fs";
71
- import { join as join4 } from "path";
75
+ import { isAbsolute, join as join4, resolve } from "path";
72
76
  var {$ } = globalThis.Bun;
73
- async function isGitRepo(repo) {
77
+ var BUILD_CONCURRENCY = 8, isGitRepo = async (repo) => {
74
78
  try {
75
79
  const out = await $`git -C ${repo} rev-parse --is-inside-work-tree 2>/dev/null`.text();
76
80
  return out.trim() === "true";
77
81
  } catch {
78
82
  return false;
79
83
  }
80
- }
81
- async function refExists(repo, ref) {
84
+ }, refExists = async (repo, ref) => {
82
85
  const r = await $`git -C ${repo} rev-parse --verify --quiet ${ref}`.nothrow().quiet();
83
86
  return r.exitCode === 0;
84
- }
85
- async function prBaseName(repo) {
87
+ }, prBaseName = async (repo) => {
86
88
  try {
87
89
  const out = await $`gh pr view --json baseRefName -q .baseRefName`.cwd(repo).nothrow().quiet().text();
88
90
  return out.trim() || null;
89
91
  } catch {
90
92
  return null;
91
93
  }
92
- }
93
- async function defaultBranchName(repo) {
94
+ }, defaultBranchName = async (repo) => {
94
95
  const r = await $`git -C ${repo} rev-parse --abbrev-ref origin/HEAD 2>/dev/null`.nothrow().quiet();
95
96
  if (r.exitCode !== 0)
96
97
  return null;
@@ -99,8 +100,7 @@ async function defaultBranchName(repo) {
99
100
  return null;
100
101
  const name = t.slice("origin/".length);
101
102
  return name && name !== "HEAD" ? name : null;
102
- }
103
- async function resolveBaseRef(repo) {
103
+ }, resolveBaseRef = async (repo) => {
104
104
  const named = await prBaseName(repo) ?? await defaultBranchName(repo);
105
105
  const candidates = named ? [`origin/${named}`, named] : ["origin/main", "origin/master", "main", "master"];
106
106
  for (const ref of candidates) {
@@ -110,19 +110,16 @@ async function resolveBaseRef(repo) {
110
110
  }
111
111
  }
112
112
  return { base: named, ref: null };
113
- }
114
- async function showBytes(repo, rev, path) {
113
+ }, showBytes = async (repo, rev, path) => {
115
114
  const buf = await $`git -C ${repo} show ${`${rev}:${path}`} 2>/dev/null`.nothrow().arrayBuffer();
116
115
  return new Uint8Array(buf);
117
- }
118
- function readWorkingBytes(repo, path) {
116
+ }, readWorkingBytes = (repo, path) => {
119
117
  try {
120
118
  return new Uint8Array(readFileSync2(join4(repo, path)));
121
119
  } catch {
122
120
  return new Uint8Array;
123
121
  }
124
- }
125
- async function buildFile(repo, base, status, name, oldName) {
122
+ }, buildFile = async (repo, base, status, name, oldName) => {
126
123
  const oldBytes = status === "added" || status === "untracked" ? new Uint8Array : await showBytes(repo, base, oldName ?? name);
127
124
  const newBytes = status === "deleted" ? new Uint8Array : readWorkingBytes(repo, name);
128
125
  const binary = oldBytes.includes(0) || newBytes.includes(0);
@@ -133,14 +130,32 @@ async function buildFile(repo, base, status, name, oldName) {
133
130
  status,
134
131
  binary,
135
132
  oldContents: binary ? "" : decoder.decode(oldBytes),
136
- newContents: binary ? "" : decoder.decode(newBytes)
133
+ newContents: binary ? "" : decoder.decode(newBytes),
134
+ ...binary ? {
135
+ blobVersion: `${Bun.hash(oldBytes).toString(36)}.${Bun.hash(newBytes).toString(36)}`
136
+ } : {}
137
137
  };
138
- }
139
- async function getDiffFiles(repo, opts = {}) {
140
- const base = opts.mode === "base" && opts.ref ? (await $`git -C ${repo} merge-base ${opts.ref} HEAD 2>/dev/null`.nothrow().text()).trim() : "HEAD";
138
+ }, resolveDiffBaseRev = async (repo, opts) => opts.mode === "base" && opts.ref ? (await $`git -C ${repo} merge-base ${opts.ref} HEAD 2>/dev/null`.nothrow().text()).trim() : "HEAD", getFileBytes = async (repo, path, side, opts = {}) => {
139
+ const root = resolve(repo);
140
+ const target = resolve(root, path);
141
+ if (!path || isAbsolute(path) || target !== root && !target.startsWith(`${root}/`)) {
142
+ return null;
143
+ }
144
+ if (side === "new") {
145
+ const bytes2 = readWorkingBytes(repo, path);
146
+ return bytes2.length > 0 ? bytes2 : null;
147
+ }
148
+ const base = await resolveDiffBaseRev(repo, opts);
149
+ if (!base)
150
+ return null;
151
+ const bytes = await showBytes(repo, base, path);
152
+ return bytes.length > 0 ? bytes : null;
153
+ }, getDiffFiles = async (repo, opts = {}) => {
154
+ const base = await resolveDiffBaseRev(repo, opts);
141
155
  const files = [];
142
156
  if (base) {
143
157
  const nameStatus = await $`git -C ${repo} diff --name-status ${base} 2>/dev/null`.nothrow().text();
158
+ const specs = [];
144
159
  for (const line of nameStatus.split(`
145
160
  `)) {
146
161
  if (!line.trim())
@@ -148,34 +163,64 @@ async function getDiffFiles(repo, opts = {}) {
148
163
  const parts = line.split("\t");
149
164
  const code = parts[0] ?? "";
150
165
  if (code.startsWith("R")) {
151
- files.push(await buildFile(repo, base, "renamed", parts[2] ?? "", parts[1]));
166
+ specs.push({
167
+ status: "renamed",
168
+ name: parts[2] ?? "",
169
+ oldName: parts[1]
170
+ });
152
171
  } else if (code.startsWith("A")) {
153
- files.push(await buildFile(repo, base, "added", parts[1] ?? ""));
172
+ specs.push({ status: "added", name: parts[1] ?? "" });
154
173
  } else if (code.startsWith("D")) {
155
- files.push(await buildFile(repo, base, "deleted", parts[1] ?? ""));
174
+ specs.push({ status: "deleted", name: parts[1] ?? "" });
156
175
  } else {
157
- files.push(await buildFile(repo, base, "modified", parts[1] ?? ""));
176
+ specs.push({ status: "modified", name: parts[1] ?? "" });
158
177
  }
159
178
  }
179
+ files.push(...await mapWithLimit(specs, BUILD_CONCURRENCY, (spec) => buildFile(repo, base, spec.status, spec.name, spec.oldName)));
160
180
  }
161
181
  if (opts.untracked) {
162
182
  const listed = await $`git -C ${repo} ls-files --others --exclude-standard 2>/dev/null`.nothrow().text();
163
- for (const path of listed.split(`
164
- `).map((s) => s.trim()).filter(Boolean)) {
165
- files.push(await buildFile(repo, base, "untracked", path));
166
- }
183
+ const paths = listed.split(`
184
+ `).map((s) => s.trim()).filter(Boolean);
185
+ files.push(...await mapWithLimit(paths, BUILD_CONCURRENCY, (path) => buildFile(repo, base, "untracked", path)));
167
186
  }
168
187
  return files;
169
- }
188
+ };
170
189
  var init_diff = () => {};
171
190
 
191
+ // src/diff-server/imageTypes.ts
192
+ var IMAGE_MIME, extensionOf = (name) => {
193
+ const dot = name.lastIndexOf(".");
194
+ if (dot <= 0 || dot === name.length - 1)
195
+ return null;
196
+ return name.slice(dot + 1).toLowerCase();
197
+ }, isImagePath = (name) => {
198
+ const ext = extensionOf(name);
199
+ return ext !== null && ext in IMAGE_MIME;
200
+ }, imageContentType = (name) => {
201
+ const ext = extensionOf(name);
202
+ return ext && IMAGE_MIME[ext] || "application/octet-stream";
203
+ };
204
+ var init_imageTypes = __esm(() => {
205
+ IMAGE_MIME = {
206
+ png: "image/png",
207
+ jpg: "image/jpeg",
208
+ jpeg: "image/jpeg",
209
+ gif: "image/gif",
210
+ webp: "image/webp",
211
+ avif: "image/avif",
212
+ bmp: "image/bmp",
213
+ ico: "image/x-icon"
214
+ };
215
+ });
216
+
172
217
  // src/diff-server/server.ts
173
218
  var exports_server = {};
174
219
  __export(exports_server, {
175
220
  startDiffServer: () => startDiffServer
176
221
  });
177
- import { resolve } from "path";
178
- async function resolveBaseCached(repo) {
222
+ import { resolve as resolve2 } from "path";
223
+ var BASE_TTL_MS = 1e4, baseCache, resolveBaseCached = async (repo) => {
179
224
  const now = Date.now();
180
225
  const hit = baseCache.get(repo);
181
226
  if (hit && now - hit.at < BASE_TTL_MS)
@@ -183,9 +228,8 @@ async function resolveBaseCached(repo) {
183
228
  const value = await resolveBaseRef(repo);
184
229
  baseCache.set(repo, { value, at: now });
185
230
  return value;
186
- }
187
- function createHandler(cfg) {
188
- const viewerRoot = resolve(cfg.viewerDir);
231
+ }, createHandler = (cfg) => {
232
+ const viewerRoot = resolve2(cfg.viewerDir);
189
233
  return async (req) => {
190
234
  const url = new URL(req.url);
191
235
  if (url.pathname === "/api/ping") {
@@ -217,8 +261,33 @@ function createHandler(cfg) {
217
261
  }
218
262
  });
219
263
  }
264
+ if (url.pathname === "/api/blob") {
265
+ if (url.searchParams.get("token") !== cfg.token) {
266
+ return new Response("forbidden", { status: 403 });
267
+ }
268
+ const repo = url.searchParams.get("repo") ?? "";
269
+ if (!repo || !await isGitRepo(repo)) {
270
+ return new Response("not a git repository", { status: 400 });
271
+ }
272
+ const path = url.searchParams.get("path") ?? "";
273
+ if (!isImagePath(path)) {
274
+ return new Response("not found", { status: 404 });
275
+ }
276
+ const side = url.searchParams.get("side") === "old" ? "old" : "new";
277
+ const mode = url.searchParams.get("mode") === "base" ? "base" : "working";
278
+ const ref = mode === "base" ? (await resolveBaseCached(repo)).ref : null;
279
+ const bytes = await getFileBytes(repo, path, side, mode === "base" && ref ? { mode, ref } : {});
280
+ if (!bytes)
281
+ return new Response("not found", { status: 404 });
282
+ return new Response(bytes, {
283
+ headers: {
284
+ "content-type": imageContentType(path),
285
+ "cache-control": "no-store"
286
+ }
287
+ });
288
+ }
220
289
  const rel = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
221
- const filePath = resolve(viewerRoot, rel);
290
+ const filePath = resolve2(viewerRoot, rel);
222
291
  if (filePath !== viewerRoot && !filePath.startsWith(`${viewerRoot}/`)) {
223
292
  return new Response("forbidden", { status: 403 });
224
293
  }
@@ -228,8 +297,7 @@ function createHandler(cfg) {
228
297
  }
229
298
  return new Response("not found", { status: 404 });
230
299
  };
231
- }
232
- function startDiffServer(opts) {
300
+ }, startDiffServer = (opts) => {
233
301
  const env = opts.env ?? process.env;
234
302
  const token = ensureToken(env);
235
303
  let lastActivity = Date.now();
@@ -253,23 +321,23 @@ function startDiffServer(opts) {
253
321
  }, 60000);
254
322
  idleTimer.unref?.();
255
323
  }
256
- function stop() {
324
+ const stop = () => {
257
325
  if (idleTimer)
258
326
  clearInterval(idleTimer);
259
327
  server.stop(true);
260
- }
328
+ };
261
329
  return { server, token, stop };
262
- }
263
- var BASE_TTL_MS = 1e4, baseCache;
330
+ };
264
331
  var init_server = __esm(() => {
265
332
  init_diff();
333
+ init_imageTypes();
266
334
  init_token();
267
335
  baseCache = new Map;
268
336
  });
269
337
 
270
338
  // src/index.ts
271
339
  init_config();
272
- import { join as join5 } from "path";
340
+ import { join as join6 } from "path";
273
341
 
274
342
  // src/diff-server/ensure.ts
275
343
  init_config();
@@ -279,7 +347,7 @@ import { join as join3 } from "path";
279
347
  var ENSURE_TTL_MS = 5000;
280
348
  var LOCK_STALE_MS = 30000;
281
349
  var checkedAt = 0;
282
- async function probeOurServer(port) {
350
+ var probeOurServer = async (port) => {
283
351
  try {
284
352
  const res = await fetch(`http://127.0.0.1:${port}/api/ping`, {
285
353
  signal: AbortSignal.timeout(150)
@@ -288,8 +356,8 @@ async function probeOurServer(port) {
288
356
  } catch {
289
357
  return false;
290
358
  }
291
- }
292
- function acquireSpawnLock(env) {
359
+ };
360
+ var acquireSpawnLock = (env) => {
293
361
  const lock = join3(getCacheDir(env), "diff-server.lock");
294
362
  mkdirSync2(getCacheDir(env), { recursive: true, mode: 448 });
295
363
  try {
@@ -305,8 +373,8 @@ function acquireSpawnLock(env) {
305
373
  } catch {}
306
374
  return false;
307
375
  }
308
- }
309
- function spawnDaemon(port, env) {
376
+ };
377
+ var spawnDaemon = (port, env) => {
310
378
  const execPath = process.execPath;
311
379
  const selfPath = Bun.main;
312
380
  Bun.spawn([
@@ -321,8 +389,8 @@ function spawnDaemon(port, env) {
321
389
  stdout: "ignore",
322
390
  stderr: "ignore"
323
391
  }).unref();
324
- }
325
- async function maybeSpawn(port, env, spawn = spawnDaemon) {
392
+ };
393
+ var maybeSpawn = async (port, env, spawn = spawnDaemon) => {
326
394
  try {
327
395
  if (await probeOurServer(port))
328
396
  return;
@@ -330,8 +398,8 @@ async function maybeSpawn(port, env, spawn = spawnDaemon) {
330
398
  return;
331
399
  spawn(port, env);
332
400
  } catch {}
333
- }
334
- async function ensureDiffServer(_repo, env = process.env, spawn = spawnDaemon) {
401
+ };
402
+ var ensureDiffServer = (_repo, env = process.env, spawn = spawnDaemon) => {
335
403
  if (isDiffViewerDisabled(env))
336
404
  return null;
337
405
  const port = resolveDiffPort(env);
@@ -342,10 +410,10 @@ async function ensureDiffServer(_repo, env = process.env, spawn = spawnDaemon) {
342
410
  }
343
411
  const token = readTokenSync(env);
344
412
  return token ? { port, token } : null;
345
- }
413
+ };
346
414
 
347
415
  // src/diff-server/link.ts
348
- function buildDiffViewerUrl(params) {
416
+ var buildDiffViewerUrl = (params) => {
349
417
  const query = new URLSearchParams({
350
418
  repo: params.repo,
351
419
  token: params.token
@@ -353,7 +421,7 @@ function buildDiffViewerUrl(params) {
353
421
  if (params.mode)
354
422
  query.set("mode", params.mode);
355
423
  return `http://127.0.0.1:${params.port}/?${query.toString()}`;
356
- }
424
+ };
357
425
 
358
426
  // src/git/baseChanges.ts
359
427
  var {$: $2 } = globalThis.Bun;
@@ -367,31 +435,33 @@ var cache = {
367
435
  baseRef: {
368
436
  value: null,
369
437
  timestamp: 0
370
- }
438
+ },
439
+ ultracode: { value: false, timestamp: 0 }
371
440
  };
372
441
  var CACHE_TTL = {
373
442
  branch: 5000,
374
443
  gitChanges: 0,
375
444
  prUrl: 30000,
376
445
  mainProjectName: 300000,
377
- baseRef: 30000
446
+ baseRef: 30000,
447
+ ultracode: 5000
378
448
  };
379
449
 
380
450
  // src/git/baseChanges.ts
381
451
  init_diff();
382
452
 
383
453
  // src/git/shortstat.ts
384
- function parseShortstat(text) {
454
+ var parseShortstat = (text) => {
385
455
  const [files, insertions, deletions] = [
386
456
  /(\d+) files?/g,
387
457
  /(\d+) insertions?/g,
388
458
  /(\d+) deletions?/g
389
459
  ].map((regex) => (text.match(regex) || []).reduce((sum, m) => sum + Number.parseInt(m, 10), 0));
390
460
  return { files, insertions, deletions };
391
- }
461
+ };
392
462
 
393
463
  // src/git/baseChanges.ts
394
- async function getBaseChangesCached() {
464
+ var getBaseChangesCached = async () => {
395
465
  try {
396
466
  let resolved = cache.baseRef.value;
397
467
  if (resolved === null || Date.now() - cache.baseRef.timestamp >= CACHE_TTL.baseRef) {
@@ -411,10 +481,10 @@ async function getBaseChangesCached() {
411
481
  } catch {
412
482
  return null;
413
483
  }
414
- }
484
+ };
415
485
  // src/git/branch.ts
416
486
  var {$: $3 } = globalThis.Bun;
417
- async function getBranchCached() {
487
+ var getBranchCached = async () => {
418
488
  if (Date.now() - cache.branch.timestamp < CACHE_TTL.branch) {
419
489
  return cache.branch.value;
420
490
  }
@@ -425,10 +495,10 @@ async function getBranchCached() {
425
495
  } catch {
426
496
  return cache.branch.value;
427
497
  }
428
- }
498
+ };
429
499
  // src/git/changes.ts
430
500
  var {$: $4 } = globalThis.Bun;
431
- async function getGitChangesCached() {
501
+ var getGitChangesCached = async () => {
432
502
  if (Date.now() - cache.gitChanges.timestamp < CACHE_TTL.gitChanges) {
433
503
  return cache.gitChanges;
434
504
  }
@@ -444,10 +514,10 @@ ${staged}`);
444
514
  } catch {
445
515
  return cache.gitChanges;
446
516
  }
447
- }
517
+ };
448
518
  // src/git/pr.ts
449
519
  var {$: $5 } = globalThis.Bun;
450
- async function getPrUrlCached() {
520
+ var getPrUrlCached = async () => {
451
521
  if (Date.now() - cache.prUrl.timestamp < CACHE_TTL.prUrl) {
452
522
  return cache.prUrl.value;
453
523
  }
@@ -458,10 +528,10 @@ async function getPrUrlCached() {
458
528
  } catch {
459
529
  return cache.prUrl.value;
460
530
  }
461
- }
531
+ };
462
532
  // src/git/worktree.ts
463
533
  var {$: $6 } = globalThis.Bun;
464
- async function getMainProjectNameCached() {
534
+ var getMainProjectNameCached = async () => {
465
535
  if (Date.now() - cache.mainProjectName.timestamp < CACHE_TTL.mainProjectName) {
466
536
  return cache.mainProjectName.value;
467
537
  }
@@ -479,7 +549,7 @@ async function getMainProjectNameCached() {
479
549
  } catch {
480
550
  return cache.mainProjectName.value;
481
551
  }
482
- }
552
+ };
483
553
  // src/colors.ts
484
554
  var C = {
485
555
  RESET: "\x1B[0m",
@@ -492,32 +562,28 @@ var C = {
492
562
  WHITE: "\x1B[38;2;200;200;200m",
493
563
  UNDERLINE: "\x1B[4m"
494
564
  };
495
- function getUsageColor(pct) {
565
+ var getUsageColor = (pct) => {
496
566
  if (pct < 50)
497
567
  return C.WHITE;
498
568
  if (pct < 80)
499
569
  return C.YELLOW;
500
570
  return C.RED;
501
- }
571
+ };
502
572
 
503
573
  // src/format/formatNumber.ts
504
- function formatNumber(n) {
505
- return n.toLocaleString("en-US");
506
- }
574
+ var formatNumber = (n) => n.toLocaleString("en-US");
507
575
  // src/format/formatResetDate.ts
508
- function formatResetDate(date) {
576
+ var formatResetDate = (date) => {
509
577
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
510
578
  const day = date.getDate().toString().padStart(2, "0");
511
579
  const hours = date.getHours().toString().padStart(2, "0");
512
580
  const minutes = date.getMinutes().toString().padStart(2, "0");
513
581
  return `${month}/${day} ${hours}:${minutes}`;
514
- }
582
+ };
515
583
  // src/format/formatTime.ts
516
- function formatTime(hours, mins) {
517
- return `${hours.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}`;
518
- }
584
+ var formatTime = (hours, mins) => `${hours.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}`;
519
585
  // src/render.ts
520
- function renderStatusLine(ctx) {
586
+ var renderStatusLine = (ctx) => {
521
587
  const lines = [];
522
588
  const folder = ctx.claudeJson.workspace?.project_dir?.split("/").pop() || "";
523
589
  const sessionMs = ctx.claudeJson.cost?.total_duration_ms || 0;
@@ -544,6 +610,14 @@ function renderStatusLine(ctx) {
544
610
  const ctxColor = getUsageColor(contextPct);
545
611
  line2 += ` | ${ctxColor}\uD83E\uDDE0 ${formatNumber(totalTokens)} (${contextPct}%)${C.RESET}`;
546
612
  }
613
+ const modelName = ctx.claudeJson.model?.display_name;
614
+ if (modelName) {
615
+ const effortLevel = ctx.claudeJson.effort?.level;
616
+ let modelText = effortLevel ? `${modelName} ${effortLevel}` : modelName;
617
+ if (ctx.ultracode && effortLevel === "xhigh")
618
+ modelText += " \u26A1ultra";
619
+ line2 += ` | ${C.WHITE}\uD83E\uDD16 ${modelText}${C.RESET}`;
620
+ }
547
621
  lines.push(line2);
548
622
  if (ctx.rateLimits) {
549
623
  const parts = [];
@@ -593,27 +667,64 @@ function renderStatusLine(ctx) {
593
667
  lines.push(line4);
594
668
  }
595
669
  return lines;
596
- }
670
+ };
597
671
 
598
672
  // src/stdin.ts
599
- async function readStdin() {
673
+ var readStdin = async () => {
600
674
  const chunks = [];
601
675
  for await (const chunk of Bun.stdin.stream()) {
602
676
  chunks.push(chunk);
603
677
  }
604
678
  return Buffer.concat(chunks).toString("utf-8");
605
- }
679
+ };
680
+
681
+ // src/ultracode.ts
682
+ import { readFile } from "fs/promises";
683
+ import { homedir as homedir2 } from "os";
684
+ import { join as join5 } from "path";
685
+ var MANAGED_SETTINGS_PATH = process.platform === "darwin" ? "/Library/Application Support/ClaudeCode/managed-settings.json" : process.platform === "win32" ? join5(process.env.ProgramData || "C:\\ProgramData", "ClaudeCode", "managed-settings.json") : "/etc/claude-code/managed-settings.json";
686
+ var ultracodeSettingsPaths = (projectDir, homeDir) => {
687
+ const paths = [MANAGED_SETTINGS_PATH];
688
+ if (projectDir) {
689
+ paths.push(join5(projectDir, ".claude", "settings.local.json"), join5(projectDir, ".claude", "settings.json"));
690
+ }
691
+ paths.push(join5(homeDir, ".claude", "settings.json"));
692
+ return paths;
693
+ };
694
+ var resolveUltracodeFromFiles = async (paths) => {
695
+ const contents = await Promise.all(paths.map((path) => readFile(path, "utf8").catch(() => null)));
696
+ for (const content of contents) {
697
+ if (content === null)
698
+ continue;
699
+ try {
700
+ const parsed = JSON.parse(content);
701
+ if (typeof parsed === "object" && parsed !== null && "ultracode" in parsed && typeof parsed.ultracode === "boolean") {
702
+ return parsed.ultracode;
703
+ }
704
+ } catch {}
705
+ }
706
+ return false;
707
+ };
708
+ var getUltracodeCached = async (projectDir, homeDir = homedir2()) => {
709
+ if (Date.now() - cache.ultracode.timestamp < CACHE_TTL.ultracode) {
710
+ return cache.ultracode.value;
711
+ }
712
+ const value = await resolveUltracodeFromFiles(ultracodeSettingsPaths(projectDir, homeDir));
713
+ cache.ultracode = { value, timestamp: Date.now() };
714
+ return value;
715
+ };
606
716
 
607
717
  // src/index.ts
608
- async function main() {
718
+ var main = async () => {
609
719
  const claudeJson = JSON.parse(await readStdin() || "{}");
610
- const [branch, gitChanges, prUrl, mainProjectName] = await Promise.all([
720
+ const repo = claudeJson.workspace?.project_dir || claudeJson.workspace?.current_dir || "";
721
+ const [branch, gitChanges, prUrl, mainProjectName, ultracode] = await Promise.all([
611
722
  getBranchCached(),
612
723
  getGitChangesCached(),
613
724
  getPrUrlCached(),
614
- getMainProjectNameCached()
725
+ getMainProjectNameCached(),
726
+ getUltracodeCached(repo)
615
727
  ]);
616
- const repo = claudeJson.workspace?.project_dir || claudeJson.workspace?.current_dir || "";
617
728
  const hasChanges = gitChanges.files > 0 || gitChanges.insertions > 0 || gitChanges.deletions > 0;
618
729
  let diffViewerUrl = null;
619
730
  let baseDiffViewerUrl = null;
@@ -622,7 +733,7 @@ async function main() {
622
733
  baseChanges = await getBaseChangesCached();
623
734
  }
624
735
  if (repo && (hasChanges || baseChanges)) {
625
- const ensured = await ensureDiffServer(repo);
736
+ const ensured = ensureDiffServer(repo);
626
737
  if (ensured) {
627
738
  if (hasChanges) {
628
739
  diffViewerUrl = buildDiffViewerUrl({
@@ -646,6 +757,7 @@ async function main() {
646
757
  branch,
647
758
  gitChanges,
648
759
  prUrl,
760
+ ultracode,
649
761
  rateLimits: claudeJson.rate_limits ?? null,
650
762
  mainProjectName,
651
763
  diffViewerUrl,
@@ -655,13 +767,13 @@ async function main() {
655
767
  for (const line of lines) {
656
768
  console.log(line);
657
769
  }
658
- }
770
+ };
659
771
  if (import.meta.main) {
660
772
  if (process.argv.includes("--diff-server")) {
661
773
  const { startDiffServer: startDiffServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
662
774
  startDiffServer2({
663
775
  port: resolveDiffPort(),
664
- viewerDir: join5(import.meta.dir, "viewer")
776
+ viewerDir: join6(import.meta.dir, "viewer")
665
777
  });
666
778
  } else {
667
779
  main().catch(console.error);