openhermes 4.3.0 → 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 (143) hide show
  1. package/CONTEXT.md +10 -1
  2. package/README.md +54 -42
  3. package/bootstrap.ts +396 -142
  4. package/harness/agents/oh-browser.md +97 -0
  5. package/harness/agents/oh-builder.md +78 -0
  6. package/harness/agents/oh-facade.md +75 -0
  7. package/harness/agents/oh-fusion.md +45 -0
  8. package/harness/agents/oh-gauntlet.md +71 -0
  9. package/harness/agents/oh-grill.md +71 -0
  10. package/harness/agents/oh-investigate.md +60 -0
  11. package/harness/agents/oh-manifest.md +95 -0
  12. package/harness/agents/oh-plan-review.md +40 -0
  13. package/harness/agents/oh-planner.md +50 -0
  14. package/harness/agents/oh-refactor.md +37 -0
  15. package/harness/agents/oh-retro.md +46 -0
  16. package/harness/agents/oh-review.md +85 -0
  17. package/harness/agents/oh-security.md +83 -0
  18. package/harness/agents/oh-ship.md +76 -0
  19. package/harness/agents/oh-skill-craft.md +38 -0
  20. package/harness/agents/openhermes.md +28 -73
  21. package/harness/codex/AUTOPILOT.md +235 -87
  22. package/harness/codex/CHARTER.md +80 -0
  23. package/harness/instructions/SHELL.md +76 -0
  24. package/harness/lib/background/background.test.ts +197 -0
  25. package/harness/lib/background/index.ts +7 -0
  26. package/harness/lib/background/interfaces.ts +31 -0
  27. package/harness/lib/background/manager.ts +320 -0
  28. package/harness/lib/composer/compose.test.ts +168 -0
  29. package/harness/lib/composer/compose.ts +65 -0
  30. package/harness/lib/composer/fragments/01-identity.md +1 -0
  31. package/harness/lib/composer/fragments/02-delegation.md +6 -0
  32. package/harness/lib/composer/fragments/03-permissions.md +13 -0
  33. package/harness/lib/composer/fragments/04-task-flow.md +15 -0
  34. package/harness/lib/composer/fragments/05-confidence.md +5 -0
  35. package/harness/lib/composer/fragments/06-parallelization.md +17 -0
  36. package/harness/lib/composer/fragments/07-shell.md +41 -0
  37. package/harness/lib/composer/fragments/08-routing.md +8 -0
  38. package/harness/lib/composer/fragments/09-guardrails.md +12 -0
  39. package/harness/lib/composer/index.ts +1 -0
  40. package/harness/lib/hooks/builtins/confidence-gate-hook.ts +70 -0
  41. package/harness/lib/hooks/builtins/delegation-depth-hook.ts +59 -0
  42. package/harness/lib/hooks/builtins/error-recovery-hook.ts +107 -0
  43. package/harness/lib/hooks/builtins/memory-sync-hook.ts +73 -0
  44. package/harness/lib/hooks/builtins/plan-check-hook.ts +43 -0
  45. package/harness/lib/hooks/builtins/route-tracking-hook.ts +147 -0
  46. package/harness/lib/hooks/builtins/sanity-check-hook.ts +52 -0
  47. package/harness/lib/hooks/builtins/shell-detect-hook.ts +96 -0
  48. package/harness/lib/hooks/hooks.test.ts +1016 -0
  49. package/harness/lib/hooks/index.ts +30 -0
  50. package/harness/lib/hooks/registry.ts +416 -0
  51. package/harness/lib/hooks/types.ts +71 -0
  52. package/harness/lib/memory/index.ts +18 -0
  53. package/harness/lib/memory/interfaces.ts +53 -0
  54. package/harness/lib/memory/memory-manager.ts +205 -0
  55. package/harness/lib/memory/memory.test.ts +491 -0
  56. package/harness/lib/memory/plan-store.ts +366 -0
  57. package/harness/lib/recovery/handler.ts +243 -0
  58. package/harness/lib/recovery/index.ts +14 -0
  59. package/harness/lib/recovery/interfaces.ts +48 -0
  60. package/harness/lib/recovery/patterns.ts +149 -0
  61. package/harness/lib/recovery/recovery.test.ts +312 -0
  62. package/harness/lib/sanity/anomaly-tracker.ts +127 -0
  63. package/harness/lib/sanity/checker.ts +178 -0
  64. package/harness/lib/sanity/index.ts +13 -0
  65. package/harness/lib/sanity/interfaces.ts +24 -0
  66. package/harness/lib/sanity/sanity.test.ts +472 -0
  67. package/harness/lib/sync/file-watcher.ts +174 -0
  68. package/harness/lib/sync/index.ts +11 -0
  69. package/harness/lib/sync/interfaces.ts +27 -0
  70. package/harness/lib/sync/plan-sync.ts +536 -0
  71. package/harness/lib/sync/sync.test.ts +832 -0
  72. package/harness/skills/oh-ascii/DEEP.md +292 -0
  73. package/harness/skills/oh-ascii/SKILL.md +31 -0
  74. package/harness/skills/oh-ascii/scripts/check_ascii_alignment.py +596 -0
  75. package/harness/skills/oh-browser/DEEP.md +54 -0
  76. package/harness/skills/oh-browser/SKILL.md +30 -0
  77. package/harness/skills/oh-builder/DEEP.md +63 -0
  78. package/harness/skills/oh-builder/SKILL.md +12 -90
  79. package/harness/skills/oh-expert/DEEP.md +85 -0
  80. package/harness/skills/oh-expert/SKILL.md +13 -106
  81. package/harness/skills/oh-facade/DEEP.md +182 -0
  82. package/harness/skills/oh-facade/SKILL.md +15 -279
  83. package/harness/skills/oh-freeze/DEEP.md +18 -0
  84. package/harness/skills/oh-freeze/SKILL.md +10 -19
  85. package/harness/skills/oh-full-output/DEEP.md +25 -0
  86. package/harness/skills/oh-full-output/SKILL.md +12 -65
  87. package/harness/skills/oh-fusion/DEEP.md +120 -0
  88. package/harness/skills/oh-fusion/SKILL.md +17 -295
  89. package/harness/skills/oh-gauntlet/DEEP.md +77 -0
  90. package/harness/skills/oh-gauntlet/SKILL.md +13 -105
  91. package/harness/skills/oh-grill/DEEP.md +51 -0
  92. package/harness/skills/oh-grill/SKILL.md +12 -63
  93. package/harness/skills/oh-guard/DEEP.md +19 -0
  94. package/harness/skills/oh-guard/SKILL.md +10 -24
  95. package/harness/skills/oh-handoff/DEEP.md +48 -0
  96. package/harness/skills/oh-handoff/SKILL.md +13 -23
  97. package/harness/skills/oh-health/DEEP.md +74 -0
  98. package/harness/skills/oh-health/SKILL.md +13 -76
  99. package/harness/skills/oh-init/DEEP.md +85 -0
  100. package/harness/skills/oh-init/SKILL.md +13 -127
  101. package/harness/skills/oh-investigate/DEEP.md +171 -0
  102. package/harness/skills/oh-investigate/SKILL.md +13 -66
  103. package/harness/skills/oh-issue/DEEP.md +21 -0
  104. package/harness/skills/oh-issue/SKILL.md +11 -27
  105. package/harness/skills/oh-manifest/DEEP.md +92 -0
  106. package/harness/skills/oh-manifest/SKILL.md +12 -109
  107. package/harness/skills/oh-plan-review/DEEP.md +90 -0
  108. package/harness/skills/oh-plan-review/SKILL.md +13 -115
  109. package/harness/skills/oh-planner/DEEP.md +172 -0
  110. package/harness/skills/oh-planner/SKILL.md +12 -149
  111. package/harness/skills/oh-prd/DEEP.md +45 -0
  112. package/harness/skills/oh-prd/SKILL.md +10 -26
  113. package/harness/skills/oh-refactor/DEEP.md +122 -0
  114. package/harness/skills/oh-refactor/SKILL.md +17 -410
  115. package/harness/skills/oh-retro/DEEP.md +26 -0
  116. package/harness/skills/oh-retro/SKILL.md +12 -24
  117. package/harness/skills/oh-review/DEEP.md +87 -0
  118. package/harness/skills/oh-review/SKILL.md +11 -97
  119. package/harness/skills/oh-security/DEEP.md +83 -0
  120. package/harness/skills/oh-security/SKILL.md +14 -96
  121. package/harness/skills/oh-ship/DEEP.md +141 -0
  122. package/harness/skills/oh-ship/SKILL.md +14 -32
  123. package/harness/skills/oh-skill-craft/DEEP.md +369 -0
  124. package/harness/skills/oh-skill-craft/SKILL.md +13 -177
  125. package/harness/skills/oh-skills-link/DEEP.md +16 -0
  126. package/harness/skills/oh-skills-link/SKILL.md +10 -20
  127. package/harness/skills/oh-skills-list/DEEP.md +20 -0
  128. package/harness/skills/oh-skills-list/SKILL.md +9 -22
  129. package/harness/skills/oh-triage/DEEP.md +23 -0
  130. package/harness/skills/oh-triage/SKILL.md +8 -24
  131. package/harness/skills/oh-worktree/DEEP.md +169 -0
  132. package/harness/skills/oh-worktree/SKILL.md +32 -0
  133. package/lib/harness-resolver.ts +8 -10
  134. package/package.json +7 -5
  135. package/tsconfig.json +1 -1
  136. package/harness/codex/CONSTITUTION.md +0 -73
  137. package/harness/codex/ROUTING.md +0 -92
  138. package/harness/commands/oh-doctor.md +0 -26
  139. package/harness/commands/oh-log.md +0 -18
  140. package/harness/instructions/RUNTIME.md +0 -30
  141. package/harness/skills/oh-caveman/SKILL.md +0 -42
  142. package/harness/skills/oh-learn/SKILL.md +0 -101
  143. package/lib/logger.ts +0 -75
