anolisa-tokenless 0.7.7

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 (70) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +770 -0
  3. package/adapters/tokenless/claude-code/.claude-plugin/marketplace.json +15 -0
  4. package/adapters/tokenless/claude-code/.claude-plugin/plugin.json +9 -0
  5. package/adapters/tokenless/claude-code/hooks/hooks.json +38 -0
  6. package/adapters/tokenless/claude-code/scripts/detect.sh +193 -0
  7. package/adapters/tokenless/claude-code/scripts/install.sh +92 -0
  8. package/adapters/tokenless/claude-code/scripts/uninstall.sh +50 -0
  9. package/adapters/tokenless/codex/.codex-plugin/plugin.json +20 -0
  10. package/adapters/tokenless/codex/README.md +160 -0
  11. package/adapters/tokenless/codex/hooks/hooks.json +52 -0
  12. package/adapters/tokenless/codex/scripts/_common.sh +25 -0
  13. package/adapters/tokenless/codex/scripts/check-tokenless +94 -0
  14. package/adapters/tokenless/codex/scripts/compress-response +441 -0
  15. package/adapters/tokenless/codex/scripts/detect.sh +61 -0
  16. package/adapters/tokenless/codex/scripts/install.sh +151 -0
  17. package/adapters/tokenless/codex/scripts/rewrite-hook +282 -0
  18. package/adapters/tokenless/codex/scripts/tool-ready +303 -0
  19. package/adapters/tokenless/codex/scripts/uninstall.sh +78 -0
  20. package/adapters/tokenless/common/commands/tokenless-stats.toml +2 -0
  21. package/adapters/tokenless/common/cosh-extension.json +65 -0
  22. package/adapters/tokenless/common/hooks/compress_response_hook.py +487 -0
  23. package/adapters/tokenless/common/hooks/compress_schema_hook.py +144 -0
  24. package/adapters/tokenless/common/hooks/compress_toon_hook.py +160 -0
  25. package/adapters/tokenless/common/hooks/hook_utils.py +584 -0
  26. package/adapters/tokenless/common/hooks/rewrite_hook.py +223 -0
  27. package/adapters/tokenless/common/hooks/run-hook.sh +62 -0
  28. package/adapters/tokenless/common/hooks/tool_categories.json +99 -0
  29. package/adapters/tokenless/common/hooks/tool_ready_hook.sh +571 -0
  30. package/adapters/tokenless/common/tokenless-env-fix.sh +730 -0
  31. package/adapters/tokenless/common/tool-ready-spec.json +113 -0
  32. package/adapters/tokenless/dsh/cordis.patch.yml +8 -0
  33. package/adapters/tokenless/dsh/dist/index.js +399 -0
  34. package/adapters/tokenless/dsh/package.json +26 -0
  35. package/adapters/tokenless/hermes/__init__.py +572 -0
  36. package/adapters/tokenless/hermes/plugin.yaml +9 -0
  37. package/adapters/tokenless/hermes/scripts/detect.sh +80 -0
  38. package/adapters/tokenless/hermes/scripts/install.sh +60 -0
  39. package/adapters/tokenless/hermes/scripts/uninstall.sh +45 -0
  40. package/adapters/tokenless/manifest.json +147 -0
  41. package/adapters/tokenless/openclaw/dist/index.d.ts +27 -0
  42. package/adapters/tokenless/openclaw/dist/index.js +598 -0
  43. package/adapters/tokenless/openclaw/dist/tool_categories.json +99 -0
  44. package/adapters/tokenless/openclaw/index.ts +720 -0
  45. package/adapters/tokenless/openclaw/openclaw.plugin.json +40 -0
  46. package/adapters/tokenless/openclaw/package.json +24 -0
  47. package/adapters/tokenless/openclaw/scripts/detect.sh +102 -0
  48. package/adapters/tokenless/openclaw/scripts/install.sh +75 -0
  49. package/adapters/tokenless/openclaw/scripts/uninstall.sh +46 -0
  50. package/adapters/tokenless/openclaw/tsconfig.json +13 -0
  51. package/adapters/tokenless/opencode/plugin.js +246 -0
  52. package/adapters/tokenless/opencode/scripts/detect.sh +38 -0
  53. package/adapters/tokenless/opencode/scripts/install.sh +56 -0
  54. package/adapters/tokenless/opencode/scripts/uninstall.sh +29 -0
  55. package/adapters/tokenless/qoder/.qoder-plugin/plugin.json +11 -0
  56. package/adapters/tokenless/qoder/commands/tokenless-stats.md +8 -0
  57. package/adapters/tokenless/qoder/hooks/hooks.json +36 -0
  58. package/adapters/tokenless/qoder/hooks/run-hook.sh +51 -0
  59. package/adapters/tokenless/qoder/scripts/detect.sh +35 -0
  60. package/adapters/tokenless/qoder/scripts/install.sh +136 -0
  61. package/adapters/tokenless/qoder/scripts/uninstall.sh +106 -0
  62. package/adapters/tokenless/qwencode/qwen-extension.json +69 -0
  63. package/adapters/tokenless/qwencode/scripts/detect.sh +125 -0
  64. package/adapters/tokenless/qwencode/scripts/install.sh +128 -0
  65. package/adapters/tokenless/qwencode/scripts/uninstall.sh +62 -0
  66. package/bin/rtk +6 -0
  67. package/bin/tokenless +6 -0
  68. package/bin/toon +6 -0
  69. package/package.json +57 -0
  70. package/scripts/postinstall.js +208 -0
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env python3
2
+ """Codex PreToolUse Tool Ready adapter, currently a silent pass-through.
3
+
4
+ Release builds of ``tokenless env-check`` return ``UNKNOWN`` with
5
+ ``enabled:false``, which this adapter silently passes through. The retained
6
+ legacy pipeline below remains dormant until the readiness model is redesigned
7
+ and intentionally re-enabled in source.
8
+
9
+ Legacy pipeline: Check → Fix → Re-check
10
+ 1. CHECK: ``tokenless env-check --json --tool <name>``
11
+ 2. FIX: ``tokenless env-check --fix --json --tool <name>``
12
+ 3. RE-CHECK: parse result after fix attempt
13
+
14
+ Protocol:
15
+ stdin ← codex PreToolUse JSON (tool_name, ...)
16
+ stdout → {"hookSpecificOutput": {"hookEventName": "PreToolUse",
17
+ "permissionDecision": "allow"|"deny",
18
+ "additionalContext": "..."}}
19
+
20
+ Status mapping (from tokenless env-check --json):
21
+ READY → passthrough (empty stdout)
22
+ PARTIAL → allow + additionalContext warning
23
+ NOT_READY → auto-fix → re-check → deny if still failing
24
+ UNKNOWN → passthrough (fail-open)
25
+
26
+ Fail-open: every error path silently passes through (exit 0 with empty
27
+ stdout) so the agent session is never blocked by a hook failure.
28
+ """
29
+
30
+ import json
31
+ import os
32
+ import shutil
33
+ import subprocess
34
+ import sys
35
+ from typing import Optional
36
+
37
+ # Resolve shared hook utilities (common/hooks/) with FHS fallback paths.
38
+ # Primary: relative path (works for source-tree and FHS/RPM install).
39
+ # Fallbacks: system and user FHS paths (works when Codex caches only the
40
+ # plugin subdirectory and the relative path resolves outside the cache).
41
+ #
42
+ # Trust model (aligned with bash is_trusted_file / Rust is_trusted_path):
43
+ # - System FHS paths (/usr/share, /usr/local/share) are unconditional.
44
+ # - User-relative paths use passwd DB home (NOT $HOME — env-controllable),
45
+ # with ownership and parent-dir permission checks.
46
+ # - Relative ../../common/hooks is trusted only if the resolved target
47
+ # exists and is under a system prefix or a passwd-validated home path.
48
+ _HERE = os.path.dirname(os.path.abspath(__file__))
49
+
50
+
51
+ def _is_trusted_dir(path: str) -> bool:
52
+ """Check whether a directory is trusted for Python module imports.
53
+
54
+ Mirrors the trust criteria in bash tool_ready_hook.sh (is_trusted_file)
55
+ and Rust env_check.rs (is_trusted_path): system paths unconditional,
56
+ user paths validated via passwd + ownership + parent permission checks.
57
+
58
+ NOTE: Callers should pass realpath-resolved paths (not just abspath)
59
+ so that symlink targets are validated before the trust check — a
60
+ symlinked /usr/share/anolisa → /tmp/ would bypass the prefix check
61
+ if only abspath is used.
62
+ """
63
+ # System FHS prefixes are always trusted
64
+ for prefix in ("/usr/share/", "/usr/local/share/", "/usr/libexec/", "/usr/lib/anolisa/"):
65
+ if path.startswith(prefix):
66
+ return True
67
+ # For paths outside system prefixes (e.g. source-tree cloned to
68
+ # /opt/anolisa/), trust them if owned by current uid or root AND
69
+ # parent directory is not world-writable. This covers developer
70
+ # worktrees without requiring the path to be under passwd home.
71
+ try:
72
+ st = os.stat(path)
73
+ except OSError:
74
+ return False
75
+ if st.st_uid != os.getuid() and st.st_uid != 0:
76
+ # Not owned by us or root — refuse. Home paths must be owned by
77
+ # us or root; source-tree paths outside system prefixes are
78
+ # already covered by the ownership check above (current uid/root).
79
+ return False
80
+ # Ownership OK — check parent directory is not world-writable
81
+ parent = os.path.dirname(path)
82
+ try:
83
+ pst = os.stat(parent)
84
+ except OSError:
85
+ return False
86
+ if pst.st_uid != os.getuid() and pst.st_uid != 0:
87
+ return False
88
+ if pst.st_mode & 0o002: # world-writable
89
+ return False
90
+ return True
91
+
92
+ # Resolve real home from passwd DB for user-install fallback path.
93
+ # Falls back to "" (empty) when unavailable — candidate is then skipped.
94
+ try:
95
+ import pwd as _pwd
96
+ _REAL_HOME = _pwd.getpwuid(os.getuid()).pw_dir
97
+ except (ImportError, KeyError):
98
+ _REAL_HOME = ""
99
+ if not os.path.isabs(_REAL_HOME):
100
+ _REAL_HOME = ""
101
+
102
+
103
+ def _user_path(*parts: str) -> str:
104
+ return os.path.join(_REAL_HOME, *parts) if _REAL_HOME else ""
105
+
106
+
107
+ _HOOK_UTILS_CANDIDATES = [
108
+ os.path.join(_HERE, "..", "..", "common", "hooks"), # source-tree / FHS
109
+ "/usr/share/anolisa/adapters/tokenless/common/hooks", # RPM system
110
+ "/usr/local/share/anolisa/adapters/tokenless/common/hooks", # manual system
111
+ os.path.join(_REAL_HOME, ".local", "share",
112
+ "anolisa", "adapters", "tokenless", "common", "hooks") if _REAL_HOME else "",
113
+ ]
114
+ _HOOK_UTILS_RESOLVED = ""
115
+ for _C in _HOOK_UTILS_CANDIDATES:
116
+ if _C and _is_trusted_dir(os.path.realpath(_C)) and os.path.isdir(_C):
117
+ _HOOK_UTILS_RESOLVED = os.path.realpath(_C)
118
+ sys.path.insert(0, _C)
119
+ break
120
+
121
+ if _HOOK_UTILS_RESOLVED:
122
+ from hook_utils import skip_silent as _skip # noqa: E402
123
+ else:
124
+ # Fail-open: no trusted hook_utils found → provide inline fallbacks
125
+ # so the hook script exits 0 (passthrough) rather than ImportError → exit 1.
126
+ def _skip() -> None: # type: ignore[assignment,misc]
127
+ sys.exit(0)
128
+
129
+ # ---------------------------------------------------------------------------
130
+ # constants
131
+ # ---------------------------------------------------------------------------
132
+
133
+ AGENT_ID = os.environ.get("TOKENLESS_AGENT_ID", "codex")
134
+ FIX_TIMEOUT = 60 # auto-fix may involve package installs (dnf/pip)
135
+
136
+ # -- tokenless binary search paths (ANOLISA FHS spec) ------------------------
137
+ # Codex can cache this script without common/hooks. Keep this standalone list
138
+ # aligned with hook_utils.py::_known_binary_paths.
139
+
140
+ _TOKENLESS_FALLBACK = "/usr/bin/tokenless"
141
+ _TOKENLESS_SYSTEM_FALLBACK = "/usr/local/bin/tokenless"
142
+ _TOKENLESS_LOCAL_BIN = _user_path(".local", "bin", "tokenless")
143
+ _TOKENLESS_LOCAL_SHARE = _user_path(
144
+ ".local", "share", "anolisa", "tokenless", "tokenless"
145
+ )
146
+ _TOKENLESS_LOCAL_LIB = _user_path(
147
+ ".local", "lib", "anolisa", "tokenless", "tokenless"
148
+ )
149
+
150
+ # ---------------------------------------------------------------------------
151
+ # helpers
152
+ # ---------------------------------------------------------------------------
153
+
154
+
155
+ def _warn(msg: str) -> None:
156
+ print(f"[tokenless:ready] {msg}", file=sys.stderr)
157
+
158
+
159
+ def _find_tokenless() -> Optional[str]:
160
+ explicit = os.environ.get("TOKENLESS_BIN", "")
161
+ if explicit and os.path.isfile(explicit) and os.access(explicit, os.X_OK):
162
+ return explicit
163
+ path = shutil.which("tokenless")
164
+ if path:
165
+ return path
166
+ for fp in (
167
+ _TOKENLESS_LOCAL_BIN,
168
+ _TOKENLESS_SYSTEM_FALLBACK,
169
+ _TOKENLESS_FALLBACK,
170
+ _TOKENLESS_LOCAL_SHARE,
171
+ _TOKENLESS_LOCAL_LIB,
172
+ ):
173
+ if os.path.isfile(fp) and os.access(fp, os.X_OK):
174
+ return fp
175
+ return None
176
+
177
+
178
+ def _run_env_check(
179
+ tokenless_bin: str, tool_name: str, fix: bool = False
180
+ ) -> Optional[dict]:
181
+ """Run tokenless env-check and return parsed JSON result, or None."""
182
+ cmd = [tokenless_bin, "env-check", "--json", "--tool", tool_name]
183
+ if fix:
184
+ cmd.append("--fix")
185
+ timeout = FIX_TIMEOUT if fix else 10
186
+ try:
187
+ proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
188
+ except Exception:
189
+ return None
190
+ if proc.returncode != 0:
191
+ _warn(f"env-check{' --fix' if fix else ''} exit {proc.returncode}")
192
+ return None
193
+ try:
194
+ return json.loads(proc.stdout.strip())
195
+ except json.JSONDecodeError:
196
+ return None
197
+
198
+
199
+ def _build_response(
200
+ tool_name: str,
201
+ status: str,
202
+ missing: list[str],
203
+ permission: str,
204
+ ) -> str:
205
+ """Build a codex PreToolUse JSON response and return it as a string."""
206
+ missing_str = ", ".join(missing) if missing else "unknown"
207
+ if status == "PARTIAL":
208
+ ctx = (
209
+ f"[tokenless:ready] {tool_name}: PARTIAL — "
210
+ f"recommended deps not installed: {missing_str}. "
211
+ f"Core tool is functional, extended features may be unavailable."
212
+ )
213
+ else:
214
+ ctx = (
215
+ f"[tokenless:ready] {tool_name}: NOT_READY — "
216
+ f"auto-fix attempted but dependencies still missing: {missing_str}. "
217
+ f"Do NOT retry the same tool — fix the environment first."
218
+ )
219
+ response = {
220
+ "hookSpecificOutput": {
221
+ "hookEventName": "PreToolUse",
222
+ "permissionDecision": permission,
223
+ "additionalContext": ctx,
224
+ }
225
+ }
226
+ return json.dumps(response, ensure_ascii=False)
227
+
228
+
229
+ # ---------------------------------------------------------------------------
230
+ # main
231
+ # ---------------------------------------------------------------------------
232
+
233
+
234
+ def main() -> None:
235
+ # 1. Locate tokenless binary
236
+ tokenless_bin = _find_tokenless()
237
+ if not tokenless_bin:
238
+ _skip()
239
+
240
+ # 2. Read stdin JSON
241
+ try:
242
+ raw = sys.stdin.read()
243
+ if not raw.strip():
244
+ _skip()
245
+ input_data = json.loads(raw)
246
+ except (json.JSONDecodeError, EOFError, ValueError):
247
+ _skip()
248
+
249
+ # 3. Extract tool_name
250
+ tool_name = input_data.get("tool_name", "")
251
+ if not tool_name:
252
+ _skip()
253
+
254
+ # === Phase 1: CHECK ===
255
+ result = _run_env_check(tokenless_bin, tool_name, fix=False)
256
+ if result is None:
257
+ _skip()
258
+
259
+ status = result.get("status", "UNKNOWN")
260
+ missing = result.get("missing", [])
261
+
262
+ if status == "READY":
263
+ _skip()
264
+
265
+ if status == "UNKNOWN":
266
+ _skip()
267
+
268
+ if status == "PARTIAL":
269
+ print(_build_response(tool_name, status, missing, "allow"))
270
+ return
271
+
272
+ # === Phase 2: FIX (auto-install missing required dependencies) ===
273
+ _warn(f"{tool_name}: {status}, attempting auto-fix"
274
+ + (f" (missing: {', '.join(missing)})" if missing else ""))
275
+
276
+ fix_result = _run_env_check(tokenless_bin, tool_name, fix=True)
277
+ if fix_result is None:
278
+ # Fix command itself failed — report what we know from check
279
+ if status == "PARTIAL":
280
+ print(_build_response(tool_name, status, missing, "allow"))
281
+ return
282
+ print(_build_response(tool_name, status, missing, "deny"))
283
+ return
284
+
285
+ fix_status = fix_result.get("status", "UNKNOWN")
286
+
287
+ # === Phase 3: RE-CHECK ===
288
+ if fix_status == "READY":
289
+ _warn(f"{tool_name}: auto-fix succeeded, tool is now READY")
290
+ _skip()
291
+
292
+ # Fix didn't fully resolve — report remaining issues
293
+ fix_missing = fix_result.get("missing", [])
294
+ if fix_status == "PARTIAL":
295
+ print(_build_response(tool_name, fix_status, fix_missing, "allow"))
296
+ return
297
+
298
+ # Still NOT_READY after fix
299
+ print(_build_response(tool_name, fix_status, fix_missing, "deny"))
300
+
301
+
302
+ if __name__ == "__main__":
303
+ main()
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # Uninstall the tokenless Codex plugin and clean up plugin data.
3
+ #
4
+ # Removes:
5
+ # - Codex plugin registration (codex plugin remove)
6
+ # - Codex marketplace entry (codex plugin marketplace remove)
7
+ # - Marketplace symlink directory
8
+ # - The tokenless binary from the install prefix
9
+ #
10
+ # NOTE: This script does NOT remove $HOME/.tokenless/ — that directory
11
+ # holds the SQLite stats DB and rewrite context shared by every tokenless
12
+ # adapter (cosh, qoder, hermes, openclaw, claude-code). Removing it here
13
+ # would destroy data belonging to plugins still installed.
14
+ #
15
+ # Usage:
16
+ # ./uninstall.sh # Interactive (asks confirmation)
17
+ # ./uninstall.sh --non-interactive # CI / automated (no confirmation)
18
+
19
+ set -euo pipefail
20
+
21
+ INTERACTIVE=1
22
+ if [[ "${1:-}" == "--non-interactive" ]]; then
23
+ INTERACTIVE=0
24
+ fi
25
+
26
+ PREFIX="${TOKENLESS_INSTALL_PREFIX:-$HOME/.local}"
27
+ BINDIR="$PREFIX/bin"
28
+ CODEX_BIN="${CODEX_BIN:-}"
29
+ MARKETPLACE_NAME="anolisa-tokenless"
30
+ MARKETPLACE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/anolisa/codex-marketplace"
31
+
32
+ # Resolve codex binary via shared helper (see _common.sh).
33
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
34
+ # shellcheck source=./_common.sh
35
+ source "$SCRIPT_DIR/_common.sh"
36
+
37
+ echo "[tokenless] Codex plugin uninstall"
38
+
39
+ # 1. Remove codex plugin registration
40
+ CODEX_BIN="$(resolve_codex)"
41
+ if [[ -n "$CODEX_BIN" ]]; then
42
+ if "$CODEX_BIN" plugin list 2>/dev/null | grep -q "tokenless"; then
43
+ echo "[tokenless] Removing codex plugin 'tokenless@${MARKETPLACE_NAME}'..."
44
+ "$CODEX_BIN" plugin remove "tokenless@${MARKETPLACE_NAME}" 2>&1 || true
45
+ fi
46
+ if "$CODEX_BIN" plugin marketplace list 2>/dev/null | grep -q "^${MARKETPLACE_NAME}[[:space:]]"; then
47
+ echo "[tokenless] Removing marketplace '${MARKETPLACE_NAME}'..."
48
+ "$CODEX_BIN" plugin marketplace remove "$MARKETPLACE_NAME" 2>&1 || true
49
+ fi
50
+ else
51
+ echo "[tokenless] codex CLI not found, skipping plugin unregistration."
52
+ fi
53
+
54
+ # 2. Remove marketplace symlink directory
55
+ if [[ -d "$MARKETPLACE_DIR" ]]; then
56
+ rm -rf "$MARKETPLACE_DIR"
57
+ echo "[tokenless] Removed marketplace directory: $MARKETPLACE_DIR"
58
+ fi
59
+
60
+ # 3. Remove binary
61
+ if [[ -f "$BINDIR/tokenless" ]]; then
62
+ if [[ $INTERACTIVE -eq 1 ]]; then
63
+ read -rp "Remove $BINDIR/tokenless? [y/N] " answer
64
+ if [[ "$answer" =~ ^[Yy]$ ]]; then
65
+ rm -f "$BINDIR/tokenless"
66
+ echo "[tokenless] Removed: $BINDIR/tokenless"
67
+ else
68
+ echo "[tokenless] Skipped: $BINDIR/tokenless"
69
+ fi
70
+ else
71
+ rm -f "$BINDIR/tokenless"
72
+ echo "[tokenless] Removed: $BINDIR/tokenless"
73
+ fi
74
+ else
75
+ echo "[tokenless] Binary not found: $BINDIR/tokenless"
76
+ fi
77
+
78
+ echo "[tokenless] Uninstall complete."
@@ -0,0 +1,2 @@
1
+ description = "Show tokenless compression stats summary"
2
+ run = "tokenless stats summary {{args}}"
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "tokenless",
3
+ "version": "0.7.0",
4
+ "contextFileName": "COPILOT.md",
5
+ "hooks": {
6
+ "PreToolUse": [
7
+ {
8
+ "matcher": "",
9
+ "sequential": true,
10
+ "hooks": [
11
+ {
12
+ "type": "command",
13
+ "name": "tokenless-tool-ready",
14
+ "description": "Registered hard-disabled Tool Ready pass-through; performs no check, repair, or block",
15
+ "command": "bash ${extensionPath}/hooks/tool_ready_hook.sh",
16
+ "timeout": 10000,
17
+ "fail_open": true,
18
+ "env": { "TOKENLESS_AGENT_ID": "copilot-shell" }
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "matcher": "^(Bash|run_shell_command|terminal|Shell|exec|process)$",
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "name": "tokenless-rewrite",
28
+ "description": "Rewrites shell commands via rtk for token savings",
29
+ "command": "python3 ${extensionPath}/hooks/rewrite_hook.py",
30
+ "timeout": 5000,
31
+ "env": { "TOKENLESS_AGENT_ID": "copilot-shell" }
32
+ }
33
+ ]
34
+ }
35
+ ],
36
+ "PostToolUse": [
37
+ {
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "name": "tokenless-compress-response",
42
+ "description": "Compresses tool responses and encodes to TOON format",
43
+ "command": "python3 ${extensionPath}/hooks/compress_response_hook.py",
44
+ "timeout": 10000,
45
+ "env": { "TOKENLESS_AGENT_ID": "copilot-shell" }
46
+ }
47
+ ]
48
+ }
49
+ ],
50
+ "BeforeModel": [
51
+ {
52
+ "hooks": [
53
+ {
54
+ "type": "command",
55
+ "name": "tokenless-compress-schema",
56
+ "description": "Compresses tool schema definitions for token savings",
57
+ "command": "python3 ${extensionPath}/hooks/compress_schema_hook.py",
58
+ "timeout": 10000,
59
+ "env": { "TOKENLESS_AGENT_ID": "copilot-shell" }
60
+ }
61
+ ]
62
+ }
63
+ ]
64
+ }
65
+ }