codehere 0.2.2 → 0.3.0-rc.10

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 (238) 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 +261 -1224
  5. package/dist/infrastructure/config/product-context.js +7 -6
  6. package/dist/infrastructure/hooks/claude-sdk-hook.js +348 -72
  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/conductor-adapter.js +340 -0
  16. package/dist/infrastructure/orchestration/generic-cli-adapter.js +553 -0
  17. package/dist/infrastructure/orchestration/opencode-adapter.js +275 -0
  18. package/dist/infrastructure/orchestration/progress-aggregator.js +189 -0
  19. package/dist/infrastructure/orchestration/readiness.js +106 -0
  20. package/dist/infrastructure/orchestration/session-manager.js +278 -0
  21. package/dist/infrastructure/orchestration/session-persistence.js +109 -0
  22. package/dist/infrastructure/protocols/mcp-helpers.js +10 -30
  23. package/dist/infrastructure/protocols/mcp-server-impl.js +359 -21
  24. package/dist/infrastructure/protocols/probe-port.js +36 -0
  25. package/dist/infrastructure/protocols/ui-page.js +1827 -0
  26. package/dist/infrastructure/security/file-collection.js +115 -0
  27. package/dist/infrastructure/security/trust-scorer.js +301 -56
  28. package/dist/infrastructure/storage/task-repository.js +8 -7
  29. package/dist/monitoring.js +9 -38
  30. package/dist/presentation/cli/commands/help-command.js +96 -139
  31. package/dist/presentation/cli/commands/hook-command.js +17 -24
  32. package/dist/presentation/cli/commands/report-command.js +59 -72
  33. package/dist/presentation/cli/commands/setup-command.js +4 -4
  34. package/dist/presentation/cli/commands/status-command.js +321 -30
  35. package/dist/presentation/cli/commands/trust-command.js +84 -72
  36. package/dist/presentation/cli/error-display.js +17 -21
  37. package/dist/presentation/cli/repl.js +474 -0
  38. package/dist/ui.js +11 -11
  39. package/package.json +24 -62
  40. package/dist/agents/base.js +0 -101
  41. package/dist/agents/orchestrator-model-driven.js +0 -141
  42. package/dist/agents/react-orchestrator-agent.js +0 -54
  43. package/dist/application/agents/execution-agent.js +0 -508
  44. package/dist/application/agents/multi-agent-orchestrator.js +0 -295
  45. package/dist/application/agents/planning-agent.js +0 -433
  46. package/dist/application/agents/validation-agent.js +0 -317
  47. package/dist/application/architectures/plan-and-act.js +0 -242
  48. package/dist/application/index.js +0 -12
  49. package/dist/application/services/agent-factory.js +0 -28
  50. package/dist/application/services/dependency-container.js +0 -596
  51. package/dist/application/services/git-context-service.js +0 -83
  52. package/dist/application/services/intelligent-router.js +0 -934
  53. package/dist/application/services/tool-executor-service.js +0 -94
  54. package/dist/application/use-cases/ask-question-use-case.js +0 -338
  55. package/dist/application/use-cases/edit-file-use-case.js +0 -830
  56. package/dist/application/use-cases/explain-file-use-case.js +0 -50
  57. package/dist/application/use-cases/index-codebase-use-case.js +0 -113
  58. package/dist/application/use-cases/planning-use-case.js +0 -276
  59. package/dist/application/use-cases/react-orchestration-use-case.js +0 -329
  60. package/dist/application/use-cases/reflexion-use-case.js +0 -30
  61. package/dist/application/workflows/deterministic-workflows.js +0 -189
  62. package/dist/ast-parser.js +0 -331
  63. package/dist/cache.js +0 -180
  64. package/dist/chat.js +0 -251
  65. package/dist/code-analysis.js +0 -327
  66. package/dist/context.js +0 -187
  67. package/dist/docs.js +0 -146
  68. package/dist/domain/entities/code-chunk.js +0 -6
  69. package/dist/domain/entities/decision.js +0 -9
  70. package/dist/domain/entities/edit.js +0 -6
  71. package/dist/domain/entities/knowledge-node.js +0 -9
  72. package/dist/domain/entities/knowledge-preservation.js +0 -10
  73. package/dist/domain/entities/memory.js +0 -6
  74. package/dist/domain/entities/pattern.js +0 -7
  75. package/dist/domain/entities/plan.js +0 -6
  76. package/dist/domain/entities/query.js +0 -6
  77. package/dist/domain/errors/embeddings-not-found-error.js +0 -13
  78. package/dist/domain/index.js +0 -19
  79. package/dist/domain/interfaces/ai-service.interface.js +0 -6
  80. package/dist/domain/interfaces/code-analyzer.interface.js +0 -6
  81. package/dist/domain/interfaces/decision-repository.interface.js +0 -9
  82. package/dist/domain/interfaces/embedding-repository.interface.js +0 -6
  83. package/dist/domain/interfaces/knowledge-graph-repository.interface.js +0 -9
  84. package/dist/domain/interfaces/knowledge-preservation-repository.interface.js +0 -8
  85. package/dist/domain/interfaces/memory-repository.interface.js +0 -6
  86. package/dist/domain/interfaces/pattern-repository.interface.js +0 -6
  87. package/dist/domain/interfaces/verification-service.interface.js +0 -6
  88. package/dist/domain/services/cross-team-pattern-sharing.js +0 -125
  89. package/dist/domain/services/decision-recorder.js +0 -223
  90. package/dist/domain/services/decision-retriever.js +0 -133
  91. package/dist/domain/services/environment-mode-manager.js +0 -22
  92. package/dist/domain/services/graded-memory-activation.js +0 -69
  93. package/dist/domain/services/knowledge-access.js +0 -132
  94. package/dist/domain/services/knowledge-extractor.js +0 -247
  95. package/dist/domain/services/knowledge-graph-builder.js +0 -268
  96. package/dist/domain/services/knowledge-graph-query.js +0 -187
  97. package/dist/domain/services/memory-retriever.js +0 -82
  98. package/dist/domain/services/memory-synthesizer.js +0 -91
  99. package/dist/domain/services/pattern-extractor.js +0 -442
  100. package/dist/domain/services/query-intent-classifier.js +0 -140
  101. package/dist/domain/services/react-loop.js +0 -186
  102. package/dist/domain/services/risk-tier-detector.js +0 -78
  103. package/dist/edit.js +0 -319
  104. package/dist/embed.js +0 -459
  105. package/dist/formatter.js +0 -168
  106. package/dist/git.js +0 -198
  107. package/dist/infrastructure/ai/cohere-ai-service.js +0 -607
  108. package/dist/infrastructure/ai/command-r-evaluation.js +0 -206
  109. package/dist/infrastructure/ai/model-config.js +0 -84
  110. package/dist/infrastructure/ai/provider-ai-service.js +0 -477
  111. package/dist/infrastructure/cache/embedding-cache.js +0 -175
  112. package/dist/infrastructure/cache/query-result-cache.js +0 -66
  113. package/dist/infrastructure/cache/response-cache.js +0 -48
  114. package/dist/infrastructure/cache/security-scan-cache.js +0 -47
  115. package/dist/infrastructure/chunking/ast-code-chunker.js +0 -19
  116. package/dist/infrastructure/chunking/code-aware-chunker.js +0 -397
  117. package/dist/infrastructure/context/context-compressor.js +0 -329
  118. package/dist/infrastructure/context/conversation-context.js +0 -128
  119. package/dist/infrastructure/context/session-manager.js +0 -94
  120. package/dist/infrastructure/cost/cost-tracker.js +0 -360
  121. package/dist/infrastructure/file-scanner/file-scanner.js +0 -106
  122. package/dist/infrastructure/governance/nist-ai-rmf.js +0 -292
  123. package/dist/infrastructure/governance/policy-as-code.js +0 -258
  124. package/dist/infrastructure/governance/prompt-to-code-lineage.js +0 -239
  125. package/dist/infrastructure/index.js +0 -7
  126. package/dist/infrastructure/observability/prompt-versioner.js +0 -145
  127. package/dist/infrastructure/protocols/a2a-metadata.js +0 -137
  128. package/dist/infrastructure/protocols/a2a-protocol.js +0 -314
  129. package/dist/infrastructure/protocols/mcp-oauth.js +0 -184
  130. package/dist/infrastructure/protocols/mcp-server.js +0 -333
  131. package/dist/infrastructure/protocols/streaming-handler.js +0 -103
  132. package/dist/infrastructure/providers/cohere-provider.js +0 -444
  133. package/dist/infrastructure/providers/fake-provider.js +0 -130
  134. package/dist/infrastructure/providers/local-llm-provider.js +0 -330
  135. package/dist/infrastructure/providers/model-config.types.js +0 -9
  136. package/dist/infrastructure/providers/model-provider.interface.js +0 -8
  137. package/dist/infrastructure/providers/openai-provider.js +0 -413
  138. package/dist/infrastructure/providers/openrouter-provider.js +0 -399
  139. package/dist/infrastructure/providers/operation-provider-resolver.js +0 -105
  140. package/dist/infrastructure/providers/provider-config-loader.js +0 -120
  141. package/dist/infrastructure/providers/provider-registry.js +0 -88
  142. package/dist/infrastructure/safety/pattern-detector.js +0 -133
  143. package/dist/infrastructure/security/ai-sast-scanner.js +0 -290
  144. package/dist/infrastructure/security/docker-sandbox.js +0 -178
  145. package/dist/infrastructure/security/enhanced-security-gate.js +0 -151
  146. package/dist/infrastructure/security/license-scanner.js +0 -167
  147. package/dist/infrastructure/security/provider-bias-detector.js +0 -164
  148. package/dist/infrastructure/security/sandbox-executor.js +0 -64
  149. package/dist/infrastructure/serialization/toon-serializer.js +0 -119
  150. package/dist/infrastructure/storage/memory-stream-service.js +0 -204
  151. package/dist/infrastructure/storage/plan-repository.js +0 -96
  152. package/dist/infrastructure/storage/sqlite-decision-repository.js +0 -232
  153. package/dist/infrastructure/storage/sqlite-embedding-repository.js +0 -311
  154. package/dist/infrastructure/storage/sqlite-knowledge-graph-repository.js +0 -417
  155. package/dist/infrastructure/storage/sqlite-knowledge-preservation-repository.js +0 -230
  156. package/dist/infrastructure/storage/sqlite-memory-repository.js +0 -229
  157. package/dist/infrastructure/storage/sqlite-pattern-repository.js +0 -249
  158. package/dist/infrastructure/storage/task-helpers.js +0 -197
  159. package/dist/infrastructure/telemetry/telemetry-service.js +0 -167
  160. package/dist/infrastructure/ux/appropriate-friction.js +0 -213
  161. package/dist/infrastructure/ux/bi-directional-learning.js +0 -337
  162. package/dist/infrastructure/ux/capability-boundaries.js +0 -42
  163. package/dist/infrastructure/ux/comprehensive-formatter.js +0 -117
  164. package/dist/infrastructure/ux/contextual-feature-discovery.js +0 -10
  165. package/dist/infrastructure/ux/expectation-management.js +0 -327
  166. package/dist/infrastructure/ux/feature-discovery.js +0 -14
  167. package/dist/infrastructure/ux/feedback-prompt.js +0 -45
  168. package/dist/infrastructure/ux/hitl-validation.js +0 -297
  169. package/dist/infrastructure/ux/progress-indicator.js +0 -116
  170. package/dist/infrastructure/ux/progressive-disclosure.js +0 -236
  171. package/dist/infrastructure/ux/review-checkpoint.js +0 -72
  172. package/dist/infrastructure/ux/staged-feature-intro.js +0 -24
  173. package/dist/infrastructure/ux/stream-markdown.js +0 -151
  174. package/dist/infrastructure/ux/syntax-highlighter.js +0 -91
  175. package/dist/infrastructure/ux/team-standards.js +0 -196
  176. package/dist/infrastructure/ux/transparency.js +0 -71
  177. package/dist/infrastructure/validation/agent-feedback.js +0 -55
  178. package/dist/infrastructure/validation/agent-validation-helper.js +0 -137
  179. package/dist/infrastructure/validation/review-handler.js +0 -40
  180. package/dist/infrastructure/validation/summary-aggregator.js +0 -70
  181. package/dist/infrastructure/validation/summary-extractor.js +0 -45
  182. package/dist/infrastructure/validation/trace-summary.js +0 -52
  183. package/dist/infrastructure/verification/verification-service.js +0 -47
  184. package/dist/infrastructure/xai/attention-visualizer.js +0 -172
  185. package/dist/infrastructure/xai/cot-visualizer.js +0 -283
  186. package/dist/infrastructure/xai/decision-tree-log.js +0 -212
  187. package/dist/infrastructure/xai/interactive-xai.js +0 -260
  188. package/dist/infrastructure/xai/uncertainty-quantifier.js +0 -198
  189. package/dist/intelligent-retrieval.js +0 -272
  190. package/dist/intent/classifier.js +0 -2
  191. package/dist/intent/context.js +0 -2
  192. package/dist/iterative-refinement.js +0 -189
  193. package/dist/learning.js +0 -232
  194. package/dist/log.js +0 -31
  195. package/dist/migrate.js +0 -133
  196. package/dist/parallel-processor.js +0 -534
  197. package/dist/planner.js +0 -198
  198. package/dist/policy.js +0 -26
  199. package/dist/presentation/cli/commands/ask-command.js +0 -314
  200. package/dist/presentation/cli/commands/cost-command.js +0 -191
  201. package/dist/presentation/cli/commands/decision-command.js +0 -207
  202. package/dist/presentation/cli/commands/docs-command.js +0 -25
  203. package/dist/presentation/cli/commands/fix-command.js +0 -53
  204. package/dist/presentation/cli/commands/knowledge-command.js +0 -129
  205. package/dist/presentation/cli/commands/learning-dashboard-command.js +0 -183
  206. package/dist/presentation/cli/commands/models-command.js +0 -194
  207. package/dist/presentation/cli/commands/orchestrate-command.js +0 -207
  208. package/dist/presentation/cli/commands/plan-command.js +0 -246
  209. package/dist/presentation/cli/commands/product-command.js +0 -199
  210. package/dist/presentation/cli/commands/react-command.js +0 -181
  211. package/dist/presentation/cli/commands/review-command.js +0 -154
  212. package/dist/presentation/cli/commands/run-command.js +0 -188
  213. package/dist/presentation/cli/commands/smart-command.js +0 -395
  214. package/dist/presentation/cli/commands/suggest-command.js +0 -138
  215. package/dist/presentation/cli/commands/trace-command.js +0 -129
  216. package/dist/presentation/cli/commands/undo-command.js +0 -150
  217. package/dist/query-optimizer.js +0 -205
  218. package/dist/refactor.js +0 -116
  219. package/dist/review.js +0 -206
  220. package/dist/search.js +0 -163
  221. package/dist/session.js +0 -704
  222. package/dist/task-verification.js +0 -336
  223. package/dist/testgen.js +0 -166
  224. package/dist/token-optimizer.js +0 -277
  225. package/dist/tools/bash.js +0 -213
  226. package/dist/tools/edit.js +0 -235
  227. package/dist/tools/executor.js +0 -153
  228. package/dist/tools/git-tool.js +0 -292
  229. package/dist/tools/parser.js +0 -158
  230. package/dist/tools/registry.js +0 -302
  231. package/dist/tools/search.js +0 -100
  232. package/dist/types.js +0 -2
  233. package/dist/utils/check-api-status.js +0 -100
  234. package/dist/utils/diff-parser.js +0 -162
  235. package/dist/verification/backup.js +0 -259
  236. package/dist/verification/compiler.js +0 -264
  237. package/dist/verification/index.js +0 -273
  238. package/dist/verification/test-runner.js +0 -379
