pakhale 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pratik Pakhale
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # pakhale
2
+
3
+ My personal CLI. It keeps my coding agents — [Claude Code](https://claude.com/claude-code) and
4
+ [opencode](https://opencode.ai) — set up the same way on every machine, from one file.
5
+
6
+ ```bash
7
+ npx pakhale setup agents # set up this machine
8
+ npx pakhale setup agents plan # dry run — show every change, write nothing
9
+ ```
10
+
11
+ Running `plan` first is always safe: it reads the machine and prints exactly what would change.
12
+
13
+ ## What it sets up
14
+
15
+ [`config.ts`](config.ts) is the whole source of truth. It lists the agents I use and the
16
+ capabilities I want them to have — plugins, skills, MCP servers — plus my shared instructions
17
+ and settings. Applying it installs whatever is missing and leaves everything else alone.
18
+
19
+ Agents package things differently, so each capability says how it reaches each agent:
20
+
21
+ ```ts
22
+ {
23
+ name: 'plannotator',
24
+ deliver: {
25
+ 'claude-code': { via: 'claude-plugin', marketplace: 'plannotator', plugin: 'plannotator' },
26
+ opencode: { via: 'opencode-plugin', package: '@plannotator/opencode@latest' },
27
+ },
28
+ }
29
+ ```
30
+
31
+ | `via` | Reaches |
32
+ | --- | --- |
33
+ | `skills` | any agent that reads `SKILL.md` |
34
+ | `mcp` | any agent |
35
+ | `claude-plugin` | Claude Code |
36
+ | `opencode-plugin` | opencode |
37
+
38
+ Leaving an agent undeclared is an error rather than a silent skip, so adding a new agent tells
39
+ me about every gap at once.
40
+
41
+ ## Options
42
+
43
+ - `plan` or `-n, --dry-run` — show every change, write nothing
44
+ - `-a, --agent <id>` — set up one agent (repeatable)
45
+ - `--all` — every configured agent, no prompt
46
+ - `--home <dir>` — apply against a different home directory
47
+ - `-h, --help` — full usage
48
+
49
+ With a terminal and no `--agent`, it asks which agents to set up — space to toggle, `a` for all.
50
+ Piped or scripted, it applies to every configured agent without asking.
51
+
52
+ ## Safe by default
53
+
54
+ - **Re-running changes nothing.** Every artifact is checked before it is written, installers
55
+ included.
56
+ - **Settings you added yourself survive.** Keys `config.ts` does not name are preserved.
57
+ - **A config file it cannot parse is left alone** rather than flattened.
58
+ - **Agents you do not have installed are skipped,** never created.
59
+ - **Anything it displaces is backed up** to `.setup-backups/<timestamp>/`.
60
+
61
+ ## Development
62
+
63
+ ```bash
64
+ bun install
65
+ bun src/cli.ts setup agents plan # run from source
66
+ bun run test # ~5s, no network, never touches your real ~
67
+ bun run typecheck
68
+ bun run build # dist/cli.js (Node >=20)
69
+ ```
70
+
71
+ [ARCHITECTURE.md](ARCHITECTURE.md) covers how it works inside — the config vocabulary, the
72
+ plan/diff/commit split, and how to add another agent.
@@ -0,0 +1,29 @@
1
+ ## DO's :
2
+
3
+ 1. Prefer established, well-maintained libraries when they reduce overall
4
+ complexity or improve reliability. Do not reimplement common
5
+ functionality without a clear reason.
6
+
7
+ 2. Lean on the dependencies already in the project before writing your own
8
+ implementation or adding packages. Do not assume a library lacks a
9
+ capability without checking its documentation and types.
10
+
11
+ 3. Make architectural decisions for the long term. Do not accept a stopgap
12
+ that only works for now and is meant to be replaced later.
13
+
14
+ ---
15
+
16
+ ## DONT's :
17
+
18
+ 1. DO NOT COMMIT OR AUTO CREATE PR UNLESS EXPLICITLY ASKED YOU TO DO SO.
19
+ AND IN ANY CASE NEVER EVER ADD YOURSELF AS COAUTHOR TO THE COMMITS!!
20
+
21
+ Use conventional commit messages (https://www.conventionalcommits.org/):
22
+ - Format: `type(scope): description` (scope is optional)
23
+ - Types: feat, fix, refactor, style, docs, test, chore, perf, ci, build
24
+ - Keep subject line under 72 chars, imperative mood, lowercase
25
+ - Use body for details when needed, separated by blank line
26
+
27
+ 2. Dont use any kind of browser agent unless explicitly told you to do so. Even to test something, do not try to operate a browser.
28
+
29
+ 3. NEVER push changes to outward-facing/shared surfaces directly — ALWAYS show me the drafted change and wait for my explicit confirmation first. This covers PR titles/descriptions/comments, issue titles/descriptions/comments, commit messages, and anything written to GitHub, Linear, Slack, or any external service. "Update the PR description" (or similar) is a request to DRAFT it, not to apply it live. Prepare the change locally, show it to me, then apply only after I say go.
@@ -0,0 +1,100 @@
1
+ #!/bin/bash
2
+ # Claude Code Status Line — minimal + info-dense
3
+ input=$(cat)
4
+
5
+ # Format integer with thousands separators (commas)
6
+ commafy() { echo "$1" | sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta'; }
7
+
8
+ # --- Extract fields ---
9
+ model_full=$(echo "$input" | jq -r '.model.display_name // empty')
10
+ # Extract only the model family (lowercase); fall back to first word of display name
11
+ model=$(echo "$model_full" | grep -oiE 'opus|sonnet|haiku|fable|mythos' | head -1 | tr '[:upper:]' '[:lower:]')
12
+ [ -z "$model" ] && model=$(echo "$model_full" | tr '[:upper:]' '[:lower:]' | awk '{print $1}')
13
+ thinking=$(echo "$input" | jq -r '.thinking.enabled // false')
14
+ effort=$(echo "$input" | jq -r '.effort.level // empty')
15
+ cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty')
16
+ project=$([ -n "$cwd" ] && basename "$cwd" || echo "")
17
+ pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
18
+ ctx_size=$(echo "$input" | jq -r '.context_window.context_window_size // 0')
19
+ tokens_k=$(echo "$input" | jq -r --argjson s "$ctx_size" --argjson p "$pct" '($s * $p / 100 / 1000) | floor')
20
+ five_h=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
21
+ seven_d=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
22
+
23
+
24
+ # Git branch + diff stats
25
+ branch=""
26
+ diff_added=""
27
+ diff_removed=""
28
+ diff_files=""
29
+ if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
30
+ branch=$(git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null || git -C "$cwd" rev-parse --short HEAD 2>/dev/null)
31
+
32
+ # Detect base branch (run only when we have a branch name)
33
+ if [ -n "$branch" ]; then
34
+ base_ref=$(git -C "$cwd" symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/||')
35
+ if [ -z "$base_ref" ]; then
36
+ for candidate in origin/release origin/main origin/master; do
37
+ if git -C "$cwd" rev-parse --verify "$candidate" >/dev/null 2>&1; then
38
+ base_ref="$candidate"
39
+ break
40
+ fi
41
+ done
42
+ fi
43
+
44
+ # Compute diff stats only when we are NOT on the base branch itself
45
+ if [ -n "$base_ref" ]; then
46
+ base_short="${base_ref#origin/}"
47
+ if [ "$branch" != "$base_short" ]; then
48
+ shortstat=$(git -C "$cwd" diff --shortstat "${base_ref}...HEAD" 2>/dev/null)
49
+ if [ -n "$shortstat" ]; then
50
+ diff_files=$(echo "$shortstat" | grep -oE '[0-9]+ file' | grep -oE '[0-9]+')
51
+ diff_added=$(echo "$shortstat" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+')
52
+ diff_removed=$(echo "$shortstat" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+')
53
+ [ -n "$diff_files" ] && diff_files=$(commafy "$diff_files")
54
+ [ -n "$diff_added" ] && diff_added=$(commafy "$diff_added")
55
+ [ -n "$diff_removed" ] && diff_removed=$(commafy "$diff_removed")
56
+ fi
57
+ fi
58
+ fi
59
+ fi
60
+ fi
61
+
62
+ # --- Colors ---
63
+ RST="\033[0m"
64
+ DIM="\033[2m"
65
+ CYAN="\033[36m"
66
+ BLUE="\033[34m"
67
+ MAG="\033[35m"
68
+ YEL="\033[33m"
69
+ RED="\033[31m"
70
+ GRN="\033[32m"
71
+
72
+ # Percentage text color
73
+ if [ "$pct" -lt 50 ]; then PCT_COLOR=$RST
74
+ elif [ "$pct" -lt 85 ]; then PCT_COLOR=$YEL
75
+ else PCT_COLOR=$RED; fi
76
+
77
+ # --- Single line ---
78
+ sep=" ${DIM}/${RST} "
79
+ model_label="${model}"
80
+ if [ "$thinking" = "true" ] || [ -n "$effort" ]; then
81
+ think_tag="think"
82
+ [ -n "$effort" ] && think_tag="${effort}"
83
+ model_label="${model} ${DIM}${think_tag}${RST}"
84
+ fi
85
+ out="${CYAN}${model_label}${RST}"
86
+ [ -n "$project" ] && out="${out}${sep}${BLUE}${project}${RST}"
87
+ [ -n "$branch" ] && out="${out}${sep}${MAG}⎇ ${branch}${RST}"
88
+ if [ -n "$diff_added" ] || [ -n "$diff_removed" ] || [ -n "$diff_files" ]; then
89
+ diff_seg=""
90
+ [ -n "$diff_added" ] && diff_seg="${GRN}+${diff_added}${RST}"
91
+ [ -n "$diff_removed" ] && diff_seg="${diff_seg:+${diff_seg} }${RED}-${diff_removed}${RST}"
92
+ [ -n "$diff_files" ] && diff_seg="${diff_seg:+${diff_seg} }${DIM}~${diff_files}f${RST}"
93
+ [ -n "$diff_seg" ] && out="${out} ${diff_seg}"
94
+ fi
95
+ out="${out}${sep}${PCT_COLOR}${pct}%${RST} ${DIM}($(commafy "$tokens_k")k)${RST}"
96
+ [ -n "$five_h" ] && out="${out}${sep}${DIM}5h:${RST}$(printf '%.0f' "$five_h")%"
97
+ [ -n "$seven_d" ] && out="${out} ${DIM}7d:${RST}$(printf '%.0f' "$seven_d")%"
98
+
99
+
100
+ printf "%b\n" "$out"