openhermes 4.9.2 → 4.11.2

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 (69) hide show
  1. package/CONTEXT.md +1 -1
  2. package/README.md +32 -31
  3. package/bootstrap.ts +262 -45
  4. package/harness/agents/oh-planner.md +1 -1
  5. package/harness/agents/openhermes.md +27 -126
  6. package/harness/codex/AUTOPILOT.md +99 -3
  7. package/harness/codex/CHARTER.md +3 -4
  8. package/harness/lib/background/background.test.ts +197 -0
  9. package/harness/lib/background/index.ts +7 -0
  10. package/harness/lib/background/interfaces.ts +31 -0
  11. package/harness/lib/background/manager.ts +320 -0
  12. package/harness/lib/composer/compose.test.ts +168 -0
  13. package/harness/lib/composer/compose.ts +65 -0
  14. package/harness/lib/composer/fragments/01-identity.md +1 -0
  15. package/harness/lib/composer/fragments/02-delegation.md +6 -0
  16. package/harness/lib/composer/fragments/03-permissions.md +13 -0
  17. package/harness/lib/composer/fragments/04-task-flow.md +15 -0
  18. package/harness/lib/composer/fragments/05-confidence.md +5 -0
  19. package/harness/lib/composer/fragments/06-parallelization.md +17 -0
  20. package/harness/lib/composer/fragments/07-shell.md +41 -0
  21. package/harness/lib/composer/fragments/08-routing.md +8 -0
  22. package/harness/lib/composer/fragments/09-guardrails.md +12 -0
  23. package/harness/lib/composer/index.ts +1 -0
  24. package/harness/lib/hooks/builtins/confidence-gate-hook.ts +70 -0
  25. package/harness/lib/hooks/builtins/delegation-depth-hook.ts +59 -0
  26. package/harness/lib/hooks/builtins/error-recovery-hook.ts +107 -0
  27. package/harness/lib/hooks/builtins/memory-sync-hook.ts +73 -0
  28. package/harness/lib/hooks/builtins/plan-check-hook.ts +43 -0
  29. package/harness/lib/hooks/builtins/route-tracking-hook.ts +147 -0
  30. package/harness/lib/hooks/builtins/sanity-check-hook.ts +52 -0
  31. package/harness/lib/hooks/builtins/shell-detect-hook.ts +96 -0
  32. package/harness/lib/hooks/hooks.test.ts +1016 -0
  33. package/harness/lib/hooks/index.ts +30 -0
  34. package/harness/lib/hooks/registry.ts +416 -0
  35. package/harness/lib/hooks/types.ts +71 -0
  36. package/harness/lib/memory/index.ts +18 -0
  37. package/harness/lib/memory/interfaces.ts +53 -0
  38. package/harness/lib/memory/memory-manager.ts +205 -0
  39. package/harness/lib/memory/memory.test.ts +491 -0
  40. package/harness/lib/memory/plan-store.ts +366 -0
  41. package/harness/lib/recovery/handler.ts +243 -0
  42. package/harness/lib/recovery/index.ts +14 -0
  43. package/harness/lib/recovery/interfaces.ts +48 -0
  44. package/harness/lib/recovery/patterns.ts +149 -0
  45. package/harness/lib/recovery/recovery.test.ts +312 -0
  46. package/harness/lib/sanity/anomaly-tracker.ts +127 -0
  47. package/harness/lib/sanity/checker.ts +178 -0
  48. package/harness/lib/sanity/index.ts +13 -0
  49. package/harness/lib/sanity/interfaces.ts +24 -0
  50. package/harness/lib/sanity/sanity.test.ts +472 -0
  51. package/harness/lib/sync/file-watcher.ts +174 -0
  52. package/harness/lib/sync/index.ts +11 -0
  53. package/harness/lib/sync/interfaces.ts +27 -0
  54. package/harness/lib/sync/plan-sync.ts +536 -0
  55. package/harness/lib/sync/sync.test.ts +832 -0
  56. package/harness/skills/oh-init/DEEP.md +2 -2
  57. package/harness/skills/oh-manifest/SKILL.md +1 -1
  58. package/harness/skills/oh-plan-review/DEEP.md +1 -1
  59. package/harness/skills/oh-planner/DEEP.md +3 -3
  60. package/harness/skills/oh-ship/SKILL.md +1 -1
  61. package/harness/skills/oh-skill-craft/SKILL.md +1 -4
  62. package/package.json +5 -5
  63. package/tsconfig.json +1 -1
  64. package/harness/commands/oh-doctor.md +0 -205
  65. package/harness/commands/oh-log.md +0 -18
  66. package/harness/skills/oh-learn/DEEP.md +0 -44
  67. package/harness/skills/oh-learn/SKILL.md +0 -30
  68. package/scripts/count-tokens.mjs +0 -158
  69. package/scripts/oh-doctor.ps1 +0 -342
