claudeline 1.6.2 → 1.6.3

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.
Files changed (2) hide show
  1. package/dist/index.js +145 -66
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -166,7 +166,7 @@ function listComponents() {
166
166
  {
167
167
  name: "Claude/Session",
168
168
  prefix: "claude",
169
- items: ["model", "model-id", "model-letter", "effort", "version", "session", "session-full", "style"]
169
+ items: ["model", "model-id", "model-letter", "effort", "effort-icon", "version", "session", "session-full", "style"]
170
170
  },
171
171
  {
172
172
  name: "Context Window",
@@ -439,7 +439,7 @@ var THEMES = {
439
439
  nerd: "nerd:nf-dev-nodejs_small env:node-short sep:dot nerd:nf-cod-folder fs:dir sep:dot nerd:nf-dev-git_branch git:branch git:status",
440
440
  compact: "claude:model sep:slash fs:dir sep:slash git:branch",
441
441
  colorful: "bold:magenta:claude:model sep:arrow cyan:nerd:nf-cod-folder cyan:fs:dir sep:arrow green:nerd:nf-dev-git_branch green:git:branch yellow:git:status sep:arrow blue:nerd:nf-fa-gauge blue:ctx:percent",
442
- luca: "bold:magenta:claude:model if:effort(dim:sep:middot text:\u{F09D1} claude:effort) dim:sep:middot cyan:nerd:nf-md-source_branch cyan:git:repo sep:none text:: sep:none green:git:branch if:subdir(sep:none white:text:/ sep:none white:fs:relative) if:dirty(dim:sep:middot git:dirty) dim:sep:middot white:account:email sep:newline bold:white:usage:5h-bar:8 usage:5h (usage:5h-pace) dim:usage:5h-reset dim:sep:middot bold:white:usage:week-bar:8 usage:week (usage:week-pace) dim:usage:week-reset dim:sep:middot white:cost:total"
442
+ luca: "bold:magenta:claude:model if:effort(dim:sep:middot claude:effort-icon claude:effort) dim:sep:middot cyan:nerd:nf-md-source_branch cyan:git:repo sep:none text:: sep:none green:git:branch if:subdir(sep:none white:text:/ sep:none white:fs:relative) if:dirty(dim:sep:middot git:dirty) dim:sep:middot white:account:email sep:newline bold:white:usage:5h-bar:8 usage:5h (usage:5h-pace) dim:usage:5h-reset dim:sep:middot bold:white:usage:week-bar:8 usage:week (usage:week-pace) dim:usage:week-reset dim:sep:middot white:cost:total"
443
443
  };
444
444
  function getTheme(name) {
445
445
  return THEMES[name] || null;
@@ -596,7 +596,7 @@ function getSampleDataJson() {
596
596
 
597
597
  // src/runtime.ts
598
598
  import * as path3 from "path";
599
- import * as os2 from "os";
599
+ import * as os3 from "os";
600
600
  import * as fs3 from "fs";
601
601
  import { execSync as execSync2 } from "child_process";
602
602
 
@@ -638,10 +638,12 @@ function getSeparator(name) {
638
638
  // src/usage.ts
639
639
  import * as fs2 from "fs";
640
640
  import * as path2 from "path";
641
+ import * as os2 from "os";
641
642
  import * as crypto from "crypto";
642
643
  import { execSync } from "child_process";
643
644
  var CACHE_TTL_MS = 5 * 60 * 1e3;
644
645
  var PROFILE_CACHE_TTL_MS = 60 * 60 * 1e3;
646
+ var ANTHROPIC_BETA_HEADER = "oauth-2025-04-20";
645
647
  function tokenHash(token) {
646
648
  return crypto.createHash("sha256").update(token).digest("hex").slice(0, 12);
647
649
  }
@@ -678,29 +680,68 @@ function getKeychainService() {
678
680
  }
679
681
  return "Claude Code-credentials";
680
682
  }
681
- function getOAuthToken() {
683
+ function extractToken(raw) {
682
684
  try {
683
- const service = getKeychainService();
684
- const raw = execSync(
685
- `security find-generic-password -s "${service}" -w 2>/dev/null`,
686
- { encoding: "utf8" }
687
- ).trim();
688
685
  const parsed = JSON.parse(raw);
689
686
  if (typeof parsed === "string") return parsed;
690
687
  if (parsed.claudeAiOauth?.accessToken) return parsed.claudeAiOauth.accessToken;
691
688
  if (parsed.accessToken) return parsed.accessToken;
692
689
  if (parsed.access_token) return parsed.access_token;
690
+ } catch {
691
+ }
692
+ return null;
693
+ }
694
+ function getOAuthTokenMacOS() {
695
+ try {
696
+ const service = getKeychainService();
697
+ const raw = execSync(
698
+ `security find-generic-password -s "${service}" -w 2>/dev/null`,
699
+ { encoding: "utf8" }
700
+ ).trim();
701
+ return extractToken(raw);
702
+ } catch {
693
703
  return null;
704
+ }
705
+ }
706
+ function getOAuthTokenLinux() {
707
+ try {
708
+ const configDir = process.env.CLAUDE_CONFIG_DIR || path2.join(os2.homedir(), ".claude");
709
+ const credPath = path2.join(configDir, ".credentials.json");
710
+ const raw = fs2.readFileSync(credPath, "utf8").trim();
711
+ return extractToken(raw);
694
712
  } catch {
695
713
  return null;
696
714
  }
697
715
  }
698
- function fetchUsage(token) {
716
+ function getOAuthToken() {
717
+ switch (process.platform) {
718
+ case "darwin":
719
+ return getOAuthTokenMacOS();
720
+ case "linux":
721
+ return getOAuthTokenLinux();
722
+ default:
723
+ return null;
724
+ }
725
+ }
726
+ function apiGet(token, urlPath) {
699
727
  try {
700
- const result = execSync(
701
- `curl -s --max-time 5 -H "Authorization: Bearer ${token}" -H "anthropic-beta: oauth-2025-04-20" "https://api.anthropic.com/api/oauth/usage"`,
702
- { encoding: "utf8" }
728
+ return execSync(
729
+ `curl -s --max-time 5 -H "Authorization: Bearer $__CLAUDE_TOKEN" -H "anthropic-beta: ${ANTHROPIC_BETA_HEADER}" "https://api.anthropic.com${urlPath}"`,
730
+ { encoding: "utf8", env: { ...process.env, __CLAUDE_TOKEN: token } }
703
731
  ).trim();
732
+ } catch {
733
+ return null;
734
+ }
735
+ }
736
+ function apiGetWithRetry(token, urlPath) {
737
+ const result = apiGet(token, urlPath);
738
+ if (result !== null) return result;
739
+ return apiGet(token, urlPath);
740
+ }
741
+ function fetchUsage(token) {
742
+ try {
743
+ const result = apiGetWithRetry(token, "/api/oauth/usage");
744
+ if (!result) return null;
704
745
  const data = JSON.parse(result);
705
746
  if (data.five_hour && data.seven_day) {
706
747
  return data;
@@ -789,10 +830,8 @@ function writeProfileCache(cacheFile, data) {
789
830
  }
790
831
  function fetchProfile(token) {
791
832
  try {
792
- const result = execSync(
793
- `curl -s --max-time 5 -H "Authorization: Bearer ${token}" -H "anthropic-beta: oauth-2025-04-20" "https://api.anthropic.com/api/oauth/profile"`,
794
- { encoding: "utf8" }
795
- ).trim();
833
+ const result = apiGetWithRetry(token, "/api/oauth/profile");
834
+ if (!result) return null;
796
835
  const data = JSON.parse(result);
797
836
  if (data.account?.email) {
798
837
  return data;
@@ -1062,7 +1101,44 @@ function applyStyles(text, styles, noColor) {
1062
1101
  if (codes.length === 0) return text;
1063
1102
  return `\x1B[0;${codes.join(";")}m${text}\x1B[${RESET}m`;
1064
1103
  }
1065
- function evaluateClaudeComponent(key, data, noColor = false) {
1104
+ var settingsCache = /* @__PURE__ */ new Map();
1105
+ var SETTINGS_CACHE_TTL = 1e4;
1106
+ function readSettingsFile(filePath) {
1107
+ const cached = settingsCache.get(filePath);
1108
+ if (cached && Date.now() - cached.ts < SETTINGS_CACHE_TTL) {
1109
+ return cached.data;
1110
+ }
1111
+ try {
1112
+ const data = JSON.parse(fs3.readFileSync(filePath, "utf8"));
1113
+ settingsCache.set(filePath, { data, ts: Date.now() });
1114
+ return data;
1115
+ } catch {
1116
+ return {};
1117
+ }
1118
+ }
1119
+ var VALID_EFFORTS = ["low", "medium", "high"];
1120
+ function resolveEffort(data) {
1121
+ const stdinEffort = data.model?.reasoning_effort;
1122
+ if (stdinEffort && VALID_EFFORTS.includes(stdinEffort)) {
1123
+ return stdinEffort;
1124
+ }
1125
+ let effort = "high";
1126
+ const globalPath = path3.join(os3.homedir(), ".claude", "settings.json");
1127
+ const globalSettings = readSettingsFile(globalPath);
1128
+ if (typeof globalSettings.effortLevel === "string" && VALID_EFFORTS.includes(globalSettings.effortLevel)) {
1129
+ effort = globalSettings.effortLevel;
1130
+ }
1131
+ const projectDir = data.workspace?.project_dir;
1132
+ if (projectDir) {
1133
+ const projectPath = path3.join(projectDir, ".claude", "settings.json");
1134
+ const projectSettings = readSettingsFile(projectPath);
1135
+ if (typeof projectSettings.effortLevel === "string" && VALID_EFFORTS.includes(projectSettings.effortLevel)) {
1136
+ effort = projectSettings.effortLevel;
1137
+ }
1138
+ }
1139
+ return effort;
1140
+ }
1141
+ function evaluateClaudeComponent(key, data, noColor = false, noIcons = false) {
1066
1142
  switch (key) {
1067
1143
  case "model":
1068
1144
  return data.model?.display_name || "Claude";
@@ -1076,31 +1152,20 @@ function evaluateClaudeComponent(key, data, noColor = false) {
1076
1152
  return (data.session_id || "").slice(0, 8);
1077
1153
  case "session-full":
1078
1154
  return data.session_id || "";
1079
- case "effort": {
1080
- try {
1081
- const globalPath = path3.join(os2.homedir(), ".claude", "settings.json");
1082
- const projectPath = path3.join(process.cwd(), ".claude", "settings.json");
1083
- let effort = "high";
1084
- try {
1085
- effort = JSON.parse(fs3.readFileSync(globalPath, "utf8")).effortLevel || effort;
1086
- } catch {
1087
- }
1088
- try {
1089
- effort = JSON.parse(fs3.readFileSync(projectPath, "utf8")).effortLevel || effort;
1090
- } catch {
1091
- }
1092
- if (noColor) return effort;
1093
- const r = `\x1B[${RESET}m`;
1094
- const colors = {
1095
- low: COLORS.green,
1096
- medium: COLORS.yellow,
1097
- high: COLORS.red
1098
- };
1099
- const code = colors[effort] || "";
1100
- return code ? `\x1B[0;${code}m${effort}${r}` : effort;
1101
- } catch {
1102
- return "";
1103
- }
1155
+ case "effort":
1156
+ case "effort-icon": {
1157
+ const effort = resolveEffort(data);
1158
+ if (key === "effort-icon" && noIcons) return "";
1159
+ const text = key === "effort-icon" ? "\u{F09D1}" : effort;
1160
+ if (noColor) return text;
1161
+ const r = `\x1B[${RESET}m`;
1162
+ const effortColors = {
1163
+ low: COLORS.green,
1164
+ medium: COLORS.yellow,
1165
+ high: COLORS.red
1166
+ };
1167
+ const code = effortColors[effort] || "";
1168
+ return code ? `\x1B[0;${code}m${text}${r}` : text;
1104
1169
  }
1105
1170
  case "style":
1106
1171
  return data.output_style?.name || "default";
@@ -1119,7 +1184,7 @@ function evaluateFsComponent(key, data) {
1119
1184
  case "project-path":
1120
1185
  return data.workspace?.project_dir || "";
1121
1186
  case "home":
1122
- return (data.workspace?.current_dir || data.cwd || "").replace(os2.homedir(), "~");
1187
+ return (data.workspace?.current_dir || data.cwd || "").replace(os3.homedir(), "~");
1123
1188
  case "cwd":
1124
1189
  return data.cwd || "";
1125
1190
  case "relative": {
@@ -1134,7 +1199,7 @@ function evaluateFsComponent(key, data) {
1134
1199
  return "";
1135
1200
  }
1136
1201
  }
1137
- function evaluateGitComponent(key, noColor = false) {
1202
+ function evaluateGitComponent(key, noColor = false, noIcons = false) {
1138
1203
  switch (key) {
1139
1204
  case "branch":
1140
1205
  return execCommand("git branch --show-current 2>/dev/null");
@@ -1146,6 +1211,7 @@ function evaluateGitComponent(key, noColor = false) {
1146
1211
  return "*";
1147
1212
  }
1148
1213
  case "status-icon":
1214
+ if (noIcons) return "";
1149
1215
  try {
1150
1216
  execSync2("git diff --quiet 2>/dev/null");
1151
1217
  return getNerdIcon("sparkle");
@@ -1234,7 +1300,7 @@ function evaluateGitComponent(key, noColor = false) {
1234
1300
  return "";
1235
1301
  }
1236
1302
  }
1237
- function evaluateContextComponent(key, data, args) {
1303
+ function evaluateContextComponent(key, data, args, noIcons = false) {
1238
1304
  const ctx = data.context_window;
1239
1305
  switch (key) {
1240
1306
  case "percent":
@@ -1259,6 +1325,7 @@ function evaluateContextComponent(key, data, args) {
1259
1325
  return "[" + "\u2588".repeat(filled) + "\u2591".repeat(width - filled) + "]";
1260
1326
  }
1261
1327
  case "icon": {
1328
+ if (noIcons) return "";
1262
1329
  const pct = ctx?.used_percentage || 0;
1263
1330
  const icon = getNerdIcon("circle");
1264
1331
  if (pct < 50) return `\x1B[0;${COLORS.green}m${icon}\x1B[${RESET}m`;
@@ -1337,11 +1404,11 @@ function evaluateEnvComponent(key) {
1337
1404
  return match?.[1] || "";
1338
1405
  }
1339
1406
  case "user":
1340
- return os2.userInfo().username;
1407
+ return os3.userInfo().username;
1341
1408
  case "hostname":
1342
- return os2.hostname();
1409
+ return os3.hostname();
1343
1410
  case "hostname-short":
1344
- return os2.hostname().split(".")[0];
1411
+ return os3.hostname().split(".")[0];
1345
1412
  case "shell":
1346
1413
  return path3.basename(process.env.SHELL || "");
1347
1414
  case "term":
@@ -1351,11 +1418,11 @@ function evaluateEnvComponent(key) {
1351
1418
  case "arch":
1352
1419
  return process.arch;
1353
1420
  case "os-release":
1354
- return os2.release();
1421
+ return os3.release();
1355
1422
  case "cpus":
1356
- return os2.cpus().length.toString();
1423
+ return os3.cpus().length.toString();
1357
1424
  case "memory":
1358
- return Math.round(os2.totalmem() / 1024 / 1024 / 1024) + "GB";
1425
+ return Math.round(os3.totalmem() / 1024 / 1024 / 1024) + "GB";
1359
1426
  default:
1360
1427
  return "";
1361
1428
  }
@@ -1403,7 +1470,7 @@ function evaluateTimeComponent(key, data) {
1403
1470
  return "";
1404
1471
  }
1405
1472
  }
1406
- function evaluateCondition(condition) {
1473
+ function evaluateCondition(condition, data) {
1407
1474
  switch (condition) {
1408
1475
  case "git":
1409
1476
  try {
@@ -1428,16 +1495,28 @@ function evaluateCondition(condition) {
1428
1495
  }
1429
1496
  case "subdir": {
1430
1497
  const root = execCommand("git rev-parse --show-toplevel 2>/dev/null");
1431
- return root !== "" && process.cwd() !== root;
1498
+ const currentDir = data.workspace?.current_dir || process.cwd();
1499
+ return root !== "" && currentDir !== root;
1432
1500
  }
1433
- case "node":
1434
- return fs3.existsSync("package.json");
1435
- case "python":
1501
+ case "node": {
1502
+ const projectDir = data.workspace?.project_dir;
1503
+ return projectDir ? fs3.existsSync(path3.join(projectDir, "package.json")) : fs3.existsSync("package.json");
1504
+ }
1505
+ case "python": {
1506
+ const projectDir = data.workspace?.project_dir;
1507
+ if (projectDir) {
1508
+ return fs3.existsSync(path3.join(projectDir, "pyproject.toml")) || fs3.existsSync(path3.join(projectDir, "setup.py")) || fs3.existsSync(path3.join(projectDir, "requirements.txt"));
1509
+ }
1436
1510
  return fs3.existsSync("pyproject.toml") || fs3.existsSync("setup.py") || fs3.existsSync("requirements.txt");
1437
- case "rust":
1438
- return fs3.existsSync("Cargo.toml");
1439
- case "go":
1440
- return fs3.existsSync("go.mod");
1511
+ }
1512
+ case "rust": {
1513
+ const projectDir = data.workspace?.project_dir;
1514
+ return projectDir ? fs3.existsSync(path3.join(projectDir, "Cargo.toml")) : fs3.existsSync("Cargo.toml");
1515
+ }
1516
+ case "go": {
1517
+ const projectDir = data.workspace?.project_dir;
1518
+ return projectDir ? fs3.existsSync(path3.join(projectDir, "go.mod")) : fs3.existsSync("go.mod");
1519
+ }
1441
1520
  case "effort": {
1442
1521
  return true;
1443
1522
  }
@@ -1449,16 +1528,16 @@ function evaluateComponent(comp, data, options) {
1449
1528
  let result = "";
1450
1529
  switch (comp.type) {
1451
1530
  case "claude":
1452
- result = evaluateClaudeComponent(comp.key, data, options.noColor);
1531
+ result = evaluateClaudeComponent(comp.key, data, options.noColor, options.noIcons);
1453
1532
  break;
1454
1533
  case "fs":
1455
1534
  result = evaluateFsComponent(comp.key, data);
1456
1535
  break;
1457
1536
  case "git":
1458
- result = evaluateGitComponent(comp.key, options.noColor);
1537
+ result = evaluateGitComponent(comp.key, options.noColor, options.noIcons);
1459
1538
  break;
1460
1539
  case "ctx":
1461
- result = evaluateContextComponent(comp.key, data, comp.args);
1540
+ result = evaluateContextComponent(comp.key, data, comp.args, options.noIcons);
1462
1541
  break;
1463
1542
  case "cost":
1464
1543
  result = evaluateCostComponent(comp.key, data);
@@ -1500,7 +1579,7 @@ function evaluateComponent(comp, data, options) {
1500
1579
  break;
1501
1580
  }
1502
1581
  case "conditional": {
1503
- if (comp.children && evaluateCondition(comp.key)) {
1582
+ if (comp.children && evaluateCondition(comp.key, data)) {
1504
1583
  result = evaluateComponents(comp.children, data, options);
1505
1584
  }
1506
1585
  break;
@@ -1534,7 +1613,7 @@ function evaluateFormat(format, data, options = {}) {
1534
1613
  }
1535
1614
 
1536
1615
  // src/index.ts
1537
- var VERSION = "1.6.2";
1616
+ var VERSION = "1.6.3";
1538
1617
  async function readStdin() {
1539
1618
  return new Promise((resolve, reject) => {
1540
1619
  let input = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeline",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "Customizable status line generator for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {