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.
- package/CONTEXT.md +1 -1
- package/README.md +32 -31
- package/bootstrap.ts +262 -45
- package/harness/agents/oh-planner.md +1 -1
- package/harness/agents/openhermes.md +27 -126
- package/harness/codex/AUTOPILOT.md +99 -3
- package/harness/codex/CHARTER.md +3 -4
- package/harness/lib/background/background.test.ts +197 -0
- package/harness/lib/background/index.ts +7 -0
- package/harness/lib/background/interfaces.ts +31 -0
- package/harness/lib/background/manager.ts +320 -0
- package/harness/lib/composer/compose.test.ts +168 -0
- package/harness/lib/composer/compose.ts +65 -0
- package/harness/lib/composer/fragments/01-identity.md +1 -0
- package/harness/lib/composer/fragments/02-delegation.md +6 -0
- package/harness/lib/composer/fragments/03-permissions.md +13 -0
- package/harness/lib/composer/fragments/04-task-flow.md +15 -0
- package/harness/lib/composer/fragments/05-confidence.md +5 -0
- package/harness/lib/composer/fragments/06-parallelization.md +17 -0
- package/harness/lib/composer/fragments/07-shell.md +41 -0
- package/harness/lib/composer/fragments/08-routing.md +8 -0
- package/harness/lib/composer/fragments/09-guardrails.md +12 -0
- package/harness/lib/composer/index.ts +1 -0
- package/harness/lib/hooks/builtins/confidence-gate-hook.ts +70 -0
- package/harness/lib/hooks/builtins/delegation-depth-hook.ts +59 -0
- package/harness/lib/hooks/builtins/error-recovery-hook.ts +107 -0
- package/harness/lib/hooks/builtins/memory-sync-hook.ts +73 -0
- package/harness/lib/hooks/builtins/plan-check-hook.ts +43 -0
- package/harness/lib/hooks/builtins/route-tracking-hook.ts +147 -0
- package/harness/lib/hooks/builtins/sanity-check-hook.ts +52 -0
- package/harness/lib/hooks/builtins/shell-detect-hook.ts +96 -0
- package/harness/lib/hooks/hooks.test.ts +1016 -0
- package/harness/lib/hooks/index.ts +30 -0
- package/harness/lib/hooks/registry.ts +416 -0
- package/harness/lib/hooks/types.ts +71 -0
- package/harness/lib/memory/index.ts +18 -0
- package/harness/lib/memory/interfaces.ts +53 -0
- package/harness/lib/memory/memory-manager.ts +205 -0
- package/harness/lib/memory/memory.test.ts +491 -0
- package/harness/lib/memory/plan-store.ts +366 -0
- package/harness/lib/recovery/handler.ts +243 -0
- package/harness/lib/recovery/index.ts +14 -0
- package/harness/lib/recovery/interfaces.ts +48 -0
- package/harness/lib/recovery/patterns.ts +149 -0
- package/harness/lib/recovery/recovery.test.ts +312 -0
- package/harness/lib/sanity/anomaly-tracker.ts +127 -0
- package/harness/lib/sanity/checker.ts +178 -0
- package/harness/lib/sanity/index.ts +13 -0
- package/harness/lib/sanity/interfaces.ts +24 -0
- package/harness/lib/sanity/sanity.test.ts +472 -0
- package/harness/lib/sync/file-watcher.ts +174 -0
- package/harness/lib/sync/index.ts +11 -0
- package/harness/lib/sync/interfaces.ts +27 -0
- package/harness/lib/sync/plan-sync.ts +536 -0
- package/harness/lib/sync/sync.test.ts +832 -0
- package/harness/skills/oh-init/DEEP.md +2 -2
- package/harness/skills/oh-manifest/SKILL.md +1 -1
- package/harness/skills/oh-plan-review/DEEP.md +1 -1
- package/harness/skills/oh-planner/DEEP.md +3 -3
- package/harness/skills/oh-ship/SKILL.md +1 -1
- package/harness/skills/oh-skill-craft/SKILL.md +1 -4
- package/package.json +5 -5
- package/tsconfig.json +1 -1
- package/harness/commands/oh-doctor.md +0 -205
- package/harness/commands/oh-log.md +0 -18
- package/harness/skills/oh-learn/DEEP.md +0 -44
- package/harness/skills/oh-learn/SKILL.md +0 -30
- package/scripts/count-tokens.mjs +0 -158
- package/scripts/oh-doctor.ps1 +0 -342
package/scripts/oh-doctor.ps1
DELETED
|
@@ -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
|