auto-context-cli 1.0.1__tar.gz → 1.0.2__tar.gz

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 (31) hide show
  1. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/PKG-INFO +53 -2
  2. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/README.md +52 -1
  3. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/pyproject.toml +1 -1
  4. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/__init__.py +1 -1
  5. auto_context_cli-1.0.2/src/auto_context/commands/update_cmd.py +392 -0
  6. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/config.py +28 -0
  7. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/main.py +14 -2
  8. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/AGENTS.template.md +1 -0
  9. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/GEMINI.template.md +1 -0
  10. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/maintain_context.template.md +1 -0
  11. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/.gitignore +0 -0
  12. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/LICENSE +0 -0
  13. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/__init__.py +0 -0
  14. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/import_cmd.py +0 -0
  15. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/init_cmd.py +0 -0
  16. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/mcp.py +0 -0
  17. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/memory.py +0 -0
  18. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/commands/share.py +0 -0
  19. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/security.py +0 -0
  20. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/context.local.template.md +0 -0
  21. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/context.template.md +0 -0
  22. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/mcp_config.template.json +0 -0
  23. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/profile.template.md +0 -0
  24. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/rule.template.md +0 -0
  25. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/rules/code-standards.md +0 -0
  26. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/rules/security-boundaries.md +0 -0
  27. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/skill.template.md +0 -0
  28. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/skills/browser-testing/SKILL.md +0 -0
  29. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/skills/docker-ops/SKILL.md +0 -0
  30. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/skills/git-workflow/SKILL.md +0 -0
  31. {auto_context_cli-1.0.1 → auto_context_cli-1.0.2}/src/auto_context/templates/skills/server-diagnostics/SKILL.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: auto-context-cli
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: Autonomous context & instruction manager for AI coding assistants
5
5
  Author: Arghya Biswas
6
6
  License: MIT
@@ -20,7 +20,7 @@ Description-Content-Type: text/markdown
20
20
 
