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
@@ -1,342 +0,0 @@
1
- <#
2
- .SYNOPSIS
3
- Quick-win diagnostic for openhermes-pkg — AI-orchestrator-facing.
4
- .DESCRIPTION
5
- Outputs JSON-Lines diagnostics consumable by the OpenHermes orchestrator.
6
- Each line is a check result; final line is the summary verdict.
7
- .PARAMETER SkipOCChecks
8
- Skip opencode CLI checks (useful when opencode isn't running).
9
- .EXAMPLE
10
- .\oh-doctor.ps1
11
- .\oh-doctor.ps1 -SkipOCChecks
12
- #>
13
-
14
- param(
15
- [switch]$SkipOCChecks
16
- )
17
-
18
- $PackageRoot = Resolve-Path "$PSScriptRoot\.."
19
- $ErrorActionPreference = "Continue"
20
- $script:checks = @()
21
- $script:checks = @()
22
-
23
- function Write-Check {
24
- param(
25
- [Parameter(Mandatory)] [string]$Id,
26
- [Parameter(Mandatory)] [string]$Name,
27
- [Parameter(Mandatory)] [ValidateSet("PASS","WARN","FAIL","SKIP")] [string]$Status,
28
- [string]$Detail = "",
29
- [hashtable]$Evidence = @{},
30
- [string]$Severity = "medium",
31
- [hashtable]$Fix = @{}
32
- )
33
- $result = @{
34
- id = $Id
35
- name = $Name
36
- status = $Status
37
- severity = $Severity
38
- detail = $Detail
39
- evidence = $Evidence
40
- fix = $Fix
41
- }
42
- $script:checks += $result
43
- $result | ConvertTo-Json -Compress -Depth 5
44
- }
45
-
46
- # ============================================================
47
- # CHECK 1: AGENTS.md accuracy
48
- # ============================================================
49
- $agentPath = Join-Path $PackageRoot "AGENTS.md"
50
- if (Test-Path $agentPath) {
51
- $agentContent = Get-Content $agentPath -Raw
52
- $skillDir = Join-Path (Join-Path $PackageRoot "harness") "skills"
53
- $actualCount = (Get-ChildItem $skillDir -Directory).Count
54
-
55
- # Skill count check
56
- if ($agentContent -match '## Skills \((\d+)\)') {
57
- $claimedCount = [int]$Matches[1]
58
- if ($claimedCount -eq $actualCount) {
59
- Write-Check -Id "agentsmd.skill_count" -Name "AGENTS.md skill count" -Status PASS `
60
- -Detail "Claims $claimedCount, filesystem has $actualCount" `
61
- -Evidence @{ file = $agentPath; claimed = $claimedCount; actual = $actualCount }
62
- } else {
63
- Write-Check -Id "agentsmd.skill_count" -Name "AGENTS.md skill count" -Status FAIL `
64
- -Severity high -Detail "Claims $claimedCount but filesystem has $actualCount" `
65
- -Evidence @{ file = $agentPath; claimed = $claimedCount; actual = $actualCount } `
66
- -Fix @{ auto = $true; command = "Update AGENTS.md header from ${claimedCount} skills to ${actualCount} skills" }
67
- }
68
- } else {
69
- Write-Check -Id "agentsmd.skill_count" -Name "AGENTS.md skill count" -Status WARN `
70
- -Detail "Could not parse skill count from AGENTS.md" `
71
- -Evidence @{ file = $agentPath }
72
- }
73
-
74
- # logger.ts reference
75
- $libDir = Join-Path $PackageRoot "lib"
76
- $libFiles = Get-ChildItem $libDir -File | ForEach-Object { $_.Name }
77
- if ($agentContent -match "logger\.ts") {
78
- if ($libFiles -contains "logger.ts") {
79
- Write-Check -Id "agentsmd.logger_ref" -Name "AGENTS.md logger.ts reference" -Status PASS `
80
- -Detail "logger.ts exists in lib/" `
81
- -Evidence @{ file = $agentPath }
82
- } else {
83
- $actualList = $libFiles -join ","
84
- Write-Check -Id "agentsmd.logger_ref" -Name "AGENTS.md logger.ts reference" -Status FAIL `
85
- -Severity high -Detail "Claims logger.ts but file does not exist" `
86
- -Evidence @{ file = $agentPath; claimed = "logger.ts"; onDisk = $actualList } `
87
- -Fix @{ auto = $true; command = "Remove 'logger.ts' from AGENTS.md" }
88
- }
89
- }
90
-
91
- # SHELL.md reference
92
- $instDir = Join-Path (Join-Path $PackageRoot "harness") "instructions"
93
- $hasShell = Test-Path (Join-Path $instDir "SHELL.md")
94
- if ($agentContent -match "SHELL\.md") {
95
- if ($hasShell) {
96
- Write-Check -Id "agentsmd.shell_ref" -Name "AGENTS.md SHELL.md reference" -Status PASS `
97
- -Detail "SHELL.md referenced and exists on disk" `
98
- -Evidence @{ file = $agentPath; referenced = "SHELL.md" }
99
- } else {
100
- Write-Check -Id "agentsmd.shell_ref" -Name "AGENTS.md SHELL.md reference" -Status WARN `
101
- -Severity medium -Detail "SHELL.md referenced but missing from disk" `
102
- -Evidence @{ file = $agentPath; referenced = "SHELL.md" }
103
- }
104
- } elseif ($hasShell) {
105
- Write-Check -Id "agentsmd.shell_ref" -Name "AGENTS.md SHELL.md reference" -Status WARN `
106
- -Severity low -Detail "SHELL.md exists on disk but AGENTS.md does not mention it" `
107
- -Evidence @{ file = $agentPath; onDisk = "harness/instructions/SHELL.md" }
108
- }
109
- } else {
110
- Write-Check -Id "agentsmd.exists" -Name "AGENTS.md exists" -Status FAIL -Severity high `
111
- -Detail "File not found at ${agentPath}" `
112
- -Evidence @{ path = $agentPath }
113
- }
114
-
115
- # ============================================================
116
- # CHECK 2: package.json files integrity
117
- # ============================================================
118
- $pkgPath = Join-Path $PackageRoot "package.json"
119
- if (Test-Path $pkgPath) {
120
- $pkg = Get-Content $pkgPath -Raw | ConvertFrom-Json
121
- $missing = @()
122
- $found = @()
123
- foreach ($entry in $pkg.files) {
124
- $resolved = Join-Path $PackageRoot $entry
125
- if (Test-Path $resolved) { $found += $entry }
126
- else { $missing += $entry }
127
- }
128
- if ($missing.Count -eq 0) {
129
- Write-Check -Id "pkg.files_integrity" -Name "package.json files field" -Status PASS `
130
- -Detail "All $($pkg.files.Count) entries exist on disk" `
131
- -Evidence @{ file = $pkgPath; entries = @($pkg.files) }
132
- } else {
133
- Write-Check -Id "pkg.files_integrity" -Name "package.json files field" -Status FAIL `
134
- -Severity high -Detail "$($missing.Count) entry(s) missing: $($missing -join ',')" `
135
- -Evidence @{ file = $pkgPath; missing = $missing } `
136
- -Fix @{ auto = $false; command = "Create or remove from files: $($missing -join ',')" }
137
- }
138
- } else {
139
- Write-Check -Id "pkg.exists" -Name "package.json exists" -Status FAIL -Severity high `
140
- -Detail "File not found at ${pkgPath}" `
141
- -Evidence @{ path = $pkgPath }
142
- }
143
-
144
- # ============================================================
145
- # CHECK 3: Harness resolver prerequisites
146
- # ============================================================
147
- # Hardcode the exact known paths — no array gymnastics
148
- $hDir = Join-Path $PackageRoot "harness"
149
- $requiredFiles = @(
150
- ,@("codex", "CHARTER.md")
151
- ,@("instructions", "SHELL.md")
152
- ,@("skills", "oh-planner", "SKILL.md")
153
- )
154
- $allOk = $true
155
- $missingReq = @()
156
- foreach ($pair in $requiredFiles) {
157
- $path = Join-Path $hDir (Join-Path $pair[0] $pair[1])
158
- if (-not (Test-Path $path)) {
159
- $allOk = $false
160
- $missingReq += ($pair[0] + "/" + $pair[1])
161
- }
162
- }
163
- if ($allOk) {
164
- Write-Check -Id "harness.required_files" -Name "Harness resolver prerequisites" -Status PASS `
165
- -Detail "All 3 required files resolve" `
166
- -Evidence @{ root = $hDir; required = @("codex/CHARTER.md","codex/AUTOPILOT.md","skills/oh-planner/SKILL.md") }
167
- } else {
168
- Write-Check -Id "harness.required_files" -Name "Harness resolver prerequisites" -Status FAIL `
169
- -Severity high -Detail "Missing: $($missingReq -join ',')" `
170
- -Evidence @{ root = $hDir; missing = $missingReq } `
171
- -Fix @{ auto = $false; command = "Create missing: $($missingReq -join ',')" }
172
- }
173
-
174
- # ============================================================
175
- # CHECK 4: Test health (direct & call from PowerShell — works)
176
- # ============================================================
177
- Push-Location $PackageRoot
178
- $testOut = & "bun" "test" 2>&1 | Out-String
179
- Pop-Location
180
- $passCount = 0; $failCount = 0; $totalCount = 0
181
- if ($testOut -match '(\d+) pass') { $passCount = [int]$Matches[1] }
182
- if ($testOut -match '(\d+) fail') { $failCount = [int]$Matches[1] }
183
- if ($testOut -match 'Ran (\d+) tests') { $totalCount = [int]$Matches[1] }
184
-
185
- if ($failCount -eq 0 -and $totalCount -gt 0) {
186
- Write-Check -Id "test.health" -Name "Test health" -Status PASS `
187
- -Severity high -Detail "$passCount pass, $failCount fail ($totalCount total)" `
188
- -Evidence @{ pass = $passCount; fail = $failCount; total = $totalCount }
189
- } elseif ($totalCount -eq 0) {
190
- $truncated = $testOut.Substring(0, [Math]::Min(200, $testOut.Length))
191
- Write-Check -Id "test.health" -Name "Test health" -Status FAIL `
192
- -Severity high -Detail "No test output" `
193
- -Evidence @{ outputTruncated = $truncated } `
194
- -Fix @{ auto = $false; command = "bun test" }
195
- } else {
196
- $truncated = $testOut.Substring(0, [Math]::Min(500, $testOut.Length))
197
- Write-Check -Id "test.health" -Name "Test health" -Status FAIL `
198
- -Severity high -Detail "$passCount pass, $failCount fail ($totalCount total)" `
199
- -Evidence @{ pass = $passCount; fail = $failCount; total = $totalCount; outputTruncated = $truncated } `
200
- -Fix @{ auto = $false; command = "bun test" }
201
- }
202
-
203
- # ============================================================
204
- # CHECK 5: TypeScript compilation
205
- # ============================================================
206
- Push-Location $PackageRoot
207
- $tscOut = & "bunx" "tsc" "--noEmit" 2>&1 | Out-String
208
- Pop-Location
209
- if ([string]::IsNullOrWhiteSpace($tscOut) -or $tscOut.Trim() -eq "") {
210
- Write-Check -Id "tsc.compilation" -Name "TypeScript compilation" -Status PASS `
211
- -Severity high -Detail "Clean compilation (strict mode, noEmit)" `
212
- -Evidence @{ command = "bunx tsc --noEmit"; errors = 0 }
213
- } else {
214
- $errorCount = ($tscOut.Trim() -split "`n").Count
215
- $truncated = $tscOut.Substring(0, [Math]::Min(1000, $tscOut.Length))
216
- Write-Check -Id "tsc.compilation" -Name "TypeScript compilation" -Status FAIL `
217
- -Severity high -Detail "$errorCount error(s)" `
218
- -Evidence @{ command = "bunx tsc --noEmit"; errors = $errorCount; outputTruncated = $truncated } `
219
- -Fix @{ auto = $false; command = "bunx tsc --noEmit" }
220
- }
221
-
222
- # ============================================================
223
- # CHECK 6: No secrets in repo
224
- # ============================================================
225
- $patterns = @("*.env*", "*.key", "*secret*", "credentials*", "auth.json", "*.pem")
226
- $secretsFound = @()
227
- foreach ($pattern in $patterns) {
228
- $matches = Get-ChildItem -Path $PackageRoot -Recurse -Filter $pattern -ErrorAction SilentlyContinue `
229
- | Where-Object { -not ($_.FullName -like "*node_modules*") }
230
- foreach ($m in $matches) { $secretsFound += $m.FullName }
231
- }
232
- if ($secretsFound.Count -eq 0) {
233
- Write-Check -Id "security.secrets" -Name "No secrets in repo" -Status PASS `
234
- -Severity high -Detail "No .env, *.key, credentials, or auth.json found" `
235
- -Evidence @{ patternsScanned = $patterns; found = @() }
236
- } else {
237
- Write-Check -Id "security.secrets" -Name "No secrets in repo" -Status FAIL `
238
- -Severity high -Detail "Found $($secretsFound.Count) sensitive file(s)" `
239
- -Evidence @{ patternsScanned = $patterns; found = $secretsFound } `
240
- -Fix @{ auto = $false; command = "Remove sensitive files and update .gitignore" }
241
- }
242
-
243
- # ============================================================
244
- # CHECK 7: .gitignore coverage
245
- # ============================================================
246
- $gitignorePath = Join-Path $PackageRoot ".gitignore"
247
- if (Test-Path $gitignorePath) {
248
- $gitignoreContent = Get-Content $gitignorePath -Raw
249
- $expected = @("node_modules", ".config", ".opencode", "PLAN.d", "coverage", "*.tgz")
250
- $missing = @()
251
- $present = @()
252
- foreach ($e in $expected) {
253
- if ($gitignoreContent -match [regex]::Escape($e)) { $present += $e }
254
- else { $missing += $e }
255
- }
256
- if ($missing.Count -eq 0) {
257
- Write-Check -Id "safety.gitignore" -Name ".gitignore coverage" -Status PASS `
258
- -Severity medium -Detail "All expected entries present" `
259
- -Evidence @{ file = $gitignorePath; entries = $expected }
260
- } else {
261
- Write-Check -Id "safety.gitignore" -Name ".gitignore coverage" -Status WARN `
262
- -Severity medium -Detail "Missing: $($missing -join ',')" `
263
- -Evidence @{ file = $gitignorePath; present = $present; missing = $missing }
264
- }
265
- } else {
266
- Write-Check -Id "safety.gitignore" -Name ".gitignore exists" -Status FAIL -Severity high `
267
- -Detail "File not found at ${gitignorePath}" `
268
- -Evidence @{ path = $gitignorePath }
269
- }
270
-
271
- # ============================================================
272
- # CHECK 8-10: Runtime state via opencode CLI
273
- # ============================================================
274
- if (-not $SkipOCChecks) {
275
- $pathsOut = & "opencode" "debug" "paths" 2>&1 | Out-String
276
- if ($LASTEXITCODE -eq 0 -and $pathsOut.Trim().Length -gt 0) {
277
- Write-Check -Id "oc.paths" -Name "opencode paths" -Status PASS -Severity low `
278
- -Detail "Paths resolved" -Evidence @{ raw = $pathsOut.Trim() }
279
- } else {
280
- Write-Check -Id "oc.paths" -Name "opencode paths" -Status SKIP -Severity low `
281
- -Detail "opencode CLI not available (exit $LASTEXITCODE)" `
282
- -Evidence @{ exitCode = $LASTEXITCODE }
283
- }
284
-
285
- $configOut = & "opencode" "debug" "config" 2>&1 | Out-String
286
- if ($LASTEXITCODE -eq 0 -and $configOut.Trim().Length -gt 0) {
287
- $hasPlugin = $configOut -match "openhermes"
288
- Write-Check -Id "oc.plugin_loaded" -Name "OpenHermes plugin loaded" -Status $(if ($hasPlugin) { "PASS" } else { "FAIL" }) `
289
- -Severity high -Detail $(if ($hasPlugin) { "Found in resolved config" } else { "Not found in resolved config" }) `
290
- -Evidence @{ pluginName = "openhermes"; found = $hasPlugin }
291
- } else {
292
- Write-Check -Id "oc.plugin_loaded" -Name "OpenHermes plugin loaded" -Status SKIP -Severity high `
293
- -Detail "Could not read config (exit $LASTEXITCODE)" `
294
- -Evidence @{ exitCode = $LASTEXITCODE }
295
- }
296
-
297
- $skillOut = & "opencode" "debug" "skill" 2>&1 | Out-String
298
- if ($LASTEXITCODE -eq 0 -and $skillOut.Trim().Length -gt 0) {
299
- $ohCount = @($skillOut | Select-String -Pattern "oh-").Count
300
- Write-Check -Id "oc.skills_discovered" -Name "OH skills discovered" -Status $(if ($ohCount -ge 30) { "PASS" } else { "WARN" }) `
301
- -Severity high -Detail "$ohCount oh-* skills found (expected >= 30)" `
302
- -Evidence @{ count = $ohCount; minExpected = 30 }
303
- } else {
304
- Write-Check -Id "oc.skills_discovered" -Name "OH skills discovered" -Status SKIP -Severity high `
305
- -Detail "Could not list skills (exit $LASTEXITCODE)" `
306
- -Evidence @{ exitCode = $LASTEXITCODE }
307
- }
308
- } else {
309
- Write-Check -Id "oc.paths" -Name "opencode paths" -Status SKIP -Severity low -Detail "Skipped" -Evidence @{ flag = "SkipOCChecks" }
310
- Write-Check -Id "oc.plugin_loaded" -Name "OpenHermes plugin loaded" -Status SKIP -Severity high -Detail "Skipped" -Evidence @{ flag = "SkipOCChecks" }
311
- Write-Check -Id "oc.skills_discovered" -Name "OH skills discovered" -Status SKIP -Severity high -Detail "Skipped" -Evidence @{ flag = "SkipOCChecks" }
312
- }
313
-
314
- # ============================================================
315
- # SUMMARY
316
- # ============================================================
317
- $passCount = ($script:checks | Where-Object { $_.status -eq "PASS" }).Count
318
- $warnCount = ($script:checks | Where-Object { $_.status -eq "WARN" }).Count
319
- $failCount = ($script:checks | Where-Object { $_.status -eq "FAIL" }).Count
320
- $skipCount = ($script:checks | Where-Object { $_.status -eq "SKIP" }).Count
321
-
322
- $verdict = if ($failCount -gt 0) { "HAS_FAILURES" } elseif ($warnCount -gt 0) { "HAS_WARNINGS" } else { "ALL_CLEAN" }
323
-
324
- $routing = switch ($verdict) {
325
- "ALL_CLEAN" { "proceed" }
326
- "HAS_WARNINGS" { "proceed_with_caution" }
327
- "HAS_FAILURES" { "investigate" }
328
- }
329
-
330
- $summary = @{
331
- verdict = $verdict
332
- summary = @{
333
- pass = $passCount
334
- warn = $warnCount
335
- fail = $failCount
336
- skip = $skipCount
337
- total = ($passCount + $warnCount + $failCount + $skipCount)
338
- }
339
- routing = $routing
340
- }
341
-
342
- $summary | ConvertTo-Json -Compress -Depth 3