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,15 @@
1
+ {
2
+ "name": "anolisa-tokenless",
3
+ "description": "ANOLISA local marketplace — bundles the Token-Less plugin for Claude Code",
4
+ "owner": {
5
+ "name": "ANOLISA"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "tokenless",
10
+ "source": "./",
11
+ "description": "Token-Less context compression for Claude Code — RTK command rewriting, response/TOON compression, and Tool Ready environment pre-check",
12
+ "category": "productivity"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "tokenless",
3
+ "version": "0.7.7",
4
+ "description": "Token-Less context compression for Claude Code — RTK command rewriting, response/TOON compression, and Tool Ready environment pre-check",
5
+ "author": { "name": "ANOLISA" },
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/alibaba/anolisa/tree/main/src/tokenless",
8
+ "keywords": ["token-optimization", "rtk", "compression", "toon", "tool-ready"]
9
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "TOKENLESS_AGENT_ID=claude-code bash \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.sh\" rewrite_hook.py",
10
+ "timeout": 10
11
+ }
12
+ ]
13
+ },
14
+ {
15
+ "matcher": "",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "TOKENLESS_AGENT_ID=claude-code bash \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.sh\" tool_ready_hook.sh",
20
+ "timeout": 15
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "PostToolUse": [
26
+ {
27
+ "matcher": "^(?!(?:Read|Glob|NotebookRead)$).+",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "TOKENLESS_AGENT_ID=claude-code bash \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.sh\" compress_response_hook.py",
32
+ "timeout": 15
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }
38
+ }
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env bash
2
+ # detect.sh — Inspect Claude Code presence and the tokenless plugin state.
3
+ # Read-only. Tri-state exit aligns with openclaw/hermes detect.sh:
4
+ # 0 = installed and ready
5
+ # 1 = not installed but installable (prereqs OK)
6
+ # 2 = missing prerequisites
7
+ set -euo pipefail
8
+
9
+ COMPONENT="${ANOLISA_COMPONENT:-tokenless}"
10
+ AGENT="${ANOLISA_TARGET:-claude-code}"
11
+ ADAPTER_DIR="${ANOLISA_ADAPTER_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}"
12
+
13
+ PLUGIN_ID="${COMPONENT}@anolisa-${COMPONENT}"
14
+ PLUGIN_SRC="$ADAPTER_DIR/claude-code"
15
+
16
+ CLAUDE_BIN="${CLAUDE_BIN:-}"
17
+ export PATH="$HOME/.local/bin:/usr/local/bin:$PATH"
18
+
19
+ # First-run settling retries: right after provisioning, the claude binary or
20
+ # the plugin registry may be transiently invisible on the very first detect.sh
21
+ # execution (filesystem/PATH init timing race). settle() only retries checks
22
+ # that report a retryable failure (exit status 1); checks that succeed or
23
+ # report a definitive result return immediately, so steady-state runs stay
24
+ # fast.
25
+ DETECT_RETRIES="${TOKENLESS_DETECT_RETRIES:-3}"
26
+ DETECT_RETRY_DELAY="${TOKENLESS_DETECT_RETRY_DELAY:-1}"
27
+
28
+ # settle <cmd...> — run cmd once; if it reports a retryable failure (exit
29
+ # status 1), sleep DETECT_RETRY_DELAY and retry, up to DETECT_RETRIES retries
30
+ # (that is, at most 1 + DETECT_RETRIES attempts in total). Exit status 0 is
31
+ # success. Any other exit status is a definitive result and is returned
32
+ # immediately without further retries. Returns the final exit status.
33
+ # Callers must therefore reserve exit status 1 for conditions that a retry
34
+ # may still resolve.
35
+ settle() {
36
+ local retry=0 rc=0
37
+ "$@"; rc=$?
38
+ while [ "$rc" -eq 1 ] && [ "$retry" -lt "$DETECT_RETRIES" ]; do
39
+ retry=$((retry + 1))
40
+ sleep "$DETECT_RETRY_DELAY"
41
+ "$@"; rc=$?
42
+ done
43
+ return "$rc"
44
+ }
45
+
46
+ line() { printf '[%s] %s\n' "$COMPONENT" "$*"; }
47
+ field() { printf '[%s] %-26s %s\n' "$COMPONENT" "$1" "$2"; }
48
+
49
+ PREREQ_MISSING=()
50
+ INSTALL_MISSING=()
51
+ note_prereq_missing() { PREREQ_MISSING+=("$1"); }
52
+ note_install_missing() { INSTALL_MISSING+=("$1"); }
53
+
54
+ find_claude_bin() {
55
+ CLAUDE_BIN="$(command -v claude 2>/dev/null || true)"
56
+ [ -n "$CLAUDE_BIN" ]
57
+ }
58
+
59
+ if [ -z "$CLAUDE_BIN" ]; then
60
+ # PATH/filesystem may still be settling right after install; re-check
61
+ # briefly before declaring the CLI missing. A genuinely absent CLI cannot
62
+ # be distinguished from that settling race, so it spends one retry budget
63
+ # (set TOKENLESS_DETECT_RETRIES=0 to opt out).
64
+ settle find_claude_bin || true
65
+ fi
66
+
67
+ line "${AGENT} detect"
68
+ if [ -n "$CLAUDE_BIN" ] && [ -x "$CLAUDE_BIN" ]; then
69
+ CLAUDE_VER="$("$CLAUDE_BIN" --version 2>/dev/null | awk '{print $1}' || echo unknown)"
70
+ field "claude CLI" "present (${CLAUDE_BIN}, v${CLAUDE_VER})"
71
+ else
72
+ field "claude CLI" "missing"
73
+ note_prereq_missing "claude CLI"
74
+ fi
75
+
76
+ # Informational only: claude creates ~/.claude on first run; absence is
77
+ # not a prerequisite failure. Check once, without settling retries: nothing in
78
+ # this script creates the directory before `claude plugin list` runs, and that
79
+ # call carries its own retry budget and initializes ~/.claude itself, so
80
+ # retrying this probe would only delay the report.
81
+ if [ -d "$HOME/.claude" ]; then
82
+ field "claude config dir" "present ($HOME/.claude)"
83
+ else
84
+ field "claude config dir" "missing (created on first claude run)"
85
+ fi
86
+
87
+ if [ -f "$PLUGIN_SRC/.claude-plugin/marketplace.json" ]; then
88
+ field "marketplace.json" "present"
89
+ else
90
+ field "marketplace.json" "missing"
91
+ note_prereq_missing "marketplace.json"
92
+ fi
93
+
94
+ if [ -f "$PLUGIN_SRC/.claude-plugin/plugin.json" ]; then
95
+ field "plugin.json" "present"
96
+ else
97
+ field "plugin.json" "missing (run: make stamp-adapter-templates)"
98
+ fi
99
+
100
+ # claude_plugin_listed — probe the plugin registry, using the settle()
101
+ # exit-status contract: 0 = plugin listed; 1 = `claude plugin list` itself
102
+ # failed (the CLI may still be initializing ~/.claude on first run, so a
103
+ # retry may still succeed); 2 = `plugin list` ran successfully but did not
104
+ # list the plugin. That is a definitive absent result — no retry can change
105
+ # it — so settle() must return immediately instead of sleeping out the
106
+ # retry budget and invoking the CLI DETECT_RETRIES + 1 times.
107
+ claude_plugin_listed() {
108
+ local listing
109
+ if ! listing="$("$CLAUDE_BIN" plugin list 2>&1)"; then
110
+ return 1
111
+ fi
112
+ if printf '%s\n' "$listing" | grep -qF "$PLUGIN_ID"; then
113
+ return 0
114
+ fi
115
+ return 2
116
+ }
117
+
118
+ if [ -n "$CLAUDE_BIN" ] && [ -x "$CLAUDE_BIN" ]; then
119
+ # First-run race: `claude plugin list` may transiently fail while the CLI
120
+ # initializes ~/.claude; settle() retries while that failure (status 1)
121
+ # persists. A successful list that simply omits the plugin is definitive
122
+ # (status 2) and is reported as "not installed" without further retries.
123
+ if settle claude_plugin_listed; then
124
+ field "plugin install" "installed ($PLUGIN_ID)"
125
+ else
126
+ field "plugin install" "not installed"
127
+ note_install_missing "$PLUGIN_ID"
128
+ fi
129
+ fi
130
+
131
+ if [ -f "$PLUGIN_SRC/hooks/run-hook.sh" ]; then
132
+ field "hook dispatcher" "present"
133
+ else
134
+ field "hook dispatcher" "missing (hooks/run-hook.sh)"
135
+ note_prereq_missing "hook dispatcher"
136
+ fi
137
+
138
+ if command -v python3 &>/dev/null; then
139
+ field "python3" "present ($(command -v python3))"
140
+ else
141
+ field "python3" "missing"
142
+ note_prereq_missing "python3"
143
+ fi
144
+
145
+ # jq is required by tool_ready_hook.sh; absence disables that hook only
146
+ # (rewrite + compress-response still work). Treat as informational.
147
+ if command -v jq &>/dev/null; then
148
+ field "jq" "present ($(command -v jq))"
149
+ else
150
+ field "jq" "missing (tool-ready hook disabled)"
151
+ fi
152
+
153
+ runtime_bin="$(command -v tokenless 2>/dev/null || true)"
154
+ if [ -n "$runtime_bin" ]; then
155
+ field "tokenless binary" "present (${runtime_bin})"
156
+ else
157
+ field "tokenless binary" "missing"
158
+ note_prereq_missing "tokenless binary"
159
+ fi
160
+
161
+ rtk_bin="$(command -v rtk 2>/dev/null || true)"
162
+ if [ -n "$rtk_bin" ]; then
163
+ field "rtk binary" "present (${rtk_bin})"
164
+ else
165
+ field "rtk binary" "missing"
166
+ note_prereq_missing "rtk binary"
167
+ fi
168
+
169
+ # Shared hook scripts live under FHS; warn when missing so user knows to run
170
+ # `make install` (or install the RPM) before adapter actually fires.
171
+ SHARED_HOOKS_DIR=""
172
+ for d in /usr/local/share/anolisa/adapters/tokenless/common/hooks \
173
+ /usr/share/anolisa/adapters/tokenless/common/hooks \
174
+ "$HOME/.local/share/anolisa/adapters/tokenless/common/hooks"; do
175
+ if [ -d "$d" ]; then SHARED_HOOKS_DIR="$d"; break; fi
176
+ done
177
+ if [ -n "$SHARED_HOOKS_DIR" ]; then
178
+ field "shared hooks dir" "present ($SHARED_HOOKS_DIR)"
179
+ else
180
+ field "shared hooks dir" "missing (run: make -C src/tokenless install)"
181
+ note_prereq_missing "shared hooks dir"
182
+ fi
183
+
184
+ if [ ${#PREREQ_MISSING[@]} -gt 0 ]; then
185
+ line "${AGENT}: missing prerequisites (${PREREQ_MISSING[*]})"
186
+ exit 2
187
+ fi
188
+ if [ ${#INSTALL_MISSING[@]} -gt 0 ]; then
189
+ line "${AGENT}: not installed (ready to install)"
190
+ exit 1
191
+ fi
192
+ line "${AGENT}: ready"
193
+ exit 0
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env bash
2
+ # install.sh — Register tokenless as a local Claude Code marketplace and
3
+ # install the plugin via the official `claude plugin` CLI.
4
+ #
5
+ # Responsibility boundary (mirrors openclaw/scripts/install.sh):
6
+ # - This script ONLY deploys an already-stamped plugin manifest.
7
+ # - Manifest stamping (plugin.json.in -> plugin.json) is the Makefile's job:
8
+ # make -C src/tokenless stamp-adapter-templates
9
+ # which `make install` runs automatically before `install-adapter-resources`
10
+ # copies the result into $SHARE_DIR/claude-code.
11
+ # - A dev-only fallback stamps the manifest in place when called outside the
12
+ # RPM/Makefile flow, so adapter-install works on a freshly checked-out tree.
13
+ #
14
+ # Claude Code v2 requires plugins to be sourced from a registered marketplace.
15
+ # We expose the adapter's claude-code/ directory itself as a single-plugin
16
+ # marketplace ("anolisa-tokenless"), then install tokenless@anolisa-tokenless
17
+ # from it. The marketplace name is component-scoped so multiple ANOLISA
18
+ # components can each register their own without colliding.
19
+ set -euo pipefail
20
+
21
+ AGENT="${ANOLISA_TARGET:-claude-code}"
22
+ COMPONENT="${ANOLISA_COMPONENT:-tokenless}"
23
+ ADAPTER_DIR="${ANOLISA_ADAPTER_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}"
24
+
25
+ PLUGIN_SRC="$ADAPTER_DIR/claude-code"
26
+ MARKETPLACE_NAME="anolisa-${COMPONENT}"
27
+ PLUGIN_ID="${COMPONENT}@${MARKETPLACE_NAME}"
28
+
29
+ CLAUDE_BIN="${CLAUDE_BIN:-claude}"
30
+ export PATH="$HOME/.local/bin:/usr/local/bin:$PATH"
31
+
32
+ echo "[${COMPONENT}] Installing ${AGENT} plugin..."
33
+
34
+ if ! command -v "$CLAUDE_BIN" &>/dev/null; then
35
+ echo "[${COMPONENT}] claude CLI not found (CLAUDE_BIN=${CLAUDE_BIN}) — skipping plugin installation."
36
+ echo "[${COMPONENT}] Install Claude Code first, then run this script again."
37
+ exit 0
38
+ fi
39
+
40
+ if [ ! -d "$PLUGIN_SRC" ]; then
41
+ echo "[${COMPONENT}] Plugin source not found: $PLUGIN_SRC" >&2
42
+ exit 1
43
+ fi
44
+
45
+ if [ ! -f "$PLUGIN_SRC/.claude-plugin/marketplace.json" ]; then
46
+ echo "[${COMPONENT}] ERROR: $PLUGIN_SRC/.claude-plugin/marketplace.json missing." >&2
47
+ exit 1
48
+ fi
49
+
50
+ # Dev-only fallback: stamp plugin.json from .in template when Makefile hasn't
51
+ # run yet. Production installs (RPM, `make install`) ship a stamped manifest
52
+ # inside SHARE_DIR, so this branch is a no-op in those flows.
53
+ PLUGIN_MANIFEST="$PLUGIN_SRC/.claude-plugin/plugin.json"
54
+ PLUGIN_TEMPLATE="$PLUGIN_SRC/.claude-plugin/plugin.json.in"
55
+ if [ ! -f "$PLUGIN_MANIFEST" ] && [ -f "$PLUGIN_TEMPLATE" ]; then
56
+ VERSION="${TOKENLESS_VERSION:-${ANOLISA_VERSION:-0.0.0-dev}}"
57
+ sed "s/@VERSION@/${VERSION}/g" "$PLUGIN_TEMPLATE" > "$PLUGIN_MANIFEST"
58
+ echo "[${COMPONENT}] dev-fallback: stamped plugin.json (version=${VERSION}) — production builds should stamp via Makefile"
59
+ fi
60
+
61
+ if [ ! -f "$PLUGIN_MANIFEST" ] ; then
62
+ echo "[${COMPONENT}] ERROR: $PLUGIN_MANIFEST missing." >&2
63
+ echo "[${COMPONENT}] Stamp the manifest first:" >&2
64
+ echo "[${COMPONENT}] make -C src/tokenless stamp-adapter-templates" >&2
65
+ exit 1
66
+ fi
67
+
68
+ # Validate the stamped plugin via the official CLI — same gate the install
69
+ # call would hit; surfacing the error here gives a cleaner failure message.
70
+ "$CLAUDE_BIN" plugin validate "$PLUGIN_SRC" >/dev/null \
71
+ || { echo "[${COMPONENT}] plugin validation failed" >&2; exit 1; }
72
+
73
+ # Idempotent marketplace add. We probe `marketplace list` first so that a
74
+ # `marketplace add` failure surfaces its real cause (bad path, malformed
75
+ # manifest, settings.json write error) instead of being swallowed as
76
+ # "already registered".
77
+ echo "[${COMPONENT}] registering marketplace '${MARKETPLACE_NAME}' from ${PLUGIN_SRC}..."
78
+ if "$CLAUDE_BIN" plugin marketplace list 2>/dev/null \
79
+ | grep -qE "(^|[[:space:]])${MARKETPLACE_NAME}([[:space:]]|$)"; then
80
+ echo "[${COMPONENT}] marketplace '${MARKETPLACE_NAME}' already registered"
81
+ else
82
+ "$CLAUDE_BIN" plugin marketplace add "$PLUGIN_SRC" \
83
+ || { echo "[${COMPONENT}] marketplace add failed" >&2; exit 1; }
84
+ fi
85
+
86
+ # Idempotent plugin install.
87
+ echo "[${COMPONENT}] installing ${PLUGIN_ID}..."
88
+ "$CLAUDE_BIN" plugin install "$PLUGIN_ID" 2>&1 \
89
+ || { echo "[${COMPONENT}] plugin install failed" >&2; exit 1; }
90
+
91
+ echo "[${COMPONENT}] ${AGENT} plugin installed via claude CLI."
92
+ echo "[${COMPONENT}] Restart claude (or run /plugin) to activate."
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+ # uninstall.sh — Remove the tokenless plugin and the anolisa marketplace via
3
+ # the official `claude plugin` CLI. Falls back to manual cleanup of the
4
+ # settings.json + plugin cache when claude is unavailable (e.g. RPM %preun
5
+ # running after the user uninstalled claude themselves).
6
+ set -euo pipefail
7
+
8
+ AGENT="${ANOLISA_TARGET:-claude-code}"
9
+ COMPONENT="${ANOLISA_COMPONENT:-tokenless}"
10
+
11
+ MARKETPLACE_NAME="anolisa-${COMPONENT}"
12
+ PLUGIN_ID="${COMPONENT}@${MARKETPLACE_NAME}"
13
+
14
+ CLAUDE_BIN="${CLAUDE_BIN:-claude}"
15
+ export PATH="$HOME/.local/bin:/usr/local/bin:$PATH"
16
+
17
+ echo "[${COMPONENT}] Uninstalling ${AGENT} plugin..."
18
+
19
+ if command -v "$CLAUDE_BIN" &>/dev/null; then
20
+ "$CLAUDE_BIN" plugin uninstall "$PLUGIN_ID" 2>&1 || true
21
+ "$CLAUDE_BIN" plugin marketplace remove "$MARKETPLACE_NAME" 2>&1 || true
22
+ echo "[${COMPONENT}] ${AGENT} plugin removed via claude CLI."
23
+ exit 0
24
+ fi
25
+
26
+ echo "[${COMPONENT}] claude CLI not found — falling back to manual cleanup."
27
+ SETTINGS="$HOME/.claude/settings.json"
28
+ if command -v jq &>/dev/null && [ -f "$SETTINGS" ]; then
29
+ # del(.[$key]) silently no-ops on non-object values. Verify shape up-front
30
+ # so a schema change in a future Claude Code release surfaces as a clear
31
+ # warning instead of a silent "cleaned" message that left residue behind.
32
+ EP_TYPE=$(jq -r '.enabledPlugins | type' "$SETTINGS" 2>/dev/null || echo "missing")
33
+ MK_TYPE=$(jq -r '.extraKnownMarketplaces | type' "$SETTINGS" 2>/dev/null || echo "missing")
34
+ if [ "$EP_TYPE" != "object" ] && [ "$EP_TYPE" != "null" ] && [ "$EP_TYPE" != "missing" ]; then
35
+ echo "[${COMPONENT}] WARN: .enabledPlugins is ${EP_TYPE}, expected object — skipping jq cleanup." >&2
36
+ echo "[${COMPONENT}] WARN: remove '${PLUGIN_ID}' from $SETTINGS manually." >&2
37
+ elif [ "$MK_TYPE" != "object" ] && [ "$MK_TYPE" != "null" ] && [ "$MK_TYPE" != "missing" ]; then
38
+ echo "[${COMPONENT}] WARN: .extraKnownMarketplaces is ${MK_TYPE}, expected object — skipping jq cleanup." >&2
39
+ echo "[${COMPONENT}] WARN: remove '${MARKETPLACE_NAME}' from $SETTINGS manually." >&2
40
+ else
41
+ tmp="$(mktemp "${SETTINGS}.XXXXXX")"
42
+ jq --arg id "$PLUGIN_ID" --arg mkt "$MARKETPLACE_NAME" '
43
+ if .enabledPlugins then .enabledPlugins |= del(.[$id]) else . end
44
+ | if .extraKnownMarketplaces then .extraKnownMarketplaces |= del(.[$mkt]) else . end
45
+ ' "$SETTINGS" > "$tmp" && mv "$tmp" "$SETTINGS"
46
+ echo "[${COMPONENT}] cleaned $SETTINGS"
47
+ fi
48
+ fi
49
+ rm -rf "$HOME/.claude/plugins/cache/${MARKETPLACE_NAME}" 2>/dev/null || true
50
+ echo "[${COMPONENT}] manual cleanup complete."
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "tokenless",
3
+ "version": "0.7.7",
4
+ "description": "Intelligent tool response compression, environment error detection, and token optimization. Strips noise (debug fields, nulls, empty values), truncates long strings/arrays, applies TOON encoding for JSON responses, and classifies environment errors with actionable fix hints.",
5
+ "keywords": [
6
+ "compression",
7
+ "token",
8
+ "context",
9
+ "optimization",
10
+ "environment",
11
+ "diagnostics"
12
+ ],
13
+ "hooks": "./hooks/hooks.json",
14
+ "interface": {
15
+ "displayName": "Tokenless",
16
+ "shortDescription": "Compress tool responses and detect environment errors to save tokens",
17
+ "category": "developer-tools",
18
+ "capabilities": ["hook"]
19
+ }
20
+ }
@@ -0,0 +1,160 @@
1
+ # Tokenless Plugin for Codex
2
+
3
+ Intelligent tool response compression and environment error detection plugin for
4
+ [Codex](https://github.com/openai/codex). Reduces token consumption by stripping
5
+ noise, truncating verbose output, and classifying environment errors with
6
+ actionable fix hints.
7
+
8
+ ## Features
9
+
10
+ | Feature | Description |
11
+ |---------|-------------|
12
+ | **Response Compression** | Strips debug fields, nulls, empty values; truncates long strings (512 chars) and arrays (16 items); limits depth to 8 levels |
13
+ | **TOON Encoding** | Further compresses valid JSON responses (15-40% additional savings vs. compressed JSON) |
14
+ | **Environment Error Detection** | Classifies tool failures as dependency/permission/file/network/package issues; injects fix hints to prevent retry loops |
15
+ | **Statistics Tracking** | Records every compression operation to SQLite for auditing and optimization |
16
+
17
+ ## How It Works
18
+
19
+ The plugin registers four hooks with Codex:
20
+
21
+ 1. **`SessionStart`** — verifies the `tokenless` CLI is installed and functional (non-blocking)
22
+ 2. **`PreToolUse` (tool-ready, hard-disabled)** — remains registered but is a
23
+ silent pass-through. `tokenless env-check` returns `UNKNOWN` with
24
+ `enabled:false`, so the hook emits no context, performs no repair, and never
25
+ blocks a tool. Re-enabling the retained legacy pipeline requires a source
26
+ change and a new release.
27
+ 3. **`PreToolUse` (rewrite)** — runs before shell command execution:
28
+ - Rewrites commands via `rtk rewrite` for token optimization
29
+ - Only applies to Bash/Shell/terminal/programmatic tools
30
+ 4. **`PostToolUse`** — runs after every tool execution:
31
+ - Skips content-reading tools (Read, Glob) and small responses (< 500 chars)
32
+ - Classifies environment errors and injects fix hints
33
+ - Compresses large JSON responses via `tokenless compress-response`
34
+ - Applies TOON encoding for additional savings
35
+ - Injects a compressed summary as `additionalContext`
36
+
37
+ > **Codex Protocol Constraint**: PostToolUse hooks cannot suppress the original
38
+ > tool output (`suppressOutput` is rejected). The plugin therefore injects a
39
+ > compressed *summary* as `additionalContext` — the model sees both the original
40
+ > output and the compressed summary, and can use the summary for efficient
41
+ > processing of large outputs.
42
+
43
+ ## Installation
44
+
45
+ ### Prerequisites
46
+
47
+ - Rust toolchain ≥ 1.89.0
48
+ - The `anolisa` source tree (this repository)
49
+
50
+ ### Install
51
+
52
+ ```bash
53
+ cd src/tokenless/adapters/tokenless/codex
54
+ ./scripts/install.sh
55
+ ```
56
+
57
+ This builds the `tokenless` Rust CLI in release mode and installs it to
58
+ `~/.local/bin/`. Add `~/.local/bin` to your `PATH` if not already present.
59
+
60
+ ### Configure Codex
61
+
62
+ Add the plugin to your Codex `config.toml`:
63
+
64
+ ```toml
65
+ [plugins]
66
+ tokenless = { enabled = true }
67
+ ```
68
+
69
+ Or install from the marketplace (once published).
70
+
71
+ ### Verify
72
+
73
+ ```bash
74
+ ./scripts/detect.sh
75
+ # {"installed": true, "version": "1.0.0", "path": "/home/user/.local/bin/tokenless"}
76
+ ```
77
+
78
+ ## Hook Output Format
79
+
80
+ The plugin injects `additionalContext` in the following format:
81
+
82
+ ```
83
+ [tokenless:compressed] Bash: 45,230 → 2,100 chars (95% reduction)
84
+ [tokenless:env:ENV_DEPENDENCY_MISSING] Missing dependency detected. ...
85
+ Do NOT retry the same command — fix the environment first.
86
+ --- compressed content ---
87
+ {... compressed JSON or TOON content ...}
88
+ --- end compressed content ---
89
+ ```
90
+
91
+ ## Configuration
92
+
93
+ Configuration is managed through the `tokenless` CLI's environment and config file:
94
+
95
+ | Variable | Default | Description |
96
+ |----------|---------|-------------|
97
+ | `TOKENLESS_AGENT_ID` | `codex` | Agent identifier for statistics |
98
+ | `TOKENLESS_BIN` | (auto-detected) | Path to tokenless binary |
99
+ | `TOKENLESS_STATS_ENABLED` | `1` | Enable statistics recording |
100
+ | `TOKENLESS_DATA_DIR` | `~/.tokenless` | Directory for `stats.db` and `stash.db` |
101
+ | `TOKENLESS_STATS_DB` | `~/.tokenless/stats.db` | Statistics database path |
102
+ | `TOKENLESS_STASH_DB` | `~/.tokenless/stash.db` | Reversible stash database path |
103
+
104
+ `TOKENLESS_STATS_DB` and `TOKENLESS_STASH_DB` take precedence over
105
+ `TOKENLESS_DATA_DIR`, which may be any accessible absolute non-root directory.
106
+ Custom database files must remain under the real user home or selected data
107
+ directory.
108
+
109
+ ### View Statistics
110
+
111
+ ```bash
112
+ tokenless stats summary
113
+ tokenless stats list --limit 20
114
+ tokenless stats show <id>
115
+ ```
116
+
117
+ ## Compression Pipeline
118
+
119
+ ```
120
+ Raw tool_response (JSON)
121
+
122
+ ├─ Step 1: ResponseCompressor
123
+ │ ├─ Drop: debug, trace, stack, stacktrace, logs, logging fields
124
+ │ ├─ Truncate: strings > 512 chars, arrays > 16 items
125
+ │ ├─ Drop: null values, empty strings, empty arrays, empty objects
126
+ │ └─ Limit: max depth 8 levels
127
+
128
+ ├─ Step 2: TOON Encoding (if result is still valid JSON)
129
+ │ └─ Binary-to-TOON format encoding (~15-40% additional savings)
130
+
131
+ └─ Guard: output only if smaller than input (safety check)
132
+ ```
133
+
134
+ ## Architecture
135
+
136
+ ```
137
+ codex-plugin-tokenless/
138
+ ├── plugin.json.in # Codex plugin manifest (version-stamped by Makefile)
139
+ ├── hooks/
140
+ │ └── hooks.json # Hook definitions (SessionStart, PreToolUse, PostToolUse)
141
+ ├── scripts/
142
+ │ ├── compress-response # PostToolUse: response compression + env error detection
143
+ │ ├── rewrite-hook # PreToolUse: RTK command rewriting
144
+ │ ├── tool-ready # PreToolUse: registered hard-disabled pass-through
145
+ │ ├── check-tokenless # SessionStart: version/availability check
146
+ │ ├── install.sh # Build and install tokenless CLI + register plugin
147
+ │ ├── detect.sh # Detect tokenless availability
148
+ │ └── uninstall.sh # Cleanup plugin registration + marketplace
149
+ └── README.md
150
+ ```
151
+
152
+ ## Related
153
+
154
+ - [Tokenless Rust CLI](../../crates/tokenless-cli/) — core compression engine
155
+ - [OpenClaw Plugin](../openclaw/) — same compression for OpenClaw
156
+ - [Hermes Plugin](../hermes/) — same compression for Hermes
157
+
158
+ ## License
159
+
160
+ Same as the ANOLISA project.
@@ -0,0 +1,52 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "${PLUGIN_ROOT}/scripts/tool-ready",
10
+ "timeout": 10
11
+ }
12
+ ]
13
+ },
14
+ {
15
+ "matcher": "Bash|run_shell_command|terminal|Shell|exec|process",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "${PLUGIN_ROOT}/scripts/rewrite-hook",
20
+ "timeout": 10,
21
+ "statusMessage": "Rewriting command via RTK..."
22
+ }
23
+ ]
24
+ }
25
+ ],
26
+ "PostToolUse": [
27
+ {
28
+ "matcher": "*",
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "${PLUGIN_ROOT}/scripts/compress-response",
33
+ "timeout": 15,
34
+ "statusMessage": "Compressing tool response..."
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ "SessionStart": [
40
+ {
41
+ "matcher": null,
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "${PLUGIN_ROOT}/scripts/check-tokenless",
46
+ "timeout": 5
47
+ }
48
+ ]
49
+ }
50
+ ]
51
+ }
52
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+ # _common.sh — Shared helpers for codex adapter scripts.
3
+ # Source this file from install.sh and uninstall.sh.
4
+
5
+ # Resolve the codex CLI binary.
6
+ resolve_codex() {
7
+ if [[ -n "$CODEX_BIN" ]] && command -v "$CODEX_BIN" &>/dev/null; then
8
+ echo "$CODEX_BIN"
9
+ return
10
+ fi
11
+ for candidate in codex /usr/local/bin/codex /usr/bin/codex "$HOME/.local/bin/codex"; do
12
+ if command -v "$candidate" &>/dev/null; then
13
+ echo "$candidate"
14
+ return
15
+ fi
16
+ done
17
+ # Last resort: direct path check
18
+ for candidate in /usr/local/bin/codex /usr/bin/codex "$HOME/.local/bin/codex"; do
19
+ if [[ -x "$candidate" ]]; then
20
+ echo "$candidate"
21
+ return
22
+ fi
23
+ done
24
+ echo ""
25
+ }