claudeline 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/dist/index.js +121 -24
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -259,6 +259,11 @@ function listComponents() {
259
259
  "elapsed"
260
260
  ]
261
261
  },
262
+ {
263
+ name: "Account",
264
+ prefix: "account",
265
+ items: ["email", "name", "display-name", "org", "plan", "tier"]
266
+ },
262
267
  {
263
268
  name: "Usage/Limits",
264
269
  prefix: "usage",
@@ -490,11 +495,14 @@ function listThemes() {
490
495
  import * as fs from "fs";
491
496
  import * as path from "path";
492
497
  import * as os from "os";
498
+ function getClaudeConfigDir() {
499
+ return process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
500
+ }
493
501
  function getClaudeDir(project) {
494
502
  if (project) {
495
503
  return path.join(process.cwd(), ".claude");
496
504
  }
497
- return path.join(os.homedir(), ".claude");
505
+ return getClaudeConfigDir();
498
506
  }
499
507
  function escapeForShell(str) {
500
508
  return str.replace(/'/g, "'\\''");
@@ -625,7 +633,7 @@ function getSampleDataJson() {
625
633
 
626
634
  // src/runtime.ts
627
635
  import * as path3 from "path";
628
- import * as os3 from "os";
636
+ import * as os2 from "os";
629
637
  import * as fs3 from "fs";
630
638
  import { execSync as execSync2 } from "child_process";
631
639
 
@@ -727,13 +735,24 @@ function getEmoji(name) {
727
735
  // src/usage.ts
728
736
  import * as fs2 from "fs";
729
737
  import * as path2 from "path";
730
- import * as os2 from "os";
738
+ import * as crypto from "crypto";
731
739
  import { execSync } from "child_process";
732
740
  var CACHE_TTL_MS = 5 * 60 * 1e3;
733
- var CACHE_FILE = path2.join(os2.tmpdir(), "claudeline-usage-cache.json");
734
- function readCache() {
741
+ var PROFILE_CACHE_TTL_MS = 60 * 60 * 1e3;
742
+ function tokenHash(token) {
743
+ return crypto.createHash("sha256").update(token).digest("hex").slice(0, 12);
744
+ }
745
+ function getCacheFile(token, type) {
746
+ const dir = path2.join(getClaudeConfigDir(), "cache");
747
+ try {
748
+ fs2.mkdirSync(dir, { recursive: true });
749
+ } catch {
750
+ }
751
+ return path2.join(dir, `claudeline-${type}-${tokenHash(token)}.json`);
752
+ }
753
+ function readCache(cacheFile) {
735
754
  try {
736
- const raw = fs2.readFileSync(CACHE_FILE, "utf8");
755
+ const raw = fs2.readFileSync(cacheFile, "utf8");
737
756
  const cached = JSON.parse(raw);
738
757
  if (Date.now() - cached.fetched_at < CACHE_TTL_MS) {
739
758
  return cached;
@@ -742,16 +761,25 @@ function readCache() {
742
761
  }
743
762
  return null;
744
763
  }
745
- function writeCache(data) {
764
+ function writeCache(cacheFile, data) {
746
765
  try {
747
- fs2.writeFileSync(CACHE_FILE, JSON.stringify({ data, fetched_at: Date.now() }));
766
+ fs2.writeFileSync(cacheFile, JSON.stringify({ data, fetched_at: Date.now() }));
748
767
  } catch {
749
768
  }
750
769
  }
770
+ function getKeychainService() {
771
+ const configDir = process.env.CLAUDE_CONFIG_DIR;
772
+ if (configDir) {
773
+ const suffix = crypto.createHash("sha256").update(configDir).digest("hex").slice(0, 8);
774
+ return `Claude Code-credentials-${suffix}`;
775
+ }
776
+ return "Claude Code-credentials";
777
+ }
751
778
  function getOAuthToken() {
752
779
  try {
780
+ const service = getKeychainService();
753
781
  const raw = execSync(
754
- 'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
782
+ `security find-generic-password -s "${service}" -w 2>/dev/null`,
755
783
  { encoding: "utf8" }
756
784
  ).trim();
757
785
  const parsed = JSON.parse(raw);
@@ -764,9 +792,7 @@ function getOAuthToken() {
764
792
  return null;
765
793
  }
766
794
  }
767
- function fetchUsage() {
768
- const token = getOAuthToken();
769
- if (!token) return null;
795
+ function fetchUsage(token) {
770
796
  try {
771
797
  const result = execSync(
772
798
  `curl -s --max-time 5 -H "Authorization: Bearer ${token}" -H "anthropic-beta: oauth-2025-04-20" "https://api.anthropic.com/api/oauth/usage"`,
@@ -782,11 +808,14 @@ function fetchUsage() {
782
808
  }
783
809
  }
784
810
  function getUsageData() {
785
- const cached = readCache();
811
+ const token = getOAuthToken();
812
+ if (!token) return null;
813
+ const cacheFile = getCacheFile(token, "usage");
814
+ const cached = readCache(cacheFile);
786
815
  if (cached) return cached.data;
787
- const data = fetchUsage();
816
+ const data = fetchUsage(token);
788
817
  if (data) {
789
- writeCache(data);
818
+ writeCache(cacheFile, data);
790
819
  }
791
820
  return data;
792
821
  }
@@ -809,6 +838,70 @@ function makeBar(pct, width, label) {
809
838
  const bar = "\u25B0".repeat(filled) + "\u25B1".repeat(width - filled);
810
839
  return label ? label + bar : bar;
811
840
  }
841
+ function readProfileCache(cacheFile) {
842
+ try {
843
+ const raw = fs2.readFileSync(cacheFile, "utf8");
844
+ const cached = JSON.parse(raw);
845
+ if (Date.now() - cached.fetched_at < PROFILE_CACHE_TTL_MS) {
846
+ return cached;
847
+ }
848
+ } catch {
849
+ }
850
+ return null;
851
+ }
852
+ function writeProfileCache(cacheFile, data) {
853
+ try {
854
+ fs2.writeFileSync(cacheFile, JSON.stringify({ data, fetched_at: Date.now() }));
855
+ } catch {
856
+ }
857
+ }
858
+ function fetchProfile(token) {
859
+ try {
860
+ const result = execSync(
861
+ `curl -s --max-time 5 -H "Authorization: Bearer ${token}" -H "anthropic-beta: oauth-2025-04-20" "https://api.anthropic.com/api/oauth/profile"`,
862
+ { encoding: "utf8" }
863
+ ).trim();
864
+ const data = JSON.parse(result);
865
+ if (data.account?.email) {
866
+ return data;
867
+ }
868
+ return null;
869
+ } catch {
870
+ return null;
871
+ }
872
+ }
873
+ function getProfileData() {
874
+ const token = getOAuthToken();
875
+ if (!token) return null;
876
+ const cacheFile = getCacheFile(token, "profile");
877
+ const cached = readProfileCache(cacheFile);
878
+ if (cached) return cached.data;
879
+ const data = fetchProfile(token);
880
+ if (data) {
881
+ writeProfileCache(cacheFile, data);
882
+ }
883
+ return data;
884
+ }
885
+ function evaluateAccountComponent(key) {
886
+ const data = getProfileData();
887
+ if (!data) return "";
888
+ switch (key) {
889
+ case "email":
890
+ return data.account.email;
891
+ case "name":
892
+ return data.account.full_name;
893
+ case "display-name":
894
+ return data.account.display_name;
895
+ case "org":
896
+ return data.organization.name;
897
+ case "plan":
898
+ return data.organization.organization_type;
899
+ case "tier":
900
+ return data.organization.rate_limit_tier;
901
+ default:
902
+ return "";
903
+ }
904
+ }
812
905
  function evaluateUsageComponent(key, args) {
813
906
  const data = getUsageData();
814
907
  if (!data) return "";
@@ -999,7 +1092,7 @@ function evaluateFsComponent(key, data) {
999
1092
  case "project-path":
1000
1093
  return data.workspace?.project_dir || "";
1001
1094
  case "home":
1002
- return (data.workspace?.current_dir || data.cwd || "").replace(os3.homedir(), "~");
1095
+ return (data.workspace?.current_dir || data.cwd || "").replace(os2.homedir(), "~");
1003
1096
  case "cwd":
1004
1097
  return data.cwd || "";
1005
1098
  case "relative": {
@@ -1216,11 +1309,11 @@ function evaluateEnvComponent(key) {
1216
1309
  return match?.[1] || "";
1217
1310
  }
1218
1311
  case "user":
1219
- return os3.userInfo().username;
1312
+ return os2.userInfo().username;
1220
1313
  case "hostname":
1221
- return os3.hostname();
1314
+ return os2.hostname();
1222
1315
  case "hostname-short":
1223
- return os3.hostname().split(".")[0];
1316
+ return os2.hostname().split(".")[0];
1224
1317
  case "shell":
1225
1318
  return path3.basename(process.env.SHELL || "");
1226
1319
  case "term":
@@ -1230,11 +1323,11 @@ function evaluateEnvComponent(key) {
1230
1323
  case "arch":
1231
1324
  return process.arch;
1232
1325
  case "os-release":
1233
- return os3.release();
1326
+ return os2.release();
1234
1327
  case "cpus":
1235
- return os3.cpus().length.toString();
1328
+ return os2.cpus().length.toString();
1236
1329
  case "memory":
1237
- return Math.round(os3.totalmem() / 1024 / 1024 / 1024) + "GB";
1330
+ return Math.round(os2.totalmem() / 1024 / 1024 / 1024) + "GB";
1238
1331
  default:
1239
1332
  return "";
1240
1333
  }
@@ -1345,6 +1438,9 @@ function evaluateComponent(comp, data, options) {
1345
1438
  case "usage":
1346
1439
  result = evaluateUsageComponent(comp.key, comp.args);
1347
1440
  break;
1441
+ case "account":
1442
+ result = evaluateAccountComponent(comp.key);
1443
+ break;
1348
1444
  case "time":
1349
1445
  result = evaluateTimeComponent(comp.key, data);
1350
1446
  break;
@@ -1404,11 +1500,12 @@ function evaluateFormat(format, data, options = {}) {
1404
1500
  noColor: options.noColor ?? false
1405
1501
  };
1406
1502
  const components = parseFormat(format);
1407
- return evaluateComponents(components, data, opts);
1503
+ const result = evaluateComponents(components, data, opts);
1504
+ return opts.noColor ? result : result + `\x1B[0m`;
1408
1505
  }
1409
1506
 
1410
1507
  // src/index.ts
1411
- var VERSION = "1.1.0";
1508
+ var VERSION = "1.3.1";
1412
1509
  async function readStdin() {
1413
1510
  return new Promise((resolve, reject) => {
1414
1511
  let input = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeline",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Customizable status line generator for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {