tokensafe 1.1.1 → 1.2.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.
@@ -110,8 +110,29 @@ def main():
110
110
  print(json.dumps(response))
111
111
  return
112
112
 
113
- # Step 3B: If a specific symbol/function is targeted in user prompt, slice to it
113
+ # Step 3B: If a specific symbol/function is targeted in user prompt, check graph-guided skeleton first
114
114
  overwrite_args, metrics = ToolSlicer.optimize_read_file(args, context_hint=last_user_input)
115
+ target_sym = metrics.get("target_symbol")
116
+ if target_sym and path and os.path.exists(path):
117
+ skel_path, orig_t, skel_t = Skeletonizer.get_skeleton_file(path, target_symbol=target_sym)
118
+ if skel_path and orig_t > skel_t:
119
+ saved = orig_t - skel_t
120
+ response["overwrite"] = {"Path": skel_path}
121
+ response["reason"] = f"Token Optimizer: Graph-guided AST view for '{target_sym}' (Saved ~{saved} tokens)"
122
+ tracker.record_event(
123
+ session_id=conversation_id,
124
+ event_type="GRAPH_SKELETON",
125
+ original_tokens=orig_t,
126
+ optimized_tokens=skel_t,
127
+ details={
128
+ "target_file": os.path.basename(path),
129
+ "symbol": target_sym,
130
+ "saved_tokens": saved
131
+ }
132
+ )
133
+ print(json.dumps(response))
134
+ return
135
+
115
136
  if overwrite_args and metrics.get("saved_tokens", 0) > 0:
116
137
  response["overwrite"] = overwrite_args
117
138
  response["reason"] = (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokensafe",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Autonomous Zero-Loss Token Economy & Context Optimizer for AI Coding Agents",
5
5
  "main": "bin/tokensafe.js",
6
6
  "bin": {
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agy-token-optimizer",
3
3
  "displayName": "TokenSafe",
4
- "version": "1.1.1",
4
+ "version": "1.2.0",
5
5
  "description": "Zero-Loss Token Economy & Context Optimizer for AI Agents. Compresses prompts, slices AST/tool outputs, and prevents stuck loops.",
6
6
  "logo": "assets/logo.svg",
7
7
  "author": {
package/rules/AGENTS.md CHANGED
@@ -24,3 +24,8 @@ Execute the specified action directly based on these extracted parameters.
24
24
  2. **Surgical Code Edits**: Prefer `edit_file` with concise `Target` and `Replacement` over `write_file` on large existing files.
25
25
  3. **Diff-Centric Responses**: Never reprint entire unmodified files or long boilerplate blocks. Reference file lines instead (e.g., `wallet.ts#L42-L50`).
26
26
  4. **Dense Formatting**: Use compact bullet points and direct technical prose.
27
+
28
+ ### 3. Architecture & Code Navigation Directives (Graph-Guided)
29
+ 1. **Never Crawl with Raw Grep/Find**: Before executing exploratory searches or answering architecture questions, inspect `tokensafe:get_architecture_graph` or `tokensafe-out/API_SURFACE.md`. It provides project God Nodes and dependencies in < 250 tokens without file crawling.
30
+ 2. **Graph-Guided File Reading**: When inspecting code implementations, call `tokensafe:smart_read_file` with the targeted `symbol`. It preserves full executable bodies for the target function and its 1-hop callees while folding inert code into signatures (-85% to -92% tokens).
31
+ 3. **Bounded Reads**: Never call `read_file` without `StartLine`/`EndLine` on files > 100 lines unless inspecting a skeleton.
@@ -2,47 +2,85 @@
2
2
  name: token-optimizer
3
3
  description: >-
4
4
  Inspect token efficiency metrics, view cost savings dashboard, test prompt compression,
5
- and operate the Token-Optimized Communication Protocol (TOCP) in Antigravity.
5
+ navigate codebases via zero-token AST architecture graphs, and operate the Token-Optimized Communication Protocol (TOCP).
6
6
  ---
7
7
 
8
- # Token Optimizer Skill
8
+ # TokenSafe Optimization & Architecture Intelligence Skill
9
9
 
10
- This skill allows the agent to inspect token savings, query the metrics database,
11
- and report resource utilization efficiency.
10
+ This skill provides autonomous AI coding assistants with deterministic, zero-token AST architecture indexing, graph-guided code slicing, command sanitization, and context optimization metrics.
12
11
 
13
- ## Quick CLI Commands
12
+ ## When to Activate This Skill
13
+ 1. **Architecture Discovery**: Mapping new or unfamiliar codebases, finding God Nodes and key dependency hubs without LLM token burn.
14
+ 2. **Graph-Guided Code Inspection**: Reading functions or classes with their 1-hop dependencies while folding inert boilerplate (-85% to -92% tokens).
15
+ 3. **Telemetry & Economics**: Inspecting token savings, breakdown by optimization source, and ROI.
16
+ 4. **Command & Prompt Optimization**: Sanitizing terminal output and testing TOCP compression.
14
17
 
15
- Use the bundled `agy-tokens` CLI from this plugin directory:
18
+ ## Core MCP Tools (`tokensafe`)
16
19
 
17
- ```bash
18
- # Display visual terminal dashboard
19
- ./bin/agy-tokens stats
20
+ | MCP Tool | Purpose | Token Cost |
21
+ |---|---|---|
22
+ | `tokensafe:get_architecture_graph` | Analyzes AST topology, God Nodes, and hub centrality for `project_path`. | ~150-250 tokens |
23
+ | `tokensafe:get_api_surface` | Exports public signatures and types for the entire project. | ~300-600 tokens |
24
+ | `tokensafe:smart_read_file` | Reads `path` focusing on `symbol` + 1-hop dependencies; folds inert code into signatures. | -85% to -92% vs raw read |
25
+ | `tokensafe:sanitize_command` | Strips lockfiles, limits test/build output, and prevents context poisoning. | Saves 10k-50k tokens |
26
+ | `tokensafe:compress_prompt` | Compresses verbose user instructions into lean TOCP S-expressions. | -40% to -65% |
27
+ | `tokensafe:get_token_savings_metrics` | Returns total tokens saved, USD value, and breakdown by source. | ~100 tokens |
20
28
 
21
- # Test compression on a prompt and view savings
22
- ./bin/agy-tokens test "Слушай, перепиши функцию get_balance в wallet.ts, добавь redis cache"
29
+ ## Agent Graph-First Workflow
23
30
 
24
- # Export Markdown summary for artifacts or chat
25
- ./bin/agy-tokens markdown
31
+ ### 1. Zero-Token Architecture Survey
32
+ Before running recursive searches or reading multi-file structures, query the architecture graph:
33
+ ```json
34
+ {
35
+ "ServerName": "tokensafe",
36
+ "ToolName": "get_architecture_graph",
37
+ "Arguments": {
38
+ "project_path": "/absolute/path/to/project"
39
+ }
40
+ }
41
+ ```
42
+ * **Output**: Centrality scores, dependent counts, and identified God Nodes (e.g., `src/graph_engine.py (71 deps)`).
26
43
 
27
- # Reset metrics database
28
- ./bin/agy-tokens reset
44
+ ### 2. Graph-Guided Symbol Inspection
45
+ To read a targeted function or class without reading hundreds of lines of inert code:
46
+ ```json
47
+ {
48
+ "ServerName": "tokensafe",
49
+ "ToolName": "smart_read_file",
50
+ "Arguments": {
51
+ "path": "/absolute/path/to/file.py",
52
+ "symbol": "TargetClassName"
53
+ }
54
+ }
29
55
  ```
56
+ * **Output**: The target definition and its direct 1-hop callees are shown in full; all other classes/methods are folded into 1-line signatures.
30
57
 
31
- ## Programmatic Usage
58
+ ### 3. Command Sanitization
59
+ Before executing potentially verbose terminal commands (`git diff`, `git grep`, `pytest`, `find`):
60
+ ```json
61
+ {
62
+ "ServerName": "tokensafe",
63
+ "ToolName": "sanitize_command",
64
+ "Arguments": {
65
+ "command": "git diff HEAD~1"
66
+ }
67
+ }
68
+ ```
32
69
 
33
- To inspect current metrics programmatically:
70
+ ## CLI Usage
34
71
 
35
- ```python
36
- from src.metrics import MetricsTracker
37
- from src.dashboard import Dashboard
72
+ Developers and agents can run `tokensafe` (or `./bin/agy-tokens`) directly from the terminal:
38
73
 
39
- tracker = MetricsTracker()
40
- dashboard = Dashboard(tracker)
41
- print(dashboard.render_markdown())
42
- ```
74
+ ```bash
75
+ # View terminal breakdown & recent optimizations
76
+ tokensafe stats
77
+
78
+ # Open interactive Apple-style HTML dashboard in browser
79
+ tokensafe html
43
80
 
44
- ## How It Works Under the Hood
45
- 1. **PreInvocation Hook**: Intercepts verbose user prompts and generates a concise S-expression `(ACTION target symbol [traits] "intent")`, stripping politeness filler.
46
- 2. **PreToolUse Hook**: Prevents dumping 800+ lines into the context window by slicing `read_file` to relevant line ranges.
47
- 3. **Prompt Cache Anchor**: Static TOCP rules in `rules/AGENTS.md` hit Gemini's prompt cache with 100% stability.
48
- 4. **Persistent Metrics**: Every token saved is recorded in SQLite (`data/metrics.db`) with timestamp, percentage reduction, and estimated USD value.
81
+ # Run universal agent installer/synchronizer
82
+ tokensafe install
83
+
84
+ # Test prompt compression
85
+ tokensafe test "Refactor get_user_balance with redis caching"
86
+ ```
package/src/__init__.py CHANGED
@@ -2,5 +2,5 @@
2
2
  TokenSafe: Autonomous Zero-Loss Token Economy & Context Optimizer for AI Coding Agents.
3
3
  """
4
4
 
5
- __version__ = "1.1.1"
5
+ __version__ = "1.2.0"
6
6
  __author__ = "TokenSafe Team"
@@ -10,14 +10,17 @@ from typing import Tuple, Dict, Any, Optional
10
10
  class CommandSanitizer:
11
11
  """Optimizes terminal command lines to eliminate token waste."""
12
12
 
13
- # Lockfiles and binary patterns that should never be dumped in git diffs
13
+ # Lockfiles and binary patterns that should never be dumped in git diffs or searches
14
14
  LOCKFILE_EXCLUDES = [
15
15
  "':!package-lock.json'",
16
16
  "':!pnpm-lock.yaml'",
17
17
  "':!yarn.lock'",
18
+ "':!bun.lock'",
19
+ "':!bun.lockb'",
18
20
  "':!Cargo.lock'",
19
21
  "':!go.sum'",
20
22
  "':!composer.lock'",
23
+ "':!*.lock'",
21
24
  "':!*.min.js'",
22
25
  "':!*.min.css'",
23
26
  "':!*.bundle.js'",
@@ -80,11 +83,36 @@ class CommandSanitizer:
80
83
  est_saved = 1500
81
84
  return new_cmd, est_saved, "Pruned .git, node_modules, and venv from find"
82
85
 
83
- # 5. grep / ripgrep unbounded search
84
- if re.search(r"\b(grep|egrep)\b", cmd):
85
- if "--exclude-dir" not in cmd and "node_modules" not in cmd:
86
- new_cmd = f"{cmd} --exclude-dir={{dist,build,node_modules,.git,coverage,__pycache__,.next,data}}"
87
- if "|" not in new_cmd:
86
+ # 5. git grep search (Exclude lockfiles & directories via pathspecs)
87
+ if re.search(r"\bgit\b.*?\bgrep\b", cmd):
88
+ if ":!*.lock" not in cmd and ":!bun.lock" not in cmd:
89
+ git_excludes = "':!*.lock' ':!bun.lock' ':!bun.lockb' ':!package-lock.json' ':!dist' ':!build' ':!node_modules'"
90
+ stages = [s.strip() for s in re.split(r'(?<!\|)\|(?!\|)', cmd)]
91
+ for i, stage in enumerate(stages):
92
+ if re.search(r"\bgit\b.*?\bgrep\b", stage):
93
+ if " -- " in stage:
94
+ stages[i] = f"{stage} {git_excludes}"
95
+ else:
96
+ stages[i] = f"{stage} -- . {git_excludes}"
97
+ new_cmd = " | ".join(stages)
98
+ has_limiter = any(re.search(r'\b(head|tail|less)\b', s) for s in stages)
99
+ if not has_limiter:
100
+ new_cmd = f"{new_cmd} | head -n 30"
101
+ est_saved = 3500
102
+ return new_cmd, est_saved, "Excluded lockfiles from git grep and capped output"
103
+
104
+ # 6. grep / ripgrep unbounded search (only when recursive or scanning directory)
105
+ if re.search(r"\b(grep|egrep)\b", cmd) and not re.search(r"\bgit\b.*?\bgrep\b", cmd):
106
+ is_recursive = bool(re.search(r"\b(grep|egrep)\b.*?\s-[a-zA-Z]*[rR]", cmd))
107
+ if is_recursive and "--exclude-dir" not in cmd and "node_modules" not in cmd:
108
+ excludes = "--exclude='*.lock' --exclude='*.lockb' --exclude-dir={dist,build,node_modules,.git,coverage,__pycache__,.next,data}"
109
+ stages = [s.strip() for s in re.split(r'(?<!\|)\|(?!\|)', cmd)]
110
+ for i, stage in enumerate(stages):
111
+ if re.search(r"\b(grep|egrep)\b", stage):
112
+ stages[i] = f"{stage} {excludes}"
113
+ new_cmd = " | ".join(stages)
114
+ has_limiter = any(re.search(r'\b(head|tail|less)\b', s) for s in stages)
115
+ if not has_limiter:
88
116
  new_cmd = f"{new_cmd} | head -n 30"
89
117
  est_saved = 2500
90
118
  return new_cmd, est_saved, "Sanitized grep directories and capped output to 30 matches"
package/src/dashboard.py CHANGED
@@ -35,6 +35,8 @@ EVENT_NAMES = {
35
35
  "PROMPT": "Prompt Compactor (TOCP)",
36
36
  "TOOL_READ": "File Line Slicer (AST)",
37
37
  "AST_SKELETON": "AST Skeletonizer (Signatures)",
38
+ "GRAPH_SKELETON": "Graph-Guided Slicer (Call-Graph)",
39
+ "GRAPH_TOPOLOGY": "Architecture Graph (God Nodes)",
38
40
  "COMMAND_FILTER": "Command Sanitizer (CLI)",
39
41
  "OUTPUT_GUARD": "Output Token Guard (write_file)",
40
42
  "LOOP_GUARD": "Anti-Stuck Loop Guard",
package/src/installer.py CHANGED
@@ -57,6 +57,14 @@ AGENTS_REGISTRY = {
57
57
  "config_path": os.path.join(HOME, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
58
58
  "detect_path": os.path.join(HOME, "Library", "Application Support", "Code")
59
59
  },
60
+ "claude_code": {
61
+ "name": "Claude Code CLI",
62
+ "type": "claude_md",
63
+ "config_path": os.path.join(HOME, ".claude.json"),
64
+ "agents_md_path": os.path.join(HOME, ".claude", "CLAUDE.md"),
65
+ "skills_path": os.path.join(HOME, ".claude", "skills", "token-optimizer"),
66
+ "detect_path": os.path.join(HOME, ".claude")
67
+ },
60
68
  "codex": {
61
69
  "name": "OpenAI Codex",
62
70
  "type": "codex_toml",
@@ -66,12 +74,19 @@ AGENTS_REGISTRY = {
66
74
  "plugin_path": os.path.join(HOME, ".codex", "plugins", "tokensafe"),
67
75
  "detect_path": os.path.join(HOME, ".codex")
68
76
  },
77
+ "copilot": {
78
+ "name": "GitHub Copilot",
79
+ "type": "copilot_json",
80
+ "config_path": os.path.join(HOME, ".copilot", "mcp-config.json"),
81
+ "detect_path": os.path.join(HOME, ".copilot")
82
+ },
69
83
  "zcode": {
70
84
  "name": "Z.ai Code",
71
85
  "type": "zcode_json",
72
86
  "config_path": os.path.join(HOME, ".zcode", "cli", "config.json"),
73
87
  "skills_path": os.path.join(HOME, ".zcode", "skills", "token-optimizer"),
74
88
  "plugin_path": os.path.join(HOME, ".zcode", "cli", "plugins", "tokensafe"),
89
+ "agents_md_path": os.path.join(HOME, ".zcode", "AGENTS.md"),
75
90
  "detect_path": os.path.join(HOME, ".zcode")
76
91
  }
77
92
  }
@@ -144,15 +159,16 @@ class AgentInstaller:
144
159
  if "rules_path" in info:
145
160
  rule_text = (
146
161
  "---\n"
147
- "description: TokenSafe token economy and context optimization protocol\n"
162
+ "description: TokenSafe token economy, graph-first navigation and context optimization protocol\n"
148
163
  "globs: *\n"
149
164
  "alwaysApply: true\n"
150
165
  "---\n\n"
151
- "# TokenSafe Optimization Protocol\n"
152
- "Always prioritize `tokensafe` MCP tools (`smart_read_file`, `compress_prompt`, `sanitize_command`) "
153
- "over default raw file reads or high-output terminal executions to preserve context tokens and prevent context overflow.\n"
154
- "- When inspecting code files, use `smart_read_file` with `symbol` or line range.\n"
155
- "- Sanitize verbose commands (`git diff`, `pytest`, `find`, `grep`) via `sanitize_command`.\n"
166
+ "# TokenSafe Graph-First Optimization Protocol\n"
167
+ "Always prioritize `tokensafe` MCP tools over default raw file reads or high-output terminal executions to prevent context window exhaustion.\n\n"
168
+ "1. **Architecture Discovery**: Always call `tokensafe:get_architecture_graph` before grep or multi-file reading. Returns project God Nodes and key dependency hubs in < 250 tokens without file crawling.\n"
169
+ "2. **Graph-Guided Symbol Inspection**: When inspecting code implementations, prioritize `tokensafe:smart_read_file` with the targeted `symbol`. Returns full executable bodies for the symbol and 1-hop dependencies while folding inert code into signatures (-85% to -92% tokens).\n"
170
+ "3. **No Unconstrained Shell Grep/Find**: Strictly avoid running raw recursive grep/find across projects. Use `get_architecture_graph` or `get_api_surface`.\n"
171
+ "4. **Command Sanitization**: Use `sanitize_command` on high-output terminal commands (`git diff`, `pytest`, `find`, `grep`) to prevent lockfile or test log context contamination.\n"
156
172
  )
157
173
  cls._write_file_safely(info["rules_path"], rule_text)
158
174
 
@@ -229,16 +245,74 @@ class AgentInstaller:
229
245
 
230
246
  if "agents_md_path" in info:
231
247
  codex_rule = (
232
- "## TOKENSAFE TOKEN OPTIMIZATION PROTOCOL\n"
233
- "Always prioritize `tokensafe` MCP tools (`smart_read_file`, `compress_prompt`, `sanitize_command`) "
234
- "over default raw file reads or high-token shell executions to preserve context tokens and prevent context overflow.\n"
235
- "- When inspecting code files, use `smart_read_file` with `symbol` or line range.\n"
236
- "- When running verbose commands (`git diff`, `pytest`, `find`, `grep`), sanitize them with `sanitize_command`.\n"
248
+ "## TOKENSAFE GRAPH-FIRST OPTIMIZATION PROTOCOL\n"
249
+ "Always prioritize `tokensafe` MCP tools over default raw file reads or high-output terminal executions to prevent context window exhaustion.\n"
250
+ "1. **Architecture Discovery**: Always call `tokensafe:get_architecture_graph` before grep or multi-file reading. Returns project God Nodes and key dependency hubs in < 250 tokens without file crawling.\n"
251
+ "2. **Graph-Guided Symbol Inspection**: When inspecting code implementations, prioritize `tokensafe:smart_read_file` with the targeted `symbol`. Returns full executable bodies for the symbol and 1-hop dependencies while folding inert code into signatures (-85% to -92% tokens).\n"
252
+ "3. **No Unconstrained Shell Grep/Find**: Strictly avoid running raw recursive grep/find across projects. Use `get_architecture_graph` or `get_api_surface`.\n"
253
+ "4. **Command Sanitization**: Use `sanitize_command` on high-output terminal commands (`git diff`, `pytest`, `find`, `grep`) to prevent lockfile or test log context contamination.\n"
237
254
  )
238
255
  cls._inject_global_rule(info["agents_md_path"], codex_rule)
239
256
 
240
257
  return True, f"Configured MCP, Plugin, Skill & AGENTS.md in {config_file}"
241
258
 
259
+ elif info["type"] == "claude_md":
260
+ if "config_path" in info:
261
+ config_file = info["config_path"]
262
+ data = {}
263
+ if os.path.exists(config_file):
264
+ try:
265
+ with open(config_file, "r", encoding="utf-8") as f:
266
+ data = json.load(f)
267
+ except Exception:
268
+ data = {}
269
+ if "mcpServers" not in data or not isinstance(data["mcpServers"], dict):
270
+ data["mcpServers"] = {}
271
+ data["mcpServers"]["tokensafe"] = {
272
+ "command": PYTHON_BIN,
273
+ "args": [MCP_SERVER_PATH]
274
+ }
275
+ with open(config_file, "w", encoding="utf-8") as f:
276
+ json.dump(data, f, indent=2)
277
+
278
+ if "agents_md_path" in info:
279
+ claude_rule = (
280
+ "## TOKENSAFE GRAPH-FIRST OPTIMIZATION PROTOCOL\n"
281
+ "Always prioritize `tokensafe` MCP tools over default raw file reads or recursive grep/find.\n"
282
+ "1. **Architecture Discovery**: Always call `tokensafe:get_architecture_graph` before grep or multi-file reading. Returns project God Nodes and key dependency hubs in < 250 tokens without file crawling.\n"
283
+ "2. **Graph-Guided Symbol Inspection**: When inspecting code implementations, prioritize `tokensafe:smart_read_file` with the targeted `symbol`. Returns full executable bodies for the symbol and 1-hop dependencies while folding inert code into signatures (-85% to -92% tokens).\n"
284
+ "3. **No Unconstrained Shell Grep/Find**: Strictly avoid running raw recursive grep/find across projects. Use `get_architecture_graph` or `get_api_surface`.\n"
285
+ "4. **Command Sanitization**: Use `sanitize_command` on high-output terminal commands (`git diff`, `pytest`, `find`, `grep`) to prevent lockfile or test log context contamination.\n"
286
+ )
287
+ cls._inject_global_rule(info["agents_md_path"], claude_rule)
288
+
289
+ if "skills_path" in info:
290
+ cls._symlink_skill(info["skills_path"])
291
+
292
+ return True, f"Configured MCP, Rule & Skill in {info.get('agents_md_path')}"
293
+
294
+ elif info["type"] == "copilot_json":
295
+ config_file = info["config_path"]
296
+ os.makedirs(os.path.dirname(config_file), exist_ok=True)
297
+ data = {}
298
+ if os.path.exists(config_file):
299
+ try:
300
+ with open(config_file, "r", encoding="utf-8") as f:
301
+ data = json.load(f)
302
+ except Exception:
303
+ data = {}
304
+ if "mcpServers" not in data or not isinstance(data["mcpServers"], dict):
305
+ data["mcpServers"] = {}
306
+ data["mcpServers"]["tokensafe"] = {
307
+ "type": "stdio",
308
+ "command": PYTHON_BIN,
309
+ "args": [MCP_SERVER_PATH],
310
+ "tools": ["*"]
311
+ }
312
+ with open(config_file, "w", encoding="utf-8") as f:
313
+ json.dump(data, f, indent=2)
314
+ return True, f"Configured MCP for GitHub Copilot in {config_file}"
315
+
242
316
  elif info["type"] == "zcode_json":
243
317
  config_file = info["config_path"]
244
318
  os.makedirs(os.path.dirname(config_file), exist_ok=True)
@@ -271,7 +345,18 @@ class AgentInstaller:
271
345
  if "plugin_path" in info:
272
346
  cls._symlink_dir(PROJECT_ROOT, info["plugin_path"])
273
347
 
274
- return True, f"Configured MCP, Plugin & Skill in {config_file}"
348
+ if "agents_md_path" in info:
349
+ zcode_rule = (
350
+ "## TOKENSAFE GRAPH-FIRST OPTIMIZATION PROTOCOL\n"
351
+ "Always prioritize `tokensafe` MCP tools over default raw file reads or high-output terminal executions to prevent context window exhaustion.\n"
352
+ "1. **Architecture Discovery**: Always call `tokensafe:get_architecture_graph` before grep or multi-file reading. Returns project God Nodes and key dependency hubs in < 250 tokens without file crawling.\n"
353
+ "2. **Graph-Guided Symbol Inspection**: When inspecting code implementations, prioritize `tokensafe:smart_read_file` with the targeted `symbol`. Returns full executable bodies for the symbol and 1-hop dependencies while folding inert code into signatures (-85% to -92% tokens).\n"
354
+ "3. **No Unconstrained Shell Grep/Find**: Strictly avoid running raw recursive grep/find across projects. Use `get_architecture_graph` or `get_api_surface`.\n"
355
+ "4. **Command Sanitization**: Use `sanitize_command` on high-output terminal commands (`git diff`, `pytest`, `find`, `grep`) to prevent lockfile or test log context contamination.\n"
356
+ )
357
+ cls._inject_global_rule(info["agents_md_path"], zcode_rule)
358
+
359
+ return True, f"Configured MCP, Plugin, Skill & AGENTS.md in {config_file}"
275
360
 
276
361
  return False, "Unsupported type"
277
362
 
package/src/mailer.py ADDED
@@ -0,0 +1,327 @@
1
+ """
2
+ TokenSafe Transactional Email Service.
3
+ Handles transactional emails via ImprovMX SMTP (port 587 TLS)
4
+ with beautiful responsive dark-mode HTML templates and asynchronous delivery.
5
+ """
6
+
7
+ import os
8
+ import ssl
9
+ import smtplib
10
+ import threading
11
+ from email.mime.multipart import MIMEMultipart
12
+ from email.mime.text import MIMEText
13
+ from typing import Optional, Dict, Any
14
+
15
+ class TokenSafeMailer:
16
+ """Dispatches transactional notifications (Welcome, Team Seat Invites)."""
17
+
18
+ SMTP_HOST = os.environ.get("SMTP_HOST", "smtp.improvmx.com")
19
+ SMTP_PORT = int(os.environ.get("SMTP_PORT", "587"))
20
+ SMTP_USER = os.environ.get("SMTP_USER", "any-alias-1@tokensafe.dev")
21
+ SMTP_PASS = os.environ.get("SMTP_PASS", "g7Qw8nB1U1Q9")
22
+ SMTP_FROM = os.environ.get("SMTP_FROM", "TokenSafe <support@tokensafe.dev>")
23
+ SMTP_TIMEOUT = 10
24
+
25
+ @classmethod
26
+ def _send_raw(cls, recipient: str, subject: str, text_content: str, html_content: str) -> bool:
27
+ """Sends an email synchronously via SMTP with STARTTLS."""
28
+ msg = MIMEMultipart("alternative")
29
+ msg["Subject"] = subject
30
+ msg["From"] = cls.SMTP_FROM
31
+ msg["To"] = recipient
32
+
33
+ # Attach plain text and HTML alternatives
34
+ msg.attach(MIMEText(text_content, "plain", "utf-8"))
35
+ msg.attach(MIMEText(html_content, "html", "utf-8"))
36
+
37
+ try:
38
+ server = smtplib.SMTP(cls.SMTP_HOST, cls.SMTP_PORT, timeout=cls.SMTP_TIMEOUT)
39
+ server.ehlo()
40
+ context = ssl.create_default_context()
41
+ server.starttls(context=context)
42
+ server.ehlo()
43
+ server.login(cls.SMTP_USER, cls.SMTP_PASS)
44
+ server.sendmail(cls.SMTP_USER, [recipient], msg.as_string())
45
+ server.quit()
46
+ return True
47
+ except Exception as e:
48
+ # Log error in production
49
+ print(f"[Mailer Error] Failed to send email to {recipient}: {e}")
50
+ return False
51
+
52
+ @classmethod
53
+ def send_async(cls, recipient: str, subject: str, text_content: str, html_content: str):
54
+ """Dispatches email sending in a non-blocking background daemon thread."""
55
+ thread = threading.Thread(
56
+ target=cls._send_raw,
57
+ args=(recipient, subject, text_content, html_content),
58
+ daemon=True
59
+ )
60
+ thread.start()
61
+
62
+ @classmethod
63
+ def send_welcome_email(cls, recipient: str, license_key: str, tier: str = "solo", is_trial: bool = True):
64
+ """Sends welcome email with license key and 1-click onboarding instructions."""
65
+ plan_name = "Solo Developer (7-Day Trial)" if tier == "solo" else "Engineering Team (7-Day Trial)"
66
+ subject = f"Welcome to TokenSafe — Your {plan_name} License Key"
67
+
68
+ text_content = f"""Welcome to TokenSafe!
69
+
70
+ Your {plan_name} has been activated.
71
+
72
+ Your License Key:
73
+ {license_key}
74
+
75
+ Quick Setup (1 command):
76
+ npx tokensafe
77
+
78
+ Or connect existing tools:
79
+ tokensafe auth {license_key}
80
+
81
+ Open your cloud dashboard:
82
+ https://tokensafe.dev/dashboard
83
+
84
+ If you need any assistance, simply reply to this email.
85
+ — The TokenSafe Team
86
+ https://tokensafe.dev
87
+ """
88
+
89
+ html_content = f"""<!DOCTYPE html>
90
+ <html>
91
+ <head>
92
+ <meta charset="utf-8">
93
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
94
+ <title>{subject}</title>
95
+ </head>
96
+ <body style="margin: 0; padding: 0; background-color: #030712; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #f3f4f6;">
97
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="background-color: #030712; padding: 40px 20px;">
98
+ <tr>
99
+ <td align="center">
100
+ <table role="presentation" width="100%" style="max-width: 580px; background-color: #0f172a; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 16px; padding: 36px; box-shadow: 0 20px 40px rgba(0,0,0,0.4);">
101
+
102
+ <!-- Logo / Header -->
103
+ <tr>
104
+ <td style="padding-bottom: 24px; border-bottom: 1px solid rgba(255, 255, 255, 0.06);">
105
+ <span style="font-size: 20px; font-weight: 800; color: #ffffff; letter-spacing: -0.5px;">
106
+ Token<span style="color: #10b981;">Safe</span>
107
+ </span>
108
+ <span style="float: right; font-size: 11px; font-weight: 700; color: #10b981; background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.2); padding: 4px 10px; border-radius: 999px; text-transform: uppercase;">
109
+ {tier.upper()} ACTIVE
110
+ </span>
111
+ </td>
112
+ </tr>
113
+
114
+ <!-- Title -->
115
+ <tr>
116
+ <td style="padding-top: 28px; padding-bottom: 12px;">
117
+ <h1 style="margin: 0; font-size: 22px; font-weight: 700; color: #ffffff; line-height: 1.3;">
118
+ Welcome to Autonomous Token Economy
119
+ </h1>
120
+ <p style="margin: 8px 0 0; font-size: 14px; color: #94a3b8; line-height: 1.6;">
121
+ Your plan <strong style="color: #f1f5f9;">{plan_name}</strong> is ready. Your agents will now compress context, eliminate stuck loops, and protect token budgets.
122
+ </p>
123
+ </td>
124
+ </tr>
125
+
126
+ <!-- License Key Box -->
127
+ <tr>
128
+ <td style="padding: 20px 0;">
129
+ <div style="background-color: #020617; border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 12px; padding: 18px; text-align: center;">
130
+ <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; color: #94a3b8; letter-spacing: 0.5px; margin-bottom: 8px;">
131
+ Your Cryptographic License Key
132
+ </div>
133
+ <div style="font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 15px; font-weight: 700; color: #34d399; letter-spacing: 0.5px; word-break: break-all;">
134
+ {license_key}
135
+ </div>
136
+ </div>
137
+ </td>
138
+ </tr>
139
+
140
+ <!-- Quick Setup Steps -->
141
+ <tr>
142
+ <td style="padding-bottom: 24px;">
143
+ <h3 style="font-size: 14px; font-weight: 600; color: #e2e8f0; margin: 0 0 12px;">
144
+ 🚀 Quick Start (Instant Installation)
145
+ </h3>
146
+
147
+ <!-- Command 1 -->
148
+ <div style="background-color: #020617; border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; padding: 12px 16px; margin-bottom: 10px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; color: #f8fafc;">
149
+ <span style="color: #10b981;">$</span> npx tokensafe
150
+ </div>
151
+
152
+ <!-- Command 2 -->
153
+ <div style="background-color: #020617; border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; padding: 12px 16px; margin-bottom: 16px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; color: #f8fafc;">
154
+ <span style="color: #10b981;">$</span> tokensafe auth {license_key}
155
+ </div>
156
+
157
+ <p style="margin: 0; font-size: 13px; color: #94a3b8; line-height: 1.5;">
158
+ Or install via Python PyPI: <code style="color: #38bdf8; background: rgba(56, 189, 248, 0.1); padding: 2px 6px; border-radius: 4px;">pip install tokensafe</code>. Compatible with Cursor, Claude Desktop, Antigravity, and Codex.
159
+ </p>
160
+ </td>
161
+ </tr>
162
+
163
+ <!-- CTA Button -->
164
+ <tr>
165
+ <td align="center" style="padding: 16px 0 28px;">
166
+ <a href="https://tokensafe.dev/dashboard?key={license_key}" style="display: inline-block; background-color: #10b981; color: #020617; font-size: 14px; font-weight: 700; text-decoration: none; padding: 14px 32px; border-radius: 10px; box-shadow: 0 8px 16px rgba(16, 185, 129, 0.2);">
167
+ Open Cloud Analytics Dashboard →
168
+ </a>
169
+ </td>
170
+ </tr>
171
+
172
+ <!-- Footer -->
173
+ <tr>
174
+ <td style="border-top: 1px solid rgba(255, 255, 255, 0.06); padding-top: 20px; font-size: 12px; color: #64748b; line-height: 1.5;">
175
+ Need help or custom integrations? Just reply to this email or reach us at <a href="mailto:support@tokensafe.dev" style="color: #10b981; text-decoration: none;">support@tokensafe.dev</a>.<br>
176
+ © 2026 TokenSafe. Autonomous Zero-Loss Token Economy.
177
+ </td>
178
+ </tr>
179
+
180
+ </table>
181
+ </td>
182
+ </tr>
183
+ </table>
184
+ </body>
185
+ </html>
186
+ """
187
+ cls.send_async(recipient, subject, text_content, html_content)
188
+
189
+ @classmethod
190
+ def send_team_invite_email(cls, recipient: str, seat_license_key: str, owner_email: str):
191
+ """Sends team member onboarding email with instructions on connecting IDEs."""
192
+ subject = f"Your TokenSafe Team Seat License — Invited by {owner_email}"
193
+
194
+ text_content = f"""Hi there!
195
+
196
+ Your team lead ({owner_email}) has granted you a TokenSafe Team developer seat.
197
+
198
+ Your Personal Seat Key:
199
+ {seat_license_key}
200
+
201
+ Setup Guide:
202
+ 1. Run the instant setup:
203
+ npx tokensafe
204
+
205
+ 2. Connect your personal seat license:
206
+ tokensafe auth {seat_license_key}
207
+
208
+ 3. IDE Integrations:
209
+ - Cursor: Extension is activated automatically.
210
+ - Claude Desktop: MCP server is configured in ~/Library/Application Support/Claude/claude_desktop_config.json.
211
+ - Terminal: Run 'tokensafe stats' anytime to see your saved context and tokens.
212
+
213
+ Track your developer economics:
214
+ https://tokensafe.dev/dashboard
215
+
216
+ If you have any questions, contact your team lead ({owner_email}) or reply to this email.
217
+ — The TokenSafe Team
218
+ """
219
+
220
+ html_content = f"""<!DOCTYPE html>
221
+ <html>
222
+ <head>
223
+ <meta charset="utf-8">
224
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
225
+ <title>{subject}</title>
226
+ </head>
227
+ <body style="margin: 0; padding: 0; background-color: #030712; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #f3f4f6;">
228
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="background-color: #030712; padding: 40px 20px;">
229
+ <tr>
230
+ <td align="center">
231
+ <table role="presentation" width="100%" style="max-width: 580px; background-color: #0f172a; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 16px; padding: 36px; box-shadow: 0 20px 40px rgba(0,0,0,0.4);">
232
+
233
+ <!-- Logo / Header -->
234
+ <tr>
235
+ <td style="padding-bottom: 24px; border-bottom: 1px solid rgba(255, 255, 255, 0.06);">
236
+ <span style="font-size: 20px; font-weight: 800; color: #ffffff; letter-spacing: -0.5px;">
237
+ Token<span style="color: #10b981;">Safe</span>
238
+ </span>
239
+ <span style="float: right; font-size: 11px; font-weight: 700; color: #38bdf8; background: rgba(56, 189, 248, 0.1); border: 1px solid rgba(56, 189, 248, 0.2); padding: 4px 10px; border-radius: 999px; text-transform: uppercase;">
240
+ TEAM SEAT INVITE
241
+ </span>
242
+ </td>
243
+ </tr>
244
+
245
+ <!-- Title -->
246
+ <tr>
247
+ <td style="padding-top: 28px; padding-bottom: 12px;">
248
+ <h1 style="margin: 0; font-size: 22px; font-weight: 700; color: #ffffff; line-height: 1.3;">
249
+ You've been added to TokenSafe Team
250
+ </h1>
251
+ <p style="margin: 8px 0 0; font-size: 14px; color: #94a3b8; line-height: 1.6;">
252
+ Team lead <strong style="color: #38bdf8;">{owner_email}</strong> has provisioned a dedicated TokenSafe developer seat for you. Context compression and token guards are now active for your workflow.
253
+ </p>
254
+ </td>
255
+ </tr>
256
+
257
+ <!-- License Key Box -->
258
+ <tr>
259
+ <td style="padding: 20px 0;">
260
+ <div style="background-color: #020617; border: 1px solid rgba(56, 189, 248, 0.3); border-radius: 12px; padding: 18px; text-align: center;">
261
+ <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; color: #94a3b8; letter-spacing: 0.5px; margin-bottom: 8px;">
262
+ Your Dedicated Team Seat Key
263
+ </div>
264
+ <div style="font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 15px; font-weight: 700; color: #38bdf8; letter-spacing: 0.5px; word-break: break-all;">
265
+ {seat_license_key}
266
+ </div>
267
+ </div>
268
+ </td>
269
+ </tr>
270
+
271
+ <!-- Setup Instructions -->
272
+ <tr>
273
+ <td style="padding-bottom: 24px;">
274
+ <h3 style="font-size: 14px; font-weight: 600; color: #e2e8f0; margin: 0 0 12px;">
275
+ ⚙️ Quick 3-Step Setup
276
+ </h3>
277
+
278
+ <div style="margin-bottom: 16px;">
279
+ <div style="font-size: 12px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Step 1: Install TokenSafe CLI</div>
280
+ <div style="background-color: #020617; border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; padding: 10px 14px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; color: #f8fafc;">
281
+ <span style="color: #10b981;">$</span> npx tokensafe
282
+ </div>
283
+ </div>
284
+
285
+ <div style="margin-bottom: 16px;">
286
+ <div style="font-size: 12px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Step 2: Bind your seat license</div>
287
+ <div style="background-color: #020617; border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; padding: 10px 14px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; color: #f8fafc;">
288
+ <span style="color: #10b981;">$</span> tokensafe auth {seat_license_key}
289
+ </div>
290
+ </div>
291
+
292
+ <div style="margin-bottom: 16px;">
293
+ <div style="font-size: 12px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Step 3: IDE Agents Automatic Hook</div>
294
+ <ul style="margin: 6px 0 0 18px; padding: 0; font-size: 13px; color: #94a3b8; line-height: 1.6;">
295
+ <li><strong>Cursor / VSCode:</strong> Hooks directly into extension background loop.</li>
296
+ <li><strong>Claude Desktop:</strong> MCP server runs at <code style="color: #34d399;">tokensafe-mcp</code>.</li>
297
+ <li><strong>Terminal:</strong> Check your stats with <code style="color: #38bdf8;">tokensafe stats</code>.</li>
298
+ </ul>
299
+ </div>
300
+ </td>
301
+ </tr>
302
+
303
+ <!-- CTA Button -->
304
+ <tr>
305
+ <td align="center" style="padding: 16px 0 28px;">
306
+ <a href="https://tokensafe.dev/dashboard?key={seat_license_key}" style="display: inline-block; background-color: #0284c7; color: #ffffff; font-size: 14px; font-weight: 700; text-decoration: none; padding: 14px 32px; border-radius: 10px; box-shadow: 0 8px 16px rgba(2, 132, 199, 0.25);">
307
+ View Your Developer Portal →
308
+ </a>
309
+ </td>
310
+ </tr>
311
+
312
+ <!-- Footer -->
313
+ <tr>
314
+ <td style="border-top: 1px solid rgba(255, 255, 255, 0.06); padding-top: 20px; font-size: 12px; color: #64748b; line-height: 1.5;">
315
+ Invited by {owner_email}. Have questions? Contact your team lead or reach us at <a href="mailto:support@tokensafe.dev" style="color: #38bdf8; text-decoration: none;">support@tokensafe.dev</a>.<br>
316
+ © 2026 TokenSafe. Autonomous Zero-Loss Token Economy.
317
+ </td>
318
+ </tr>
319
+
320
+ </table>
321
+ </td>
322
+ </tr>
323
+ </table>
324
+ </body>
325
+ </html>
326
+ """
327
+ cls.send_async(recipient, subject, text_content, html_content)
package/src/mcp_server.py CHANGED
@@ -22,10 +22,11 @@ from src.loop_detector import LoopDetector
22
22
  from src.metrics import MetricsTracker
23
23
  from src.dashboard import Dashboard
24
24
  from src.graph_engine import GraphEngine
25
+ from src.tokenizer import count_tokens
25
26
 
26
27
  SERVER_INFO = {
27
28
  "name": "tokensafe-mcp",
28
- "version": "1.1.1"
29
+ "version": "1.2.0"
29
30
  }
30
31
 
31
32
  TOOLS = [
@@ -127,6 +128,18 @@ def handle_tool_call(name: str, args: dict) -> dict:
127
128
  graph, rel_path = GraphEngine.for_file(path)
128
129
  graph_skel = graph.graph_guided_skeletonize(path, target_symbol=symbol)
129
130
  if graph_skel:
131
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
132
+ raw_code = f.read()
133
+ orig_t = count_tokens(raw_code)
134
+ skel_t = count_tokens(graph_skel)
135
+ saved = max(0, orig_t - skel_t)
136
+ tracker.record_event(
137
+ session_id="mcp_session",
138
+ event_type="GRAPH_SKELETON",
139
+ original_tokens=orig_t,
140
+ optimized_tokens=skel_t,
141
+ details={"file": os.path.basename(path), "symbol": symbol, "saved_tokens": saved}
142
+ )
130
143
  header = f"// [TokenSafe Graph-Guided Skeleton for '{symbol}' | Full body + 1-hop dependencies]\n"
131
144
  return {"content": [{"type": "text", "text": (prefetch_block or "") + header + graph_skel}]}
132
145
  except Exception:
@@ -186,12 +199,30 @@ def handle_tool_call(name: str, args: dict) -> dict:
186
199
  "total_symbols": len(graph.symbols),
187
200
  "god_nodes": god_nodes
188
201
  }
202
+ est_crawl_tokens = max(5000, len(graph.file_symbols) * 800)
203
+ topo_tokens = 250
204
+ tracker.record_event(
205
+ session_id="mcp_session",
206
+ event_type="GRAPH_TOPOLOGY",
207
+ original_tokens=est_crawl_tokens,
208
+ optimized_tokens=topo_tokens,
209
+ details={"hubs_count": len(god_nodes), "indexed_files": len(graph.file_symbols)}
210
+ )
189
211
  return {"content": [{"type": "text", "text": json.dumps(payload, indent=2, ensure_ascii=False)}]}
190
212
 
191
213
  elif name == "get_api_surface":
192
214
  target = args.get("project_path") or os.getcwd()
193
215
  graph = GraphEngine.get_instance(target)
194
216
  surface_md = graph.generate_api_surface()
217
+ surface_tokens = count_tokens(surface_md)
218
+ est_orig_tokens = max(10000, len(graph.file_symbols) * 1200)
219
+ tracker.record_event(
220
+ session_id="mcp_session",
221
+ event_type="GRAPH_TOPOLOGY",
222
+ original_tokens=est_orig_tokens,
223
+ optimized_tokens=surface_tokens,
224
+ details={"type": "API_SURFACE", "symbols_count": len(graph.symbols)}
225
+ )
195
226
  return {"content": [{"type": "text", "text": surface_md}]}
196
227
 
197
228
  return {"isError": True, "content": [{"type": "text", "text": f"Unknown tool: {name}"}]}
@@ -77,9 +77,10 @@ class Skeletonizer:
77
77
  return "\n".join(out)
78
78
 
79
79
  @classmethod
80
- def get_skeleton_file(cls, original_path: str) -> Tuple[Optional[str], int, int]:
80
+ def get_skeleton_file(cls, original_path: str, target_symbol: Optional[str] = None) -> Tuple[Optional[str], int, int]:
81
81
  """
82
82
  Reads original_path, checks mtime cache, generates skeleton if modified or absent.
83
+ If target_symbol is provided, applies Graph-Guided AST skeletonization retaining 1-hop dependencies.
83
84
  Returns: (skeleton_path_or_none, orig_tokens, skeleton_tokens)
84
85
  """
85
86
  if not original_path or not os.path.exists(original_path):
@@ -95,9 +96,10 @@ class Skeletonizer:
95
96
  os.makedirs(cls.CACHE_DIR, exist_ok=True)
96
97
  path_hash = hashlib.md5(original_path.encode("utf-8")).hexdigest()[:8]
97
98
  base_name = os.path.basename(original_path)
98
- skeleton_filename = f"{path_hash}_{base_name}"
99
+ sym_suffix = f"_{target_symbol}" if target_symbol else ""
100
+ skeleton_filename = f"{path_hash}{sym_suffix}_{base_name}"
99
101
  skeleton_path = os.path.join(cls.CACHE_DIR, skeleton_filename)
100
- meta_path = os.path.join(cls.CACHE_DIR, f"{path_hash}_{base_name}.meta.json")
102
+ meta_path = os.path.join(cls.CACHE_DIR, f"{path_hash}{sym_suffix}_{base_name}.meta.json")
101
103
 
102
104
  # 1. Check incremental mtime cache
103
105
  if os.path.exists(skeleton_path) and os.path.exists(meta_path):
@@ -122,7 +124,18 @@ class Skeletonizer:
122
124
  return None, 0, 0
123
125
 
124
126
  ext = os.path.splitext(original_path)[1]
125
- skeleton_content = cls.skeletonize_code(code, ext)
127
+
128
+ # If target symbol specified, use Graph-Guided skeletonization
129
+ if target_symbol:
130
+ try:
131
+ from src.graph_engine import GraphEngine
132
+ graph, rel_path = GraphEngine.for_file(original_path)
133
+ graph_content = graph.graph_guided_skeletonize(original_path, target_symbol=target_symbol)
134
+ skeleton_content = graph_content if graph_content else cls.skeletonize_code(code, ext)
135
+ except Exception:
136
+ skeleton_content = cls.skeletonize_code(code, ext)
137
+ else:
138
+ skeleton_content = cls.skeletonize_code(code, ext)
126
139
 
127
140
  # Prefetch local dependency signatures
128
141
  from src.dependency_prefetcher import DependencyPrefetcher
@@ -134,13 +147,20 @@ class Skeletonizer:
134
147
  if skel_tokens >= orig_tokens * 0.7:
135
148
  return None, 0, 0
136
149
 
137
- header_comment = (
138
- f"// [TOCP AST Skeleton: {lines_count} lines folded into API signatures]\n"
139
- f"// [To inspect implementation of a specific method, call read_file with StartLine/EndLine]\n\n"
140
- ) if ext != ".py" else (
141
- f"# [TOCP AST Skeleton: {lines_count} lines folded into API signatures]\n"
142
- f"# [To inspect implementation of a specific method, call read_file with StartLine/EndLine]\n\n"
143
- )
150
+ if target_symbol:
151
+ header_comment = (
152
+ f"// [TokenSafe Graph-Guided Skeleton for '{target_symbol}': target & 1-hop dependencies kept full]\n\n"
153
+ ) if ext != ".py" else (
154
+ f"# [TokenSafe Graph-Guided Skeleton for '{target_symbol}': target & 1-hop dependencies kept full]\n\n"
155
+ )
156
+ else:
157
+ header_comment = (
158
+ f"// [TOCP AST Skeleton: {lines_count} lines folded into API signatures]\n"
159
+ f"// [To inspect implementation of a specific method, call read_file with StartLine/EndLine]\n\n"
160
+ ) if ext != ".py" else (
161
+ f"# [TOCP AST Skeleton: {lines_count} lines folded into API signatures]\n"
162
+ f"# [To inspect implementation of a specific method, call read_file with StartLine/EndLine]\n\n"
163
+ )
144
164
 
145
165
  full_content = header_comment + (prefetch_block + "\n" if prefetch_block else "") + skeleton_content
146
166
 
package/src/slicer.py CHANGED
@@ -91,7 +91,8 @@ class ToolSlicer:
91
91
  "original_tokens": total_tokens,
92
92
  "optimized_tokens": sliced_tokens,
93
93
  "lines_total": total_lines,
94
- "lines_sliced": (new_end - new_start + 1)
94
+ "lines_sliced": (new_end - new_start + 1),
95
+ "target_symbol": target_symbol
95
96
  }
96
97
  return overwrite, metrics
97
98