@@ -0,0 +1,278 @@
1
+ /**
2
+ * In-memory registry of active task sessions + audit-log derived observation.
3
+ *
4
+ * Two kinds of session surfaced to the UI:
5
+ * 1. spawned — started via codehere.spawn; we own the subprocess, can kill.
6
+ * 2. observed — derived from the audit log. Claude Code sessions running
7
+ * in the user's terminals, IDE, or elsewhere on this machine.
8
+ * codehere didn't start them and can't kill them, but shows
9
+ * them so the dashboard reflects reality from first load.
10
+ *
11
+ * Durable state lives in the audit log (F0). On daemon restart, spawned
12
+ * sessions are gone but observed ones remain (they're re-derived from the log).
13
+ */
14
+ import { existsSync, readFileSync } from 'fs';
15
+ import { execFileSync } from 'child_process';
16
+ import { ClaudeCodeAdapter } from './claude-code-adapter.js';
17
+ import { CodexAdapter } from './codex-adapter.js';
18
+ import { AiderAdapter } from './aider-adapter.js';
19
+ import { OpenCodeAdapter } from './opencode-adapter.js';
20
+ import { buildGenericAdapter, loadAgentsConfig } from './generic-cli-adapter.js';
21
+ import { buildConductorAdapter } from './conductor-adapter.js';
22
+ import { seedAgentsConfig } from './agents-config-seed.js';
23
+ import { AUDIT_FILE } from '../hooks/claude-sdk-hook.js';
24
+ import { appendSpawned, appendCompleted, loadRecent } from './session-persistence.js';
25
+ // ── Agent registry ─────────────────────────────────────────────────────────────
26
+ // All backends codehere can spawn. Order here drives the default UI dropdown
27
+ // order. Built-in adapters first; user-config-driven ones appended from
28
+ // ~/.codehere/agents.yaml (generic-cli-adapter). isInstalled() gates visibility
29
+ // so an adapter registering for an un-installed CLI is harmless.
30
+ const BUILTIN_REGISTRY = [ClaudeCodeAdapter, CodexAdapter, AiderAdapter, OpenCodeAdapter];
31
+ // Seed the default agents.yaml if this user has never configured one, so Gemini
32
+ // / Cursor / Pi / Antigravity / Goose appear in the registry pre-wired. They
33
+ // stay hidden in the UI until isInstalled() flips to true. Idempotent.
34
+ seedAgentsConfig();
35
+ const REGISTRY = [
36
+ ...BUILTIN_REGISTRY,
37
+ // User-configurable adapters — "plug any CLI" escape hatch, seeded with
38
+ // popular CLI agents above. Users can add/edit/remove entries freely.
39
+ ...loadAgentsConfig().map(buildGenericAdapter),
40
+ ];
41
+ // F6 Conductor — the meta-agent. Registered LAST so it sees the full registry
42
+ // at lookup time. The lookup function is closed over `REGISTRY` so it always
43
+ // returns the current populated array (including any future user adapters).
44
+ // Conductor is appended to the same array so UIs that iterate REGISTRY see it.
45
+ REGISTRY.push(buildConductorAdapter(() => REGISTRY));
46
+ export function availableAgents() {
47
+ return REGISTRY.map((a) => ({ id: a.id, label: a.label, installed: a.isInstalled() }));
48
+ }
49
+ /** Per-agent readiness across the full registry. Powers the setup-aware UI. */
50
+ export function readinessForAllAgents() {
51
+ return REGISTRY.map((a) => {
52
+ if (a.checkReadiness)
53
+ return a.checkReadiness();
54
+ // Fallback for adapters that haven't implemented checkReadiness yet: treat
55
+ // "installed" as "ready", "not installed" as "needs_install without hint".
56
+ const installed = a.isInstalled();
57
+ return installed
58
+ ? { id: a.id, label: a.label, state: 'ready', installed: true }
59
+ : { id: a.id, label: a.label, state: 'needs_install', installed: false };
60
+ });
61
+ }
62
+ export function getAdapter(id) {
63
+ return REGISTRY.find((a) => a.id === id);
64
+ }
65
+ export function allAdapters() {
66
+ return REGISTRY;
67
+ }
68
+ export function agentProcessPatterns() {
69
+ return REGISTRY.map((a) => ({
70
+ regex: a.processPattern,
71
+ agent: a.id,
72
+ label: a.label,
73
+ }));
74
+ }
75
+ const DEFAULT_OBSERVED_WINDOW_MS = 10 * 60 * 1000; // 10 minutes
76
+ function parseEtime(s) {
77
+ // ps etime formats: "MM:SS", "HH:MM:SS", "D-HH:MM:SS"
78
+ let rest = s;
79
+ let days = 0;
80
+ if (rest.includes('-')) {
81
+ const [d, r] = rest.split('-');
82
+ days = parseInt(d, 10) || 0;
83
+ rest = r;
84
+ }
85
+ const parts = rest.split(':').map((p) => parseInt(p, 10) || 0);
86
+ if (parts.length === 2)
87
+ return parts[0] * 60 + parts[1];
88
+ if (parts.length === 3)
89
+ return days * 86400 + parts[0] * 3600 + parts[1] * 60 + parts[2];
90
+ return 0;
91
+ }
92
+ export class SessionManager {
93
+ sessions = new Map();
94
+ /** Read-only sessions replayed from ~/.codehere/sessions.jsonl on daemon start.
95
+ * These subprocesses are long-dead; we surface them so the user doesn't lose
96
+ * their Final reports across restarts. */
97
+ persistedCache = loadRecent(20);
98
+ spawn(prompt, agentId = 'claude-code', options) {
99
+ const adapter = getAdapter(agentId);
100
+ if (!adapter) {
101
+ throw new Error(`Unknown agent: ${agentId}. Registered: ${REGISTRY.map((a) => a.id).join(', ')}`);
102
+ }
103
+ if (!adapter.isInstalled()) {
104
+ throw new Error(`Agent ${adapter.label} (${adapter.id}) is not installed on this machine`);
105
+ }
106
+ const session = adapter.spawn(prompt, options);
107
+ this.sessions.set(session.sessionId, session);
108
+ // Persistence: write the spawned record immediately so a daemon crash still
109
+ // leaves an audit trail of what was attempted. Subscribe to exit so we can
110
+ // capture the final status + steps + artifacts when the session settles.
111
+ const cwd = options?.cwd ?? process.cwd();
112
+ appendSpawned({
113
+ id: session.sessionId,
114
+ agent: session.agent,
115
+ prompt,
116
+ cwd,
117
+ startedAt: session.startedAt,
118
+ });
119
+ const unsubscribe = session.subscribe((event) => {
120
+ if (event.type !== 'exit')
121
+ return;
122
+ const data = event.data;
123
+ appendCompleted({
124
+ id: session.sessionId,
125
+ status: session.status,
126
+ durationMs: Number(data?.durationMs ?? Date.now() - session.startedAt),
127
+ completedAt: Date.now(),
128
+ steps: session.steps ? [...session.steps] : undefined,
129
+ artifacts: session.artifacts,
130
+ });
131
+ unsubscribe();
132
+ });
133
+ return session;
134
+ }
135
+ /** Persisted (read-only) sessions from prior daemon runs. Cached at boot. */
136
+ listPersisted() {
137
+ return this.persistedCache;
138
+ }
139
+ get(sessionId) {
140
+ return this.sessions.get(sessionId);
141
+ }
142
+ list() {
143
+ return Array.from(this.sessions.values());
144
+ }
145
+ kill(sessionId) {
146
+ const session = this.sessions.get(sessionId);
147
+ if (!session)
148
+ return false;
149
+ session.kill();
150
+ return true;
151
+ }
152
+ /**
153
+ * Active Claude Code sessions on this machine, derived from the audit log.
154
+ * A session is "active" if any tool call from it was recorded within the
155
+ * last `maxAgeMs` milliseconds. Returns most-recent first.
156
+ *
157
+ * Note: codehere-spawned sessions may also appear here because they produce
158
+ * audit entries just like any other Claude Code session. The UI distinguishes
159
+ * by provenance.
160
+ */
161
+ listObserved(maxAgeMs = DEFAULT_OBSERVED_WINDOW_MS) {
162
+ if (!existsSync(AUDIT_FILE))
163
+ return [];
164
+ const now = Date.now();
165
+ const cutoff = now - maxAgeMs;
166
+ const byId = new Map();
167
+ let content;
168
+ try {
169
+ content = readFileSync(AUDIT_FILE, 'utf-8');
170
+ }
171
+ catch {
172
+ return [];
173
+ }
174
+ const lines = content.split('\n');
175
+ // Walk backwards — most recent lines first — and stop early when we
176
+ // pass the window. Audit log appends chronologically.
177
+ for (let i = lines.length - 1; i >= 0; i--) {
178
+ const line = lines[i].trim();
179
+ if (!line)
180
+ continue;
181
+ let entry;
182
+ try {
183
+ entry = JSON.parse(line);
184
+ }
185
+ catch {
186
+ continue;
187
+ }
188
+ if (!entry.sessionId)
189
+ continue;
190
+ const ts = typeof entry.timestamp === 'number'
191
+ ? entry.timestamp
192
+ : entry.timestamp
193
+ ? Date.parse(String(entry.timestamp))
194
+ : 0;
195
+ if (!ts)
196
+ continue;
197
+ if (ts < cutoff)
198
+ break; // past the window; older entries can't qualify
199
+ const existing = byId.get(entry.sessionId);
200
+ if (existing) {
201
+ existing.eventCount += 1;
202
+ if (ts < existing.firstEventAt)
203
+ existing.firstEventAt = ts;
204
+ }
205
+ else {
206
+ byId.set(entry.sessionId, {
207
+ sessionId: entry.sessionId,
208
+ firstEventAt: ts,
209
+ lastEventAt: ts,
210
+ eventCount: 1,
211
+ recentTool: entry.toolName,
212
+ provenance: 'observed',
213
+ });
214
+ }
215
+ }
216
+ return Array.from(byId.values()).sort((a, b) => b.lastEventAt - a.lastEventAt);
217
+ }
218
+ /**
219
+ * Agent processes running on this machine right now.
220
+ * Enumerates via `ps`, filters to known agent executables, returns most
221
+ * recently started first. This is the primary F1d surface — it reflects
222
+ * "what AI agents are alive on your machine" independent of whether
223
+ * they've produced audit events yet.
224
+ */
225
+ listActiveAgents() {
226
+ let out;
227
+ try {
228
+ out = execFileSync('ps', ['-A', '-o', 'pid,tty,etime,args'], {
229
+ encoding: 'utf-8',
230
+ timeout: 2000,
231
+ });
232
+ }
233
+ catch {
234
+ return [];
235
+ }
236
+ const agents = [];
237
+ const lines = out.trim().split('\n').slice(1); // drop header
238
+ for (const line of lines) {
239
+ const m = line.trim().match(/^(\d+)\s+(\S+)\s+(\S+)\s+(.+)$/);
240
+ if (!m)
241
+ continue;
242
+ const [, pidStr, tty, etime, args] = m;
243
+ // Skip ourselves — the codehere daemon would otherwise show up repeatedly
244
+ if (/\bcodehere\b|\bch\s+start\b/.test(args))
245
+ continue;
246
+ // Skip the audit tailer from other codehere commands
247
+ if (/scan-tool|codehere-audit/.test(args))
248
+ continue;
249
+ let matched = null;
250
+ for (const p of agentProcessPatterns()) {
251
+ if (p.regex.test(args)) {
252
+ matched = { agent: p.agent, label: p.label };
253
+ break;
254
+ }
255
+ }
256
+ if (!matched)
257
+ continue;
258
+ const uptimeSeconds = parseEtime(etime);
259
+ const startedAt = Date.now() - uptimeSeconds * 1000;
260
+ agents.push({
261
+ pid: parseInt(pidStr, 10),
262
+ tty,
263
+ agent: matched.agent,
264
+ label: matched.label,
265
+ args: args.length > 200 ? args.slice(0, 200) + '…' : args,
266
+ startedAt,
267
+ uptimeSeconds,
268
+ provenance: 'detected',
269
+ });
270
+ }
271
+ return agents.sort((a, b) => b.startedAt - a.startedAt);
272
+ }
273
+ static _instance;
274
+ static getInstance() {
275
+ return (this._instance ??= new SessionManager());
276
+ }
277
+ }
278
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Session persistence — survives daemon restart.
3
+ *
4
+ * Beta.3 dogfood surfaced a reliability gap: after `ch start` exited and was
5
+ * relaunched, the task UI was empty even when completed sessions had produced
6
+ * valuable final reports. The audit log (hook-events.jsonl) persisted every
7
+ * tool call but not the session-level PM state (prompt, artifacts, steps).
8
+ *
9
+ * This module adds a minimal two-record schema:
10
+ * { t: 'spawned', id, agent, prompt, cwd, startedAt }
11
+ * { t: 'completed', id, status, durationMs, steps, artifacts, completedAt }
12
+ *
13
+ * On spawn, we write the first line. On exit, we write the second. On daemon
14
+ * start, we read the last N pairs and surface them as read-only "persisted"
15
+ * sessions (no kill button, no live stream; the subprocess died with the
16
+ * previous daemon).
17
+ *
18
+ * Write path stays append-only — never rewrites history. Lock-free because
19
+ * single writer (the daemon). If two daemons ran concurrently the worst case
20
+ * is interleaved lines, which the reader tolerates.
21
+ */
22
+ import { existsSync, mkdirSync, appendFileSync, readFileSync } from 'fs';
23
+ import { homedir } from 'os';
24
+ import { join, dirname } from 'path';
25
+ const SESSIONS_FILE = join(homedir(), '.codehere', 'sessions.jsonl');
26
+ function ensureDir() {
27
+ const dir = dirname(SESSIONS_FILE);
28
+ if (!existsSync(dir))
29
+ mkdirSync(dir, { recursive: true });
30
+ }
31
+ export function appendSpawned(rec) {
32
+ try {
33
+ ensureDir();
34
+ appendFileSync(SESSIONS_FILE, JSON.stringify({ t: 'spawned', ...rec }) + '\n', 'utf-8');
35
+ }
36
+ catch {
37
+ /* persistence is best-effort; never break the spawn path */
38
+ }
39
+ }
40
+ export function appendCompleted(rec) {
41
+ try {
42
+ ensureDir();
43
+ appendFileSync(SESSIONS_FILE, JSON.stringify({ t: 'completed', ...rec }) + '\n', 'utf-8');
44
+ }
45
+ catch {
46
+ /* best-effort */
47
+ }
48
+ }
49
+ /**
50
+ * Walk the session log backward, pair spawned+completed records by id, return
51
+ * the most recent `limit` completed pairs sorted newest-first.
52
+ *
53
+ * We only surface fully-completed sessions because an orphaned `spawned` with
54
+ * no `completed` means either: (a) the daemon died mid-task (subprocess also
55
+ * died, no artifacts), or (b) a concurrent daemon is mid-flight (not ours to
56
+ * show). Either way, not useful in the UI.
57
+ */
58
+ export function loadRecent(limit = 20) {
59
+ if (!existsSync(SESSIONS_FILE))
60
+ return [];
61
+ let content;
62
+ try {
63
+ content = readFileSync(SESSIONS_FILE, 'utf-8');
64
+ }
65
+ catch {
66
+ return [];
67
+ }
68
+ const spawned = new Map();
69
+ const completed = [];
70
+ for (const line of content.split('\n')) {
71
+ const trimmed = line.trim();
72
+ if (!trimmed)
73
+ continue;
74
+ let rec;
75
+ try {
76
+ rec = JSON.parse(trimmed);
77
+ }
78
+ catch {
79
+ continue;
80
+ }
81
+ if (rec.t === 'spawned')
82
+ spawned.set(rec.id, rec);
83
+ else if (rec.t === 'completed')
84
+ completed.push(rec);
85
+ }
86
+ const merged = [];
87
+ // Walk completed in reverse so we return newest-first
88
+ for (let i = completed.length - 1; i >= 0 && merged.length < limit; i--) {
89
+ const c = completed[i];
90
+ const s = spawned.get(c.id);
91
+ if (!s)
92
+ continue; // orphan completed (shouldn't happen but harmless)
93
+ merged.push({
94
+ sessionId: s.id,
95
+ agent: s.agent,
96
+ prompt: s.prompt,
97
+ cwd: s.cwd,
98
+ startedAt: s.startedAt,
99
+ status: c.status,
100
+ durationMs: c.durationMs,
101
+ completedAt: c.completedAt,
102
+ steps: c.steps,
103
+ artifacts: c.artifacts,
104
+ provenance: 'persisted',
105
+ });
106
+ }
107
+ return merged;
108
+ }
109
+ //# sourceMappingURL=session-persistence.js.map
@@ -2,41 +2,21 @@
2
2
  * MCP helper functions — shared between MCP server and trust command.
