@say8425/cc-statusline 3.1.0 → 4.0.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
@@ -1,351 +1,177 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var __defProp = Object.defineProperty;
4
- var __returnValue = (v) => v;
5
- function __exportSetter(name, newValue) {
6
- this[name] = __returnValue.bind(null, newValue);
7
- }
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, {
11
- get: all[name],
12
- enumerable: true,
13
- configurable: true,
14
- set: __exportSetter.bind(all, name)
15
- });
16
- };
17
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
3
+
4
+ // src/diff-server/ensure.ts
5
+ import { mkdirSync, readFileSync as readFileSync2, rmSync, statSync } from "fs";
6
+ import { dirname, join as join3 } from "path";
7
+ import { fileURLToPath } from "url";
18
8
 
19
9
  // src/diff-server/config.ts
20
10
  import { homedir } from "os";
21
11
  import { join } from "path";
22
- function resolveDiffPort(env = process.env) {
12
+ var DEFAULT_DIFF_PORT = 49573;
13
+ var resolveDiffPort = (env = process.env) => {
23
14
  const raw = env.CC_STATUSLINE_DIFF_PORT;
24
15
  if (!raw)
25
16
  return DEFAULT_DIFF_PORT;
26
17
  const n = Number.parseInt(raw, 10);
27
18
  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) {
19
+ };
20
+ var isDiffViewerDisabled = (env = process.env) => env.CC_STATUSLINE_DIFF_DISABLE === "1";
21
+ var getCacheDir = (env = process.env) => {
33
22
  const base = env.XDG_CACHE_HOME || join(env.HOME || homedir(), ".cache");
34
23
  return join(base, "cc-statusline");
35
- }
36
- var DEFAULT_DIFF_PORT = 49573;
37
- var init_config = () => {};
24
+ };
25
+ var getDiffdeckCacheDir = (env = process.env) => {
26
+ const base = env.XDG_CACHE_HOME || join(env.HOME || homedir(), ".cache");
27
+ return join(base, "diffdeck");
28
+ };
38
29
 
39
30
  // src/diff-server/token.ts
