auto-context-cli 1.0.0__tar.gz → 1.0.1__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.0 → auto_context_cli-1.0.1}/PKG-INFO +34 -10
  2. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/README.md +33 -9
  3. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/pyproject.toml +1 -1
  4. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/__init__.py +1 -1
  5. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/commands/init_cmd.py +41 -0
  6. auto_context_cli-1.0.1/src/auto_context/commands/memory.py +320 -0
  7. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/main.py +2 -1
  8. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/AGENTS.template.md +7 -4
  9. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/GEMINI.template.md +7 -4
  10. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/maintain_context.template.md +4 -4
  11. auto_context_cli-1.0.0/src/auto_context/commands/memory.py +0 -236
  12. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/.gitignore +0 -0
  13. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/LICENSE +0 -0
  14. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/commands/__init__.py +0 -0
  15. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/commands/import_cmd.py +0 -0
  16. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/commands/mcp.py +0 -0
  17. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/commands/share.py +0 -0
  18. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/config.py +0 -0
  19. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/security.py +0 -0
  20. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/context.local.template.md +0 -0
  21. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/context.template.md +0 -0
  22. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/mcp_config.template.json +0 -0
  23. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/profile.template.md +0 -0
  24. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/rule.template.md +0 -0
  25. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/rules/code-standards.md +0 -0
  26. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/rules/security-boundaries.md +0 -0
  27. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/skill.template.md +0 -0
  28. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/skills/browser-testing/SKILL.md +0 -0
  29. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/skills/docker-ops/SKILL.md +0 -0
  30. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/src/auto_context/templates/skills/git-workflow/SKILL.md +0 -0
  31. {auto_context_cli-1.0.0 → auto_context_cli-1.0.1}/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.0
3
+ Version: 1.0.1
4
4
  Summary: Autonomous context & instruction manager for AI coding assistants
5
5
  Author: Arghya Biswas
6
6
  License: MIT
@@ -18,10 +18,12 @@ Description-Content-Type: text/markdown
18
18
 
19
19
  **Autonomous Context & Instruction Management Protocol for AI Coding Assistants**
20
20
 
21
+ [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
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)
21
24
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
22
- [![Platform](https://img.shields.io/badge/Platform-Windows%20PowerShell%20%7C%20Linux%20WSL2%20%7C%20macOS-success.svg)](#-quick-one-line-install)
25
+ [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
23
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)
24
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Cyber-arghya/auto-context/pulls)
25
27
 
26
28
  *Never lose context, forgotten architecture decisions, or unlogged bug fixes again.*
27
29
 
@@ -33,19 +35,26 @@ Description-Content-Type: text/markdown
33
35
 
34
36
  ## ⚡ Quick One-Line Install
35
37
 
36
- No manual downloads or complex PATH configurations required. Run the command matching your terminal:
38
+ No manual git clones or complex PATH configurations required. Install directly via PyPI or using our 1-click installer:
37
39
 
38
- ### 📦 Universal via `uv` (Fastest, Windows / Mac / Linux / WSL2):
40
+ ### 📦 Direct via PyPI (Universal - Windows, macOS, Linux, WSL2):
39
41
  ```bash
40
- uv tool install git+https://github.com/Cyber-arghya/auto-context.git
42
+ # Recommended via uv (fast & isolated):
43
+ uv tool install auto-context-cli
44
+
45
+ # Or via standard pip:
46
+ pip install auto-context-cli
47
+
48
+ # Or via pipx:
49
+ pipx install auto-context-cli
41
50
  ```
42
51
 
43
- ### 🪟 Windows (PowerShell / `pwsh` 1-Click):
52
+ ### 🪟 Windows (PowerShell / `pwsh` 1-Click Installer):
44
53
  ```powershell
45
54
  irm https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.ps1 | iex
46
55
  ```
47
56
 
48
- ### 🐧 Linux / WSL2 / macOS (Bash / Zsh 1-Click):
57
+ ### 🐧 Linux / WSL2 / macOS (Bash / Zsh 1-Click Installer):
49
58
  ```bash
50
59
  curl -sSL https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.sh | bash
51
60
  ```
@@ -184,6 +193,11 @@ You can easily teach your AI assistants new abilities (**Skills**) or enforce cu
184
193
  | **Rule** | Behavioral constraints, coding standards, security boundaries, or test requirements. | Always active (`trigger: always_on`) or context-triggered. | `.agents/rules/<name>.md` or `GEMINI.md` |
185
194
  | **Skill** | Step-by-step procedures, deployment runbooks, debugging steps, or CLI tool guides. | Activated on-demand when relevant task is requested. | `.agents/skills/<name>/SKILL.md` |
186
195
 
196
+ > [!IMPORTANT]
197
+ > **Core Directives for AI Coding Agents:**
198
+ > - **Zero Token Waste:** DO NOT burn tokens manually searching directories or reading files to check for existing rules. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
199
+ > - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
200
+
187
201
  ---
188
202
 
189
203
  ### 1️⃣ How to Add a New Rule
@@ -454,11 +468,17 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
454
468
  3. **পাসওয়ার্ড ও পোর্ট ভল্ট:** সার্ভারের স্ট্যাটিক আইপি, ক্লাউডফ্লেয়ার টানেল আইডি বা ডাটাবেজ পোর্ট সবসময় এক ফাইলে নিখুঁতভাবে থাকবে।
455
469
 
456
470
  ### ইনস্টলেশন ও ব্যবহার:
457
- * **উইন্ডোজ পাওয়ারশেল (PowerShell)-এ:**
471
+ * **PyPI থেকে সরাসরি ইনস্টল করতে (সবার জন্য সহজ):**
472
+ ```bash
473
+ pip install auto-context-cli
474
+ # অথবা uv দিয়ে:
475
+ uv tool install auto-context-cli
476
+ ```
477
+ * **উইন্ডোজ পাওয়ারশেল (1-Click Installer):**
458
478
  ```powershell
459
479
  irm https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.ps1 | iex
460
480
  ```
461
- * **লিনাক্স / WSL2-এ:**
481
+ * **লিনাক্স / WSL2 / macOS (1-Click Installer):**
462
482
  ```bash
463
483
  curl -sSL https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.sh | bash
464
484
  ```
@@ -470,6 +490,10 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
470
490
  ব্যস! আপনার প্রজেক্টে স্বয়ংক্রিয় কনটেক্সট ট্র্যাকিং চালু হয়ে যাবে।
471
491
 
472
492
  ### নতুন স্কিল বা রুল তৈরি করার নিয়ম:
493
+ > [!IMPORTANT]
494
+ > **এআই কোডিং এজেন্টের জন্য বাধ্যতামূলক নির্দেশিকা:**
495
+ > - **জিরো টোকেন অপচয় (Zero Token Waste):** কোনো রুল বা স্কিল আগে থেকে আছে কিনা তা চেক করতে ম্যানুয়ালি ফাইল খোঁজা বা পড়ার কোনো প্রয়োজন নেই। সরাসরি `init-context -r <name> [-g]` রান করুন — সিএলআই স্বয়ংক্রিয়ভাবে ডুপ্লিকেট শনাক্ত ও কলিশন গার্ড দিয়ে প্রোটেক্ট করে।
496
+ > - **বাধ্যতামূলক গ্লোবাল স্কোপ (Mandatory Global Scope):** ইউজার যখন "for future", "always" বা ভবিষ্যতের জন্য কোনো সাধারণ নিয়ম সেভ করতে বলবে, তখন অবশ্যই `--global` (`-g`) ব্যবহার করতে হবে এবং সাথে সাথে `init-context memory push` রান করে সেন্ট্রাল মেমরিতে সিঙ্ক করতে হবে।
473
497
  * **নতুন রুল (Rule) তৈরি করতে:**
474
498
  ```bash
475
499
  init-context -r my-rule-name # বর্তমান প্রজেক্টের জন্য
@@ -4,10 +4,12 @@
4
4
 
5
5
  **Autonomous Context & Instruction Management Protocol for AI Coding Assistants**
6
6
 
7
+ [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
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)
7
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
- [![Platform](https://img.shields.io/badge/Platform-Windows%20PowerShell%20%7C%20Linux%20WSL2%20%7C%20macOS-success.svg)](#-quick-one-line-install)
11
+ [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
9
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)
10
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Cyber-arghya/auto-context/pulls)
11
13
 
12
14
  *Never lose context, forgotten architecture decisions, or unlogged bug fixes again.*
13
15
 
@@ -19,19 +21,26 @@
19
21
 
20
22
  ## ⚡ Quick One-Line Install
21
23
 
22
- No manual downloads or complex PATH configurations required. Run the command matching your terminal:
24
+ No manual git clones or complex PATH configurations required. Install directly via PyPI or using our 1-click installer:
23
25
 
24
- ### 📦 Universal via `uv` (Fastest, Windows / Mac / Linux / WSL2):
26
+ ### 📦 Direct via PyPI (Universal - Windows, macOS, Linux, WSL2):
25
27
  ```bash
26
- uv tool install git+https://github.com/Cyber-arghya/auto-context.git
28
+ # Recommended via uv (fast & isolated):
29
+ uv tool install auto-context-cli
30
+
31
+ # Or via standard pip:
32
+ pip install auto-context-cli
33
+
34
+ # Or via pipx:
35
+ pipx install auto-context-cli
27
36
  ```
28
37
 
29
- ### 🪟 Windows (PowerShell / `pwsh` 1-Click):
38
+ ### 🪟 Windows (PowerShell / `pwsh` 1-Click Installer):
30
39
  ```powershell
31
40
  irm https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.ps1 | iex
32
41
  ```
33
42
 
34
- ### 🐧 Linux / WSL2 / macOS (Bash / Zsh 1-Click):
43
+ ### 🐧 Linux / WSL2 / macOS (Bash / Zsh 1-Click Installer):
35
44
  ```bash
36
45
  curl -sSL https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.sh | bash
37
46
  ```
@@ -170,6 +179,11 @@ You can easily teach your AI assistants new abilities (**Skills**) or enforce cu
170
179
  | **Rule** | Behavioral constraints, coding standards, security boundaries, or test requirements. | Always active (`trigger: always_on`) or context-triggered. | `.agents/rules/<name>.md` or `GEMINI.md` |
171
180
  | **Skill** | Step-by-step procedures, deployment runbooks, debugging steps, or CLI tool guides. | Activated on-demand when relevant task is requested. | `.agents/skills/<name>/SKILL.md` |
172
181
 
182
+ > [!IMPORTANT]
183
+ > **Core Directives for AI Coding Agents:**
184
+ > - **Zero Token Waste:** DO NOT burn tokens manually searching directories or reading files to check for existing rules. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
185
+ > - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
186
+
173
187
  ---
174
188
 
175
189
  ### 1️⃣ How to Add a New Rule
@@ -440,11 +454,17 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
440
454
  3. **পাসওয়ার্ড ও পোর্ট ভল্ট:** সার্ভারের স্ট্যাটিক আইপি, ক্লাউডফ্লেয়ার টানেল আইডি বা ডাটাবেজ পোর্ট সবসময় এক ফাইলে নিখুঁতভাবে থাকবে।
441
455
 
442
456
  ### ইনস্টলেশন ও ব্যবহার:
443
- * **উইন্ডোজ পাওয়ারশেল (PowerShell)-এ:**
457
+ * **PyPI থেকে সরাসরি ইনস্টল করতে (সবার জন্য সহজ):**
458
+ ```bash
459
+ pip install auto-context-cli
460
+ # অথবা uv দিয়ে:
461
+ uv tool install auto-context-cli
462
+ ```
463
+ * **উইন্ডোজ পাওয়ারশেল (1-Click Installer):**
444
464
  ```powershell
445
465
  irm https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.ps1 | iex
446
466
  ```
447
- * **লিনাক্স / WSL2-এ:**
467
+ * **লিনাক্স / WSL2 / macOS (1-Click Installer):**
448
468
  ```bash
449
469
  curl -sSL https://raw.githubusercontent.com/Cyber-arghya/auto-context/main/install.sh | bash
450
470
  ```
@@ -456,6 +476,10 @@ To prevent **Prompt Injection Leaks** and keep production secrets safe:
456
476
  ব্যস! আপনার প্রজেক্টে স্বয়ংক্রিয় কনটেক্সট ট্র্যাকিং চালু হয়ে যাবে।
457
477
 
458
478
  ### নতুন স্কিল বা রুল তৈরি করার নিয়ম:
479
+ > [!IMPORTANT]
480
+ > **এআই কোডিং এজেন্টের জন্য বাধ্যতামূলক নির্দেশিকা:**
481
+ > - **জিরো টোকেন অপচয় (Zero Token Waste):** কোনো রুল বা স্কিল আগে থেকে আছে কিনা তা চেক করতে ম্যানুয়ালি ফাইল খোঁজা বা পড়ার কোনো প্রয়োজন নেই। সরাসরি `init-context -r <name> [-g]` রান করুন — সিএলআই স্বয়ংক্রিয়ভাবে ডুপ্লিকেট শনাক্ত ও কলিশন গার্ড দিয়ে প্রোটেক্ট করে।
482
+ > - **বাধ্যতামূলক গ্লোবাল স্কোপ (Mandatory Global Scope):** ইউজার যখন "for future", "always" বা ভবিষ্যতের জন্য কোনো সাধারণ নিয়ম সেভ করতে বলবে, তখন অবশ্যই `--global` (`-g`) ব্যবহার করতে হবে এবং সাথে সাথে `init-context memory push` রান করে সেন্ট্রাল মেমরিতে সিঙ্ক করতে হবে।
459
483
  * **নতুন রুল (Rule) তৈরি করতে:**
460
484
  ```bash
461
485
  init-context -r my-rule-name # বর্তমান প্রজেক্টের জন্য
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "auto-context-cli"
3
- version = "1.0.0"
3
+ version = "1.0.1"
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.0"
3
+ __version__ = "1.0.1"
@@ -307,3 +307,44 @@ def new_skill(
307
307
  f"[green] File: [/] {dest_file}",
308
308
  border_style="cyan",
309
309
  ))