3
3
  * Extracted to avoid circular imports.
4
4
  */
5
- import { readFileSync, statSync, readdirSync } from 'fs';
6
- import { join, extname } from 'path';
5
+ import { readFileSync } from 'fs';
6
+ import { collectCodeFiles } from '../security/file-collection.js';
7
7
  // ── File collection ──────────────────────────────────────────────────────────
8
- const CODE_EXTENSIONS = new Set([
9
- '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
10
- '.py', '.rb', '.go', '.java', '.cs', '.php',
11
- '.sh', '.bash', '.zsh',
12
- '.sql', '.html', '.vue', '.svelte',
13
- ]);
14
- const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'coverage', '.cache', '.codehere', '.codehere-cache']);
8
+ // Uses the shared walker — same exclusion rules as trust and report.
15
9
  export function collectFilesForMCP(target) {
10
+ const paths = collectCodeFiles(target);
16
11
  const result = [];
17
- function walk(dir) {
18
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
19
- if (IGNORE_DIRS.has(entry.name))
20
- continue;
21
- const full = join(dir, entry.name);
22
- if (entry.isDirectory()) {
23
- walk(full);
24
- }
25
- else if (CODE_EXTENSIONS.has(extname(entry.name))) {
26
- try {
27
- result.push({ filepath: full, code: readFileSync(full, 'utf-8') });
28
- }
29
- catch {
30
- // skip unreadable files
31
- }
32
- }
12
+ for (const filepath of paths) {
13
+ try {
14
+ result.push({ filepath, code: readFileSync(filepath, 'utf-8') });
15
+ }
16
+ catch {
17
+ // skip unreadable files (iCloud-evicted, permissions, too large)
33
18
  }
34
19
  }
35
- const stat = statSync(target);
36
- if (stat.isFile()) {
37
- return [{ filepath: target, code: readFileSync(target, 'utf-8') }];
38
- }
39
- walk(target);
40
20
  return result;
41
21
  }
42
22
  // ── Scoring ──────────────────────────────────────────────────────────────────