40
- import { mkdirSync, readFileSync, writeFileSync } from "fs";
31
+ import { readFileSync } from "fs";
41
32
  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) {
33
+ var getTokenPath = (env = process.env) => join2(getDiffdeckCacheDir(env), "diff-server.token");
34
+ var readTokenSync = (env = process.env) => {
49
35
  try {
50
36
  const value = readFileSync(getTokenPath(env), "utf8").trim();
51
37
  return value || null;
52
38
  } catch {
53
39
  return null;
54
40
  }
55
- }
56
- function ensureToken(env = process.env) {
57
- const existing = readTokenSync(env);
58
- if (existing)
59
- return existing;
60
- const token = generateToken();
61
- mkdirSync(getCacheDir(env), { recursive: true, mode: 448 });
62
- writeFileSync(getTokenPath(env), token, { mode: 384 });
63
- return token;
64
- }
65
- var init_token = __esm(() => {
66
- init_config();
67
- });
68
-
69
- // src/diff-server/diff.ts
70
- import { readFileSync as readFileSync2 } from "fs";
71
- import { join as join4 } from "path";
72
- var {$ } = globalThis.Bun;
73
- async function isGitRepo(repo) {
74
- try {
75
- const out = await $`git -C ${repo} rev-parse --is-inside-work-tree 2>/dev/null`.text();
76
- return out.trim() === "true";
77
- } catch {
78
- return false;
79
- }
80
- }
81
- async function refExists(repo, ref) {
82
- const r = await $`git -C ${repo} rev-parse --verify --quiet ${ref}`.nothrow().quiet();
83
- return r.exitCode === 0;
84
- }
85
- async function prBaseName(repo) {
86
- try {
87
- const out = await $`gh pr view --json baseRefName -q .baseRefName`.cwd(repo).nothrow().quiet().text();
88
- return out.trim() || null;
89
- } catch {
90
- return null;
91
- }
92
- }
93
- async function defaultBranchName(repo) {
94
- const r = await $`git -C ${repo} rev-parse --abbrev-ref origin/HEAD 2>/dev/null`.nothrow().quiet();
95
- if (r.exitCode !== 0)
96
- return null;
97
- const t = r.text().trim();
98
- if (!t.startsWith("origin/"))
99
- return null;
100
- const name = t.slice("origin/".length);
101
- return name && name !== "HEAD" ? name : null;
102
- }
103
- async function resolveBaseRef(repo) {
104
- const named = await prBaseName(repo) ?? await defaultBranchName(repo);
105
- const candidates = named ? [`origin/${named}`, named] : ["origin/main", "origin/master", "main", "master"];
106
- for (const ref of candidates) {
107
- if (await refExists(repo, ref)) {
108
- const base = ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
109
- return { base, ref };
110
- }
111
- }
112
- return { base: named, ref: null };
113
- }
114
- async function showBytes(repo, rev, path) {
115
- const buf = await $`git -C ${repo} show ${`${rev}:${path}`} 2>/dev/null`.nothrow().arrayBuffer();
116
- return new Uint8Array(buf);
117
- }
118
- function readWorkingBytes(repo, path) {
119
- try {
120
- return new Uint8Array(readFileSync2(join4(repo, path)));
121
- } catch {
122
- return new Uint8Array;
123
- }
124
- }
125
- async function buildFile(repo, base, status, name, oldName) {
126
- const oldBytes = status === "added" || status === "untracked" ? new Uint8Array : await showBytes(repo, base, oldName ?? name);
127
- const newBytes = status === "deleted" ? new Uint8Array : readWorkingBytes(repo, name);
128
- const binary = oldBytes.includes(0) || newBytes.includes(0);
129
- const decoder = new TextDecoder;
130
- return {
131
- name,
132
- ...oldName ? { oldName } : {},
133
- status,
134
- binary,
135
- oldContents: binary ? "" : decoder.decode(oldBytes),
136
- newContents: binary ? "" : decoder.decode(newBytes)
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";
141
- const files = [];
142
- if (base) {
143
- const nameStatus = await $`git -C ${repo} diff --name-status ${base} 2>/dev/null`.nothrow().text();
144
- for (const line of nameStatus.split(`
145
- `)) {
146
- if (!line.trim())
147
- continue;
148
- const parts = line.split("\t");
149
- const code = parts[0] ?? "";
150
- if (code.startsWith("R")) {
151
- files.push(await buildFile(repo, base, "renamed", parts[2] ?? "", parts[1]));
152
- } else if (code.startsWith("A")) {
153
- files.push(await buildFile(repo, base, "added", parts[1] ?? ""));
154
- } else if (code.startsWith("D")) {
155
- files.push(await buildFile(repo, base, "deleted", parts[1] ?? ""));
156
- } else {
157
- files.push(await buildFile(repo, base, "modified", parts[1] ?? ""));
158
- }
159
- }
160
- }
161
- if (opts.untracked) {
162
- 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
- }
167
- }
168
- return files;
169
- }
170
- var init_diff = () => {};
171
-
172
- // src/diff-server/server.ts
173
- var exports_server = {};
174
- __export(exports_server, {
175
- startDiffServer: () => startDiffServer
176
- });
177
- import { resolve } from "path";
178
- async function resolveBaseCached(repo) {
179
- const now = Date.now();
180
- const hit = baseCache.get(repo);
181
- if (hit && now - hit.at < BASE_TTL_MS)
182
- return hit.value;
183
- const value = await resolveBaseRef(repo);
184
- baseCache.set(repo, { value, at: now });
185
- return value;
186
- }
187
- function createHandler(cfg) {
188
- const viewerRoot = resolve(cfg.viewerDir);
189
- return async (req) => {
190
- const url = new URL(req.url);
191
- if (url.pathname === "/api/ping") {
192
- return new Response(null, {
193
- status: 204,
194
- headers: { "x-cc-statusline": "1" }
195
- });
196
- }
197
- if (url.pathname === "/api/diff") {
198
- if (url.searchParams.get("token") !== cfg.token) {
199
- return new Response("forbidden", { status: 403 });
200
- }
201
- const repo = url.searchParams.get("repo") ?? "";
202
- if (!repo || !await isGitRepo(repo)) {
203
- return new Response("not a git repository", { status: 400 });
204
- }
205
- const untracked = url.searchParams.get("untracked") === "1";
206
- const mode = url.searchParams.get("mode") === "base" ? "base" : "working";
207
- const { base, ref } = await resolveBaseCached(repo);
208
- const files = mode === "base" ? await getDiffFiles(repo, {
209
- untracked,
210
- mode: "base",
211
- ref: ref ?? undefined
212
- }) : await getDiffFiles(repo, { untracked });
213
- return new Response(JSON.stringify(files), {
214
- headers: {
215
- "content-type": "application/json; charset=utf-8",
216
- "x-diff-base": base ?? ""
217
- }
218
- });
219
- }
220
- const rel = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
221
- const filePath = resolve(viewerRoot, rel);
222
- if (filePath !== viewerRoot && !filePath.startsWith(`${viewerRoot}/`)) {
223
- return new Response("forbidden", { status: 403 });
224
- }
225
- const file = Bun.file(filePath);
226
- if (await file.exists()) {
227
- return new Response(file, { headers: { "cache-control": "no-store" } });
228
- }
229
- return new Response("not found", { status: 404 });
230
- };
231
- }
232
- function startDiffServer(opts) {
233
- const env = opts.env ?? process.env;
234
- const token = ensureToken(env);
235
- let lastActivity = Date.now();
236
- const handler = createHandler({ viewerDir: opts.viewerDir, token });
237
- const server = Bun.serve({
238
- hostname: "127.0.0.1",
239
- port: opts.port,
240
- fetch: (req) => {
241
- lastActivity = Date.now();
242
- return handler(req);
243
- }
244
- });
245
- let idleTimer;
246
- const idleTimeoutMs = opts.idleTimeoutMs;
247
- if (idleTimeoutMs && idleTimeoutMs > 0) {
248
- idleTimer = setInterval(() => {
249
- if (Date.now() - lastActivity > idleTimeoutMs) {
250
- stop();
251
- process.exit(0);
252
- }
253
- }, 60000);
254
- idleTimer.unref?.();
255
- }
256
- function stop() {
257
- if (idleTimer)
258
- clearInterval(idleTimer);
259
- server.stop(true);
260
- }
261
- return { server, token, stop };
262
- }
263
- var BASE_TTL_MS = 1e4, baseCache;
264
- var init_server = __esm(() => {
265
- init_diff();
266
- init_token();
267
- baseCache = new Map;
268
- });
269
-
270
- // src/index.ts
271
- init_config();
272
- import { join as join5 } from "path";
41
+ };
273
42
 
