Fix CRLF line endings, harden install.sh
- Add .gitattributes enforcing LF line endings - Renormalize all files from CRLF to LF - Replace fragile sed-based JSON manipulation with node -e - Add Node.js 18+ version check (required for built-in fetch) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
212
fetch-usage.js
212
fetch-usage.js
@@ -1,106 +1,106 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Claude Usage Fetcher (Standalone)
|
* Claude Usage Fetcher (Standalone)
|
||||||
*
|
*
|
||||||
* Fetches token usage from claude.ai API using a session key.
|
* Fetches token usage from claude.ai API using a session key.
|
||||||
* Designed to run as a cron job on headless servers.
|
* Designed to run as a cron job on headless servers.
|
||||||
*
|
*
|
||||||
* Session key source (checked in order):
|
* Session key source (checked in order):
|
||||||
* 1. CLAUDE_SESSION_KEY env var
|
* 1. CLAUDE_SESSION_KEY env var
|
||||||
* 2. ~/.config/claude-statusline/session-key (plain text file)
|
* 2. ~/.config/claude-statusline/session-key (plain text file)
|
||||||
*
|
*
|
||||||
* To get your session key:
|
* To get your session key:
|
||||||
* 1. Log into claude.ai in any browser
|
* 1. Log into claude.ai in any browser
|
||||||
* 2. Open DevTools → Application → Cookies → claude.ai
|
* 2. Open DevTools → Application → Cookies → claude.ai
|
||||||
* 3. Copy the value of the "sessionKey" cookie
|
* 3. Copy the value of the "sessionKey" cookie
|
||||||
* 4. Save it: echo "sk-ant-..." > ~/.config/claude-statusline/session-key
|
* 4. Save it: echo "sk-ant-..." > ~/.config/claude-statusline/session-key
|
||||||
*
|
*
|
||||||
* Output: Writes JSON to $CLAUDE_USAGE_CACHE or /tmp/claude_usage.json
|
* Output: Writes JSON to $CLAUDE_USAGE_CACHE or /tmp/claude_usage.json
|
||||||
*
|
*
|
||||||
* Cron example (every 5 min):
|
* Cron example (every 5 min):
|
||||||
* */5 * * * * /usr/bin/node /path/to/fetch-usage.js 2>/dev/null
|
* */5 * * * * /usr/bin/node /path/to/fetch-usage.js 2>/dev/null
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
// --- Config ---
|
// --- Config ---
|
||||||
const CONFIG_DIR = process.env.CLAUDE_STATUSLINE_CONFIG
|
const CONFIG_DIR = process.env.CLAUDE_STATUSLINE_CONFIG
|
||||||
|| path.join(process.env.HOME || '/root', '.config', 'claude-statusline');
|
|| path.join(process.env.HOME || '/root', '.config', 'claude-statusline');
|
||||||
const CACHE_FILE = process.env.CLAUDE_USAGE_CACHE
|
const CACHE_FILE = process.env.CLAUDE_USAGE_CACHE
|
||||||
|| path.join(process.env.TMPDIR || '/tmp', 'claude_usage.json');
|
|| path.join(process.env.TMPDIR || '/tmp', 'claude_usage.json');
|
||||||
const ORG_ID = process.env.CLAUDE_ORG_ID || '';
|
const ORG_ID = process.env.CLAUDE_ORG_ID || '';
|
||||||
|
|
||||||
// --- Session Key ---
|
// --- Session Key ---
|
||||||
function getSessionKey() {
|
function getSessionKey() {
|
||||||
// env var first
|
// env var first
|
||||||
if (process.env.CLAUDE_SESSION_KEY) return process.env.CLAUDE_SESSION_KEY.trim();
|
if (process.env.CLAUDE_SESSION_KEY) return process.env.CLAUDE_SESSION_KEY.trim();
|
||||||
|
|
||||||
// config file
|
// config file
|
||||||
const keyFile = path.join(CONFIG_DIR, 'session-key');
|
const keyFile = path.join(CONFIG_DIR, 'session-key');
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(keyFile, 'utf8').trim();
|
return fs.readFileSync(keyFile, 'utf8').trim();
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Discover org ID ---
|
// --- Discover org ID ---
|
||||||
async function getOrgId(sessionKey) {
|
async function getOrgId(sessionKey) {
|
||||||
if (ORG_ID) return ORG_ID;
|
if (ORG_ID) return ORG_ID;
|
||||||
|
|
||||||
const resp = await fetch('https://claude.ai/api/organizations', {
|
const resp = await fetch('https://claude.ai/api/organizations', {
|
||||||
headers: headers(sessionKey),
|
headers: headers(sessionKey),
|
||||||
signal: AbortSignal.timeout(10000),
|
signal: AbortSignal.timeout(10000),
|
||||||
});
|
});
|
||||||
if (!resp.ok) throw new Error('Failed to list orgs: ' + resp.status);
|
if (!resp.ok) throw new Error('Failed to list orgs: ' + resp.status);
|
||||||
const orgs = await resp.json();
|
const orgs = await resp.json();
|
||||||
if (!orgs.length) throw new Error('No organizations found');
|
if (!orgs.length) throw new Error('No organizations found');
|
||||||
return orgs[0].uuid;
|
return orgs[0].uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function headers(sessionKey) {
|
function headers(sessionKey) {
|
||||||
return {
|
return {
|
||||||
'Cookie': 'sessionKey=' + sessionKey,
|
'Cookie': 'sessionKey=' + sessionKey,
|
||||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0',
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Referer': 'https://claude.ai/',
|
'Referer': 'https://claude.ai/',
|
||||||
'Origin': 'https://claude.ai',
|
'Origin': 'https://claude.ai',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Fetch ---
|
// --- Fetch ---
|
||||||
async function main() {
|
async function main() {
|
||||||
const sessionKey = getSessionKey();
|
const sessionKey = getSessionKey();
|
||||||
if (!sessionKey) {
|
if (!sessionKey) {
|
||||||
console.error('No session key found. Set CLAUDE_SESSION_KEY or create ' +
|
console.error('No session key found. Set CLAUDE_SESSION_KEY or create ' +
|
||||||
path.join(CONFIG_DIR, 'session-key'));
|
path.join(CONFIG_DIR, 'session-key'));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const orgId = await getOrgId(sessionKey);
|
const orgId = await getOrgId(sessionKey);
|
||||||
const resp = await fetch('https://claude.ai/api/organizations/' + orgId + '/usage', {
|
const resp = await fetch('https://claude.ai/api/organizations/' + orgId + '/usage', {
|
||||||
headers: headers(sessionKey),
|
headers: headers(sessionKey),
|
||||||
signal: AbortSignal.timeout(10000),
|
signal: AbortSignal.timeout(10000),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
console.error('API error: ' + resp.status);
|
console.error('API error: ' + resp.status);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
|
|
||||||
// Ensure cache dir exists
|
// Ensure cache dir exists
|
||||||
const cacheDir = path.dirname(CACHE_FILE);
|
const cacheDir = path.dirname(CACHE_FILE);
|
||||||
if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
|
if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
|
||||||
|
|
||||||
fs.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2));
|
fs.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2));
|
||||||
console.log('OK — wrote ' + CACHE_FILE);
|
console.log('OK — wrote ' + CACHE_FILE);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Fetch error: ' + e.message);
|
console.error('Fetch error: ' + e.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|||||||
151
install.sh
151
install.sh
@@ -1,73 +1,78 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Install claude-statusline for the current user.
|
# Install claude-statusline for the current user.
|
||||||
# Usage: bash install.sh
|
# Usage: bash install.sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
INSTALL_DIR="${HOME}/.local/share/claude-statusline"
|
INSTALL_DIR="${HOME}/.local/share/claude-statusline"
|
||||||
CONFIG_DIR="${HOME}/.config/claude-statusline"
|
CONFIG_DIR="${HOME}/.config/claude-statusline"
|
||||||
CLAUDE_DIR="${HOME}/.claude"
|
CLAUDE_DIR="${HOME}/.claude"
|
||||||
|
|
||||||
echo "==> Installing claude-statusline..."
|
# --- Check Node.js version (need 18+ for built-in fetch) ---
|
||||||
|
NODE_BIN="$(which node 2>/dev/null || echo '')"
|
||||||
# Copy scripts
|
if [ -z "$NODE_BIN" ]; then
|
||||||
mkdir -p "$INSTALL_DIR"
|
echo "ERROR: Node.js not found. Install Node.js 18+ first."
|
||||||
cp "$SCRIPT_DIR/statusline.js" "$INSTALL_DIR/"
|
exit 1
|
||||||
cp "$SCRIPT_DIR/fetch-usage.js" "$INSTALL_DIR/"
|
fi
|
||||||
chmod +x "$INSTALL_DIR"/*.js
|
NODE_MAJOR=$("$NODE_BIN" -e "process.stdout.write(String(process.versions.node.split('.')[0]))")
|
||||||
|
if [ "$NODE_MAJOR" -lt 18 ]; then
|
||||||
# Create config dir
|
echo "ERROR: Node.js $("$NODE_BIN" --version) found, but 18+ is required (built-in fetch)."
|
||||||
mkdir -p "$CONFIG_DIR"
|
exit 1
|
||||||
if [ ! -f "$CONFIG_DIR/session-key" ]; then
|
fi
|
||||||
echo "# Paste your claude.ai sessionKey cookie value here" > "$CONFIG_DIR/session-key"
|
echo "==> Node.js v${NODE_MAJOR} found at $NODE_BIN"
|
||||||
chmod 600 "$CONFIG_DIR/session-key"
|
|
||||||
echo " Created $CONFIG_DIR/session-key (edit with your session key)"
|
echo "==> Installing claude-statusline..."
|
||||||
fi
|
|
||||||
|
# Copy scripts
|
||||||
# Configure Claude Code statusline
|
mkdir -p "$INSTALL_DIR"
|
||||||
mkdir -p "$CLAUDE_DIR"
|
cp "$SCRIPT_DIR/statusline.js" "$INSTALL_DIR/"
|
||||||
SETTINGS="$CLAUDE_DIR/settings.json"
|
cp "$SCRIPT_DIR/fetch-usage.js" "$INSTALL_DIR/"
|
||||||
NODE_BIN="$(which node 2>/dev/null || echo '/usr/bin/node')"
|
chmod +x "$INSTALL_DIR"/*.js
|
||||||
|
|
||||||
if [ -f "$SETTINGS" ]; then
|
# Create config dir
|
||||||
# Check if statusLine already configured
|
mkdir -p "$CONFIG_DIR"
|
||||||
if grep -q '"statusLine"' "$SETTINGS" 2>/dev/null; then
|
if [ ! -f "$CONFIG_DIR/session-key" ]; then
|
||||||
echo " statusLine already configured in $SETTINGS — skipping"
|
echo "# Paste your claude.ai sessionKey cookie value here" > "$CONFIG_DIR/session-key"
|
||||||
else
|
chmod 600 "$CONFIG_DIR/session-key"
|
||||||
# Insert statusLine before last closing brace
|
echo " Created $CONFIG_DIR/session-key (edit with your session key)"
|
||||||
TMP=$(mktemp)
|
fi
|
||||||
sed '$ d' "$SETTINGS" > "$TMP"
|
|
||||||
# Add comma if needed
|
# Configure Claude Code statusline
|
||||||
if grep -q '[^{]' "$TMP"; then
|
mkdir -p "$CLAUDE_DIR"
|
||||||
echo ',' >> "$TMP"
|
SETTINGS="$CLAUDE_DIR/settings.json"
|
||||||
fi
|
|
||||||
cat >> "$TMP" <<SEOF
|
if [ -f "$SETTINGS" ]; then
|
||||||
"statusLine": {
|
if grep -q '"statusLine"' "$SETTINGS" 2>/dev/null; then
|
||||||
"type": "command",
|
echo " statusLine already configured in $SETTINGS — skipping"
|
||||||
"command": "${NODE_BIN} --no-warnings ${INSTALL_DIR}/statusline.js"
|
else
|
||||||
}
|
"$NODE_BIN" -e "
|
||||||
}
|
const fs = require('fs');
|
||||||
SEOF
|
const settings = JSON.parse(fs.readFileSync('$SETTINGS', 'utf8'));
|
||||||
mv "$TMP" "$SETTINGS"
|
settings.statusLine = {
|
||||||
echo " Added statusLine to $SETTINGS"
|
type: 'command',
|
||||||
fi
|
command: '$NODE_BIN --no-warnings $INSTALL_DIR/statusline.js'
|
||||||
else
|
};
|
||||||
cat > "$SETTINGS" <<SEOF
|
fs.writeFileSync('$SETTINGS', JSON.stringify(settings, null, 2) + '\n');
|
||||||
{
|
"
|
||||||
"statusLine": {
|
echo " Added statusLine to $SETTINGS"
|
||||||
"type": "command",
|
fi
|
||||||
"command": "${NODE_BIN} --no-warnings ${INSTALL_DIR}/statusline.js"
|
else
|
||||||
}
|
cat > "$SETTINGS" <<SEOF
|
||||||
}
|
{
|
||||||
SEOF
|
"statusLine": {
|
||||||
echo " Created $SETTINGS with statusLine config"
|
"type": "command",
|
||||||
fi
|
"command": "${NODE_BIN} --no-warnings ${INSTALL_DIR}/statusline.js"
|
||||||
|
}
|
||||||
# Offer cron setup
|
}
|
||||||
echo ""
|
SEOF
|
||||||
echo "==> Optional: set up usage fetcher cron (every 5 min):"
|
echo " Created $SETTINGS with statusLine config"
|
||||||
echo " crontab -e"
|
fi
|
||||||
echo " */5 * * * * ${NODE_BIN} ${INSTALL_DIR}/fetch-usage.js 2>/dev/null"
|
|
||||||
echo ""
|
# Offer cron setup
|
||||||
echo "==> Done! Restart Claude Code to see the statusline."
|
echo ""
|
||||||
echo " Don't forget to add your session key to: $CONFIG_DIR/session-key"
|
echo "==> Optional: set up usage fetcher cron (every 5 min):"
|
||||||
|
echo " crontab -e"
|
||||||
|
echo " */5 * * * * ${NODE_BIN} ${INSTALL_DIR}/fetch-usage.js 2>/dev/null"
|
||||||
|
echo ""
|
||||||
|
echo "==> Done! Restart Claude Code to see the statusline."
|
||||||
|
echo " Don't forget to add your session key to: $CONFIG_DIR/session-key"
|
||||||
|
|||||||
26
package.json
26
package.json
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-statusline",
|
"name": "claude-statusline",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Standalone Claude Code statusline for headless Linux servers",
|
"description": "Standalone Claude Code statusline for headless Linux servers",
|
||||||
"main": "statusline.js",
|
"main": "statusline.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"statusline": "node statusline.js",
|
"statusline": "node statusline.js",
|
||||||
"fetch": "node fetch-usage.js",
|
"fetch": "node fetch-usage.js",
|
||||||
"install-statusline": "bash install.sh"
|
"install-statusline": "bash install.sh"
|
||||||
},
|
},
|
||||||
"keywords": ["claude", "statusline", "cli"],
|
"keywords": ["claude", "statusline", "cli"],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
|
|||||||
184
statusline.js
184
statusline.js
@@ -1,92 +1,92 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Claude Code Status Line (Standalone)
|
* Claude Code Status Line (Standalone)
|
||||||
*
|
*
|
||||||
* Designed for headless Linux servers — no browser, no tray app needed.
|
* Designed for headless Linux servers — no browser, no tray app needed.
|
||||||
*
|
*
|
||||||
* Context window: Always shown, read from stdin (JSON piped by Claude Code).
|
* Context window: Always shown, read from stdin (JSON piped by Claude Code).
|
||||||
* Token usage: Optional. Reads from a cache file that can be populated by
|
* Token usage: Optional. Reads from a cache file that can be populated by
|
||||||
* the included fetcher (cron) or any external source.
|
* the included fetcher (cron) or any external source.
|
||||||
*
|
*
|
||||||
* Output: Context ▓▓▓▓░░░░░░ 40% | Token ░░░░░░░░░░ 10% 267M
|
* Output: Context ▓▓▓▓░░░░░░ 40% | Token ░░░░░░░░░░ 10% 267M
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
// --- Config ---
|
// --- Config ---
|
||||||
const CACHE_FILE = process.env.CLAUDE_USAGE_CACHE
|
const CACHE_FILE = process.env.CLAUDE_USAGE_CACHE
|
||||||
|| path.join(process.env.TMPDIR || process.env.TEMP || '/tmp', 'claude_usage.json');
|
|| path.join(process.env.TMPDIR || process.env.TEMP || '/tmp', 'claude_usage.json');
|
||||||
const CACHE_MAX_AGE_S = parseInt(process.env.CLAUDE_USAGE_MAX_AGE || '900', 10); // 15 min default
|
const CACHE_MAX_AGE_S = parseInt(process.env.CLAUDE_USAGE_MAX_AGE || '900', 10); // 15 min default
|
||||||
|
|
||||||
// --- Bar renderer ---
|
// --- Bar renderer ---
|
||||||
function bar(pct, width) {
|
function bar(pct, width) {
|
||||||
width = width || 10;
|
width = width || 10;
|
||||||
const filled = Math.floor(Math.min(100, Math.max(0, pct)) / (100 / width));
|
const filled = Math.floor(Math.min(100, Math.max(0, pct)) / (100 / width));
|
||||||
return '\u2593'.repeat(filled) + '\u2591'.repeat(width - filled);
|
return '\u2593'.repeat(filled) + '\u2591'.repeat(width - filled);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Context Window ---
|
// --- Context Window ---
|
||||||
function getContextPart(data) {
|
function getContextPart(data) {
|
||||||
try {
|
try {
|
||||||
const pct = Math.round(parseFloat(data?.context_window?.used_percentage) || 0);
|
const pct = Math.round(parseFloat(data?.context_window?.used_percentage) || 0);
|
||||||
return 'Context ' + bar(pct) + ' ' + pct + '%';
|
return 'Context ' + bar(pct) + ' ' + pct + '%';
|
||||||
} catch {
|
} catch {
|
||||||
return 'Context ' + '\u2591'.repeat(10);
|
return 'Context ' + '\u2591'.repeat(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Usage Cache ---
|
// --- Usage Cache ---
|
||||||
function readCache() {
|
function readCache() {
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(CACHE_FILE)) return null;
|
if (!fs.existsSync(CACHE_FILE)) return null;
|
||||||
const stat = fs.statSync(CACHE_FILE);
|
const stat = fs.statSync(CACHE_FILE);
|
||||||
const ageS = (Date.now() - stat.mtimeMs) / 1000;
|
const ageS = (Date.now() - stat.mtimeMs) / 1000;
|
||||||
if (ageS > CACHE_MAX_AGE_S) return null;
|
if (ageS > CACHE_MAX_AGE_S) return null;
|
||||||
return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
|
return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMinutes(isoStr) {
|
function formatMinutes(isoStr) {
|
||||||
if (!isoStr) return '';
|
if (!isoStr) return '';
|
||||||
try {
|
try {
|
||||||
const remaining = Math.max(0, Math.round((new Date(isoStr).getTime() - Date.now()) / 60000));
|
const remaining = Math.max(0, Math.round((new Date(isoStr).getTime() - Date.now()) / 60000));
|
||||||
return remaining + 'M';
|
return remaining + 'M';
|
||||||
} catch {
|
} catch {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsagePart(data) {
|
function getUsagePart(data) {
|
||||||
if (!data) return '';
|
if (!data) return '';
|
||||||
const parts = [];
|
const parts = [];
|
||||||
|
|
||||||
if (data.five_hour && data.five_hour.utilization > 0) {
|
if (data.five_hour && data.five_hour.utilization > 0) {
|
||||||
const pct = Math.round(data.five_hour.utilization);
|
const pct = Math.round(data.five_hour.utilization);
|
||||||
const remaining = formatMinutes(data.five_hour.resets_at);
|
const remaining = formatMinutes(data.five_hour.resets_at);
|
||||||
parts.push('Token ' + bar(pct) + ' ' + pct + '%' + (remaining ? ' ' + remaining : ''));
|
parts.push('Token ' + bar(pct) + ' ' + pct + '%' + (remaining ? ' ' + remaining : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.seven_day && data.seven_day.utilization > 20) {
|
if (data.seven_day && data.seven_day.utilization > 20) {
|
||||||
const pct = Math.round(data.seven_day.utilization);
|
const pct = Math.round(data.seven_day.utilization);
|
||||||
parts.push('7d ' + pct + '%');
|
parts.push('7d ' + pct + '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts.join(' | ');
|
return parts.join(' | ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main ---
|
// --- Main ---
|
||||||
function main() {
|
function main() {
|
||||||
let stdinData = {};
|
let stdinData = {};
|
||||||
try {
|
try {
|
||||||
stdinData = JSON.parse(fs.readFileSync(0, 'utf8'));
|
stdinData = JSON.parse(fs.readFileSync(0, 'utf8'));
|
||||||
} catch { /* no stdin or invalid JSON */ }
|
} catch { /* no stdin or invalid JSON */ }
|
||||||
|
|
||||||
const ctx = getContextPart(stdinData);
|
const ctx = getContextPart(stdinData);
|
||||||
const usage = getUsagePart(readCache());
|
const usage = getUsagePart(readCache());
|
||||||
|
|
||||||
console.log(usage ? ctx + ' | ' + usage : ctx);
|
console.log(usage ? ctx + ' | ' + usage : ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|||||||
Reference in New Issue
Block a user