codehere 0.3.4 → 0.5.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -11
- package/dist/index.js +43 -0
- package/dist/infrastructure/hooks/claude-sdk-hook.js +18 -3
- package/dist/infrastructure/orchestration/aider-adapter.js +12 -2
- package/dist/infrastructure/orchestration/claude-code-adapter.js +9 -1
- package/dist/infrastructure/orchestration/codex-adapter.js +6 -1
- package/dist/infrastructure/orchestration/conductor-adapter.js +12 -2
- package/dist/infrastructure/orchestration/gemini-adapter.js +425 -0
- package/dist/infrastructure/orchestration/generic-cli-adapter.js +10 -2
- package/dist/infrastructure/orchestration/memory-injector.js +337 -0
- package/dist/infrastructure/orchestration/opencode-adapter.js +34 -4
- package/dist/infrastructure/orchestration/progress-aggregator.js +157 -0
- package/dist/infrastructure/orchestration/readiness.js +2 -5
- package/dist/infrastructure/orchestration/session-manager.js +2 -1
- package/dist/infrastructure/orchestration/session-persistence.js +13 -1
- package/dist/infrastructure/protocols/mcp-server-impl.js +30 -3
- package/dist/infrastructure/protocols/ui-page.js +468 -59
- package/dist/presentation/cli/commands/init-command.js +342 -24
- package/dist/presentation/cli/commands/memory-command.js +1017 -0
- package/dist/presentation/cli/commands/protocols-builder.js +254 -0
- package/dist/presentation/cli/commands/protocols-command.js +84 -0
- package/dist/presentation/cli/commands/repo-map-builder.js +247 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/codehere)
|
|
6
6
|
[](../LICENSE)
|
|
7
|
-
[]()
|
|
8
8
|
[]()
|
|
9
9
|
|
|
10
|
-
codehere is **a PM for your AI coding agents.** Delegate a task. codehere picks the right specialist (Claude Code, Codex, Aider, or
|
|
10
|
+
codehere is **a PM for your AI coding agents.** Delegate a task. codehere picks the right specialist (Claude Code, Codex, Aider, OpenCode, or Gemini), spawns it, streams its work back to you, and hands you a plain-English Final Report with a **trust score on every file changed**. Today, Claude Code gets full pre-execution safety-hook enforcement on every tool call; other adapters are session-traced and reported, with per-tool hook parity planned for v0.4.
|
|
11
11
|
|
|
12
12
|
One manager, many specialists, every action recorded.
|
|
13
13
|
|
|
@@ -25,9 +25,10 @@ One manager, many specialists, every action recorded.
|
|
|
25
25
|
| 1 | **Install** | `npm install -g codehere` (Node 20+) |
|
|
26
26
|
| 2 | **Detect environment** | `codehere setup` — checks API key, finds your repo |
|
|
27
27
|
| 3 | **Install the safety hook** | `codehere hook install` — every Claude Code tool call now audited |
|
|
28
|
-
| 4 | **Install at least one specialist** | Claude Code: `npm i -g @anthropic-ai/claude-code` (Codex / Aider / OpenCode also supported) |
|
|
29
|
-
| 5 | **Scaffold this repo** | `cd /your/repo && codehere init` — creates `.codehere/
|
|
30
|
-
| 6 | **Fill in
|
|
28
|
+
| 4 | **Install at least one specialist** | Claude Code: `npm i -g @anthropic-ai/claude-code` (Codex / Aider / OpenCode / Gemini also supported · see [docs/integrations/](../docs/integrations/) for Cursor MCP setup) |
|
|
29
|
+
| 5 | **Scaffold this repo** | `cd /your/repo && codehere init` — creates `.codehere/` with the F3 memory tree (working / episodic / semantic / personal / candidates) plus `AGENTS.md` (project briefing) and `skills/` (prompt templates) |
|
|
30
|
+
| 6 | **Fill in AGENTS.md** | 5 minutes. The agent will follow what's written there. |
|
|
31
|
+
| 7 | **Build the symbol map (optional)** | `codehere memory repo-map` — JSON map of every top-level export in your repo, ranked by reference count. Spawned agents read it on entry instead of cold-grepping. |
|
|
31
32
|
|
|
32
33
|
You're done. `codehere start` opens the web UI at `:3773`; you delegate from there.
|
|
33
34
|
|
|
@@ -43,11 +44,20 @@ Context + End State + Constraints
|
|
|
43
44
|
|
|
44
45
|
### Folder convention (what `codehere init` writes)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
The v0.5 layout — F3 project memory:
|
|
48
|
+
|
|
49
|
+
| Path | Purpose | Committed? |
|
|
47
50
|
|---|---|---|
|
|
48
|
-
| `.codehere/CONTEXT.md` | What this repo is. Conventions. Style. Constraints. | yes |
|
|
49
|
-
| `.codehere/HANDOVER.md` |
|
|
50
|
-
| `.codehere/
|
|
51
|
+
| `.codehere/AGENTS.md` *(or legacy `CONTEXT.md`)* | What this repo is. Conventions. Style. Constraints. | yes |
|
|
52
|
+
| `.codehere/memory/working/session.md` *(or legacy `HANDOVER.md`)* | What's in flight in the current session. | **no** |
|
|
53
|
+
| `.codehere/memory/episodic/AGENT_LEARNINGS.jsonl` | Symlink to your full session history at `~/.codehere/sessions.jsonl`. | (symlink) |
|
|
54
|
+
| `.codehere/memory/episodic/repo_map.json` | Ranked symbol map. Built by `codehere memory repo-map`. | yes |
|
|
55
|
+
| `.codehere/memory/semantic/lessons.jsonl` | Project-specific lessons promoted from episodic patterns. | yes |
|
|
56
|
+
| `.codehere/memory/personal/preferences.json` | Per-developer prefs. | **no** |
|
|
57
|
+
| `.codehere/skills/<name>/SKILL.md` *(or legacy flat `PROMPTS.md`)* | Prompt templates — one folder per skill. | yes |
|
|
58
|
+
| `.codehere/protocols/permissions.md` + `hook_patterns.json` | Safety policy for the PreToolUse hook. | yes |
|
|
59
|
+
|
|
60
|
+
Upgrading from v0.4.1? Run `codehere memory init` once — it migrates `CONTEXT/HANDOVER/PROMPTS` into the new layout and leaves symlinks at the old paths so back-compat holds. `--dry-run` shows what would move first.
|
|
51
61
|
|
|
52
62
|
---
|
|
53
63
|
|
|
@@ -57,7 +67,7 @@ Context + End State + Constraints
|
|
|
57
67
|
|
|
58
68
|
1. Spawns the agent with the right headless flags
|
|
59
69
|
2. Streams the steps back as readable progress · *"Read src/auth.ts · Edit src/auth.ts · Run npm test"*
|
|
60
|
-
3. For Claude Code tasks: routes every tool call through the codehere safety hook — you see *"🛡 5 safe · 0 blocked"* grow live. For Codex / Aider / OpenCode tasks: emits the agent's native event stream (no per-tool blocking yet)
|
|
70
|
+
3. For Claude Code tasks: routes every tool call through the codehere safety hook — you see *"🛡 5 safe · 0 blocked"* grow live. For Codex / Aider / OpenCode / Gemini tasks: emits the agent's native event stream (no per-tool blocking yet)
|
|
61
71
|
4. On completion, hands you a **Final report**: files changed with `+/-` lines, trust score per file, test pass/fail, token usage
|
|
62
72
|
|
|
63
73
|
Claude Code tool calls are logged to `~/.codehere/audit/hook-events.jsonl`; spawned-task lifecycle (any adapter) is logged to `~/.codehere/sessions.jsonl`. Open-source MIT. Node 20+.
|
|
@@ -75,6 +85,52 @@ codehere status # quick dashboard · sessions, blocks, trust trends
|
|
|
75
85
|
|
|
76
86
|
The hook intercepts every `Bash`, `Edit`, `Write`, `MultiEdit`, and `NotebookEdit` call from any Claude Code session running on your machine, runs it through the trust-scorer pattern bank in under 5 ms, blocks anything matching the destructive / credential / injection patterns, and appends every decision to an append-only JSONL audit log at `~/.codehere/audit/`. (Hook coverage today is Claude Code-only — Codex / Aider / OpenCode adapters spawn through their native CLIs and emit to `~/.codehere/sessions.jsonl`; full hook parity across all adapters is v0.4 work.)
|
|
77
87
|
|
|
88
|
+
## Memory · F3 (v0.5)
|
|
89
|
+
|
|
90
|
+
Once you've run `codehere init` in a project, every spawned agent — Claude Code, Codex, Aider, OpenCode, or Gemini — automatically reads the project's memory on entry. The agent starts warm with the briefing, recent lessons, and the most-referenced symbols in your codebase, instead of cold-grepping every session.
|
|
91
|
+
|
|
92
|
+
**What gets injected, in priority order:**
|
|
93
|
+
1. **`.codehere/AGENTS.md`** — your project briefing (conventions, style, constraints)
|
|
94
|
+
2. **`.codehere/memory/working/session.md`** — what's in flight right now (per-machine, gitignored)
|
|
95
|
+
3. **`.codehere/memory/semantic/lessons.jsonl`** — graduated project-wide lessons
|
|
96
|
+
4. **`.codehere/memory/episodic/repo_map.json`** — top-N most-referenced symbols (run `codehere memory repo-map` to build / refresh)
|
|
97
|
+
|
|
98
|
+
The injection is token-budget-aware (default ~3000 tokens, drops lower-priority sections first to fit; AGENTS.md is never dropped). Pass `--no-memory-prefix` if you want the bare prompt for a one-off task.
|
|
99
|
+
|
|
100
|
+
**Inspect what would inject** before spawning anything:
|
|
101
|
+
```bash
|
|
102
|
+
codehere memory show injection
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Add a lesson** so future spawns learn from it:
|
|
106
|
+
```bash
|
|
107
|
+
codehere memory graduate --add "auth tests live alongside source files"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**See everything codehere has accumulated:**
|
|
111
|
+
```bash
|
|
112
|
+
codehere memory show # one-line summary per layer
|
|
113
|
+
codehere memory show semantic # numbered lesson list
|
|
114
|
+
codehere memory show episodic # session count + top symbols
|
|
115
|
+
codehere memory show protocols # safety patterns by category
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Other memory commands:**
|
|
119
|
+
- `codehere memory init` — migrate the v0.4.1 layout (`CONTEXT.md` / `HANDOVER.md` / `PROMPTS.md`) into the F3 layout (one shot, leaves back-compat symlinks; `--dry-run` previews)
|
|
120
|
+
- `codehere memory repo-map [--rebuild]` — build the symbol map; v0.5 ships a TS-native MVP, v0.6 swaps in tree-sitter
|
|
121
|
+
- `codehere protocols export [--rebuild]` — write the trust-scorer pattern bank to `.codehere/protocols/hook_patterns.json` for inspection / cross-tool ingestion
|
|
122
|
+
|
|
123
|
+
## Going deeper
|
|
124
|
+
|
|
125
|
+
For technical readers — the living documents that describe codehere as a system, not just a CLI:
|
|
126
|
+
|
|
127
|
+
| Doc | What it is |
|
|
128
|
+
|---|---|
|
|
129
|
+
| [`docs/decisions/`](../docs/decisions/) | ADR registry — every locked architectural decision (audit-first moat, supervisor-agent positioning, local-first, F3 memory layout, generic-CLI adapter, ...) numbered, dated, with rejected alternatives + rollback triggers |
|
|
130
|
+
| [`docs/THREAT_MODEL.md`](../docs/THREAT_MODEL.md) | Every attack surface, current mitigation, residual risk, planned hardening — npm supply chain, hook bypass, symlink redirect, audit log tampering, MCP server, prompt injection |
|
|
131
|
+
| [`docs/CAPABILITIES.md`](../docs/CAPABILITIES.md) | Honest matrix of what each adapter can and cannot do today — Claude Code, Codex, Aider, OpenCode, Gemini, Generic CLI — across spawn, stream, per-tool block, audit, F3 memory, auth |
|
|
132
|
+
| [`agent/REPO_MAP.md`](./REPO_MAP.md) | One-line-per-file index of the 54 source files with their top-level exports — generated, regenerated via `npm run repomap` after renames |
|
|
133
|
+
|
|
78
134
|
## Commands
|
|
79
135
|
|
|
80
136
|
```
|
|
@@ -129,6 +185,7 @@ For depth beyond this README:
|
|
|
129
185
|
- **[CODEHERE.md](../CODEHERE.md)** · product spec · positioning, six-ring adoption funnel, F0–F6 foundations, defensibility, GTM, revenue model
|
|
130
186
|
- **[EXPERIENCE.md](../EXPERIENCE.md)** · the human story · how engineering teams, CISOs, and regulated-industry buyers adopt codehere
|
|
131
187
|
- **[AUDIT.md](../AUDIT.md)** · pre-publish audit report · methodology, findings, remediation
|
|
188
|
+
- **[docs/SECURITY_AUDIT_2026-05-01.md](../docs/SECURITY_AUDIT_2026-05-01.md)** · first-party security audit · OWASP Top 10 + STRIDE · 0 critical / 0 high · 2 medium fixed inline · methodology disclosed · reproducible
|
|
132
189
|
- **[CONTRIBUTING.md](../CONTRIBUTING.md)** · how to contribute · setup, commit discipline, testing philosophy
|
|
133
190
|
- **[SECURITY.md](../SECURITY.md)** · responsible disclosure · `security@codehere.uk`
|
|
134
191
|
- **[CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md)** · community standards
|
|
@@ -138,7 +195,7 @@ For depth beyond this README:
|
|
|
138
195
|
|
|
139
196
|
- **Node.js 20+** (pinned in `.nvmrc` and `engines.node`)
|
|
140
197
|
- **macOS or Linux** · Windows via WSL works for development; native Windows is on the v0.4 roadmap
|
|
141
|
-
- **Optional but recommended:** at least one supported agent (Claude Code, Codex, Aider, or
|
|
198
|
+
- **Optional but recommended:** at least one supported agent (Claude Code, Codex, Aider, OpenCode, or Gemini) installed before running `codehere start`
|
|
142
199
|
|
|
143
200
|
## License
|
|
144
201
|
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import { join, dirname } from 'path';
|
|
|
16
16
|
import { fileURLToPath } from 'url';
|
|
17
17
|
import { executeSetupCommand } from './presentation/cli/commands/setup-command.js';
|
|
18
18
|
import { executeInitCommand } from './presentation/cli/commands/init-command.js';
|
|
19
|
+
import { executeMemoryCommand } from './presentation/cli/commands/memory-command.js';
|
|
20
|
+
import { executeProtocolsCommand } from './presentation/cli/commands/protocols-command.js';
|
|
19
21
|
import { executeConfigCommand } from './presentation/cli/commands/config-command.js';
|
|
20
22
|
import { executeHelpCommand } from './presentation/cli/commands/help-command.js';
|
|
21
23
|
import { executeStatusCommand } from './presentation/cli/commands/status-command.js';
|
|
@@ -103,6 +105,47 @@ program
|
|
|
103
105
|
.action((options) => {
|
|
104
106
|
executeInitCommand({ force: options.force, noGitignore: !options.gitignore });
|
|
105
107
|
});
|
|
108
|
+
// ── memory ───────────────────────────────────────────────────────────────────
|
|
109
|
+
// F3 v0.5: project memory operations. `memory init` migrates v0.4.1 layout
|
|
110
|
+
// (CONTEXT/HANDOVER/PROMPTS) into the four-layer F3 layout (AGENTS.md +
|
|
111
|
+
// memory/ + skills/). `memory repo-map` builds a JSON symbol map. Future:
|
|
112
|
+
// memory show, memory graduate.
|
|
113
|
+
program
|
|
114
|
+
.command('memory')
|
|
115
|
+
.description('F3 project memory · init / repo-map / show / graduate / help')
|
|
116
|
+
.argument('[action]', 'Action: init, repo-map, show, graduate, help')
|
|
117
|
+
.argument('[layer]', 'Layer for `memory show` (working / episodic / semantic / personal / skills / protocols / injection)')
|
|
118
|
+
.option('-f, --force', 'Overwrite existing target files (memory init)')
|
|
119
|
+
.option('--no-symlinks', 'Delete old paths instead of leaving back-compat symlinks (memory init)')
|
|
120
|
+
.option('--dry-run', 'Print planned moves without touching disk (memory init)')
|
|
121
|
+
.option('--rebuild', 'Force a fresh build (memory repo-map)')
|
|
122
|
+
.option('--add <text>', 'Add a free-text lesson directly (memory graduate)')
|
|
123
|
+
.option('--accept <id>', 'Graduate a candidate by id (memory graduate)')
|
|
124
|
+
.option('--reject <id>', 'Reject a candidate by id without graduating (memory graduate)')
|
|
125
|
+
.action((action, layer, options) => {
|
|
126
|
+
executeMemoryCommand(action, {
|
|
127
|
+
force: options.force,
|
|
128
|
+
noSymlinks: !options.symlinks,
|
|
129
|
+
dryRun: options.dryRun,
|
|
130
|
+
rebuild: options.rebuild,
|
|
131
|
+
layer,
|
|
132
|
+
add: options.add,
|
|
133
|
+
accept: options.accept,
|
|
134
|
+
reject: options.reject,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
// ── protocols ────────────────────────────────────────────────────────────────
|
|
138
|
+
// F3 v0.5: protocols layer operations. `protocols export` writes the
|
|
139
|
+
// trust-scorer pattern bank to .codehere/protocols/hook_patterns.json so
|
|
140
|
+
// auditors / cross-tool consumers can read codehere's safety surface.
|
|
141
|
+
program
|
|
142
|
+
.command('protocols')
|
|
143
|
+
.description('F3 protocols layer · export (write hook_patterns.json from trust-scorer bank)')
|
|
144
|
+
.argument('[action]', 'Action: export, help')
|
|
145
|
+
.option('--rebuild', 'Refresh built-in patterns (project patterns are preserved)')
|
|
146
|
+
.action((action, options) => {
|
|
147
|
+
executeProtocolsCommand(action, { rebuild: options.rebuild });
|
|
148
|
+
});
|
|
106
149
|
// ── config ───────────────────────────────────────────────────────────────────
|
|
107
150
|
program
|
|
108
151
|
.command('config')
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
|
|
15
15
|
*/
|
|
16
|
-
import { appendFileSync, existsSync, mkdirSync } from 'fs';
|
|
16
|
+
import { appendFileSync, chmodSync, existsSync, mkdirSync } from 'fs';
|
|
17
17
|
import { join } from 'path';
|
|
18
18
|
import { homedir } from 'os';
|
|
19
19
|
const PATTERNS = [
|
|
@@ -392,9 +392,24 @@ export function appendAuditLog(entry) {
|
|
|
392
392
|
try {
|
|
393
393
|
const dir = AUDIT_FILE.substring(0, AUDIT_FILE.lastIndexOf('/'));
|
|
394
394
|
if (dir && !existsSync(dir)) {
|
|
395
|
-
|
|
395
|
+
// mode 0o700 — owner-only directory. The audit log records every tool call
|
|
396
|
+
// including bash commands and file paths; on multi-user systems a default
|
|
397
|
+
// 0o755 dir would let other users walk in and read the file. Surfaced by
|
|
398
|
+
// the May 1 2026 /cso security audit (Finding #1, MEDIUM).
|
|
399
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
400
|
+
}
|
|
401
|
+
// mode 0o600 — owner-only file. Same reasoning as the dir above. Only takes
|
|
402
|
+
// effect on first write (file creation); existing files are chmod'd below
|
|
403
|
+
// for backwards compatibility with audit logs created before this fix.
|
|
404
|
+
appendFileSync(AUDIT_FILE, JSON.stringify(entry) + '\n', { mode: 0o600 });
|
|
405
|
+
// Idempotent: if the file existed pre-fix with 0o644, tighten it now. The
|
|
406
|
+
// chmod is cheap and silent on already-0o600 files.
|
|
407
|
+
try {
|
|
408
|
+
chmodSync(AUDIT_FILE, 0o600);
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
/* fall through — chmod failure shouldn't block the audit append */
|
|
396
412
|
}
|
|
397
|
-
appendFileSync(AUDIT_FILE, JSON.stringify(entry) + '\n');
|
|
398
413
|
}
|
|
399
414
|
catch {
|
|
400
415
|
// Audit log failure must not block tool execution
|
|
@@ -16,6 +16,7 @@ import { spawn, execFileSync } from 'child_process';
|
|
|
16
16
|
import { EventEmitter } from 'events';
|
|
17
17
|
import { randomUUID } from 'crypto';
|
|
18
18
|
import { ProgressAggregator } from './progress-aggregator.js';
|
|
19
|
+
import { applyMemoryPrefix } from './memory-injector.js';
|
|
19
20
|
import { snapshotCwd, extractArtifacts } from './artifacts-extractor.js';
|
|
20
21
|
const HEADLESS_FLAGS = [
|
|
21
22
|
'--yes-always', // auto-accept all file-edit confirmations
|
|
@@ -70,8 +71,16 @@ export function spawnAider(prompt, options = {}) {
|
|
|
70
71
|
let statusValue = 'running';
|
|
71
72
|
let killRequested = false;
|
|
72
73
|
const cwd = options.cwd ?? process.cwd();
|
|
74
|
+
// F3 Task 8 — memory injection (same shape as every other adapter).
|
|
75
|
+
const injected = applyMemoryPrefix(prompt, cwd, options);
|
|
76
|
+
const finalPrompt = injected.prompt;
|
|
73
77
|
const snapshot = snapshotCwd(cwd);
|
|
74
|
-
|
|
78
|
+
// ProgressAggregator parses aider's stdout for `Running ...`, `Applied edit
|
|
79
|
+
// to ...`, and `Creating empty file ...` lines and emits Run/Edit/Write
|
|
80
|
+
// ProgressSteps. Observability parity (Path B) — see ingestAider() in
|
|
81
|
+
// progress-aggregator.ts. Blocking parity (Path A) needs the upstream
|
|
82
|
+
// `--pre-action-hook` PR.
|
|
83
|
+
const aggregator = new ProgressAggregator('aider');
|
|
75
84
|
let stepsSnapshot = [];
|
|
76
85
|
let artifactsSnapshot;
|
|
77
86
|
let textAccum = '';
|
|
@@ -139,7 +148,7 @@ export function spawnAider(prompt, options = {}) {
|
|
|
139
148
|
const spawnEnv = { ...process.env, ...(options.env ?? {}) };
|
|
140
149
|
let child;
|
|
141
150
|
try {
|
|
142
|
-
child = spawn('aider', ['--message',
|
|
151
|
+
child = spawn('aider', ['--message', finalPrompt, ...HEADLESS_FLAGS, ...(options.extraArgs ?? [])], {
|
|
143
152
|
cwd,
|
|
144
153
|
env: spawnEnv,
|
|
145
154
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -225,6 +234,7 @@ export function spawnAider(prompt, options = {}) {
|
|
|
225
234
|
startedAt,
|
|
226
235
|
prompt,
|
|
227
236
|
agent: 'aider',
|
|
237
|
+
memoryInjection: injected.record,
|
|
228
238
|
get status() {
|
|
229
239
|
return statusValue;
|
|
230
240
|
},
|
|
@@ -19,6 +19,7 @@ import { EventEmitter } from 'events';
|
|
|
19
19
|
import { randomUUID } from 'crypto';
|
|
20
20
|
import { ProgressAggregator } from './progress-aggregator.js';
|
|
21
21
|
import { snapshotCwd, extractArtifacts } from './artifacts-extractor.js';
|
|
22
|
+
import { applyMemoryPrefix } from './memory-injector.js';
|
|
22
23
|
// Runtime-error fingerprints → structured codehere:error events with recovery hints.
|
|
23
24
|
// Matched against any stderr line or assistant-text content we see on the stream.
|
|
24
25
|
const ERROR_PATTERNS = [
|
|
@@ -78,6 +79,12 @@ export function spawnClaudeCode(prompt, options = {}) {
|
|
|
78
79
|
let killRequested = false;
|
|
79
80
|
// PM UX Layer 2+3 state. Shared helper modules; per-session instances.
|
|
80
81
|
const cwd = options.cwd ?? process.cwd();
|
|
82
|
+
// F3 Task 8 — inject project memory (AGENTS.md + lessons + repo_map slice)
|
|
83
|
+
// into the prompt prefix unless the caller opted out. Pure, side-effect-
|
|
84
|
+
// free; returns unchanged prompt + record=undefined when there's no
|
|
85
|
+
// .codehere/ at cwd.
|
|
86
|
+
const injected = applyMemoryPrefix(prompt, cwd, options);
|
|
87
|
+
const finalPrompt = injected.prompt;
|
|
81
88
|
const snapshot = snapshotCwd(cwd);
|
|
82
89
|
const aggregator = new ProgressAggregator('claude-code');
|
|
83
90
|
let stepsSnapshot = [];
|
|
@@ -176,7 +183,7 @@ export function spawnClaudeCode(prompt, options = {}) {
|
|
|
176
183
|
}
|
|
177
184
|
let child;
|
|
178
185
|
try {
|
|
179
|
-
child = spawn('claude', ['-p',
|
|
186
|
+
child = spawn('claude', ['-p', finalPrompt, ...HEADLESS_FLAGS, ...(options.extraArgs ?? [])], {
|
|
180
187
|
cwd,
|
|
181
188
|
env: spawnEnv,
|
|
182
189
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -277,6 +284,7 @@ export function spawnClaudeCode(prompt, options = {}) {
|
|
|
277
284
|
startedAt,
|
|
278
285
|
prompt,
|
|
279
286
|
agent: 'claude-code',
|
|
287
|
+
memoryInjection: injected.record,
|
|
280
288
|
get status() {
|
|
281
289
|
return statusValue;
|
|
282
290
|
},
|
|
@@ -18,6 +18,7 @@ import { EventEmitter } from 'events';
|
|
|
18
18
|
import { randomUUID } from 'crypto';
|
|
19
19
|
import { ProgressAggregator } from './progress-aggregator.js';
|
|
20
20
|
import { snapshotCwd, extractArtifacts } from './artifacts-extractor.js';
|
|
21
|
+
import { applyMemoryPrefix } from './memory-injector.js';
|
|
21
22
|
const HEADLESS_FLAGS = [
|
|
22
23
|
'exec',
|
|
23
24
|
'--json',
|
|
@@ -73,6 +74,9 @@ export function spawnCodex(prompt, options = {}) {
|
|
|
73
74
|
// PM UX Layer 2+3 state — same shape as claude-code-adapter. Kept in-file (not
|
|
74
75
|
// extracted to a base class) because the two CLIs diverge in more than they share.
|
|
75
76
|
const cwd = options.cwd ?? process.cwd();
|
|
77
|
+
// F3 Task 8 — memory injection (same shape as every other adapter).
|
|
78
|
+
const injected = applyMemoryPrefix(prompt, cwd, options);
|
|
79
|
+
const finalPrompt = injected.prompt;
|
|
76
80
|
const snapshot = snapshotCwd(cwd);
|
|
77
81
|
const aggregator = new ProgressAggregator('codex');
|
|
78
82
|
let stepsSnapshot = [];
|
|
@@ -151,7 +155,7 @@ export function spawnCodex(prompt, options = {}) {
|
|
|
151
155
|
env: spawnEnv,
|
|
152
156
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
153
157
|
});
|
|
154
|
-
child.stdin?.write(
|
|
158
|
+
child.stdin?.write(finalPrompt);
|
|
155
159
|
child.stdin?.end();
|
|
156
160
|
}
|
|
157
161
|
catch (err) {
|
|
@@ -241,6 +245,7 @@ export function spawnCodex(prompt, options = {}) {
|
|
|
241
245
|
startedAt,
|
|
242
246
|
prompt,
|
|
243
247
|
agent: 'codex',
|
|
248
|
+
memoryInjection: injected.record,
|
|
244
249
|
get status() {
|
|
245
250
|
return statusValue;
|
|
246
251
|
},
|
|
@@ -284,8 +284,17 @@ function spawnConductor(prompt, options, lookup) {
|
|
|
284
284
|
let artifactsSnapshot;
|
|
285
285
|
specialistSession.subscribe((evt) => {
|
|
286
286
|
buffer.push(evt);
|
|
287
|
-
|
|
288
|
-
//
|
|
287
|
+
// Mirror progress + artifacts BEFORE re-emitting so any subscriber that
|
|
288
|
+
// reads `session.status` / `session.steps` / `session.artifacts` from
|
|
289
|
+
// inside its event handler sees the up-to-date conductor state.
|
|
290
|
+
//
|
|
291
|
+
// BUG 2 (zombie RUNNING sessions, May 1 2026, 138/155 records affected):
|
|
292
|
+
// pre-fix this block emitted FIRST and updated status SECOND. session-
|
|
293
|
+
// manager.ts subscribes to the conductor session and persists `session.status`
|
|
294
|
+
// synchronously inside its on-exit handler. With emit-before-update,
|
|
295
|
+
// every conductor session was persisted with status='running' even though
|
|
296
|
+
// the underlying specialist had already finished. The fix reorders so the
|
|
297
|
+
// emit() at the end sees the freshly-mirrored statusValue.
|
|
289
298
|
if (specialistSession.steps)
|
|
290
299
|
stepsSnapshot = specialistSession.steps;
|
|
291
300
|
if (specialistSession.artifacts)
|
|
@@ -298,6 +307,7 @@ function spawnConductor(prompt, options, lookup) {
|
|
|
298
307
|
if (evt.type === 'exit' || evt.type === 'codehere:complete' || evt.type === 'codehere:error') {
|
|
299
308
|
statusValue = specialistSession.status;
|
|
300
309
|
}
|
|
310
|
+
emitter.emit('event', evt);
|
|
301
311
|
});
|
|
302
312
|
return {
|
|
303
313
|
sessionId,
|