274
43
  // src/diff-server/ensure.ts
275
- init_config();
276
- init_token();
277
- import { mkdirSync as mkdirSync2, rmSync, statSync } from "fs";
278
- import { join as join3 } from "path";
279
44
  var ENSURE_TTL_MS = 5000;
280
45
  var LOCK_STALE_MS = 30000;
46
+ var PORT_FREE_TRIES = 20;
47
+ var PORT_FREE_INTERVAL_MS = 100;
281
48
  var checkedAt = 0;
282
- async function probeOurServer(port) {
49
+ var probeServer = async (port) => {
283
50
  try {
284
51
  const res = await fetch(`http://127.0.0.1:${port}/api/ping`, {
285
52
  signal: AbortSignal.timeout(150)
286
53
  });
287
- return res.headers.get("x-cc-statusline") === "1";
54
+ const ours = res.headers.get("x-diffdeck") === "1" || res.headers.get("x-cc-statusline") === "1";
55
+ if (!ours)
56
+ return null;
57
+ const version = res.headers.get("x-diffdeck-version");
58
+ const pidRaw = res.headers.get("x-diffdeck-pid");
59
+ const pid = pidRaw == null ? null : Number.parseInt(pidRaw, 10);
60
+ return { version, pid: Number.isInteger(pid) ? pid : null };
288
61
  } catch {
289
- return false;
62
+ return null;
290
63
  }
291
- }
292
- function acquireSpawnLock(env) {
64
+ };
65
+ var lsofPortOwner = (port) => {
66
+ try {
67
+ const out = Bun.spawnSync(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
68
+ if (out.exitCode !== 0)
69
+ return null;
70
+ const first = out.stdout.toString().trim().split(`
71
+ `)[0] ?? "";
72
+ const pid = Number.parseInt(first, 10);
73
+ return Number.isInteger(pid) ? pid : null;
74
+ } catch {
75
+ return null;
76
+ }
77
+ };
78
+ var acquireSpawnLock = (env) => {
293
79
  const lock = join3(getCacheDir(env), "diff-server.lock");
294
- mkdirSync2(getCacheDir(env), { recursive: true, mode: 448 });
80
+ mkdirSync(getCacheDir(env), { recursive: true, mode: 448 });
295
81
  try {
296
- mkdirSync2(lock);
82
+ mkdirSync(lock);
297
83
  return true;
298
84
  } catch {
299
85
  try {
300
86
  if (Date.now() - statSync(lock).mtimeMs > LOCK_STALE_MS) {
301
87
  rmSync(lock, { recursive: true, force: true });
302
- mkdirSync2(lock);
88
+ mkdirSync(lock);
303
89
  return true;
304
90
  }
305
91
  } catch {}
306
92
  return false;
307
93
  }
308
- }
309
- function spawnDaemon(port, env) {
310
- const execPath = process.execPath;
311
- const selfPath = Bun.main;
94
+ };
95
+ var resolveDiffdeck = () => {
96
+ const pkgDir = dirname(fileURLToPath(import.meta.resolve("@say8425/diffdeck/package.json")));
97
+ const pkg = JSON.parse(readFileSync2(join3(pkgDir, "package.json"), "utf8"));
98
+ return { cli: join3(pkgDir, pkg.bin.diffdeck), version: pkg.version };
99
+ };
100
+ var spawnDaemon = (port, env) => {
101
+ const { cli } = resolveDiffdeck();
312
102
  Bun.spawn([
313
103
  "sh",
314
104
  "-c",
315
- 'nohup "$0" "$1" --diff-server >/dev/null 2>&1 &',
316
- execPath,
317
- selfPath
105
+ 'nohup "$0" "$1" --no-open --port "$2" >/dev/null 2>&1 &',
106
+ process.execPath,
107
+ cli,
108
+ String(port)
318
109
  ], {
319
- env: { ...process.env, ...env, CC_STATUSLINE_DIFF_PORT: String(port) },
110
+ env: { ...process.env, ...env, DIFFDECK_PORT: String(port) },
320
111
  stdin: "ignore",
321
112
  stdout: "ignore",
322
113
  stderr: "ignore"
323
114
  }).unref();
324
- }
325
- async function maybeSpawn(port, env, spawn = spawnDaemon) {
115
+ };
116
+ var realDeps = {
117
+ spawn: spawnDaemon,
118
+ probe: probeServer,
119
+ portOwner: lsofPortOwner,
120
+ kill: (pid) => process.kill(pid, "SIGTERM"),
121
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
122
+ currentVersion: () => {
123
+ try {
124
+ return resolveDiffdeck().version;
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+ };
130
+ var waitPortFree = async (port, d) => {
131
+ for (let i = 0;i < PORT_FREE_TRIES; i++) {
132
+ await d.sleep(PORT_FREE_INTERVAL_MS);
133
+ if (await d.probe(port) == null)
134
+ return true;
135
+ }
136
+ return false;
137
+ };
138
+ var maybeSpawn = async (port, env, deps = {}) => {
139
+ const d = { ...realDeps, ...deps };
326
140
  try {
327
- if (await probeOurServer(port))
141
+ const found = await d.probe(port);
142
+ const current = d.currentVersion();
143
+ if (found && (current == null || found.version === current))
328
144
  return;
329
145
  if (!acquireSpawnLock(env))
330
146
  return;
331
- spawn(port, env);
147
+ if (found) {
148
+ const owner = d.portOwner(port);
149
+ if (owner == null)
150
+ return;
151
+ if (found.pid != null && found.pid !== owner)
152
+ return;
153
+ d.kill(owner);
154
+ if (!await waitPortFree(port, d))
155
+ return;
156
+ }
157
+ d.spawn(port, env);
332
158
  } catch {}
333
- }
334
- async function ensureDiffServer(_repo, env = process.env, spawn = spawnDaemon) {
159
+ };
160
+ var ensureDiffServer = (_repo, env = process.env, deps = {}) => {
335
161
  if (isDiffViewerDisabled(env))
336
162
  return null;
337
163
  const port = resolveDiffPort(env);
338
164
  const now = Date.now();
339
165
  if (now - checkedAt >= ENSURE_TTL_MS) {
340
166
  checkedAt = now;
341
- maybeSpawn(port, env, spawn);
167
+ maybeSpawn(port, env, deps);
342
168
  }
343
169
  const token = readTokenSync(env);
344
170
  return token ? { port, token } : null;
345
- }
171
+ };
346
172
 
347
173
  // src/diff-server/link.ts
348
- function buildDiffViewerUrl(params) {
174
+ var buildDiffViewerUrl = (params) => {
349
175
  const query = new URLSearchParams({
350
176
  repo: params.repo,
351
177
  token: params.token
@@ -353,7 +179,7 @@ function buildDiffViewerUrl(params) {
353
179
  if (params.mode)
354
180
  query.set("mode", params.mode);
355
181
  return `http://127.0.0.1:${params.port}/?${query.toString()}`;
356
- }
182
+ };
357
183
 
358
184
  // src/git/baseChanges.ts
359
185
  var {$: $2 } = globalThis.Bun;
@@ -367,31 +193,66 @@ var cache = {
367
193
  baseRef: {
368
194
  value: null,
369
195
  timestamp: 0
370
- }
196
+ },
197
+ ultracode: { value: false, timestamp: 0 }
371
198
  };
372
199
  var CACHE_TTL = {
373
200
  branch: 5000,
374
201
  gitChanges: 0,
375
202
  prUrl: 30000,
376
203
  mainProjectName: 300000,
377
- baseRef: 30000
204
+ baseRef: 30000,
205
+ ultracode: 5000
378
206
  };
379
207
 
380
- // src/git/baseChanges.ts
381
- init_diff();
208
+ // src/git/baseRef.ts
209
+ var {$ } = globalThis.Bun;
210
+ var refExists = async (repo, ref) => {
211
+ const r = await $`git -C ${repo} rev-parse --verify --quiet ${ref}`.nothrow().quiet();
212
+ return r.exitCode === 0;
213
+ };
214
+ var prBaseName = async (repo) => {
215
+ try {
216
+ const out = await $`gh pr view --json baseRefName -q .baseRefName`.cwd(repo).nothrow().quiet().text();
217
+ return out.trim() || null;
218
+ } catch {
219
+ return null;
220
+ }
221
+ };
222
+ var defaultBranchName = async (repo) => {
223
+ const r = await $`git -C ${repo} rev-parse --abbrev-ref origin/HEAD 2>/dev/null`.nothrow().quiet();
224
+ if (r.exitCode !== 0)
225
+ return null;
226
+ const t = r.text().trim();
227
+ if (!t.startsWith("origin/"))
228
+ return null;
229
+ const name = t.slice("origin/".length);
230
+ return name && name !== "HEAD" ? name : null;
231
+ };
232
+ var resolveBaseRef = async (repo) => {
233
+ const named = await prBaseName(repo) ?? await defaultBranchName(repo);
234
+ const candidates = named ? [`origin/${named}`, named] : ["origin/main", "origin/master", "main", "master"];
235
+ for (const ref of candidates) {
236
+ if (await refExists(repo, ref)) {
237
+ const base = ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
238
+ return { base, ref };
239
+ }
240
+ }
241
+ return { base: named, ref: null };
242
+ };
382
243
 
383
244
  // src/git/shortstat.ts
384
- function parseShortstat(text) {
245
+ var parseShortstat = (text) => {
385
246
  const [files, insertions, deletions] = [
386
247
  /(\d+) files?/g,
387
248
  /(\d+) insertions?/g,
388
249
  /(\d+) deletions?/g
389
250
  ].map((regex) => (text.match(regex) || []).reduce((sum, m) => sum + Number.parseInt(m, 10), 0));
390
251
  return { files, insertions, deletions };
391
- }
252
+ };
392
253
 
393
254
  // src/git/baseChanges.ts
394
- async function getBaseChangesCached() {
255
+ var getBaseChangesCached = async () => {
395
256
  try {
396
257
  let resolved = cache.baseRef.value;
397
258
  if (resolved === null || Date.now() - cache.baseRef.timestamp >= CACHE_TTL.baseRef) {
@@ -411,10 +272,10 @@ async function getBaseChangesCached() {
411
272
  } catch {
412
273
  return null;
413
274
  }
414
- }
275
+ };
415
276
  // src/git/branch.ts
416
277
  var {$: $3 } = globalThis.Bun;
417
- async function getBranchCached() {
278
+ var getBranchCached = async () => {
418
279
  if (Date.now() - cache.branch.timestamp < CACHE_TTL.branch) {
419
280
  return cache.branch.value;
420
281
  }
@@ -425,10 +286,10 @@ async function getBranchCached() {
425
286
  } catch {
426
287
  return cache.branch.value;
427
288
  }
428
- }
289
+ };
429
290
  // src/git/changes.ts
430
291
  var {$: $4 } = globalThis.Bun;
431
- async function getGitChangesCached() {
292
+ var getGitChangesCached = async () => {
432
293
  if (Date.now() - cache.gitChanges.timestamp < CACHE_TTL.gitChanges) {
433
294
  return cache.gitChanges;
434
295
  }
@@ -444,10 +305,10 @@ ${staged}`);
444
305
  } catch {
445
306
  return cache.gitChanges;
446
307
  }
447
- }
308
+ };
448
309
  // src/git/pr.ts
449
310
  var {$: $5 } = globalThis.Bun;
450
- async function getPrUrlCached() {
311
+ var getPrUrlCached = async () => {
451
312
  if (Date.now() - cache.prUrl.timestamp < CACHE_TTL.prUrl) {
452
313
  return cache.prUrl.value;
453
314
  }
@@ -458,10 +319,10 @@ async function getPrUrlCached() {
458
319
  } catch {
459
320
  return cache.prUrl.value;
460
321
  }
461
- }
322
+ };
462
323
  // src/git/worktree.ts
463
324
  var {$: $6 } = globalThis.Bun;
464
- async function getMainProjectNameCached() {
325
+ var getMainProjectNameCached = async () => {
465
326
  if (Date.now() - cache.mainProjectName.timestamp < CACHE_TTL.mainProjectName) {
466
327
  return cache.mainProjectName.value;
467
328
  }
@@ -479,7 +340,7 @@ async function getMainProjectNameCached() {
479
340
  } catch {
480
341
  return cache.mainProjectName.value;
481
342
  }
482
- }
343
+ };
483
344
  // src/colors.ts
484
345
  var C = {
485
346
  RESET: "\x1B[0m",
@@ -492,32 +353,28 @@ var C = {
492
353
  WHITE: "\x1B[38;2;200;200;200m",
493
354
  UNDERLINE: "\x1B[4m"
494
355
  };
495
- function getUsageColor(pct) {
356
+ var getUsageColor = (pct) => {
496
357
  if (pct < 50)
497
358
  return C.WHITE;
498
359
  if (pct < 80)
499
360
  return C.YELLOW;
500
361
  return C.RED;
501
- }
362
+ };
502
363
 
503
364
  // src/format/formatNumber.ts
504
- function formatNumber(n) {
505
- return n.toLocaleString("en-US");
506
- }
365
+ var formatNumber = (n) => n.toLocaleString("en-US");
507
366
  // src/format/formatResetDate.ts
508
- function formatResetDate(date) {
367
+ var formatResetDate = (date) => {
509
368
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
510
369
  const day = date.getDate().toString().padStart(2, "0");
511
370
  const hours = date.getHours().toString().padStart(2, "0");
512
371
  const minutes = date.getMinutes().toString().padStart(2, "0");
513
372
  return `${month}/${day} ${hours}:${minutes}`;
514
- }
373
+ };
515
374
  // src/format/formatTime.ts
516
- function formatTime(hours, mins) {
517
- return `${hours.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}`;
518
- }
375
+ var formatTime = (hours, mins) => `${hours.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}`;
519
376
  // src/render.ts
520
- function renderStatusLine(ctx) {
377
+ var renderStatusLine = (ctx) => {
521
378
  const lines = [];
522
379
  const folder = ctx.claudeJson.workspace?.project_dir?.split("/").pop() || "";
523
380
  const sessionMs = ctx.claudeJson.cost?.total_duration_ms || 0;
@@ -544,6 +401,14 @@ function renderStatusLine(ctx) {
544
401
  const ctxColor = getUsageColor(contextPct);
545
402
  line2 += ` | ${ctxColor}\uD83E\uDDE0 ${formatNumber(totalTokens)} (${contextPct}%)${C.RESET}`;
546
403
  }
404
+ const modelName = ctx.claudeJson.model?.display_name;
405
+ if (modelName) {
406
+ const effortLevel = ctx.claudeJson.effort?.level;
407
+ let modelText = effortLevel ? `${modelName} ${effortLevel}` : modelName;
408
+ if (ctx.ultracode && effortLevel === "xhigh")
409
+ modelText += " \u26A1ultra";
410
+ line2 += ` | ${C.WHITE}\uD83E\uDD16 ${modelText}${C.RESET}`;
411
+ }
547
412
  lines.push(line2);
548
413
  if (ctx.rateLimits) {
549
414
  const parts = [];
@@ -593,27 +458,64 @@ function renderStatusLine(ctx) {
593
458
  lines.push(line4);
594
459
  }
595
460
  return lines;
596
- }
461
+ };
597
462
 
598
463
  // src/stdin.ts
599
- async function readStdin() {
464
+ var readStdin = async () => {
600
465
  const chunks = [];
601
466
  for await (const chunk of Bun.stdin.stream()) {
602
467
  chunks.push(chunk);
603
468
  }
604
469
  return Buffer.concat(chunks).toString("utf-8");
605
- }
470
+ };
471
+
472
+ // src/ultracode.ts
473
+ import { readFile } from "fs/promises";
474
+ import { homedir as homedir2 } from "os";
475
+ import { join as join4 } from "path";
476
+ var MANAGED_SETTINGS_PATH = process.platform === "darwin" ? "/Library/Application Support/ClaudeCode/managed-settings.json" : process.platform === "win32" ? join4(process.env.ProgramData || "C:\\ProgramData", "ClaudeCode", "managed-settings.json") : "/etc/claude-code/managed-settings.json";
477
+ var ultracodeSettingsPaths = (projectDir, homeDir) => {
478
+ const paths = [MANAGED_SETTINGS_PATH];
479
+ if (projectDir) {
480
+ paths.push(join4(projectDir, ".claude", "settings.local.json"), join4(projectDir, ".claude", "settings.json"));
481
+ }
482
+ paths.push(join4(homeDir, ".claude", "settings.json"));
483
+ return paths;
484
+ };
485
+ var resolveUltracodeFromFiles = async (paths) => {
486
+ const contents = await Promise.all(paths.map((path) => readFile(path, "utf8").catch(() => null)));
487
+ for (const content of contents) {
488
+ if (content === null)
489
+ continue;
490
+ try {
491
+ const parsed = JSON.parse(content);
492
+ if (typeof parsed === "object" && parsed !== null && "ultracode" in parsed && typeof parsed.ultracode === "boolean") {
493
+ return parsed.ultracode;
494
+ }
495
+ } catch {}
496
+ }
497
+ return false;
498
+ };
499
+ var getUltracodeCached = async (projectDir, homeDir = homedir2()) => {
500
+ if (Date.now() - cache.ultracode.timestamp < CACHE_TTL.ultracode) {
501
+ return cache.ultracode.value;
502
+ }
503
+ const value = await resolveUltracodeFromFiles(ultracodeSettingsPaths(projectDir, homeDir));
504
+ cache.ultracode = { value, timestamp: Date.now() };
505
+ return value;
506
+ };
606
507
 
607
508
  // src/index.ts
608
- async function main() {
509
+ var main = async () => {
609
510
  const claudeJson = JSON.parse(await readStdin() || "{}");
610
- const [branch, gitChanges, prUrl, mainProjectName] = await Promise.all([
511
+ const repo = claudeJson.workspace?.project_dir || claudeJson.workspace?.current_dir || "";
512
+ const [branch, gitChanges, prUrl, mainProjectName, ultracode] = await Promise.all([
611
513
  getBranchCached(),
612
514
  getGitChangesCached(),
613
515
  getPrUrlCached(),
614
- getMainProjectNameCached()
516
+ getMainProjectNameCached(),
517
+ getUltracodeCached(repo)
615
518
  ]);
616
- const repo = claudeJson.workspace?.project_dir || claudeJson.workspace?.current_dir || "";
617
519
  const hasChanges = gitChanges.files > 0 || gitChanges.insertions > 0 || gitChanges.deletions > 0;
618
520
  let diffViewerUrl = null;
619
521
  let baseDiffViewerUrl = null;
@@ -622,7 +524,7 @@ async function main() {
622
524
  baseChanges = await getBaseChangesCached();
623
525
  }
624
526
  if (repo && (hasChanges || baseChanges)) {
625
- const ensured = await ensureDiffServer(repo);
527
+ const ensured = ensureDiffServer(repo);
626
528
  if (ensured) {
627
529
  if (hasChanges) {
628
530
  diffViewerUrl = buildDiffViewerUrl({
@@ -646,6 +548,7 @@ async function main() {
646
548
  branch,
647
549
  gitChanges,
648
550
  prUrl,
551
+ ultracode,
649
552
  rateLimits: claudeJson.rate_limits ?? null,
650
553
  mainProjectName,
651
554
  diffViewerUrl,
@@ -655,17 +558,9 @@ async function main() {
655
558
  for (const line of lines) {
656
559
  console.log(line);
657
560
  }
658
- }
561
+ };
659
562
  if (import.meta.main) {
660
- if (process.argv.includes("--diff-server")) {
661
- const { startDiffServer: startDiffServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
662
- startDiffServer2({
663
- port: resolveDiffPort(),
664
- viewerDir: join5(import.meta.dir, "viewer")
665
- });
666
- } else {
667
- main().catch(console.error);
668
- }
563
+ main().catch(console.error);
669
564
  }
670
565
  export {
671
566
  main