@@ -0,0 +1,73 @@
1
+ // ---------------------------------------------------------------------------
2
+ // MemorySyncHook — PostToolUse, priority=40, phase=LATE
3
+ //
4
+ // After each step, sync memory entries to plan file.
5
+ // Uses MemoryManager from harness/lib/memory/memory-manager.ts
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import { HookPhase, HookResult } from "../types.ts";
9
+ import type { HookContext, PostToolUseHook } from "../types.ts";
10
+ import { MemoryManager } from "../../memory/memory-manager.ts";
11
+ import { PlanStore } from "../../memory/plan-store.ts";
12
+ import { findLatestPlanFile } from "../../../../bootstrap.ts";
13
+ import { MemoryLevel } from "../../memory/interfaces.ts";
14
+
15
+ export const memorySyncHook: PostToolUseHook = {
16
+ metadata: {
17
+ name: "memory-sync",
18
+ priority: 40,
19
+ phase: HookPhase.LATE,
20
+ dependencies: [],
21
+ errorHandling: "isolate",
22
+ },
23
+
24
+ async execute(context: HookContext, output: string) {
25
+ // Sync memory entries to plan file
26
+ const planFile = findLatestPlanFile(context.directory);
27
+ if (!planFile) {
28
+ // No plan file to sync to — skip silently
29
+ return { result: HookResult.CONTINUE };
30
+ }
31
+
32
+ const mem = MemoryManager.getInstance();
33
+
34
+ // Extract findings from the session memory (TASK level)
35
+ const taskEntries = mem.getEntries(MemoryLevel.TASK);
36
+
37
+ // Sync important task entries as plan findings
38
+ for (const entry of taskEntries) {
39
+ if (entry.importance >= 0.6) {
40
+ try {
41
+ await PlanStore.addFinding(planFile, context.sessionId, {
42
+ description: entry.content,
43
+ severity: entry.importance >= 0.8 ? "warning" : "info",
44
+ });
45
+ } catch {
46
+ // Plan sync is best-effort — don't break execution
47
+ }
48
+ }
49
+ }
50
+
51
+ // Sync any decisions
52
+ const missionEntries = mem.getEntries(MemoryLevel.MISSION);
53
+ for (const entry of missionEntries) {
54
+ if (entry.metadata?.type === "decision" && entry.importance >= 0.7) {
55
+ try {
56
+ await PlanStore.addDecision(planFile, context.sessionId, {
57
+ description: entry.content,
58
+ rationale: (entry.metadata.rationale as string) ?? "Auto-synced decision",
59
+ });
60
+ } catch {
61
+ // Best-effort
62
+ }
63
+ }
64
+ }
65
+
66
+ return {
67
+ result: HookResult.CONTINUE,
68
+ modifiedContext: {
69
+ _memorySyncCount: taskEntries.filter((e) => e.importance >= 0.6).length,
70
+ },
71
+ };
72
+ },
73
+ };
@@ -0,0 +1,43 @@
1
+ // ---------------------------------------------------------------------------
2
+ // PlanCheckHook — PreToolUse, priority=90, phase=EARLY
3
+ //
4
+ // Before any sub-agent call, verify plan file exists at the expected path.
5
+ // If missing, inject "create plan first" instruction.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import { HookPhase, HookResult } from "../types.ts";
9
+ import type { HookContext, PreToolUseHook } from "../types.ts";
10
+ import { findLatestPlanFile } from "../../../../bootstrap.ts";
11
+
12
+ export const planCheckHook: PreToolUseHook = {
13
+ metadata: {
14
+ name: "plan-check",
15
+ priority: 90,
16
+ phase: HookPhase.EARLY,
17
+ dependencies: [],
18
+ errorHandling: "propagate",
19
+ },
20
+
21
+ async execute(context: HookContext) {
22
+ const planFile = findLatestPlanFile(context.directory);
23
+
24
+ if (!planFile) {
25
+ return {
26
+ result: HookResult.INJECT,
27
+ modifiedContext: {
28
+ _planCheck: "missing",
29
+ _planCheckInstruction:
30
+ "No plan file found. Create a plan first before proceeding with any sub-agent tasks.",
31
+ },
32
+ };
33
+ }
34
+
35
+ return {
36
+ result: HookResult.CONTINUE,
37
+ modifiedContext: {
38
+ _planCheck: "found",
39
+ _planFilePath: planFile,
40
+ },
41
+ };
42
+ },
43
+ };
@@ -0,0 +1,147 @@
1
+ // ---------------------------------------------------------------------------
2
+ // RouteTrackingHook — RouteHook, priority=55, phase=LATE
3
+ //
4
+ // Loop guard — mechanically enforce two limits:
5
+ // 1. Same skill visited 5+ times in one chain
6
+ // 2. 8+ consecutive unproductive hops
7
+ // ---------------------------------------------------------------------------
8
+
9
+ import { HookPhase, HookResult } from "../types.ts";
10
+ import type { HookContext, RouteHook } from "../types.ts";
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Types
14
+ // ---------------------------------------------------------------------------
15
+
16
+ export interface HopRecord {
17
+ skill: string;
18
+ timestamp: number;
19
+ producedArtifact: boolean;
20
+ }
21
+
22
+ export interface RouteTrackingConfig {
23
+ maxSkillRepeats: number;
24
+ maxUnproductiveHops: number;
25
+ artifactCheck: (route: string) => boolean | Promise<boolean>;
26
+ }
27
+
28
+ interface RouteTrackingState {
29
+ hops: HopRecord[];
30
+ skillCounts: Map<string, number>;
31
+ unproductiveCount: number;
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Module-level state
36
+ // ---------------------------------------------------------------------------
37
+
38
+ const sessionStates = new Map<string, RouteTrackingState>();
39
+
40
+ export function resetRouteTracker(sessionId?: string): void {
41
+ if (sessionId) {
42
+ sessionStates.delete(sessionId);
43
+ } else {
44
+ sessionStates.clear();
45
+ }
46
+ }
47
+
48
+ export function getHopHistory(sessionId: string): HopRecord[] {
49
+ return sessionStates.get(sessionId)?.hops ?? [];
50
+ }
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Default artifact check (conservative — assumes unproductive)
54
+ // ---------------------------------------------------------------------------
55
+
56
+ const defaultArtifactCheck: (route: string) => boolean = () => false;
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // Hook
60
+ // ---------------------------------------------------------------------------
61
+
62
+ export const routeTrackingHook: RouteHook = {
63
+ metadata: {
64
+ name: "route-tracking",
65
+ priority: 55,
66
+ phase: HookPhase.LATE,
67
+ dependencies: [],
68
+ errorHandling: "propagate",
69
+ },
70
+
71
+ async execute(context: HookContext, route: string) {
72
+ // Skip terminal routes — they don't count as routing hops
73
+ const terminalRoutes = new Set(["surface", "done", "oh-handoff"]);
74
+ if (terminalRoutes.has(route)) {
75
+ return { result: HookResult.CONTINUE, modifiedRoute: route };
76
+ }
77
+
78
+ const sessionId = context.sessionId;
79
+
80
+ // Get or create state for this session
81
+ let state = sessionStates.get(sessionId);
82
+ if (!state) {
83
+ state = {
84
+ hops: [],
85
+ skillCounts: new Map<string, number>(),
86
+ unproductiveCount: 0,
87
+ };
88
+ sessionStates.set(sessionId, state);
89
+ }
90
+
91
+ // Read config from context (or use defaults)
92
+ // Support both `_routeTrackingConfig` and `hooks.route_tracking.*` conventions
93
+ const config =
94
+ (context._routeTrackingConfig ?? {}) as RouteTrackingConfig;
95
+ const maxSkillRepeats = config.maxSkillRepeats ?? 5;
96
+ const maxUnproductiveHops = config.maxUnproductiveHops ?? 8;
97
+ const artifactCheck = config.artifactCheck ?? defaultArtifactCheck;
98
+
99
+ // Record the hop
100
+ const producedArtifact = await artifactCheck(route);
101
+ const hop: HopRecord = {
102
+ skill: route,
103
+ timestamp: Date.now(),
104
+ producedArtifact,
105
+ };
106
+ state.hops.push(hop);
107
+
108
+ // Update skill count
109
+ const currentSkillCount = (state.skillCounts.get(route) ?? 0) + 1;
110
+ state.skillCounts.set(route, currentSkillCount);
111
+
112
+ // Update unproductive counter (resets on any productive hop)
113
+ if (producedArtifact) {
114
+ state.unproductiveCount = 0;
115
+ } else {
116
+ state.unproductiveCount += 1;
117
+ }
118
+
119
+ // Check 1: Same skill repeated too many times
120
+ if (currentSkillCount >= maxSkillRepeats) {
121
+ context._optiRoute = {
122
+ reason: `Same skill "${route}" visited ${currentSkillCount} times (max ${maxSkillRepeats})`,
123
+ chain: [...state.hops],
124
+ skillCounts: Object.fromEntries(state.skillCounts),
125
+ unproductiveCount: state.unproductiveCount,
126
+ maxSkillRepeats,
127
+ maxUnproductiveHops,
128
+ };
129
+ return { result: HookResult.STOP };
130
+ }
131
+
132
+ // Check 2: Too many consecutive unproductive hops
133
+ if (state.unproductiveCount >= maxUnproductiveHops) {
134
+ context._optiRoute = {
135
+ reason: `${state.unproductiveCount} consecutive unproductive hops (max ${maxUnproductiveHops})`,
136
+ chain: [...state.hops],
137
+ skillCounts: Object.fromEntries(state.skillCounts),
138
+ unproductiveCount: state.unproductiveCount,
139
+ maxSkillRepeats,
140
+ maxUnproductiveHops,
141
+ };
142
+ return { result: HookResult.STOP };
143
+ }
144
+
145
+ return { result: HookResult.CONTINUE, modifiedRoute: route };
146
+ },
147
+ };
@@ -0,0 +1,52 @@
1
+ // ---------------------------------------------------------------------------
2
+ // SanityCheckHook — PostToolUse, priority=30, phase=LATE
3
+ //
4
+ // After each tool invocation, check the output for LLM degeneration patterns
5
+ // (repetition, low diversity, gibberish, etc.). Track consecutive anomalies
6
+ // per session. If 2+ consecutive anomalies detected, inject a recovery
7
+ // instruction to compact/refresh context before it cascades.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ import { HookPhase, HookResult } from "../types.ts";
11
+ import type { HookContext, PostToolUseHook } from "../types.ts";
12
+ import { checkOutputSanity } from "../../sanity/checker.ts";
13
+ import { AnomalyTracker } from "../../sanity/anomaly-tracker.ts";
14
+
15
+ export const sanityCheckHook: PostToolUseHook = {
16
+ metadata: {
17
+ name: "sanity-check",
18
+ priority: 30,
19
+ phase: HookPhase.LATE,
20
+ dependencies: [],
21
+ errorHandling: "isolate",
22
+ },
23
+
24
+ async execute(context: HookContext, output: string) {
25
+ const sessionId = context.sessionId;
26
+
27
+ // Run the sanity checker on the output
28
+ const result = checkOutputSanity(output);
29
+
30
+ // Record the result in the anomaly tracker
31
+ const tracker = AnomalyTracker.getInstance();
32
+ const tracking = tracker.record(sessionId, result);
33
+
34
+ if (result.isHealthy) {
35
+ // Output is healthy — no action needed
36
+ return { result: HookResult.CONTINUE };
37
+ }
38
+
39
+ // Unhealthy output detected
40
+ if (tracking.shouldEscalate) {
41
+ // Escalation threshold reached — inject recovery instruction
42
+ return {
43
+ result: HookResult.INJECT,
44
+ modifiedOutput: output,
45
+ injectRecovery: tracking.recoveryMessage ?? "recovery: compact context",
46
+ };
47
+ }
48
+
49
+ // First anomaly (below threshold) — let it pass with a warning
50
+ return { result: HookResult.CONTINUE };
51
+ },
52
+ };
@@ -0,0 +1,96 @@
1
+ // ---------------------------------------------------------------------------
2
+ // ShellDetectHook — PreToolUse, priority=80, phase=EARLY
3
+ //
4
+ // Before sub-agent calls that need CLI, inject SHELL.md preamble.
5
+ // Detect platform, add appropriate shell context.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import { HookPhase, HookResult } from "../types.ts";
9
+ import type { HookContext, PreToolUseHook } from "../types.ts";
10
+ import { getHarnessDir } from "../../../../lib/harness-resolver.ts";
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import os from "node:os";
14
+
15
+ export const shellDetectHook: PreToolUseHook = {
16
+ metadata: {
17
+ name: "shell-detect",
18
+ priority: 80,
19
+ phase: HookPhase.EARLY,
20
+ dependencies: [],
21
+ errorHandling: "isolate",
22
+ },
23
+
24
+ async execute(context: HookContext) {
25
+ const platform = os.platform();
26
+ const isWindows = platform === "win32";
27
+
28
+ // Detect shell type
29
+ let shellType = "unknown";
30
+ if (isWindows) {
31
+ // On Windows: detect PowerShell, CMD, or Git Bash
32
+ const comSpec = process.env.COMSPEC ?? "";
33
+ if (process.env.PSModulePath || process.env.PSExecutionPolicy) {
34
+ shellType = "powershell";
35
+ } else if (comSpec.toLowerCase().includes("cmd")) {
36
+ shellType = "cmd";
37
+ } else {
38
+ // Could be Git Bash
39
+ shellType = process.env.BASH ? "bash" : "powershell";
40
+ }
41
+ } else {
42
+ shellType = "bash";
43
+ }
44
+
45
+ // Try to load SHELL.md
46
+ let shellPreamble = "";
47
+ try {
48
+ const shellDocPath = path.join(getHarnessDir(), "instructions", "SHELL.md");
49
+ await fs.promises.access(shellDocPath);
50
+ shellPreamble = (await fs.promises.readFile(shellDocPath, "utf8")).trim();
51
+ } catch {
52
+ // If SHELL.md can't be read, provide minimal preamble
53
+ shellPreamble = "";
54
+ }
55
+
56
+ return {
57
+ result: HookResult.CONTINUE,
58
+ modifiedContext: {
59
+ _shellPlatform: platform,
60
+ _shellType: shellType,
61
+ _shellPreamble: shellPreamble || getDefaultPreamble(shellType, platform),
62
+ },
63
+ };
64
+ },
65
+ };
66
+
67
+ function getDefaultPreamble(shellType: string, _platform: string): string {
68
+ if (shellType === "powershell") {
69
+ return [
70
+ "## Shell Environment",
71
+ "",
72
+ "Detected: PowerShell on Windows",
73
+ "- File ops, scoop installs, ps1 scripts, env vars → PowerShell",
74
+ "- git, bun, npm, node → any shell (all work)",
75
+ "- rm -rf, make, unix scripts → Git Bash",
76
+ "",
77
+ ].join("\n");
78
+ }
79
+ if (shellType === "cmd") {
80
+ return [
81
+ "## Shell Environment",
82
+ "",
83
+ "Detected: CMD on Windows",
84
+ "- .bat/.cmd scripts → CMD",
85
+ "- git, bun, npm, node → any shell",
86
+ "",
87
+ ].join("\n");
88
+ }
89
+ return [
90
+ "## Shell Environment",
91
+ "",
92
+ `Detected: ${shellType}`,
93
+ "- Standard POSIX shell commands available",
94
+ "",
95
+ ].join("\n");
96
+ }