310
+
311
+
312
+ # ── promote command ───────────────────────────────────────────────────────────
313
+
314
+ def promote(
315
+ name: Annotated[str, typer.Argument(help="Rule or skill name to promote to Central Memory.")],
316
+ target: Annotated[Optional[Path], typer.Option("--target", "-t")] = None,
317
+ ) -> None:
318
+ """Promote a local workspace rule or skill to Central Memory and global scope."""
319
+ project_dir = (target or Path.cwd()).resolve()
320
+ clean_name = name.lower().replace(" ", "-").replace("_", "-").removesuffix(".md")
321
+
322
+ local_rule = project_dir / AGENTS_SUBDIR / "rules" / f"{clean_name}.md"
323
+ local_skill = project_dir / AGENTS_SUBDIR / "skills" / clean_name / "SKILL.md"
324
+
325
+ promoted = False
326
+ if local_rule.exists():
327
+ content = local_rule.read_text(encoding="utf-8")
328
+ (config.GLOBAL_PLUGIN_DIR / "rules").mkdir(parents=True, exist_ok=True)
329
+ (config.GLOBAL_PLUGIN_DIR / "rules" / f"{clean_name}.md").write_text(content, encoding="utf-8")
330
+ if config.MEMORY_DIR.exists():
331
+ (config.MEMORY_DIR / "rules").mkdir(parents=True, exist_ok=True)
332
+ (config.MEMORY_DIR / "rules" / f"{clean_name}.md").write_text(content, encoding="utf-8")
333
+ console.print(f"[bold green][✓] Promoted local rule '{clean_name}' to Global Plugin and Central Memory![/]")
334
+ promoted = True
335
+
336
+ if local_skill.exists():
337
+ content = local_skill.read_text(encoding="utf-8")
338
+ (config.GLOBAL_PLUGIN_DIR / "skills" / clean_name).mkdir(parents=True, exist_ok=True)
339
+ (config.GLOBAL_PLUGIN_DIR / "skills" / clean_name / "SKILL.md").write_text(content, encoding="utf-8")
340
+ if config.MEMORY_DIR.exists():
341
+ (config.MEMORY_DIR / "skills" / clean_name).mkdir(parents=True, exist_ok=True)
342
+ (config.MEMORY_DIR / "skills" / clean_name / "SKILL.md").write_text(content, encoding="utf-8")
343
+ console.print(f"[bold green][✓] Promoted local skill '{clean_name}' to Global Plugin and Central Memory![/]")
344
+ promoted = True
345
+
346
+ if not promoted:
347
+ console.print(f"[red][✗] Rule or skill '{clean_name}' not found in local workspace ({project_dir}).[/]")
348
+ raise typer.Exit(1)
349
+
350
+ console.print(" [cyan]💡 Run 'init-context memory push' to push changes to your private GitHub repo.[/]\n")
@@ -0,0 +1,320 @@
1
+ """
2
+ commands/memory.py — Central memory brain management.
3
+
4
+ Wraps git CLI via subprocess.run. Runs security.audit_path()
5
+ before every commit or push — zero-bypass hard-block.
6
+
7
+ Subcommands: init, push, pull, status
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import shutil
12
+ import subprocess
13
+ from datetime import datetime
14
+ from pathlib import Path
15
+ from typing import Annotated, Optional
16
+
17
+ import typer
18
+ from rich.console import Console
19
+ from rich.panel import Panel
20
+
21
+ from auto_context import config, security
22
+
23
+ app = typer.Typer(help="Central memory brain management.")
24
+ console = Console()
25
+
26
+ MEMORY_DIR = config.MEMORY_DIR
27
+
28
+ _GITIGNORE_ENTRIES = """\
29
+ # Security: Prohibit credentials and environment files from central memory
30
+ .env
31
+ .env.*
32
+ *.local.md
33
+ context.local.md
34
+ *.key
35
+ *.pem
36
+ *.p12
37
+ *.pfx
38
+ *.kdbx
39
+ id_rsa*
40
+ id_ed25519*
41
+ id_ecdsa*
42
+ id_dsa*
43
+ authorized_keys
44
+ known_hosts
45
+ """
46
+
47
+
48
+ def _git(cwd: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess:
49
+ """Run a git command in *cwd*, capturing output."""
50
+ return subprocess.run(
51
+ ["git", "-C", str(cwd), *args],
52
+ capture_output=True,
53
+ text=True,
54
+ check=check,
55
+ )
56
+
57
+
58
+ def _has_gh() -> bool:
59
+ return shutil.which("gh") is not None
60
+
61
+
62
+ # ── init ──────────────────────────────────────────────────────────────────────
63
+
64
+ @app.command("init")
65
+ def memory_init(
66
+ repo_name: Annotated[str, typer.Argument(help="GitHub repo name.")] = "auto-context-memory",
67
+ ) -> None:
68
+ """Initialize a private central memory brain repository."""
69
+ console.print(Panel(
70
+ f"[bold green]🧠 Initializing Private Central Memory Brain[/]\n"
71
+ f"[yellow] Directory:[/] {MEMORY_DIR}\n"
72
+ f"[cyan] Repo: [/] {repo_name} (Strictly Private)",
73
+ border_style="cyan",
74
+ ))
75
+
76
+ (MEMORY_DIR / "rules").mkdir(parents=True, exist_ok=True)
77
+ (MEMORY_DIR / "skills").mkdir(parents=True, exist_ok=True)
78
+
79
+ # Init git repo
80
+ if not (MEMORY_DIR / ".git").exists():
81
+ _git(MEMORY_DIR, "init")
82
+ console.print(" [green][✓] Initialized Git repository[/]")
83
+
84
+ # Hardened .gitignore
85
+ (MEMORY_DIR / ".gitignore").write_text(_GITIGNORE_ENTRIES, encoding="utf-8")
86
+ console.print(" [green][✓] Hardened .gitignore written[/]")
87
+
88
+ # profile.md
89
+ _write_profile(repo_name)
90
+
91
+ # Security audit before first commit
92
+ console.print(" [cyan][*] Running pre-commit security audit...[/]")
93
+ violations = security.audit_path(MEMORY_DIR)
94
+ security.abort_if_violations(violations)
95
+
96
+ _git(MEMORY_DIR, "add", "-A", check=False)
97
+ _git(MEMORY_DIR, "commit", "-m", config.GIT_COMMIT_INIT, check=False)
98
+ _git(MEMORY_DIR, "branch", "-M", "main", check=False)
99
+
100
+ if _has_gh():
101
+ console.print(" [cyan][*] Creating strictly private GitHub repository via gh...[/]")
102
+ result = subprocess.run(
103
+ ["gh", "repo", "create", repo_name,
104
+ "--private", f"--source={MEMORY_DIR}", "--remote=origin", "--push"],
105
+ capture_output=True, text=True,
106
+ )
107
+ if result.returncode == 0:
108
+ console.print(" [green][✓] Private GitHub memory repository created and pushed![/]")
109
+ else:
110
+ _print_manual_push(repo_name)
111
+ else:
112
+ console.print(" [yellow][!] GitHub CLI ('gh') not found. Install it or connect manually:[/]")
113
+ _print_manual_push(repo_name)
114
+
115
+ console.print(f"\n[bold green]🎉 Central Memory Initialized![/]")
116
+ console.print(f" [yellow]Local Brain:[/] {MEMORY_DIR}")
117
+ console.print(f" [green]Sync Command:[/] init-context memory push\n")
118
+
119
+
120
+ def _print_manual_push(repo_name: str) -> None:
121
+ console.print(f" [dim]git -C \"{MEMORY_DIR}\" remote add origin git@github.com:<username>/{repo_name}.git[/]")
122
+ console.print(f" [dim]git -C \"{MEMORY_DIR}\" push -u origin main[/]")
123
+
124
+
125
+ def _write_profile(repo_name: str) -> None:
126
+ profile = MEMORY_DIR / "profile.md"
127
+ if profile.exists():
128
+ return
129
+ import getpass
130
+ username = getpass.getuser()
131
+ date_now = datetime.now().strftime("%Y-%m-%d")
132
+ profile.write_text(
133
+ f"# Agent Memory & Developer Profile\n\n"
134
+ f"> **Owner:** {username} \n"
135
+ f"> **Initialized:** {date_now} \n"
136
+ f"> **Repository:** {repo_name} \n"
137
+ f"> **Visibility:** Private Central Agent Brain \n\n---\n\n"
138
+ f"## 1. Developer Preferences\n- Edit this file to personalise agent behaviour.\n\n"
139
+ f"## 2. Central Knowledge Base Index\n"
140
+ f"- **Global Rules:** `rules/`\n"
141
+ f"- **Reusable Skills:** `skills/`\n",
142
+ encoding="utf-8",
143
+ )
144
+ console.print(" [green][✓] Generated Developer Profile: profile.md[/]")
145
+
146
+
147
+ # ── local harvester ─────────────────────────────────────────────────────────
148
+
149
+ def _sync_local_to_memory(project_dir: Path) -> int:
150
+ """Harvest newly created local project rules & skills into central memory."""
151
+ harvested = 0
152
+ try:
153
+ local_rules = project_dir / config.AGENTS_SUBDIR / "rules"
154
+ if local_rules.exists():
155
+ (MEMORY_DIR / "rules").mkdir(parents=True, exist_ok=True)
156
+ for rfile in local_rules.glob("*.md"):
157
+ # Skip standard default boilerplates from polluting memory if already synced
158
+ dest = MEMORY_DIR / "rules" / rfile.name
159
+ if not dest.exists():
160
+ shutil.copy2(rfile, dest)
161
+ harvested += 1
162
+ console.print(f" [green][✓] Harvested local rule to Central Memory:[/] {rfile.name}")
163
+ elif rfile.stat().st_mtime > dest.stat().st_mtime:
164
+ shutil.copy2(rfile, dest)
165
+ harvested += 1
166
+ console.print(f" [green][✓] Updated local rule in Central Memory:[/] {rfile.name}")
167
+
168
+ local_skills = project_dir / config.AGENTS_SUBDIR / "skills"
169
+ if local_skills.exists():
170
+ (MEMORY_DIR / "skills").mkdir(parents=True, exist_ok=True)
171
+ for sdir in local_skills.iterdir():
172
+ if sdir.is_dir() and (sdir / "SKILL.md").exists():
173
+ dest_dir = MEMORY_DIR / "skills" / sdir.name
174
+ dest_file = dest_dir / "SKILL.md"
175
+ src_file = sdir / "SKILL.md"
176
+ if not dest_file.exists() or src_file.stat().st_mtime > dest_file.stat().st_mtime:
177
+ dest_dir.mkdir(parents=True, exist_ok=True)
178
+ shutil.copy2(src_file, dest_file)
179
+ harvested += 1
180
+ console.print(f" [green][✓] Harvested local skill to Central Memory:[/] {sdir.name}")
181
+ except OSError:
182
+ pass
183
+ return harvested
184
+
185
+
186
+ # ── push ──────────────────────────────────────────────────────────────────────
187
+
188
+ @app.command("push")
189
+ def memory_push(
190
+ harvest: Annotated[bool, typer.Option("--harvest/--no-harvest", "-h/-n", help="Auto-harvest local workspace rules/skills into central memory.")] = True,
191
+ ) -> None:
192
+ """Audit secrets and push memory brain to private GitHub repo."""
193
+ console.print(Panel(
194
+ "[bold green]🧠 Synchronizing Central Memory Brain[/]\n"
195
+ f"[yellow] Location:[/] {MEMORY_DIR}",
196
+ border_style="cyan",
197
+ ))
198
+
199
+ try:
200
+ if not MEMORY_DIR.exists():
201
+ console.print(f"[red][✗] Memory directory not found:[/] {MEMORY_DIR}")
202
+ console.print(" Run: [cyan]init-context memory init[/]")
203
+ raise typer.Exit(1)
204
+
205
+ # Harvest local rules/skills if in a project directory
206
+ if harvest:
207
+ _sync_local_to_memory(Path.cwd().resolve())
208
+
209
+ console.print(" [cyan][*] Running Zero-Bypass Security Auditor...[/]")
210
+ violations = security.audit_path(MEMORY_DIR)
211
+ security.abort_if_violations(violations)
212
+
213
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
214
+ _git(MEMORY_DIR, "add", "-A", check=False)
215
+ _git(MEMORY_DIR, "commit", "-m", f"{config.GIT_COMMIT_SYNC} [{timestamp}]", check=False)
216
+
217
+ remote = _git(MEMORY_DIR, "remote", "get-url", "origin", check=False).stdout.strip()
218
+ if remote:
219
+ console.print(" [cyan][*] Pushing to private remote repository...[/]")
220
+ result = _git(MEMORY_DIR, "push", "origin", "main", check=False)
221
+ if result.returncode == 0:
222
+ console.print(" [green][✓] Memory brain pushed successfully![/]")
223
+ else:
224
+ console.print(f" [red][✗] Push failed:[/] {result.stderr.strip()}")
225
+ else:
226
+ console.print(" [yellow][!] No remote 'origin' configured. Run memory init first.[/]")
227
+
228
+ console.print("\n[bold green]✨ Memory synchronization complete![/]\n")
229
+
230
+ except PermissionError as pe:
231
+ console.print(Panel(
232
+ f"[bold red][✗] Permission Denied Accessing Central Memory[/]\n"
233
+ f"[yellow] Path:[/] {MEMORY_DIR}\n\n"
234
+ f"[white] Cause:[/] Running inside a restricted sandbox without host filesystem access.\n"
235
+ f"[cyan] Fix:[/] Run this command in your external terminal (PowerShell / Bash), or enable unsandboxed mode.",
236
+ border_style="red",
237
+ ))
238
+ raise typer.Exit(1)
239
+ except OSError as err:
240
+ console.print(f"[red][✗] Central memory error:[/] {err}")
241
+ raise typer.Exit(1)
242
+
243
+
244
+ # ── pull ──────────────────────────────────────────────────────────────────────
245
+
246
+ @app.command("pull")
247
+ def memory_pull(
248
+ repo_url: Annotated[Optional[str], typer.Argument(help="Remote repo URL (required for first pull).")] = None,
249
+ ) -> None:
250
+ """Pull and sync the central memory brain from remote."""
251
+ console.print(Panel(
252
+ "[bold green]🧠 Pulling Central Memory Brain[/]",
253
+ border_style="cyan",
254
+ ))
255
+
256
+ try:
257
+ if not MEMORY_DIR.exists():
258
+ if not repo_url:
259
+ console.print("[red][✗] Memory directory not found. Provide a repo URL:[/]")
260
+ console.print(" [cyan]init-context memory pull <url>[/]")
261
+ raise typer.Exit(1)
262
+ subprocess.run(["git", "clone", repo_url, str(MEMORY_DIR)], check=True)
263
+ else:
264
+ _git(MEMORY_DIR, "pull", "origin", "main")
265
+
266
+ console.print(" [cyan][*] Running post-pull security audit...[/]")
267
+ violations = security.audit_path(MEMORY_DIR)
268
+ security.abort_if_violations(violations)
269
+ console.print("\n[bold green]✨ Central memory updated successfully![/]\n")
270
+
271
+ except PermissionError as pe:
272
+ console.print(Panel(
273
+ f"[bold red][✗] Permission Denied Accessing Central Memory[/]\n"
274
+ f"[yellow] Path:[/] {MEMORY_DIR}\n\n"
275
+ f"[white] Fix:[/] Run in external terminal or enable unsandboxed execution mode.",
276
+ border_style="red",
277
+ ))
278
+ raise typer.Exit(1)
279
+
280
+
281
+ # ── status ────────────────────────────────────────────────────────────────────
282
+
283
+ @app.command("status")
284
+ def memory_status() -> None:
285
+ """Show status of the central memory brain."""
286
+ console.print(Panel(
287
+ "[bold green]🧠 Central Memory Status[/]",
288
+ border_style="cyan",
289
+ ))
290
+
291
+ try:
292
+ if not MEMORY_DIR.exists():
293
+ console.print(" [yellow][!] Central memory not initialized.[/]")
294
+ console.print(" Run: [cyan]init-context memory init[/]")
295
+ return
296
+
297
+ remote = _git(MEMORY_DIR, "remote", "get-url", "origin", check=False).stdout.strip()
298
+ rules_path = MEMORY_DIR / "rules"
299
+ skills_path = MEMORY_DIR / "skills"
300
+
301
+ rules_count = len(list(rules_path.glob("*.md"))) if rules_path.exists() else 0
302
+ skills_count = len([d for d in skills_path.iterdir() if d.is_dir()]) if skills_path.exists() else 0
303
+
304
+ console.print(f" [yellow]Location:[/] {MEMORY_DIR}")
305
+ console.print(f" [cyan]Remote: [/] {remote or '(none)'}")
306
+ console.print(f" [green]Rules: [/] {rules_count} registered")
307
+ console.print(f" [green]Skills: [/] {skills_count} registered")
308
+ console.print()
309
+
310
+ except PermissionError:
311
+ console.print(Panel(
312
+ f"[bold red][✗] Permission Denied Accessing Central Memory[/]\n"
313
+ f"[yellow] Path:[/] {MEMORY_DIR}\n\n"
314
+ f"[white] Cause:[/] Sandboxed IDE terminal lacks access to host directory ~/.auto-context.\n"
315
+ f"[cyan] Fix:[/] Run 'init-context memory status' in your host terminal (PowerShell / Bash), or grant filesystem access.",
316
+ border_style="red",
317
+ ))
318
+ except OSError as err:
319
+ console.print(f" [yellow][!] Central memory status warning:[/] {err}")
320
+
@@ -29,6 +29,7 @@ app.add_typer(mcp.app, name="mcp", help="MCP tool registry management.")
29
29
  app.command("init")(init_cmd.init)
30
30
  app.command("rule")(init_cmd.new_rule)
31
31
  app.command("skill")(init_cmd.new_skill)
32
+ app.command("promote")(init_cmd.promote)
32
33
  app.command("share")(share.share)
33
34
  app.command("import")(import_cmd.import_item)
34
35
 
@@ -65,7 +66,7 @@ def root(
65
66
  try:
66
67
  v = pkg_version("auto-context")
67
68
  except Exception:
68
- v = "1.0.0"
69
+ v = "1.0.1"
69
70
  console.print(f"init-context v{v}")
70
71
  raise typer.Exit()
71
72
 
@@ -17,10 +17,12 @@ Whenever you learn a new pattern, receive a correction, observe a coding prefere
17
17
  1. **Identify the Type:**
18
18
  - **Rule:** If it is a constraint, coding standard, safety boundary, or architectural preference -> Create a Rule (`init-context -r <name>`).
19
19
  - **Skill:** If it is a multi-step procedure, deployment workflow, diagnosis runbook, or CLI sequence -> Create a Skill (`init-context -s <name>`).
20
- 2. **Scope Decision:**
21
- - **Project-Specific:** Save in `.agents/rules/` or `.agents/skills/`.
22
- - **Machine-Wide / Global:** If it applies to all projects, use `--global` (`-g`) to register in `~/.gemini/config/plugins/auto-context/`.
23
- 3. **Execution:**
20
+ 2. **Zero Token Waste:**
21
+ - **DO NOT burn tokens manually searching directories or reading files to check for existing rules.** Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
22
+ 3. **Mandatory Global Scope:**
23
+ - When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
24
+ - **Project-Specific:** Only omit `-g` if strictly confined to this specific project repository.
25
+ 4. **Execution:**
24
26
  - Use the `init-context` CLI tool to scaffold the file.
25
27
  - Populate it with clear objectives, constraints, or step-by-step instructions.
26
28
  - Inform the user of the new rule or skill codified.
@@ -30,6 +32,7 @@ You have native access to run `init-context` via terminal commands:
30
32
  - `init-context`: Scaffolds or repairs project context.
31
33
  - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
32
34
  - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
+ - `init-context memory push`: Synchronizes central brain memory to private Git repository.
33
36
 
34
37
  ### 4. Required Content & Structure in `context.md`
35
38
  1. **Master Credentials & Configuration Vault (Section 1):** Keep all ports, IPs, secrets, tokens, and endpoints synchronized.
@@ -17,10 +17,12 @@ Whenever you learn a new pattern, receive a correction, observe a coding prefere
17
17
  1. **Identify the Type:**
18
18
  - **Rule:** If it is a constraint, coding standard, safety boundary, or architectural preference -> Create a Rule (`init-context -r <name>`).
19
19
  - **Skill:** If it is a multi-step procedure, deployment workflow, diagnosis runbook, or CLI sequence -> Create a Skill (`init-context -s <name>`).
20
- 2. **Scope Decision:**
21
- - **Project-Specific:** Save in `.agents/rules/` or `.agents/skills/`.
22
- - **Machine-Wide / Global:** If it applies to all projects, use `--global` (`-g`) to register in `~/.gemini/config/plugins/auto-context/`.
23
- 3. **Execution:**
20
+ 2. **Zero Token Waste:**
21
+ - **DO NOT burn tokens manually searching directories or reading files to check for existing rules.** Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
22
+ 3. **Mandatory Global Scope:**
23
+ - When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
24
+ - **Project-Specific:** Only omit `-g` if strictly confined to this specific project repository.
25
+ 4. **Execution:**
24
26
  - Use the `init-context` CLI tool to scaffold the file.
25
27
  - Populate it with clear objectives, constraints, or step-by-step instructions.
26
28
  - Inform the user of the new rule or skill codified.
@@ -30,6 +32,7 @@ You have native access to run `init-context` via terminal commands:
30
32
  - `init-context`: Scaffolds or repairs project context.
31
33
  - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
32
34
  - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
+ - `init-context memory push`: Synchronizes central brain memory to private Git repository.
33
36
 
34
37
  ### 4. Required Content & Structure in `context.md`
35
38
  1. **Master Credentials & Configuration Vault (Section 1):** Keep all ports, IPs, secrets, tokens, and endpoints synchronized.
@@ -13,16 +13,16 @@ trigger: always_on
13
13
  - Architectural decisions or operational runbooks.
14
14
 
15
15
  2. **Autonomous Learning & Skill Crystallization**:
16
- - Whenever a new pattern, user preference, architectural guideline, or multi-step procedure is discovered or instructed:
17
- - Scaffolds a **Rule** (`init-context -r <name> [-g]`) if it is a constraint, coding standard, or guideline.
18
- - Scaffolds a **Skill** (`init-context -s <name> [-g]`) if it is a multi-step procedure or deployment runbook.
19
- - Populates the file with clear instructions and notifies the user.
16
+ - **Zero Token Waste:** DO NOT burn tokens manually searching directories or reading files to check for existing rules. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
17
+ - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
18
+ - Populates the file with clear instructions and notifies the user.
20
19
 
21
20
  3. **CLI Tool Availability**:
22
21
  - The agent has full access to run `init-context` directly via terminal:
23
22
  - `init-context`: Initialize/repair context.
24
23
  - `init-context -r <name> [-g]`: Create rule.
25
24
  - `init-context -s <name> [-g]`: Create skill.
25
+ - `init-context memory push`: Push updates to central memory.
26
26
 
27
27
  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.
28
28
 
@@ -1,236 +0,0 @@
1
- """
2
- commands/memory.py — Central memory brain management.
3
-
4
- Wraps git CLI via subprocess.run. Runs security.audit_path()
5
- before every commit or push — zero-bypass hard-block.
6
-
7
- Subcommands: init, push, pull, status
8
- """
9
- from __future__ import annotations
10
-
11
- import shutil
12
- import subprocess
13
- from datetime import datetime
14
- from pathlib import Path
15
- from typing import Annotated, Optional
16
-
17
- import typer
18
- from rich.console import Console
19
- from rich.panel import Panel
20
-
21
- from auto_context import config, security
22
-
23
- app = typer.Typer(help="Central memory brain management.")
24
- console = Console()
25
-
26
- MEMORY_DIR = config.MEMORY_DIR
27
-
28
- _GITIGNORE_ENTRIES = """\
29
- # Security: Prohibit credentials and environment files from central memory
30
- .env
31
- .env.*
32
- *.local.md
33
- context.local.md
34
- *.key
35
- *.pem
36
- *.p12
37
- *.pfx
38
- *.kdbx
39
- id_rsa*
40
- id_ed25519*
41
- id_ecdsa*
42
- id_dsa*
43
- authorized_keys
44
- known_hosts
45
- """
46
-
47
-
48
- def _git(cwd: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess:
49
- """Run a git command in *cwd*, capturing output."""
50
- return subprocess.run(
51
- ["git", "-C", str(cwd), *args],
52
- capture_output=True,
53
- text=True,
54
- check=check,
55
- )
56
-
57
-
58
- def _has_gh() -> bool:
59
- return shutil.which("gh") is not None
60
-
61
-
62
- # ── init ──────────────────────────────────────────────────────────────────────
63
-
64
- @app.command("init")
65
- def memory_init(
66
- repo_name: Annotated[str, typer.Argument(help="GitHub repo name.")] = "auto-context-memory",
67
- ) -> None:
68
- """Initialize a private central memory brain repository."""
69
- console.print(Panel(
70
- f"[bold green]🧠 Initializing Private Central Memory Brain[/]\n"
71
- f"[yellow] Directory:[/] {MEMORY_DIR}\n"
72
- f"[cyan] Repo: [/] {repo_name} (Strictly Private)",
73
- border_style="cyan",
74
- ))
75
-
76
- (MEMORY_DIR / "rules").mkdir(parents=True, exist_ok=True)
77
- (MEMORY_DIR / "skills").mkdir(parents=True, exist_ok=True)
78
-
79
- # Init git repo
80
- if not (MEMORY_DIR / ".git").exists():
81
- _git(MEMORY_DIR, "init")
82
- console.print(" [green][✓] Initialized Git repository[/]")
83
-
84
- # Hardened .gitignore
85
- (MEMORY_DIR / ".gitignore").write_text(_GITIGNORE_ENTRIES, encoding="utf-8")
86
- console.print(" [green][✓] Hardened .gitignore written[/]")
87
-
88
- # profile.md
89
- _write_profile(repo_name)
90
-
91
- # Security audit before first commit
92
- console.print(" [cyan][*] Running pre-commit security audit...[/]")
93
- violations = security.audit_path(MEMORY_DIR)
94
- security.abort_if_violations(violations)
95
-
96
- _git(MEMORY_DIR, "add", "-A", check=False)
97
- _git(MEMORY_DIR, "commit", "-m", config.GIT_COMMIT_INIT, check=False)
98
- _git(MEMORY_DIR, "branch", "-M", "main", check=False)
99
-
100
- if _has_gh():
101
- console.print(" [cyan][*] Creating strictly private GitHub repository via gh...[/]")
102
- result = subprocess.run(
103
- ["gh", "repo", "create", repo_name,
104
- "--private", f"--source={MEMORY_DIR}", "--remote=origin", "--push"],
105
- capture_output=True, text=True,
106
- )
107
- if result.returncode == 0:
108
- console.print(" [green][✓] Private GitHub memory repository created and pushed![/]")
109
- else:
110
- _print_manual_push(repo_name)
111
- else:
112
- console.print(" [yellow][!] GitHub CLI ('gh') not found. Install it or connect manually:[/]")
113
- _print_manual_push(repo_name)
114
-
115
- console.print(f"\n[bold green]🎉 Central Memory Initialized![/]")
116
- console.print(f" [yellow]Local Brain:[/] {MEMORY_DIR}")
117
- console.print(f" [green]Sync Command:[/] init-context memory push\n")
118
-
119
-
120
- def _print_manual_push(repo_name: str) -> None:
121
- console.print(f" [dim]git -C \"{MEMORY_DIR}\" remote add origin git@github.com:<username>/{repo_name}.git[/]")
122
- console.print(f" [dim]git -C \"{MEMORY_DIR}\" push -u origin main[/]")
123
-
124
-
125
- def _write_profile(repo_name: str) -> None:
126
- profile = MEMORY_DIR / "profile.md"
127
- if profile.exists():
128
- return
129
- import getpass
130
- username = getpass.getuser()
131
- date_now = datetime.now().strftime("%Y-%m-%d")
132
- profile.write_text(
133
- f"# Agent Memory & Developer Profile\n\n"
134
- f"> **Owner:** {username} \n"
135
- f"> **Initialized:** {date_now} \n"
136
- f"> **Repository:** {repo_name} \n"
137
- f"> **Visibility:** Private Central Agent Brain \n\n---\n\n"
138
- f"## 1. Developer Preferences\n- Edit this file to personalise agent behaviour.\n\n"
139
- f"## 2. Central Knowledge Base Index\n"
140
- f"- **Global Rules:** `rules/`\n"
141
- f"- **Reusable Skills:** `skills/`\n",
142
- encoding="utf-8",
143
- )
144
- console.print(" [green][✓] Generated Developer Profile: profile.md[/]")
145
-
146
-
147
- # ── push ──────────────────────────────────────────────────────────────────────
148
-
149
- @app.command("push")
150
- def memory_push() -> None:
151
- """Audit secrets and push memory brain to private GitHub repo."""
152
- console.print(Panel(
153
- "[bold green]🧠 Synchronizing Central Memory Brain[/]\n"
154
- f"[yellow] Location:[/] {MEMORY_DIR}",
155
- border_style="cyan",
156
- ))
157
-
158
- if not MEMORY_DIR.exists():
159
- console.print(f"[red][✗] Memory directory not found:[/] {MEMORY_DIR}")
160
- console.print(" Run: [cyan]init-context memory init[/]")
161
- raise typer.Exit(1)
162
-
163
- console.print(" [cyan][*] Running Zero-Bypass Security Auditor...[/]")
164
- violations = security.audit_path(MEMORY_DIR)
165
- security.abort_if_violations(violations)
166
-
167
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
168
- _git(MEMORY_DIR, "add", "-A", check=False)
169
- _git(MEMORY_DIR, "commit", "-m", f"{config.GIT_COMMIT_SYNC} [{timestamp}]", check=False)
170
-
171
- remote = _git(MEMORY_DIR, "remote", "get-url", "origin", check=False).stdout.strip()
172
- if remote:
173
- console.print(" [cyan][*] Pushing to private remote repository...[/]")
174
- result = _git(MEMORY_DIR, "push", "origin", "main", check=False)
175
- if result.returncode == 0:
176
- console.print(" [green][✓] Memory brain pushed successfully![/]")
177
- else:
178
- console.print(f" [red][✗] Push failed:[/] {result.stderr.strip()}")
179
- else:
180
- console.print(" [yellow][!] No remote 'origin' configured. Run memory init first.[/]")
181
-
182
- console.print("\n[bold green]✨ Memory synchronization complete![/]\n")
183
-
184
-
185
- # ── pull ──────────────────────────────────────────────────────────────────────
186
-
187
- @app.command("pull")
188
- def memory_pull(
189
- repo_url: Annotated[Optional[str], typer.Argument(help="Remote repo URL (required for first pull).")] = None,
190
- ) -> None:
191
- """Pull and sync the central memory brain from remote."""
192
- console.print(Panel(
193
- "[bold green]🧠 Pulling Central Memory Brain[/]",
194
- border_style="cyan",
195
- ))
196
-
197
- if not MEMORY_DIR.exists():
198
- if not repo_url:
199
- console.print("[red][✗] Memory directory not found. Provide a repo URL:[/]")
200
- console.print(" [cyan]init-context memory pull <url>[/]")
201
- raise typer.Exit(1)
202
- subprocess.run(["git", "clone", repo_url, str(MEMORY_DIR)], check=True)
203
- else:
204
- _git(MEMORY_DIR, "pull", "origin", "main")
205
-
206
- console.print(" [cyan][*] Running post-pull security audit...[/]")
207
- violations = security.audit_path(MEMORY_DIR)
208
- security.abort_if_violations(violations)
209
- console.print("\n[bold green]✨ Central memory updated successfully![/]\n")
210
-
211
-
212
- # ── status ────────────────────────────────────────────────────────────────────
213
-
214
- @app.command("status")
215
- def memory_status() -> None:
216
- """Show status of the central memory brain."""
217
- console.print(Panel(
218
- "[bold green]🧠 Central Memory Status[/]",
219
- border_style="cyan",
220
- ))
221
-
222
- if not MEMORY_DIR.exists():
223
- console.print(" [yellow][!] Central memory not initialized.[/]")
224
- console.print(" Run: [cyan]init-context memory init[/]")
225
- return
226
-
227
- remote = _git(MEMORY_DIR, "remote", "get-url", "origin", check=False).stdout.strip()
228
- rules_count = len(list((MEMORY_DIR / "rules").glob("*.md"))) if (MEMORY_DIR / "rules").exists() else 0
229
- skills_count = len([d for d in (MEMORY_DIR / "skills").iterdir() if d.is_dir()]) if (MEMORY_DIR / "skills").exists() else 0
230
-
231
- console.print(f" [yellow]Location:[/] {MEMORY_DIR}")
232
- console.print(f" [cyan]Remote: [/] {remote or '(none)'}")
233
- console.print(f" [green]Rules: [/] {rules_count} registered")
234
- console.print(f" [green]Skills: [/] {skills_count} registered")
235
- console.print()
236
-