@@ -26,7 +26,7 @@ OpenHermes is the primary orchestrator. All routing, planning, and delegation fl
26
26
  - **Test command**: <fill or auto-detect>
27
27
 
28
28
  ## Key Directives
29
- - Plan first. Write to `~/.local/share/opencode/openhermes/plans/<project>-plan-<nnn>.md` before multi-file changes.
29
+ - Plan first. Write to `~/.local/share/openhermes/plans/<project>/plan-<nnn>.md` before multi-file changes.
30
30
  - OpenHermes delegates everything to sub-agents — never executes directly.
31
31
  - Verify before claiming success. Read files, run commands, confirm output.
32
32
  - Use oh-* skills on demand via the skill tool.
@@ -40,7 +40,7 @@ Ask user to fill or auto-detect from manifests.
40
40
  ```markdown
41
41
  ## OpenHermes Orchestrator
42
42
  OpenHermes is the primary orchestrator.
43
- - **Plan**: `~/.local/share/opencode/openhermes/plans/<project>-plan-<nnn>.md`
43
+ - **Plan**: `~/.local/share/openhermes/plans/<project>/plan-<nnn>.md`
44
44
  - **Never execute**: delegates everything to sub-agents
45
45
  - **Verify before claim**: read files, run commands, confirm output
46
46
  ```
@@ -26,6 +26,6 @@ Full build orchestration loop: pre-flight → plan → build → verify → loop
26
26
 
27
27
  | Outcome | Route |
28
28
  |---------|-------|
29
- | pass | → pipeline continues (planner→builder→gauntlet→ship) |
29
+ | pass | → oh-planner |
30
30
  | fail | → oh-expert (diagnose loop failure) |
31
31
  | blocker | → surface with context and options |
@@ -80,7 +80,7 @@ One section at a time: Architecture → Code Quality → Tests → Performance.
80
80
 
81
81
  ## Output
82
82
 
83
- Plan file (`~/.local/share/opencode/openhermes/plans/<project-name>-plan-<nnn>.md`) updated with findings and decisions.
83
+ Plan file (`~/.local/share/openhermes/plans/<project-name>/plan-<nnn>.md`) updated with findings and decisions.
84
84
 
85
85
  ## Anti-patterns
86
86
 
@@ -92,18 +92,18 @@ Runs sequentially: **Strategy → Architecture → Design → Engineering → DX
92
92
  Every plan written by oh-planner uses this canonical format.
93
93
 
94
94
  ### Storage
95
- Canonical path: `~/.local/share/opencode/openhermes/plans/<project>-plan-<nnn>.md`
95
+ Canonical path: `~/.local/share/openhermes/plans/<project>/plan-<nnn>.md`
96
96
 
97
97
  ### Template
