Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ecbcdf55b | ||
|
|
c3f8738f00 | ||
|
|
9a2e352202 | ||
|
|
0dd174d8c7 | ||
|
|
0c0c914431 | ||
|
|
cffe15e1f6 | ||
|
|
9b839ffaf1 | ||
|
|
c68e8c38cb | ||
|
|
fb57093a75 |
@@ -38,6 +38,7 @@ The installer automatically exposes scripts from the `scripts/` directory as glo
|
|||||||
- **`blob_glass [on|off|toggle]`**: A quick toggle to enable or disable window transparency on the fly.
|
- **`blob_glass [on|off|toggle]`**: A quick toggle to enable or disable window transparency on the fly.
|
||||||
- **`blob_boot [path]`**: Safely updates your Plymouth boot splash image (defaults to `branding/boot_flash.png`) and rebuilds the `initramfs` (GRUB compatible via `mkinitcpio`).
|
- **`blob_boot [path]`**: Safely updates your Plymouth boot splash image (defaults to `branding/boot_flash.png`) and rebuilds the `initramfs` (GRUB compatible via `mkinitcpio`).
|
||||||
- **`blob_wifi`**: A streamlined script to connect to the GMU Eduroam Wi-Fi network using `iwd` and `systemd-resolved` (replaces NetworkManager).
|
- **`blob_wifi`**: A streamlined script to connect to the GMU Eduroam Wi-Fi network using `iwd` and `systemd-resolved` (replaces NetworkManager).
|
||||||
|
- **`blob_key <set|show|clear|list> [NAME] [VALUE]`**: Stores secrets/env values for widgets and services, e.g. `blob_key set SOME_TOKEN value`.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROJECTS_DIR="$HOME/.claude/projects"
|
||||||
|
TODAY=$(date -u '+%Y-%m-%d')
|
||||||
|
EMPTY='{"available":false,"tokens":0,"messages":0,"cacheHitPercent":0}'
|
||||||
|
|
||||||
|
if [ ! -d "$PROJECTS_DIR" ]; then
|
||||||
|
echo "$EMPTY"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
FILES=$(find "$PROJECTS_DIR" -name "*.jsonl" -newermt "$TODAY")
|
||||||
|
|
||||||
|
if [ -z "$FILES" ]; then
|
||||||
|
echo '{"available":true,"tokens":0,"messages":0,"cacheHitPercent":0}'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -s --arg today "$TODAY" '
|
||||||
|
[.[] | select(.timestamp != null and (.timestamp | startswith($today)) and .message.usage != null) | .message.usage] as $usages
|
||||||
|
| ([$usages[] | .input_tokens // 0] | add // 0) as $input
|
||||||
|
| ([$usages[] | .output_tokens // 0] | add // 0) as $output
|
||||||
|
| ([$usages[] | .cache_creation_input_tokens // 0] | add // 0) as $cacheCreate
|
||||||
|
| ([$usages[] | .cache_read_input_tokens // 0] | add // 0) as $cacheRead
|
||||||
|
| ($input + $cacheCreate + $cacheRead) as $totalInput
|
||||||
|
| {
|
||||||
|
available: true,
|
||||||
|
tokens: ($totalInput + $output),
|
||||||
|
messages: ($usages | length),
|
||||||
|
cacheHitPercent: (if $totalInput > 0 then (($cacheRead / $totalInput) * 100) else 0 end)
|
||||||
|
}
|
||||||
|
' $FILES 2>/dev/null || echo "$EMPTY"
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LOCATION="Great+Falls,VA"
|
||||||
|
|
||||||
|
icon=$(omarchy-weather-icon 2>/dev/null)
|
||||||
|
weather=$(curl -fsS --max-time 4 "https://wttr.in/${LOCATION}?format=%l|%t|%w" 2>/dev/null | tr -d '\n')
|
||||||
|
|
||||||
|
if [[ -z $weather ]]; then
|
||||||
|
echo "Weather unavailable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='|' read -r place temperature wind <<< "$weather"
|
||||||
|
place=${place%%,*}
|
||||||
|
temperature=${temperature#+}
|
||||||
|
|
||||||
|
echo "$icon $place · Temp $temperature · Wind $wind"
|
||||||
+73
-9
@@ -349,6 +349,79 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qs-side-panel {
|
||||||
|
min-width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card-header {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-icon-badge {
|
||||||
|
background-color: alpha(@accent, 0.18);
|
||||||
|
border-radius: 8px;
|
||||||
|
min-width: 32px;
|
||||||
|
min-height: 32px;
|
||||||
|
color: @accent;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-icon-badge label {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: @foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card-label {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card-value {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: @foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-card-empty {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-stat-row {
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-stat-icon {
|
||||||
|
color: @color5;
|
||||||
|
font-size: 13px;
|
||||||
|
min-width: 22px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-level-bar {
|
||||||
|
min-height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-level-bar trough {
|
||||||
|
min-height: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: alpha(@foreground, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-level-bar block.filled {
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: @accent;
|
||||||
|
}
|
||||||
|
|
||||||
.control-center {
|
.control-center {
|
||||||
min-width: 360px;
|
min-width: 360px;
|
||||||
}
|
}
|
||||||
@@ -357,15 +430,6 @@
|
|||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cc-uptime {
|
|
||||||
font-size: 13px;
|
|
||||||
color: @foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-uptime-icon {
|
|
||||||
color: @accent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-clock {
|
.cc-clock {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Gtk } from "ags/gtk3"
|
||||||
|
import { createPoll } from "ags/time"
|
||||||
|
import { shell } from "../lib/utils"
|
||||||
|
import { CardHeader, StatRow } from "./WidgetCard"
|
||||||
|
|
||||||
|
type ClaudeUsage = {
|
||||||
|
available: boolean
|
||||||
|
tokens: number
|
||||||
|
messages: number
|
||||||
|
cacheHitPercent: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const usage = createPoll<ClaudeUsage>(
|
||||||
|
{ available: false, tokens: 0, messages: 0, cacheHitPercent: 0 },
|
||||||
|
60000,
|
||||||
|
shell("bash $HOME/.config/ags/lib/claude-usage.sh"),
|
||||||
|
(stdout) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(stdout.trim())
|
||||||
|
} catch {
|
||||||
|
return { available: false, tokens: 0, messages: 0, cacheHitPercent: 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
function formatTokens(tokens: number) {
|
||||||
|
if (tokens >= 1000000) return `${(tokens / 1000000).toFixed(2)}M`
|
||||||
|
if (tokens >= 1000) return `${(tokens / 1000).toFixed(1)}K`
|
||||||
|
return `${tokens}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ClaudeUsageCard() {
|
||||||
|
return (
|
||||||
|
<box class="panel widget-card" vertical spacing={10}>
|
||||||
|
<CardHeader icon={""} title="Claude Code" />
|
||||||
|
<label
|
||||||
|
class="widget-card-empty"
|
||||||
|
label="No usage logs found"
|
||||||
|
xalign={0}
|
||||||
|
halign={Gtk.Align.START}
|
||||||
|
visible={usage.as((u) => !u.available)}
|
||||||
|
/>
|
||||||
|
<box vertical spacing={8} visible={usage.as((u) => u.available)}>
|
||||||
|
<StatRow icon={""} label="Tokens today" value={usage.as((u) => formatTokens(u.tokens))} />
|
||||||
|
<StatRow icon={""} label="Messages today" value={usage.as((u) => `${u.messages}`)} />
|
||||||
|
<box vertical spacing={4}>
|
||||||
|
<box spacing={8}>
|
||||||
|
<label class="widget-card-label" label="Cache hit rate" xalign={0} halign={Gtk.Align.START} hexpand />
|
||||||
|
<label class="widget-card-value" label={usage.as((u) => `${Math.round(u.cacheHitPercent)}%`)} />
|
||||||
|
</box>
|
||||||
|
<levelbar class="widget-level-bar" value={usage.as((u) => u.cacheHitPercent / 100)} />
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ import { Astal, Gtk } from "ags/gtk3"
|
|||||||
import { createState } from "ags"
|
import { createState } from "ags"
|
||||||
import { createPoll, interval } from "ags/time"
|
import { createPoll, interval } from "ags/time"
|
||||||
import { sh, shell } from "../lib/utils"
|
import { sh, shell } from "../lib/utils"
|
||||||
|
import { ClaudeUsageCard } from "./ClaudeUsage"
|
||||||
|
import { CardHeader, StatRow } from "./WidgetCard"
|
||||||
|
|
||||||
export const QUICKSETTINGS_WINDOW = "quick-settings"
|
export const QUICKSETTINGS_WINDOW = "quick-settings"
|
||||||
|
|
||||||
@@ -142,6 +144,16 @@ function Toggles() {
|
|||||||
sh("omarchy-launch-bluetooth")
|
sh("omarchy-launch-bluetooth")
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Tile
|
||||||
|
icon={""}
|
||||||
|
label="Wallpaper"
|
||||||
|
onClicked={() => {
|
||||||
|
closePanel()
|
||||||
|
sh("blob_wallpaper")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</box>
|
||||||
|
<box class="qs-tiles" spacing={8} homogeneous>
|
||||||
<Tile
|
<Tile
|
||||||
icon={""}
|
icon={""}
|
||||||
label="Silence"
|
label="Silence"
|
||||||
@@ -151,8 +163,6 @@ function Toggles() {
|
|||||||
sh("makoctl mode -t do-not-disturb")
|
sh("makoctl mode -t do-not-disturb")
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</box>
|
|
||||||
<box class="qs-tiles" spacing={8} homogeneous>
|
|
||||||
<Tile
|
<Tile
|
||||||
icon={""}
|
icon={""}
|
||||||
label="Night Light"
|
label="Night Light"
|
||||||
@@ -163,6 +173,8 @@ function Toggles() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tile icon={""} label="Record" onClicked={() => { closePanel(); sh("omarchy-capture-screenrecording") }} />
|
<Tile icon={""} label="Record" onClicked={() => { closePanel(); sh("omarchy-capture-screenrecording") }} />
|
||||||
|
</box>
|
||||||
|
<box class="qs-tiles" spacing={8} homogeneous>
|
||||||
<Tile icon={""} label="Pick Color" onClicked={() => { closePanel(); sh("hyprpicker -a") }} />
|
<Tile icon={""} label="Pick Color" onClicked={() => { closePanel(); sh("hyprpicker -a") }} />
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
@@ -306,6 +318,63 @@ function CalendarSection() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Weather = { ok: boolean; icon: string; place: string; temp: string; wind: string }
|
||||||
|
|
||||||
|
function parseWeather(raw: string): Weather {
|
||||||
|
const parts = raw.split(" · ")
|
||||||
|
if (parts.length < 3) return { ok: false, icon: "", place: raw, temp: "", wind: "" }
|
||||||
|
const match = parts[0].match(/^(\S+)\s*(.*)$/)
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
icon: match ? match[1] : "",
|
||||||
|
place: match ? match[2].trim() : parts[0].trim(),
|
||||||
|
temp: parts[1].replace(/^Temp\s*/, ""),
|
||||||
|
wind: parts[2].replace(/^Wind\s*/, ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const weather = createPoll<Weather>(
|
||||||
|
{ ok: false, icon: "", place: "Loading...", temp: "", wind: "" },
|
||||||
|
600000,
|
||||||
|
shell("bash $HOME/.config/ags/lib/weather.sh"),
|
||||||
|
(stdout) => parseWeather(stdout.trim()),
|
||||||
|
)
|
||||||
|
|
||||||
|
function WeatherCard() {
|
||||||
|
return (
|
||||||
|
<box class="panel widget-card" vertical spacing={10}>
|
||||||
|
<CardHeader icon={weather.as((w) => w.icon)} title={weather.as((w) => w.place)} />
|
||||||
|
<label
|
||||||
|
class="widget-card-empty"
|
||||||
|
label="Weather unavailable"
|
||||||
|
xalign={0}
|
||||||
|
halign={Gtk.Align.START}
|
||||||
|
visible={weather.as((w) => !w.ok)}
|
||||||
|
/>
|
||||||
|
<box vertical spacing={8} visible={weather.as((w) => w.ok)}>
|
||||||
|
<StatRow icon={""} label="Temperature" value={weather.as((w) => w.temp)} />
|
||||||
|
<StatRow icon={""} label="Wind" value={weather.as((w) => w.wind)} />
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function LeftPanel() {
|
||||||
|
return (
|
||||||
|
<box class="qs-side-panel" vertical spacing={12} valign={Gtk.Align.START}>
|
||||||
|
<WeatherCard />
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function RightPanel() {
|
||||||
|
return (
|
||||||
|
<box class="qs-side-panel" vertical spacing={12} valign={Gtk.Align.START}>
|
||||||
|
<ClaudeUsageCard />
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function QuickSettings() {
|
export default function QuickSettings() {
|
||||||
const { TOP } = Astal.WindowAnchor
|
const { TOP } = Astal.WindowAnchor
|
||||||
|
|
||||||
@@ -321,6 +390,8 @@ export default function QuickSettings() {
|
|||||||
visible={false}
|
visible={false}
|
||||||
application={app}
|
application={app}
|
||||||
>
|
>
|
||||||
|
<box spacing={12}>
|
||||||
|
<LeftPanel />
|
||||||
<box class="panel quick-settings control-center" vertical spacing={12}>
|
<box class="panel quick-settings control-center" vertical spacing={12}>
|
||||||
<Header />
|
<Header />
|
||||||
<CalendarSection />
|
<CalendarSection />
|
||||||
@@ -329,6 +400,8 @@ export default function QuickSettings() {
|
|||||||
<BrightnessSlider />
|
<BrightnessSlider />
|
||||||
<MediaPlayer />
|
<MediaPlayer />
|
||||||
</box>
|
</box>
|
||||||
|
<RightPanel />
|
||||||
|
</box>
|
||||||
</window>
|
</window>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Gtk } from "ags/gtk3"
|
||||||
|
|
||||||
|
export function CardHeader({ icon, title }: { icon: any; title: any }) {
|
||||||
|
return (
|
||||||
|
<box class="widget-card-header" spacing={10}>
|
||||||
|
<box class="widget-icon-badge">
|
||||||
|
<label label={icon} hexpand vexpand halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} />
|
||||||
|
</box>
|
||||||
|
<label class="widget-card-title" label={title} xalign={0} halign={Gtk.Align.START} hexpand />
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatRow({ icon, label, value }: { icon: string; label: string; value: any }) {
|
||||||
|
return (
|
||||||
|
<box class="widget-stat-row" spacing={8}>
|
||||||
|
<label class="widget-stat-icon" label={icon} />
|
||||||
|
<label class="widget-card-label" label={label} xalign={0} halign={Gtk.Align.START} hexpand />
|
||||||
|
<label class="widget-card-value" label={value} />
|
||||||
|
</box>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -139,11 +139,15 @@ check_file "$SCRIPT_DIR/omarchy/hooks/theme-set" "$HOME_DIR/.config/omarchy/hook
|
|||||||
check_file "$SCRIPT_DIR/ags/app.ts" "$HOME_DIR/.config/ags/app.ts" "ags/app.ts" || check_status=1
|
check_file "$SCRIPT_DIR/ags/app.ts" "$HOME_DIR/.config/ags/app.ts" "ags/app.ts" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/style.css" "$HOME_DIR/.config/ags/style.css" "ags/style.css" || check_status=1
|
check_file "$SCRIPT_DIR/ags/style.css" "$HOME_DIR/.config/ags/style.css" "ags/style.css" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/lib/utils.ts" "$HOME_DIR/.config/ags/lib/utils.ts" "ags/lib/utils.ts" || check_status=1
|
check_file "$SCRIPT_DIR/ags/lib/utils.ts" "$HOME_DIR/.config/ags/lib/utils.ts" "ags/lib/utils.ts" || check_status=1
|
||||||
|
check_file "$SCRIPT_DIR/ags/lib/claude-usage.sh" "$HOME_DIR/.config/ags/lib/claude-usage.sh" "ags/lib/claude-usage.sh" || check_status=1
|
||||||
|
check_file "$SCRIPT_DIR/ags/lib/weather.sh" "$HOME_DIR/.config/ags/lib/weather.sh" "ags/lib/weather.sh" || check_status=1
|
||||||
|
check_file "$SCRIPT_DIR/ags/widget/ClaudeUsage.tsx" "$HOME_DIR/.config/ags/widget/ClaudeUsage.tsx" "ags/widget/ClaudeUsage.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/widget/Media.tsx" "$HOME_DIR/.config/ags/widget/Media.tsx" "ags/widget/Media.tsx" || check_status=1
|
check_file "$SCRIPT_DIR/ags/widget/Media.tsx" "$HOME_DIR/.config/ags/widget/Media.tsx" "ags/widget/Media.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/widget/Notifications.tsx" "$HOME_DIR/.config/ags/widget/Notifications.tsx" "ags/widget/Notifications.tsx" || check_status=1
|
check_file "$SCRIPT_DIR/ags/widget/Notifications.tsx" "$HOME_DIR/.config/ags/widget/Notifications.tsx" "ags/widget/Notifications.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/widget/QuickSettings.tsx" "$HOME_DIR/.config/ags/widget/QuickSettings.tsx" "ags/widget/QuickSettings.tsx" || check_status=1
|
check_file "$SCRIPT_DIR/ags/widget/QuickSettings.tsx" "$HOME_DIR/.config/ags/widget/QuickSettings.tsx" "ags/widget/QuickSettings.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/widget/SysMonitor.tsx" "$HOME_DIR/.config/ags/widget/SysMonitor.tsx" "ags/widget/SysMonitor.tsx" || check_status=1
|
check_file "$SCRIPT_DIR/ags/widget/SysMonitor.tsx" "$HOME_DIR/.config/ags/widget/SysMonitor.tsx" "ags/widget/SysMonitor.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/ags/widget/WallPicker.tsx" "$HOME_DIR/.config/ags/widget/WallPicker.tsx" "ags/widget/WallPicker.tsx" || check_status=1
|
check_file "$SCRIPT_DIR/ags/widget/WallPicker.tsx" "$HOME_DIR/.config/ags/widget/WallPicker.tsx" "ags/widget/WallPicker.tsx" || check_status=1
|
||||||
|
check_file "$SCRIPT_DIR/ags/widget/WidgetCard.tsx" "$HOME_DIR/.config/ags/widget/WidgetCard.tsx" "ags/widget/WidgetCard.tsx" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/waybar/style.css" "$HOME_DIR/.config/waybar/style.css" "waybar/style.css" || check_status=1
|
check_file "$SCRIPT_DIR/waybar/style.css" "$HOME_DIR/.config/waybar/style.css" "waybar/style.css" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/elephant/menus/blob_background_selector.lua" "$HOME_DIR/.config/elephant/menus/blob_background_selector.lua" "elephant/menus/blob_background_selector.lua" || check_status=1
|
check_file "$SCRIPT_DIR/elephant/menus/blob_background_selector.lua" "$HOME_DIR/.config/elephant/menus/blob_background_selector.lua" "elephant/menus/blob_background_selector.lua" || check_status=1
|
||||||
check_file "$SCRIPT_DIR/branding/about.txt" "$HOME_DIR/.config/omarchy/branding/about.txt" "branding/about.txt" || check_status=1
|
check_file "$SCRIPT_DIR/branding/about.txt" "$HOME_DIR/.config/omarchy/branding/about.txt" "branding/about.txt" || check_status=1
|
||||||
|
|||||||
Executable
+59
@@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SECRETS_DIR="$HOME/.config/ags/secrets"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: blob_key <set|show|clear|list> [NAME] [VALUE]"
|
||||||
|
echo " set <NAME> <VALUE> Store a secret (e.g. ANTHROPIC_ADMIN_KEY)"
|
||||||
|
echo " show <NAME> Print a stored secret, masked"
|
||||||
|
echo " clear <NAME> Remove a stored secret"
|
||||||
|
echo " list List the names of stored secrets"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
set)
|
||||||
|
name="$2"
|
||||||
|
value="$3"
|
||||||
|
if [ -z "$name" ] || [ -z "$value" ]; then
|
||||||
|
echo "Usage: blob_key set <NAME> <VALUE>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$SECRETS_DIR"
|
||||||
|
printf '%s' "$value" > "$SECRETS_DIR/$name"
|
||||||
|
chmod 600 "$SECRETS_DIR/$name"
|
||||||
|
echo "Saved $name to $SECRETS_DIR/$name"
|
||||||
|
;;
|
||||||
|
show)
|
||||||
|
name="$2"
|
||||||
|
if [ -z "$name" ]; then
|
||||||
|
echo "Usage: blob_key show <NAME>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -f "$SECRETS_DIR/$name" ]; then
|
||||||
|
value=$(cat "$SECRETS_DIR/$name")
|
||||||
|
echo "${value:0:6}...${value: -4}"
|
||||||
|
else
|
||||||
|
echo "No key stored for $name"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
clear)
|
||||||
|
name="$2"
|
||||||
|
if [ -z "$name" ]; then
|
||||||
|
echo "Usage: blob_key clear <NAME>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -f "$SECRETS_DIR/$name"
|
||||||
|
echo "Removed $name"
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
if [ -d "$SECRETS_DIR" ]; then
|
||||||
|
ls -1 "$SECRETS_DIR"
|
||||||
|
else
|
||||||
|
echo "No keys stored"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user