21
21
  [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
22
22
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/auto-context-cli.svg)](https://pypi.org/project/auto-context-cli/)
23
- [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.1)
23
+ [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.2)
24
24
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
25
25
  [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
26
26
  [![AI Supported](https://img.shields.io/badge/AI%20Supported-Antigravity%20%7C%20Cursor%20%7C%20Claude%20Code%20%7C%20Copilot%20%7C%20Windsurf-orange.svg)](#-supported-ai-assistants)
@@ -95,6 +95,11 @@ OPTIONS (CENTRAL MEMORY & GRANULAR SHARING):
95
95
  memory status Show status of central memory brain
96
96
  share <NAME> Audit & publish skill or rule to GitHub Gist
97
97
  import <URL> Audit & import skill or rule from GitHub Gist or URL
98
+ update Safely update CLI, global plugin & public rules (Non-breaking)
99
+ update --check Check for updates without modifying files
100
+ update -w, --workspace Update managed system rules in active workspace
101
+ update -g, --global Sync global plugin (~/.gemini/config/plugins/auto-context/)
102
+ update -c, --cli Upgrade auto-context-cli package via uv/pipx/pip
98
103
  --as <NAME> Custom name when importing a skill or rule
99
104
  --public Publish shared Gist as public (default)
100
105
  --secret, --private Publish shared Gist as unlisted/secret
@@ -112,6 +117,38 @@ OPTIONS (MCP TOOLING):
112
117
 
113
118
  ---
114
119
 
120
+ ## 🔄 Modular Upstream Sync & Non-Breaking Updates (আপডেট ও সিঙ্ক)
121
+
122
+ When new public rules, skills, or agent capabilities are added to the official [Cyber-arghya/auto-context](https://github.com/Cyber-arghya/auto-context) repository:
123
+
124
+ ### 1️⃣ Automatic Background Notification
125
+ `auto-context` includes a lightweight, cached (24h TTL) update notifier. Whenever you or an AI agent runs `init-context`, it unobtrusively checks PyPI and GitHub. If new upstream rules or versions are available, a clean banner is displayed:
126
+ ```text
127
+ ╭─────────────────────────────────────────────────────────────────────────────╮
128
+ │ 🔔 Auto-Context Update Available: v1.0.1 → v1.0.2 │
129
+ │ New public rules, skills, and upstream capabilities are ready. │
130
+ │ Run 'init-context update' to sync modularly without breaking local context.│
131
+ ╰─────────────────────────────────────────────────────────────────────────────╯
132
+ ```
133
+
134
+ ### 2️⃣ 1-Command Safe Modular Update
135
+ Run:
136
+ ```bash
137
+ init-context update
138
+ ```
139
+ - **Upgrades CLI Package:** Automatically updates `auto-context-cli` via `uv tool`, `pipx`, or `pip`.
140
+ - **Syncs Global Plugin:** Updates `~/.gemini/config/plugins/auto-context/` (`rules/AGENTS.md`, `skills/auto-context/SKILL.md`) with upstream instructions.
141
+ - **Syncs Workspace System Rules:** Updates system rules (`.agents/rules/maintain_context.md`, `AGENTS.md`, `GEMINI.md`).
142
+
143
+ > [!TIP]
144
+ > **Strict Non-Breaking Guarantees:**
145
+ > - **Zero Context Loss:** `context.md` is **NEVER** modified or overwritten. All project credentials, architecture diagrams, and problem history remain 100% intact.
146
+ > - **Secret Protection:** `context.local.md`, `.env`, and test logins are **NEVER** touched.
147
+ > - **Custom Rule Safety:** Your personal rules (e.g. `docker-multi-stage.md`, `my-style.md`) are **NEVER** overwritten or deleted.
148
+ > - **Automatic Backup:** If you customized `AGENTS.md`, the updater automatically creates an `AGENTS.md.bak` backup.
149
+
150
+ ---
151
+
115
152
  ## 🔌 MCP (Model Context Protocol) Tooling Management (টুল ম্যানেজমেন্ট)
116
153
 
117
154
  Auto-Context allows you and your AI agents to seamlessly install, update, list, and delete **MCP servers** with single commands:
@@ -537,6 +574,20 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
537
574
  ```
538
575
  > **কলিশন গার্ড:** যদি একই নামের কোনো স্কিল আগে থেকেই থেকে থাকে, তবে এটি না জানিয়ে কখনো ওভাররাইট করবে না। টার্মিনালে আপনাকে ৩টি অপশন দেবে: `[O]verwrite / [R]ename / [C]ancel`।
539
576
 
577
+ ### 🔄 মডুলার আপস্ট্রিম আপডেট ও স্বয়ংক্রিয় নোটিফিকেশন (Update & Sync):
578
+ অফিশিয়াল গিটহাব রিপোজিটরিতে নতুন কোনো রুলবুক, স্কিল বা এআই এজেন্ট টুল যুক্ত হলে ব্যবহারকারীরা খুব সহজে আপডেট পেতে পারেন:
579
+ 1. **স্বয়ংক্রিয় নোটিফিকেশন ব্যানার:** চব্বিশ ঘণ্টায় একবার ব্যাকগ্রাউন্ডে চেক করে নতুন রুল আসলে টার্মিনালে সুন্দর নোটিফিকেশন দেখাবে।
580
+ 2. **এক কমান্ডে নিরাপদ আপডেট (`init-context update`):**
581
+ ```bash
582
+ init-context update # ফুল মডুলার আপডেট (CLI + গ্লোবাল প্লাগইন + সিস্টেম রুলস)
583
+ init-context update --check # কোনো আপডেট আছে কিনা শুধু চেক করতে
584
+ init-context update -w # শুধুমাত্র বর্তমান প্রজেক্টের সিস্টেম রুলস আপডেট করতে
585
+ ```
586
+ > **ব্রেকিং-চেঞ্জ মুক্ত সুরক্ষা (Zero Breaking Guarantee):**
587
+ > * আপনার প্রজেক্টের `context.md`, `context.local.md` বা `.env` ফাইলে **কখনোই হাত দেওয়া হবে না**।
588
+ > * আপনার তৈরিকৃত কোনো কাস্টম রুল মুছে যাবে না।
589
+ > * কোনো ফাইলে কাস্টম পরিবর্তন থাকলে স্বয়ংক্রিয়ভাবে `.bak` ব্যাকআপ তৈরি হবে।
590
+
540
591
  ### নিরাপদ MCP টুল ম্যানেজমেন্ট (Secure Secrets via .env):
541
592
  টোকেন বা পাসওয়ার্ড কখনোই কনফিগ ফাইলে ওপেন টেক্সটে সেভ হয় না, বরং `.env` এবং `.gitignore`-এর মাধ্যমে নিরাপদ থাকে:
542
593
  * **টুল যুক্ত করতে (Node `npx` বা Python `uvx` সাপোর্ট):**
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
8
8
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/auto-context-cli.svg)](https://pypi.org/project/auto-context-cli/)
9
- [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.1)
9
+ [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.2)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
11
11
  [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
12
12
  [![AI Supported](https://img.shields.io/badge/AI%20Supported-Antigravity%20%7C%20Cursor%20%7C%20Claude%20Code%20%7C%20Copilot%20%7C%20Windsurf-orange.svg)](#-supported-ai-assistants)
@@ -81,6 +81,11 @@ OPTIONS (CENTRAL MEMORY & GRANULAR SHARING):
81
81
  memory status Show status of central memory brain
82
82
  share <NAME> Audit & publish skill or rule to GitHub Gist
83
83
  import <URL> Audit & import skill or rule from GitHub Gist or URL
84
+ update Safely update CLI, global plugin & public rules (Non-breaking)
85
+ update --check Check for updates without modifying files
86
+ update -w, --workspace Update managed system rules in active workspace
87
+ update -g, --global Sync global plugin (~/.gemini/config/plugins/auto-context/)
88
+ update -c, --cli Upgrade auto-context-cli package via uv/pipx/pip
84
89
  --as <NAME> Custom name when importing a skill or rule
85
90
  --public Publish shared Gist as public (default)
86
91
  --secret, --private Publish shared Gist as unlisted/secret
@@ -98,6 +103,38 @@ OPTIONS (MCP TOOLING):
98
103
 
99
104
  ---
100
105
 
106
+ ## 🔄 Modular Upstream Sync & Non-Breaking Updates (আপডেট ও সিঙ্ক)
107
+
108
+ When new public rules, skills, or agent capabilities are added to the official [Cyber-arghya/auto-context](https://github.com/Cyber-arghya/auto-context) repository:
109
+
110
+ ### 1️⃣ Automatic Background Notification
111
+ `auto-context` includes a lightweight, cached (24h TTL) update notifier. Whenever you or an AI agent runs `init-context`, it unobtrusively checks PyPI and GitHub. If new upstream rules or versions are available, a clean banner is displayed:
112
+ ```text
113
+ ╭─────────────────────────────────────────────────────────────────────────────╮
114
+ │ 🔔 Auto-Context Update Available: v1.0.1 → v1.0.2 │
115
+ │ New public rules, skills, and upstream capabilities are ready. │
116
+ │ Run 'init-context update' to sync modularly without breaking local context.│
117
+ ╰─────────────────────────────────────────────────────────────────────────────╯
118
+ ```
119
+
120
+ ### 2️⃣ 1-Command Safe Modular Update
121
+ Run:
122
+ ```bash
123
+ init-context update
124
+ ```
125
+ - **Upgrades CLI Package:** Automatically updates `auto-context-cli` via `uv tool`, `pipx`, or `pip`.
126
+ - **Syncs Global Plugin:** Updates `~/.gemini/config/plugins/auto-context/` (`rules/AGENTS.md`, `skills/auto-context/SKILL.md`) with upstream instructions.
127
+ - **Syncs Workspace System Rules:** Updates system rules (`.agents/rules/maintain_context.md`, `AGENTS.md`, `GEMINI.md`).
128
+
129
+ > [!TIP]
130
+ > **Strict Non-Breaking Guarantees:**
131
+ > - **Zero Context Loss:** `context.md` is **NEVER** modified or overwritten. All project credentials, architecture diagrams, and problem history remain 100% intact.
132
+ > - **Secret Protection:** `context.local.md`, `.env`, and test logins are **NEVER** touched.
133
+ > - **Custom Rule Safety:** Your personal rules (e.g. `docker-multi-stage.md`, `my-style.md`) are **NEVER** overwritten or deleted.
134
+ > - **Automatic Backup:** If you customized `AGENTS.md`, the updater automatically creates an `AGENTS.md.bak` backup.
135
+
136
+ ---
137
+
101
138
  ## 🔌 MCP (Model Context Protocol) Tooling Management (টুল ম্যানেজমেন্ট)
102
139
 
103
140
  Auto-Context allows you and your AI agents to seamlessly install, update, list, and delete **MCP servers** with single commands:
@@ -523,6 +560,20 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
523
560
  ```
524
561
  > **কলিশন গার্ড:** যদি একই নামের কোনো স্কিল আগে থেকেই থেকে থাকে, তবে এটি না জানিয়ে কখনো ওভাররাইট করবে না। টার্মিনালে আপনাকে ৩টি অপশন দেবে: `[O]verwrite / [R]ename / [C]ancel`।
525
562
 
563
+ ### 🔄 মডুলার আপস্ট্রিম আপডেট ও স্বয়ংক্রিয় নোটিফিকেশন (Update & Sync):
564
+ অফিশিয়াল গিটহাব রিপোজিটরিতে নতুন কোনো রুলবুক, স্কিল বা এআই এজেন্ট টুল যুক্ত হলে ব্যবহারকারীরা খুব সহজে আপডেট পেতে পারেন:
565
+ 1. **স্বয়ংক্রিয় নোটিফিকেশন ব্যানার:** চব্বিশ ঘণ্টায় একবার ব্যাকগ্রাউন্ডে চেক করে নতুন রুল আসলে টার্মিনালে সুন্দর নোটিফিকেশন দেখাবে।
566
+ 2. **এক কমান্ডে নিরাপদ আপডেট (`init-context update`):**
567
+ ```bash
568
+ init-context update # ফুল মডুলার আপডেট (CLI + গ্লোবাল প্লাগইন + সিস্টেম রুলস)
569
+ init-context update --check # কোনো আপডেট আছে কিনা শুধু চেক করতে
570
+ init-context update -w # শুধুমাত্র বর্তমান প্রজেক্টের সিস্টেম রুলস আপডেট করতে
571
+ ```
572
+ > **ব্রেকিং-চেঞ্জ মুক্ত সুরক্ষা (Zero Breaking Guarantee):**
573
+ > * আপনার প্রজেক্টের `context.md`, `context.local.md` বা `.env` ফাইলে **কখনোই হাত দেওয়া হবে না**।
574
+ > * আপনার তৈরিকৃত কোনো কাস্টম রুল মুছে যাবে না।
575
+ > * কোনো ফাইলে কাস্টম পরিবর্তন থাকলে স্বয়ংক্রিয়ভাবে `.bak` ব্যাকআপ তৈরি হবে।
576
+
526
577
  ### নিরাপদ MCP টুল ম্যানেজমেন্ট (Secure Secrets via .env):
527
578
  টোকেন বা পাসওয়ার্ড কখনোই কনফিগ ফাইলে ওপেন টেক্সটে সেভ হয় না, বরং `.env` এবং `.gitignore`-এর মাধ্যমে নিরাপদ থাকে:
528
579
  * **টুল যুক্ত করতে (Node `npx` বা Python `uvx` সাপোর্ট):**
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "auto-context-cli"
3
- version = "1.0.1"
3
+ version = "1.0.2"
4
4
  description = "Autonomous context & instruction manager for AI coding assistants"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """auto-context: Autonomous context & instruction manager for AI coding assistants."""
2
2
 
3
- __version__ = "1.0.1"
3
+ __version__ = "1.0.2"
@@ -0,0 +1,392 @@
1
+ """
2
+ update_cmd.py — Modular, non-breaking update manager and upstream notification engine.
3
+
4
+ Ensures users stay synchronized with public rules, skills, and tools added to
5
+ https://github.com/Cyber-arghya/auto-context without breaking local project context,
6
+ custom user rules, or private memory.
7
+ """
8
+ from importlib.metadata import version as get_pkg_version
9
+ import json
10
+ from pathlib import Path
11
+ import shutil
12
+ import subprocess
13
+ import sys
14
+ import time
15
+ from typing import Annotated, Optional
16
+ import urllib.error
17
+ import urllib.request
18
+
19
+ from rich.console import Console
20
+ from rich.panel import Panel
21
+ import typer
22
+
23
+ from auto_context import config
24
+
25
+ console = Console()
26
+
27
+
28
+ def _parse_version(v_str: str) -> tuple[int, ...]:
29
+ """Parse version string like '1.0.1' or 'v1.0.2' into an integer tuple."""
30
+ clean = v_str.strip().lstrip("v").split("-")[0]
31
+ parts = []
32
+ for p in clean.split("."):
33
+ try:
34
+ parts.append(int(p))
35
+ except ValueError:
36
+ break
37
+ return tuple(parts) if parts else (0, 0, 0)
38
+
39
+
40
+ def get_installed_version() -> str:
41
+ """Return the currently installed package version."""
42
+ for pkg in (config.PYPI_PACKAGE, "auto-context"):
43
+ try:
44
+ return get_pkg_version(pkg)
45
+ except Exception:
46
+ pass
47
+ return "1.0.1"
48
+
49
+
50
+ # ── Update Checking & Cache Engine ────────────────────────────────────────────
51
+
52
+ def check_upstream_version(timeout: float = 2.0) -> Optional[dict]:
53
+ """
54
+ Query PyPI and GitHub to determine the latest upstream version.
55
+ Returns dict with metadata or None if offline/error.
56
+ """
57
+ # 1. Try PyPI first (fastest, no rate limits)
58
+ try:
59
+ req = urllib.request.Request(
60
+ config.PYPI_JSON_URL,
61
+ headers={"User-Agent": f"auto-context-cli/{get_installed_version()}"},
62
+ )
63
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
64
+ data = json.loads(resp.read().decode("utf-8"))
65
+ latest = data.get("info", {}).get("version")
66
+ if latest:
67
+ return {
68
+ "latest_version": latest,
69
+ "source": "pypi",
70
+ "package": config.PYPI_PACKAGE,
71
+ }
72
+ except Exception:
73
+ pass
74
+
75
+ # 2. Fallback to GitHub Latest Release API
76
+ try:
77
+ req = urllib.request.Request(
78
+ config.GITHUB_LATEST_RELEASE_URL,
79
+ headers={"User-Agent": f"auto-context-cli/{get_installed_version()}"},
80
+ )
81
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
82
+ data = json.loads(resp.read().decode("utf-8"))
83
+ tag = data.get("tag_name", "").lstrip("v")
84
+ if tag:
85
+ return {
86
+ "latest_version": tag,
87
+ "source": "github",
88
+ "url": data.get("html_url"),
89
+ }
90
+ except Exception:
91
+ pass
92
+
93
+ return None
94
+
95
+
96
+ def get_cached_update_status(force_check: bool = False) -> Optional[dict]:
97
+ """
98
+ Retrieve update status from local cache or refresh if cache expired.
99
+ Cached for 24 hours to ensure 0ms latency for daily CLI usage.
100
+ """
101
+ now = time.time()
102
+ cache_file = config.UPDATE_CACHE_FILE
103
+
104
+ try:
105
+ if not force_check and cache_file.exists():
106
+ cached = json.loads(cache_file.read_text(encoding="utf-8"))
107
+ timestamp = cached.get("timestamp", 0)
108
+ if now - timestamp < config.UPDATE_CHECK_INTERVAL:
109
+ return cached
110
+ except Exception:
111
+ pass
112
+
113
+ # Cache expired or missing — refresh in background
114
+ upstream = check_upstream_version()
115
+ if not upstream:
116
+ return None
117
+
118
+ current_v = get_installed_version()
119
+ latest_v = upstream["latest_version"]
120
+ update_available = _parse_version(latest_v) > _parse_version(current_v)
121
+
122
+ cache_data = {
123
+ "timestamp": now,
124
+ "current_version": current_v,
125
+ "latest_version": latest_v,
126
+ "update_available": update_available,
127
+ "source": upstream.get("source"),
128
+ }
129
+
130
+ try:
131
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
132
+ cache_file.write_text(json.dumps(cache_data, indent=2), encoding="utf-8")
133
+ except Exception:
134
+ pass
135
+
136
+ return cache_data
137
+
138
+
139
+ def maybe_notify_update() -> None:
140
+ """
141
+ Subtle, non-intrusive notification banner rendered at CLI termination.
142
+ Only displays if an update is genuinely available and cache confirms it.
143
+ """
144
+ try:
145
+ status = get_cached_update_status(force_check=False)
146
+ if not status or not status.get("update_available"):
147
+ return
148
+
149
+ cur = status.get("current_version", "")
150
+ latest = status.get("latest_version", "")
151
+ console.print()
152
+ console.print(Panel(
153
+ f"[bold cyan]🔔 Auto-Context Update Available:[/] [yellow]v{cur}[/] → [bold green]v{latest}[/]\n"
154
+ f"[white] New public rules, skills, and upstream capabilities are ready.[/]\n"
155
+ f"[cyan] Run:[/] [bold yellow]init-context update[/] [dim]to sync modularly without breaking local context.[/]",
156
+ border_style="cyan",
157
+ title="[bold yellow]✨ Upstream Sync[/]",
158
+ ))
159
+ except Exception:
160
+ # Never fail user command due to notification error
161
+ pass
162
+
163
+
164
+ # ── Modular Update Implementations ───────────────────────────────────────────
165
+
166
+ def update_cli_package() -> bool:
167
+ """Upgrade the auto-context-cli package using the user's active environment."""
168
+ console.print(" [cyan][*] Upgrading auto-context-cli package...[/]")
169
+
170
+ # 1. uv tool upgrade
171
+ if shutil.which("uv"):
172
+ try:
173
+ res = subprocess.run(["uv", "tool", "upgrade", config.PYPI_PACKAGE], capture_output=True, text=True)
174
+ if res.returncode == 0:
175
+ console.print(f" [green][✓] Upgraded via uv tool:[/] {config.PYPI_PACKAGE}")
176
+ return True
177
+ except Exception:
178
+ pass
179
+
180
+ # 2. pipx upgrade
181
+ if shutil.which("pipx"):
182
+ try:
183
+ res = subprocess.run(["pipx", "upgrade", config.PYPI_PACKAGE], capture_output=True, text=True)
184
+ if res.returncode == 0:
185
+ console.print(f" [green][✓] Upgraded via pipx:[/] {config.PYPI_PACKAGE}")
186
+ return True
187
+ except Exception:
188
+ pass
189
+
190
+ # 3. pip fallback
191
+ try:
192
+ res = subprocess.run(
193
+ [sys.executable, "-m", "pip", "install", "--upgrade", config.PYPI_PACKAGE],
194
+ capture_output=True, text=True
195
+ )
196
+ if res.returncode == 0:
197
+ console.print(f" [green][✓] Upgraded via pip:[/] {config.PYPI_PACKAGE}")
198
+ return True
199
+ else:
200
+ console.print(f" [yellow][!] pip upgrade notice:[/] {res.stderr.strip()[:100]}")
201
+ except Exception as e:
202
+ console.print(f" [yellow][!] Could not auto-upgrade CLI package:[/] {e}")
203
+
204
+ return False
205
+
206
+
207
+ def _download_text(url: str, timeout: float = 4.0) -> Optional[str]:
208
+ """Download raw text file from remote repository."""
209
+ try:
210
+ req = urllib.request.Request(url, headers={"User-Agent": "auto-context-cli"})
211
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
212
+ return resp.read().decode("utf-8")
213
+ except Exception:
214
+ return None
215
+
216
+
217
+ def update_global_plugin() -> int:
218
+ """
219
+ Sync upstream public rules and plugin definitions into ~/.gemini/config/plugins/auto-context/.
220
+ Preserves all existing user-defined custom rules and private skills.
221
+ """
222
+ console.print(f" [cyan][*] Syncing Global AI Plugin:[/] {config.GLOBAL_PLUGIN_DIR}")
223
+ updated_count = 0
224
+
225
+ plugin_dir = config.GLOBAL_PLUGIN_DIR
226
+ rules_dir = plugin_dir / "rules"
227
+ skills_dir = plugin_dir / "skills" / "auto-context"
228
+
229
+ try:
230
+ rules_dir.mkdir(parents=True, exist_ok=True)
231
+ skills_dir.mkdir(parents=True, exist_ok=True)
232
+ except PermissionError:
233
+ console.print(f" [yellow][!] Sandbox notice: Permission denied creating {plugin_dir}. Run in host terminal.[/]")
234
+ return 0
235
+
236
+ # Sync core plugin files from upstream repository
237
+ core_files = [
238
+ ("plugin.json", plugin_dir / "plugin.json"),
239
+ ("plugin/rules/AGENTS.md", rules_dir / "AGENTS.md"),
240
+ ("plugin/skills/auto-context/SKILL.md", skills_dir / "SKILL.md"),
241
+ ]
242
+
243
+ for rel_path, dest_path in core_files:
244
+ url = f"{config.RAW_GITHUB_BASE}/{rel_path}"
245
+ content = _download_text(url)
246
+ if content:
247
+ dest_path.write_text(content, encoding="utf-8")
248
+ console.print(f" [green][✓] Updated public definition:[/] {dest_path.name}")
249
+ updated_count += 1
250
+ else:
251
+ # Fallback to locally bundled templates if offline
252
+ tmpl_dir = config.get_templates_dir()
253
+ fallback_map = {
254
+ "AGENTS.md": tmpl_dir / "AGENTS.template.md",
255
+ "SKILL.md": tmpl_dir / "skill.template.md",
256
+ }
257
+ if dest_path.name in fallback_map and fallback_map[dest_path.name].exists():
258
+ shutil.copy2(fallback_map[dest_path.name], dest_path)
259
+ console.print(f" [green][✓] Restored from bundled template:[/] {dest_path.name}")
260
+ updated_count += 1
261
+
262
+ return updated_count
263
+
264
+
265
+ def update_workspace(target_dir: Path, force: bool = False) -> int:
266
+ """
267
+ Safely update system-managed standing rules in the current project workspace.
268
+
269
+ NON-BREAKING SAFETY GUARANTEES:
270
+ - NEVER touches context.md (preserves project architecture, credentials & problem log).
271
+ - NEVER touches context.local.md or .env (zero test credential or secret loss).
272
+ - NEVER touches custom user rules in .agents/rules/*.md.
273
+ - Only updates system standing rules (maintain_context.md, AGENTS.md, GEMINI.md).
274
+ """
275
+ console.print(f" [cyan][*] Updating workspace system rules:[/] {target_dir.name}")
276
+ updated_count = 0
277
+ templates = config.get_templates_dir()
278
+
279
+ # System-managed files to refresh
280
+ system_rules = [
281
+ (templates / "maintain_context.template.md", target_dir / config.AGENTS_SUBDIR / "rules" / "maintain_context.md"),
282
+ (templates / "AGENTS.template.md", target_dir / "AGENTS.md"),
283
+ (templates / "GEMINI.template.md", target_dir / "GEMINI.md"),
284
+ ]
285
+
286
+ variables = {
287
+ "PROJECT_NAME": target_dir.name,
288
+ "PROJECT_DIR": str(target_dir),
289
+ }
290
+
291
+ for tmpl_path, dest_path in system_rules:
292
+ if not tmpl_path.exists():
293
+ continue
294
+
295
+ content = tmpl_path.read_text(encoding="utf-8")
296
+ for k, v in variables.items():
297
+ content = content.replace(f"{{{{{k}}}}}", v)
298
+
299
+ if dest_path.exists() and not force:
300
+ existing = dest_path.read_text(encoding="utf-8")
301
+ if existing == content:
302
+ console.print(f" [dim]— Up to date:[/] {dest_path.name}")
303
+ continue
304
+
305
+ # Backup modified file if different
306
+ bak_path = dest_path.with_suffix(".md.bak")
307
+ shutil.copy2(dest_path, bak_path)
308
+ console.print(f" [yellow][*] Backed up customized file:[/] {bak_path.name}")
309
+
310
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
311
+ dest_path.write_text(content, encoding="utf-8")
312
+ console.print(f" [green][✓] Updated system rule:[/] {dest_path.name}")
313
+ updated_count += 1
314
+
315
+ return updated_count
316
+
317
+
318
+ # ── CLI update Command ────────────────────────────────────────────────────────
319
+
320
+ def update(
321
+ workspace: Annotated[bool, typer.Option("--workspace", "-w", help="Update managed system rules in active project.")] = False,
322
+ global_: Annotated[bool, typer.Option("--global", "-g", help="Update global plugin and public rules only.")] = False,
323
+ cli: Annotated[bool, typer.Option("--cli", "-c", help="Upgrade auto-context-cli package only.")] = False,
324
+ check: Annotated[bool, typer.Option("--check", help="Check for available updates without modifying files.")] = False,
325
+ force: Annotated[bool, typer.Option("--force", "-f", help="Force overwrite without creating backups.")] = False,
326
+ target: Annotated[Optional[Path], typer.Option("--target", "-t", help="Target project directory.")] = None,
327
+ ) -> None:
328
+ """
329
+ Safely update auto-context CLI, public rulebooks, and global agent plugins.
330
+
331
+ Guaranteed Non-Breaking:
332
+ - Never modifies context.md, context.local.md, or .env.
333
+ - Never overwrites custom user-created rules or private skills.
334
+ - Seamlessly pulls new upstream guidelines and capabilities.
335
+ """
336
+ console.print(Panel(
337
+ "[bold cyan]🔄 Auto-Context: Modular Upstream Sync & Updater[/]\n"
338
+ f"[dim]Upstream Repository: https://github.com/{config.GITHUB_REPO}[/]",
339
+ border_style="cyan",
340
+ ))
341
+
342
+ # 1. Check upstream status
343
+ status = get_cached_update_status(force_check=True)
344
+ cur = get_installed_version()
345
+ latest = status.get("latest_version", cur) if status else cur
346
+ has_update = status.get("update_available", False) if status else False
347
+
348
+ console.print(f" [yellow]Installed Version:[/] v{cur}")
349
+ console.print(f" [cyan]Upstream Version: [/] v{latest}")
350
+ if has_update:
351
+ console.print(f" [bold green]✨ New version available:[/] v{latest}")
352
+ else:
353
+ console.print(" [green][✓] You are running the latest version.[/]")
354
+
355
+ if check:
356
+ # Check-only mode ends here
357
+ console.print("\n[dim]Run 'init-context update' to apply updates.[/]\n")
358
+ return
359
+
360
+ console.print()
361
+
362
+ # Determine what to update
363
+ all_selected = not (workspace or global_ or cli)
364
+ project_dir = (target or Path.cwd()).resolve()
365
+ has_project_context = (project_dir / "context.md").exists() or (project_dir / config.AGENTS_SUBDIR).exists()
366
+
367
+ # Step A: Upgrade CLI Package
368
+ if all_selected or cli:
369
+ update_cli_package()
370
+
371
+ # Step B: Sync Global Plugin & Public Rules
372
+ if all_selected or global_:
373
+ update_global_plugin()
374
+
375
+ # Step C: Workspace System Rules
376
+ if (all_selected and has_project_context) or workspace:
377
+ update_workspace(project_dir, force=force)
378
+
379
+ # Invalidate cache so notification disappears after successful update
380
+ if config.UPDATE_CACHE_FILE.exists():
381
+ try:
382
+ config.UPDATE_CACHE_FILE.unlink()
383
+ except Exception:
384
+ pass
385
+
386
+ console.print(Panel(
387
+ "[bold green]✨ Modular update completed successfully![/]\n"
388
+ "[white]• Custom user rules & private skills: [green]Untouched (Safe)[/]\n"
389
+ "• Project context.md & credentials: [green]Untouched (Zero Data Loss)[/]\n"
390
+ "• Global plugin & system rules: [bold green]Synchronized[/]",
391
+ border_style="green",
392
+ ))
@@ -63,3 +63,31 @@ STACK_INDICATORS: list[tuple[str, str, str]] = [
63
63
  GIT_COMMIT_INIT = "feat(memory): initialize central agent brain knowledge base"
64
64
  GIT_COMMIT_SYNC = "chore(memory): sync agent brain knowledge base"
65
65
 
66
+ # ── Update & Upstream Configuration ──────────────────────────────────────────
67
+ GITHUB_REPO = "Cyber-arghya/auto-context"
68
+ PYPI_PACKAGE = "auto-context-cli"
69
+ RAW_GITHUB_BASE = "https://raw.githubusercontent.com/Cyber-arghya/auto-context/main"
70
+ PYPI_JSON_URL = f"https://pypi.org/pypi/{PYPI_PACKAGE}/json"
71
+ GITHUB_LATEST_RELEASE_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
72
+
73
+ import tempfile
74
+
75
+ def get_cache_dir() -> Path:
76
+ """Return user cache directory, falling back to tempdir if permission restricted."""
77
+ try:
78
+ p = HOME / ".auto-context" / "cache"
79
+ p.mkdir(parents=True, exist_ok=True)
80
+ return p
81
+ except Exception:
82
+ p = Path(tempfile.gettempdir()) / "auto-context-cache"
83
+ try:
84
+ p.mkdir(parents=True, exist_ok=True)
85
+ except Exception:
86
+ pass
87
+ return p
88
+
89
+ CACHE_DIR: Path = get_cache_dir()
90
+ UPDATE_CACHE_FILE: Path = CACHE_DIR / "update_check.json"
91
+ UPDATE_CHECK_INTERVAL: int = 86400 # 24 hours in seconds
92
+
93
+
@@ -11,7 +11,7 @@ from typing import Annotated, Optional
11
11
  import typer
12
12
  from rich.console import Console
13
13
 
14
- from auto_context.commands import init_cmd, memory, mcp, share, import_cmd
14
+ from auto_context.commands import init_cmd, memory, mcp, share, import_cmd, update_cmd
15
15
 
16
16
  app = typer.Typer(
17
17
  name="init-context",
@@ -32,6 +32,7 @@ app.command("skill")(init_cmd.new_skill)
32
32
  app.command("promote")(init_cmd.promote)
33
33
  app.command("share")(share.share)
34
34
  app.command("import")(import_cmd.import_item)
35
+ app.command("update")(update_cmd.update)
35
36
 
36
37
 
37
38
  @app.callback(invoke_without_command=True)
@@ -119,4 +120,15 @@ def main() -> None: # pragma: no cover
119
120
  sys.stderr.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
120
121
  except AttributeError:
121
122
  pass
122
- app()
123
+
124
+ try:
125
+ app()
126
+ except SystemExit as e:
127
+ if e.code == 0 and not any(arg in sys.argv for arg in ("--version", "-v", "update", "--help", "-h")):
128
+ update_cmd.maybe_notify_update()
129
+ raise
130
+ except Exception:
131
+ raise
132
+ else:
133
+ if not any(arg in sys.argv for arg in ("--version", "-v", "update", "--help", "-h")):
134
+ update_cmd.maybe_notify_update()
@@ -32,6 +32,7 @@ You have native access to run `init-context` via terminal commands:
32
32
  - `init-context`: Scaffolds or repairs project context.
33
33
  - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
34
34
  - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
+ - `init-context update`: Safely syncs public rules and upstream capabilities (non-breaking).
35
36
  - `init-context memory push`: Synchronizes central brain memory to private Git repository.
36
37
 
37
38
  ### 4. Required Content & Structure in `context.md`
@@ -32,6 +32,7 @@ You have native access to run `init-context` via terminal commands:
32
32
  - `init-context`: Scaffolds or repairs project context.
33
33
  - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
34
34
  - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
+ - `init-context update`: Safely syncs public rules and upstream capabilities (non-breaking).
35
36
  - `init-context memory push`: Synchronizes central brain memory to private Git repository.
36
37
 
37
38
  ### 4. Required Content & Structure in `context.md`
@@ -22,6 +22,7 @@ trigger: always_on
22
22
  - `init-context`: Initialize/repair context.
23
23
  - `init-context -r <name> [-g]`: Create rule.
24
24
  - `init-context -s <name> [-g]`: Create skill.
25
+ - `init-context update`: Safely sync public rules and upstream capabilities (non-breaking).
25
26
  - `init-context memory push`: Push updates to central memory.
26
27
 
27
28
  4. **No User Reminder Needed**: The user must never need to ask the agent to update `context.md` or learn rules. This is a strict automated post-condition for all actions.