98
98
  ```markdown
99
99
  # PLAN: <project>
100
100
 
101
- Plan ID: <project>-plan-<nnn>
101
+ Plan ID: <project>/plan-<nnn>
102
102
  Project: <project>
103
103
  Status: active | in-progress | blocked | complete | abandoned
104
104
  Created: <ts> | Updated: <ts>
105
105
  Project Path: <absolute-path>
106
- Plan Path: <canonical-path>/<project>-plan-<nnn>.md
106
+ Plan Path: <canonical-path>/<project>/plan-<nnn>.md
107
107
  Objective: <short>
108
108
 
109
109
  ## Current State
@@ -3,7 +3,7 @@ name: oh-ship
3
3
  description: "Use when code is ready to ship. Tests, version bump, commit, push to current branch, deploy, and verify. PRs only on request."
4
4
  tier: 4
5
5
  route:
6
- pass: oh-retro
6
+ pass: surface
7
7
  fail: oh-expert
8
8
  blocker: surface
9
9
  ---
@@ -3,9 +3,7 @@ name: oh-skill-craft
3
3
  description: "Use when a new OH skill needs to be created, existing skill needs review against standards, or an external capability should be integrated as a skill. Meta-skill for growing the harness."
4
4
  tier: 2
5
5
  route:
6
- pass:
7
- - oh-skills-link
8
- - oh-learn
6
+ pass: oh-skills-link
9
7
  fail: oh-expert
10
8
  blocker: surface
11
9
  ---
@@ -29,6 +27,5 @@ Create new agent skills for the OpenHermes harness.
29
27
  | Outcome | Route |
30
28
  |---------|-------|
31
29
  | pass | → oh-skills-link (verify discovery) |
32
- | iteration data | → oh-learn (extract patterns) |
33
30
  | fail | → oh-expert (diagnose) |
34
31
  | blocker | → surface |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openhermes",
3
- "version": "4.9.2",
3
+ "version": "4.11.2",
4
4
  "description": "Autonomous agent orchestration for OpenCode.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,8 +9,7 @@
9
9
  },
10
10
  "main": "./index.ts",
11
11
  "dependencies": {
12
- "@opencode-ai/plugin": "1.15.0",
13
- "gpt-tokenizer": "^3.4.0"
12
+ "@opencode-ai/plugin": "1.15.0"
14
13
  },
15
14
  "exports": {
16
15
  ".": "./index.ts",
@@ -28,10 +27,11 @@
28
27
  "harness/instructions/",
29
28
  "harness/skills/",
30
29
  "harness/commands/",
31
- "harness/agents/"
30
+ "harness/agents/",
31
+ "harness/lib/"
32
32
  ],
33
33
  "scripts": {
34
- "test": "bun test test/*.test.ts"
34
+ "test": "bun test"
35
35
  },
36
36
  "keywords": [
37
37
  "opencode",
package/tsconfig.json CHANGED
@@ -12,5 +12,5 @@
12
12
  "allowImportingTsExtensions": true,
13
13
  "types": ["node"]
14
14
  },
15
- "include": ["index.ts", "bootstrap.ts", "lib/**/*.ts", "test/**/*.ts"]
15
+ "include": ["index.ts", "bootstrap.ts", "lib/**/*.ts", "harness/lib/**/*.ts", "test/**/*.ts"]
16
16
  }
@@ -1,205 +0,0 @@
1
- ---
2
- description: Diagnose OpenHermes + OpenCode health with concrete file-level checks
3
- agent: OpenHermes
4
- ---
5
-
6
- Run a structured 8-category diagnostic. For each check, inspect the actual files on disk and report PASS/FAIL/WARN with evidence.
7
-
8
- ## 1. Plugin load path
9
-
10
- **What to check:**
11
- - Read `%USERPROFILE%\.config\opencode\opencode.jsonc` — verify the `plugin` array contains `"openhermes@git+https://github.com/nathwn12/openhermes.git#dev"`.
12
- - Check for trailing commas: line 23 has a known trailing `,` after the single plugin entry. The parser may fail on this.
13
- - Check the resolved install path: `%USERPROFILE%\.cache\opencode\packages\openhermes@git+https_/github.com/nathwn12/openhermes.git#dev/node_modules/openhermes/` — does it exist? Does `harness/` and `index.ts` resolve?
14
-
15
- **Troubleshooting:**
16
- - Trailing comma fix: remove `,` from end of line 23 in opencode.jsonc.
17
- - If the plugin path doesn't match, update opencode.jsonc to point to the correct git ref.
18
- - If the package directory is missing, OpenCode reinstalls on next launch. Restart and check again.
19
-
20
- ---
21
-
22
- ## 2. Skills discovery
23
-
24
- **What to check:**
25
- - Count directories in `harness/skills/` — expect exactly 31.
26
- - Spot-check 3 SKILL.md files for valid YAML frontmatter (must have `name`, `description`, `route`, `tier`, `triggers`).
27
- - Verify bootstrap.ts injects `config.skills.paths` with two sources: the built-in skills dir AND user skill dirs (`~/.agents/skills/`, `~/.config/opencode/skills/`, `~/.claude/skills/`).
28
- - Verify NO symlinks are required — discovery uses the plugin API `config.skills.paths` mechanism.
29
-
30
- **Expected current count:** 31 (confirmed directories match filesystem)
31
-
32
- ---
33
-
34
- ## 3. Command registration
35
-
36
- **What to check:**
37
- - List `harness/commands/` — expect exactly 2 `.md` files: `oh-doctor.md` and `oh-log.md`.
38
- - Read each file's frontmatter — both must have `description` + `agent: OpenHermes`.
39
- - Verify bootstrap.ts `commandDefinitions()` reads this directory and merges into `config.command`.
40
-
41
- ---
42
-
43
- ## 4. Agent registration
44
-
45
- **What to check:**
46
- - List `harness/agents/` — expect exactly 17 `.md` files (1 primary + 16 subagents).
47
- - Read `openhermes.md` frontmatter — must have `mode: primary`.
48
- - Verify primary agent permissions in bootstrap.ts (lines 370-391): `bash: deny`, `edit: deny`, `task: allow`.
49
- - Verify 16 subagents have explicit permissions in `SUBAGENT_PERMISSIONS` (lines 335-350): `bash: allow`, `edit: allow`, `task: { "oh-*": "deny" }`.
50
- - Verify delegation loop guard (line 424): max depth = 10.
51
- - Verify `oh-planner` + `oh-grill` + `oh-skill-craft` are hidden from @-menu (line 366).
52
-
53
- **Expected:** 17 entries, no missing agent definitions, all permissions assigned.
54
-
55
- ---
56
-
57
- ## 5. Instruction injection
58
-
59
- **What to check:**
60
- - Verify all 3 files exist:
61
- - `harness/codex/CHARTER.md` (target: ~80 lines)
62
- - `harness/codex/AUTOPILOT.md` (target: ~200 lines)
63
- - `harness/instructions/SHELL.md` (76 lines)
64
- - Each file must be > 0 bytes and not a placeholder/stub.
65
- - Verify bootstrap.ts injects both `harness/codex/` and `harness/instructions/` directories via `config.instructions`.
66
-
67
- ---
68
-
69
- ## 6. Package integrity
70
-
71
- **What to check:**
72
- - Read `package.json` — verify these fields:
73
- - `name: "openhermes"`
74
- - `version` — note current version
75
- - `exports: { ".": "./index.ts", "./bootstrap": "./bootstrap.ts" }`
76
- - `files` — all 11 entries must resolve to real files/dirs on disk
77
- - Read `tsconfig.json` — must have: `strict: true`, `target: ESNext`, `module: ESNext`, `moduleResolution: bundler`.
78
- - Verify `lib/harness-resolver.ts` — check its `REQUIRED_HARNESS_FILES` (CHARTER.md, AUTOPILOT.md, oh-planner/SKILL.md) all resolve from the harness root.
79
- - Check `scripts/` directory — no `.ps1` files exist. This is the current state. If some are expected, note absence.
80
- - Run `bun test` if available — note any failures.
81
-
82
- ---
83
-
84
- ## 7. Auth & config safety
85
-
86
- **What to check (grep entire project dir):**
87
- - `.env*` — expect 0 matches
88
- - `*.key` — expect 0 matches
89
- - `*secret*` — expect 0 matches
90
- - `credentials*` — expect 0 matches
91
- - `auth.json` — expect 0 matches (should be at `%USERPROFILE%\.local\share\opencode\auth.json`, outside the project)
92
- - Read `.gitignore` — must cover: `node_modules/`, `.config/`, `.opencode/`, `PLAN.d/`, `coverage/`, `*.tgz`
93
-
94
- ---
95
-
96
- ## 8. Documentation accuracy
97
-
98
- **What to check:**
99
- Read `AGENTS.md` and compare its claims against the actual filesystem. Known discrepancies to flag:
100
-
101
- | Claim | Actual | Status |
102
- |---|---|---|
103
- | Line 22: "31 skills (see below)" | Directory has 31 skills | Up to date |
104
- | Line 19: \`harness/instructions/ — SHELL.md\` | Directory only has SHELL.md | Up to date |
105
- | Line 23: `lib/ — harness-resolver.ts, logger.ts` | Only `harness-resolver.ts` exists | `logger.ts` removed |
106
-
107
- ---
108
-
109
- ## Quick-wins (automated)
110
-
111
- For instant automated checks, run the companion PowerShell script which outputs JSON-Lines diagnostics consumable by the OpenHermes orchestrator:
112
-
113
- ```powershell
114
- powershell -NoProfile -ExecutionPolicy Bypass -File scripts/oh-doctor.ps1
115
- powershell -NoProfile -ExecutionPolicy Bypass -File scripts/oh-doctor.ps1 -SkipOCChecks
116
- ```
117
-
118
- This script checks:
119
-
120
- 1. **AGENTS.md accuracy** — skill count (expects 31) and file references
121
- 2. **Package files field** — all `package.json` `files` entries exist on disk
122
- 3. **Harness prerequisites** — CHARTER.md, AUTOPILOT.md, oh-planner/SKILL.md resolve
123
- 4. **Test health** — `bun test` pass/fail counts
124
- 5. **TypeScript compilation** — `bunx tsc --noEmit` clean check
125
- 6. **Secrets scan** — .env, *.key, credentials, auth.json in repo
126
- 7. **.gitignore coverage** — expected entries present
127
- 8. **Runtime checks** — opencode CLI paths, plugin load, skills discovery (skippable)
128
-
129
- Each check reports PASS/FAIL/WARN with evidence and a suggested fix.
130
-
131
- ---
132
-
133
- ## Troubleshooting reference
134
-
135
- Use these when a check fails.
136
-
137
- ### Config won't parse
138
- ```
139
- %USERPROFILE%\.config\opencode\opencode.jsonc
140
- ```
141
- - Trailing commas: JSONC tolerates them in some parsers but OpenCode's validator rejects them.
142
- - Fix: open the file and remove any trailing `,` after the last array/object element.
143
- - Test: run `opencode --print-logs` — parser errors appear in the first few lines.
144
-
145
- ### Plugin won't load
146
- - Temporarily disable all plugins by setting `"plugin": []` in opencode.jsonc.
147
- - Restart. If OpenCode works, re-enable plugins one at a time.
148
- - If the app crashes on launch, check `%USERPROFILE%\.config\opencode\plugins\` directory and move it aside.
149
-
150
- ### Stuck or corrupted cache
151
- - Clear the full cache: `rm -rf %USERPROFILE%\.cache\opencode` (Windows: delete `%USERPROFILE%\.cache\opencode`).
152
- - This forces OpenCode to reinstall provider packages on next launch.
153
- - This resolves `AI_APICallError` and stale provider package issues.
154
-
155
- ### Authentication failures
156
- - Run `/connect` in the TUI to re-authenticate.
157
- - Check auth file: `%USERPROFILE%\.local\share\opencode\auth.json` — should be >0 bytes and valid JSON.
158
- - If corrupted: delete the file, then re-run `/connect`.
159
-
160
- ### Model not found / ProviderModelNotFoundError
161
- - Run `opencode models` to see available models.
162
- - Model format: `<providerId>/<modelId>` (e.g. `openai/gpt-4.1`).
163
- - Verify the provider is authenticated and has access to the requested model.
164
-
165
- ### Log inspection
166
- - Logs at `%USERPROFILE%\.local\share\opencode\log\` — newest file first.
167
- - Run `opencode --log-level DEBUG` for verbose output.
168
- - Run `/oh-log` in OpenCode to read OpenHermes-specific session logs.
169
-
170
- ### ProviderInitError
171
- - Corrupted or invalid configuration in `~/.local/share/opencode`.
172
- - Last resort: delete `~/.local/share/opencode` and re-authenticate with `/connect`.
173
-
174
- ---
175
-
176
- ## Report format
177
-
178
- Summarize diagnostics as:
179
-
180
- ```
181
- ## Diagnosis
182
-
183
- ### PASS items
184
- - check name — evidence
185
-
186
- ### FAIL / WARN items
187
- - ❌ FAIL: check name — evidence — fix
188
- - ⚠️ WARN: check name — evidence — suggestion
189
-
190
- ### Issues table
191
- | # | Severity | Check | File | Fix |
192
- |---|----------|-------|------|-----|
193
-
194
- ### Next actions
195
- 1. Priority action — command or manual step
196
- 2. ...
197
- ```
198
-
199
- ## Routing
200
-
201
- | Outcome | Route |
202
- |---------|-------|
203
- | All PASS or WARN only | → surface report to user |
204
- | Any FAIL | → oh-investigate (diagnose issues found) |
205
- | Unrecoverable (env broken) | → surface to user with findings |
@@ -1,18 +0,0 @@
1
- ---
2
- description: Read and summarize the OpenHermes session log
3
- agent: OpenHermes
4
- ---
5
-
6
- Inspect the OpenHermes session log at `~/.local/share/opencode/log/openhermes.log`.
7
-
8
- Return a structured summary grouped by session ID.
9
-
10
- Focus on:
11
-
12
- - `session.created`
13
- - `session.compacted`
14
- - `session.error`
15
-
16
- For each session, show the timeline in order and highlight any error details.
17
-
18
- Do not dump the whole log verbatim unless explicitly asked.
@@ -1,44 +0,0 @@
1
- # oh-learn — Deep Reference
2
-
3
- ## When to Use
4
-
5
- Session learnings should be captured, reviewed, or promoted as reusable instincts for future work.
6
-
7
- Triggers: learn from session, extract patterns, run oh-learn.
8
-
9
- ## Instinct Data Model
10
-
11
- JSONL at `~/.local/share/opencode/openhermes/plans/<project>-instincts.jsonl`:
12
-
13
- ```json
14
- {"trigger": "specific situation", "action": "recommended response", "confidence": 0.5, "applications": 1, "successes": 1, "category": "coding", "source": "oh-learn:extract", "ts": "2026-05-15T12:00:00Z"}
15
- ```
16
-
17
- **Trigger:** specific, matchable (not general advice). **Action:** executable (not belief). **Confidence:** starts 0.5, +0.05 per success, -0.02/day decay. **Category:** coding, testing, security, git, planning, orchestration, debugging, ux.
18
-
19
- ## Workflows
20
-
21
- ### Extract
22
-
23
- Scan session for repeated decisions. For each: write instinct. Check existing file for near-duplicates. Merge (max confidence, increment applications) or append.
24
-
25
- ### Evolve
26
-
27
- Read all instincts. Group by category then topic. ≥5 instincts with avg confidence ≥ 0.7 → oh-skill-craft spec. 3-4 with confidence ≥ 0.8 → suggest update to existing skill.
28
-
29
- ### Promote
30
-
31
- Instincts with confidence ≥ 0.85 AND applications ≥ 10 → filter project-specific → append to global `%USERPROFILE%\.config\opencode\instincts.jsonl`. Tag promoted.
32
-
33
- ### Review / Search / Prune / Export
34
-
35
- Review: totals + distributions. Search: by topic, trigger, category, confidence. Prune: stale >30d with confidence < 0.3. Export: portable JSON.
36
-
37
- ## Anti-patterns
38
-
39
- - Hoarding every observation (most aren't learnings)
40
- - Never pruning
41
- - Storing what not why
42
- - Over-promoting to global
43
- - Extracting without applying
44
- - Ignoring confidence
@@ -1,30 +0,0 @@
1
- ---
2
- name: oh-learn
3
- description: "Capture, review, and promote session learnings as reusable instincts"
4
- tier: 2
5
- route:
6
- pass: done
7
- fail: surface
8
- blocker: surface
9
- ---
10
-
11
- # oh-learn
12
-
13
- Distill session patterns into instincts, cluster into skill candidates, and promote high-signal patterns.
14
-
15
- ## Steps
16
-
17
- 1. Scan session for repeated decisions
18
- 2. Write instinct for each pattern — trigger, action, confidence
19
- 3. Check existing file for near-duplicates; merge or append
20
- 4. Group instincts by category and topic
21
- 5. Promote high-confidence instincts (≥0.85, ≥10 applications) to global scope
22
- 6. Prune stale low-confidence instincts (<0.3, >30 days)
23
-
24
- ## Routing
25
-
26
- | Outcome | Route |
27
- |---------|-------|
28
- | pass | → done |
29
- | fail | → surface |
30
- | blocker | → surface |
@@ -1,158 +0,0 @@
1
- /**
2
- * Exact token counting using gpt-tokenizer.
3
- * Counts every SKILL.md, bootstrap doc, AGENTS.md, and instructions.
4
- */
5
- import { encode } from "gpt-tokenizer";
6
- import fs from "fs";
7
- import path from "path";
8
-
9
- const HOME = process.env.USERPROFILE || process.env.HOME;
10
- const ROOT = path.resolve("Q:/PROJECTS/PERSONAL/openhermes-pkg");
11
-
12
- const categories = {
13
- "OH Bootstrap Docs (on disk, NOT injected)": [
14
- path.join(ROOT, "harness/codex/AUTOPILOT.md"),
15
- path.join(ROOT, "harness/codex/CHARTER.md"),
16
- path.join(ROOT, "harness/instructions/SHELL.md"),
17
- path.join(ROOT, "CONTEXT.md"),
18
- path.join(ROOT, "ETHOS.md"),
19
- ],
20
- "OH Agent Prompt (injected as system prompt)": [
21
- path.join(ROOT, "harness/agents/openhermes.md"),
22
- ],
23
- "OH Built-in Skills (31, registered)": [],
24
- "User Skills (.agents/skills) — on disk, NOT registered": [],
25
- "User Skills (.config/opencode/skills) — on disk, NOT registered": [],
26
- "Instructions": [
27
- path.join(ROOT, "AGENTS.md"),
28
- path.join(HOME, ".config/opencode/AGENTS.md"),
29
- ],
30
- };
31
-
32
- // Discover OH built-in skills
33
- const skillsDir = path.join(ROOT, "harness/skills");
34
- for (const entry of fs.readdirSync(skillsDir)) {
35
- const skPath = path.join(skillsDir, entry, "SKILL.md");
36
- if (fs.existsSync(skPath)) categories["OH Built-in Skills (31, registered)"].push(skPath);
37
- }
38
-
39
- // Discover user skills
40
- const userDirs = [
41
- path.join(HOME, ".agents/skills"),
42
- path.join(HOME, ".config/opencode/skills"),
43
- ];
44
- for (const dir of userDirs) {
45
- const key = dir.includes(".agents")
46
- ? "User Skills (.agents/skills) — on disk, NOT registered"
47
- : "User Skills (.config/opencode/skills) — on disk, NOT registered";
48
- if (fs.existsSync(dir)) {
49
- for (const entry of fs.readdirSync(dir)) {
50
- const skPath = path.join(dir, entry, "SKILL.md");
51
- if (fs.existsSync(skPath)) categories[key].push(skPath);
52
- }
53
- }
54
- }
55
-
56
- // Extract frontmatter description
57
- function extractDescription(filePath) {
58
- try {
59
- const content = fs.readFileSync(filePath, "utf8");
60
- const match = content.match(/^---\n([\s\S]*?)\n---/);
61
- if (!match) return { description: "", body: content };
62
- const fm = match[1];
63
- const descLine = fm.split("\n").find(l => l.trim().startsWith("description:"));
64
- if (!descLine) return { description: "", body: content.slice(match[0].length) };
65
- const desc = descLine.slice(descLine.indexOf(":") + 1).trim().replace(/^['"]|['"]$/g, "");
66
- return { description: desc, body: content.slice(match[0].length) };
67
- } catch { return { description: "", body: "" }; }
68
- }
69
-
70
- // Build what the available_skills XML block looks like (OH built-in skills only)
71
- function buildAvailableSkillsXml(includeUserSkills = false) {
72
- const parts = ['<available_skills>'];
73
- const allDirs = [path.join(ROOT, "harness/skills")];
74
- if (includeUserSkills) {
75
- allDirs.push(
76
- path.join(HOME, ".agents/skills"),
77
- path.join(HOME, ".config/opencode/skills"),
78
- );
79
- }
80
- for (const dir of allDirs) {
81
- if (!fs.existsSync(dir)) continue;
82
- for (const entry of fs.readdirSync(dir).sort()) {
83
- const skPath = path.join(dir, entry, "SKILL.md");
84
- if (!fs.existsSync(skPath)) continue;
85
- const { description } = extractDescription(skPath);
86
- parts.push(` <skill>`);
87
- parts.push(` <name>${entry}</name>`);
88
- parts.push(` <description>${description}</description>`);
89
- parts.push(` <location>file:///${skPath.replace(/\\/g, '/')}</location>`);
90
- parts.push(` </skill>`);
91
- }
92
- }
93
- parts.push('</available_skills>');
94
- return parts.join('\n');
95
- }
96
-
97
- // Count everything
98
- console.log("=".repeat(80));
99
- console.log("EXACT TOKEN COUNTS (gpt-tokenizer)");
100
- console.log("=".repeat(80));
101
-
102
- let grandTotal = 0;
103
-
104
- for (const [category, files] of Object.entries(categories)) {
105
- console.log(`\n--- ${category} ---`);
106
- let catTotal = 0;
107
- for (const file of files) {
108
- if (!fs.existsSync(file)) continue;
109
- const content = fs.readFileSync(file, "utf8");
110
- const tokens = encode(content).length;
111
- const name = path.basename(path.dirname(file)) !== "skills"
112
- ? path.basename(file)
113
- : path.basename(path.dirname(file));
114
- console.log(` ${name.padEnd(40)} ${String(tokens).padStart(6)} tokens (${content.length.toLocaleString()} bytes)`);
115
- catTotal += tokens;
116
- }
117
- console.log(` ${"-".repeat(50)}`);
118
- console.log(` TOTAL: ${catTotal} tokens`);
119
- grandTotal += catTotal;
120
- }
121
-
122
- // Available skills XML cost (OH built-in only — user skills no longer registered)
123
- console.log(`\n--- available_skills XML Block (OH only, 31 skills) ---`);
124
- const xmlContent = buildAvailableSkillsXml(false);
125
- const xmlTokens = encode(xmlContent).length;
126
- console.log(` Total: ${xmlTokens} tokens (${xmlContent.length.toLocaleString()} bytes)`);
127
-
128
- console.log(`\n--- available_skills XML Block (ALL 61 skills, for comparison) ---`);
129
- const xmlContentAll = buildAvailableSkillsXml(true);
130
- const xmlTokensAll = encode(xmlContentAll).length;
131
- console.log(` Total: ${xmlTokensAll} tokens (${xmlContentAll.length.toLocaleString()} bytes)`);
132
-
133
- grandTotal += xmlTokens;
134
-
135
- // System prompt components
136
- const instructionsTotal = categories["Instructions"].reduce((s, f) => {
137
- if (!fs.existsSync(f)) return s;
138
- return s + encode(fs.readFileSync(f, "utf8")).length;
139
- }, 0);
140
- const agentPromptTotal = categories["OH Agent Prompt (injected as system prompt)"].reduce((s, f) => {
141
- if (!fs.existsSync(f)) return s;
142
- return s + encode(fs.readFileSync(f, "utf8")).length;
143
- }, 0);
144
-
145
- console.log(`\n${"=".repeat(80)}`);
146
- console.log(`TOTAL ALL SKILL FILES: ${categories["OH Built-in Skills (31, registered)"].reduce((s, f) => s + encode(fs.readFileSync(f, "utf8")).length, 0)} tokens`);
147
- console.log(`TOTAL USER SKILL FILES: ${categories["User Skills (.agents/skills) — on disk, NOT registered"].reduce((s, f) => s + encode(fs.readFileSync(f, "utf8")).length, 0)} tokens`);
148
- console.log(`TOTAL CONFIG SKILLS: ${categories["User Skills (.config/opencode/skills) — on disk, NOT registered"].reduce((s, f) => s + encode(fs.readFileSync(f, "utf8")).length, 0)} tokens`);
149
- console.log(`TOTAL INSTRUCTIONS: ${instructionsTotal} tokens`);
150
- console.log(`AGENT PROMPT (openhermes.md): ${agentPromptTotal} tokens`);
151
- console.log(`available_skills XML (ALL 61 skills, registered): ${xmlTokensAll} tokens`);
152
- console.log(`\nBOOTSTRAP INJECTION: REMOVED (was 4,503 via transform hook)`);
153
- console.log(`ROUTING INVENTORY: REMOVED (was ~902 via buildRoutingInventory())`);
154
- console.log(`\nPER-TURN SYSTEM PROMPT COST: ${instructionsTotal + xmlTokensAll + agentPromptTotal} tokens`);
155
- console.log(` (instructions ${instructionsTotal} + available_skills ${xmlTokensAll} + agent prompt ${agentPromptTotal})`);
156
- console.log(`PRE-REFACTOR COST: ${instructionsTotal + xmlTokensAll + 4503 + 902} tokens`);
157
- console.log(`SAVINGS: ${(instructionsTotal + xmlTokensAll + 4503 + 902) - (instructionsTotal + xmlTokensAll + agentPromptTotal)} tokens per turn`);
158
- console.log("=".repeat(80));