codehere 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +36 -192
  2. package/dist/application/use-cases/check-claimed-tests.js +81 -0
  3. package/dist/application/use-cases/detect-test-weakening.js +237 -0
  4. package/dist/application/use-cases/rerun-tests.js +110 -7
  5. package/dist/index.js +38 -1212
  6. package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -323
  7. package/dist/presentation/cli/commands/check-command.js +178 -23
  8. package/dist/presentation/cli/commands/help-command.js +21 -285
  9. package/dist/ui.js +5 -236
  10. package/dist/utils/version.js +0 -6
  11. package/package.json +9 -38
  12. package/dist/application/services/verdict-service.js +0 -154
  13. package/dist/application/use-cases/assess-cross-vendor.js +0 -126
  14. package/dist/application/use-cases/build-cross-vendor-verdict.js +0 -118
  15. package/dist/application/use-cases/domain-trust.js +0 -110
  16. package/dist/application/use-cases/export-aat.js +0 -107
  17. package/dist/application/use-cases/generate-acceptance-criteria.js +0 -223
  18. package/dist/application/use-cases/generate-final-report.js +0 -259
  19. package/dist/application/use-cases/generate-narration.js +0 -130
  20. package/dist/application/use-cases/generate-thread-title.js +0 -181
  21. package/dist/application/use-cases/narrator-prompt-template.js +0 -158
  22. package/dist/application/use-cases/plan-auto-review.js +0 -57
  23. package/dist/application/use-cases/reconcile-audit.js +0 -100
  24. package/dist/application/use-cases/search-sessions.js +0 -70
  25. package/dist/application/use-cases/should-auto-review.js +0 -71
  26. package/dist/application/use-cases/thread-export.js +0 -245
  27. package/dist/application/use-cases/verify-claim.js +0 -456
  28. package/dist/application/use-cases/write-pass.js +0 -277
  29. package/dist/domain/audit.js +0 -11
  30. package/dist/domain/services/codebase-detector.js +0 -85
  31. package/dist/domain/task.js +0 -91
  32. package/dist/error-handler.js +0 -139
  33. package/dist/infrastructure/completion/bash-completion.js +0 -29
  34. package/dist/infrastructure/completion/fish-completion.js +0 -17
  35. package/dist/infrastructure/completion/zsh-completion.js +0 -25
  36. package/dist/infrastructure/config/config-manager.js +0 -174
  37. package/dist/infrastructure/config/product-context.js +0 -49
  38. package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
  39. package/dist/infrastructure/context/adapters/figma-source.js +0 -198
  40. package/dist/infrastructure/context/adapters/github-issue-source.js +0 -160
  41. package/dist/infrastructure/context/adapters/linear-source.js +0 -190
  42. package/dist/infrastructure/context/context-resolver.js +0 -144
  43. package/dist/infrastructure/context/context-source.js +0 -114
  44. package/dist/infrastructure/context/github-api.js +0 -110
  45. package/dist/infrastructure/context/github-device-flow.js +0 -65
  46. package/dist/infrastructure/context/oauth-flow.js +0 -207
  47. package/dist/infrastructure/context/oauth-store.js +0 -122
  48. package/dist/infrastructure/context/registry-bootstrap.js +0 -95
  49. package/dist/infrastructure/context/write-pass-resolver.js +0 -106
  50. package/dist/infrastructure/cost/budget-config.js +0 -114
  51. package/dist/infrastructure/cost/cost-router.js +0 -97
  52. package/dist/infrastructure/cost/spend-aggregator.js +0 -222
  53. package/dist/infrastructure/cost/team-ledger.js +0 -355
  54. package/dist/infrastructure/discovery/discovery-log.js +0 -85
  55. package/dist/infrastructure/hooks/audit-tip-signature.js +0 -336
  56. package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -1018
  57. package/dist/infrastructure/hooks/hook-mode.js +0 -87
  58. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -49
  59. package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
  60. package/dist/infrastructure/hooks/session-analyzer.js +0 -177
  61. package/dist/infrastructure/observability/execution-tracer.js +0 -227
  62. package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
  63. package/dist/infrastructure/orchestration/agent-installer.js +0 -101
  64. package/dist/infrastructure/orchestration/agents-config-seed.js +0 -68
  65. package/dist/infrastructure/orchestration/aider-adapter.js +0 -611
  66. package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
  67. package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -592
  68. package/dist/infrastructure/orchestration/codex-adapter.js +0 -574
  69. package/dist/infrastructure/orchestration/conductor-adapter.js +0 -416
  70. package/dist/infrastructure/orchestration/context-handoff.js +0 -162
  71. package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
  72. package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
  73. package/dist/infrastructure/orchestration/detect-ollama.js +0 -75
  74. package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
  75. package/dist/infrastructure/orchestration/failover-config.js +0 -67
  76. package/dist/infrastructure/orchestration/failover-policy.js +0 -106
  77. package/dist/infrastructure/orchestration/gemini-adapter.js +0 -663
  78. package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -689
  79. package/dist/infrastructure/orchestration/graphify-context.js +0 -209
  80. package/dist/infrastructure/orchestration/memory-injector.js +0 -380
  81. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -388
  82. package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
  83. package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
  84. package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
  85. package/dist/infrastructure/orchestration/opencode-adapter.js +0 -580
  86. package/dist/infrastructure/orchestration/progress-aggregator.js +0 -906
  87. package/dist/infrastructure/orchestration/readiness.js +0 -103
  88. package/dist/infrastructure/orchestration/session-manager.js +0 -1590
  89. package/dist/infrastructure/orchestration/session-persistence.js +0 -394
  90. package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
  91. package/dist/infrastructure/orchestration/write-pass-store.js +0 -38
  92. package/dist/infrastructure/protocols/cloud-sync.js +0 -207
  93. package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
  94. package/dist/infrastructure/protocols/mcp-server-impl.js +0 -3935
  95. package/dist/infrastructure/protocols/mcp-tools.js +0 -401
  96. package/dist/infrastructure/protocols/probe-port.js +0 -36
  97. package/dist/infrastructure/protocols/thread-phase.js +0 -105
  98. package/dist/infrastructure/protocols/ui/app-script-artifacts.js +0 -121
  99. package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +0 -44
  100. package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +0 -56
  101. package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +0 -588
  102. package/dist/infrastructure/protocols/ui/app-script-context-sources.js +0 -168
  103. package/dist/infrastructure/protocols/ui/app-script-conversation.js +0 -67
  104. package/dist/infrastructure/protocols/ui/app-script-drawer.js +0 -115
  105. package/dist/infrastructure/protocols/ui/app-script-failover.js +0 -133
  106. package/dist/infrastructure/protocols/ui/app-script-github.js +0 -113
  107. package/dist/infrastructure/protocols/ui/app-script-observer.js +0 -104
  108. package/dist/infrastructure/protocols/ui/app-script-onboarding.js +0 -80
  109. package/dist/infrastructure/protocols/ui/app-script-overlay.js +0 -203
  110. package/dist/infrastructure/protocols/ui/app-script-recovery.js +0 -136
  111. package/dist/infrastructure/protocols/ui/app-script-render.js +0 -166
  112. package/dist/infrastructure/protocols/ui/app-script-share.js +0 -78
  113. package/dist/infrastructure/protocols/ui/app-script-sidebar.js +0 -194
  114. package/dist/infrastructure/protocols/ui/app-script-tour.js +0 -78
  115. package/dist/infrastructure/protocols/ui/app-script-wpass.js +0 -312
  116. package/dist/infrastructure/protocols/ui/app-script.js +0 -2998
  117. package/dist/infrastructure/protocols/ui/font-faces.js +0 -7
  118. package/dist/infrastructure/protocols/ui/styles.js +0 -2147
  119. package/dist/infrastructure/protocols/ui/tokens.js +0 -96
  120. package/dist/infrastructure/protocols/ui-page-v2.js +0 -320
  121. package/dist/infrastructure/protocols/verify-page.js +0 -1677
  122. package/dist/infrastructure/security/file-collection.js +0 -118
  123. package/dist/infrastructure/security/fix-code.js +0 -144
  124. package/dist/infrastructure/security/fix-secret.js +0 -89
  125. package/dist/infrastructure/security/permissions-config.js +0 -235
  126. package/dist/infrastructure/security/scan-types.js +0 -10
  127. package/dist/infrastructure/security/ship-scan.js +0 -195
  128. package/dist/infrastructure/security/trust-scorer.js +0 -724
  129. package/dist/infrastructure/security/vibe-checks.js +0 -99
  130. package/dist/infrastructure/storage/atomic-write.js +0 -86
  131. package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
  132. package/dist/infrastructure/storage/project-thread-migration.js +0 -237
  133. package/dist/infrastructure/storage/project-thread-mirror.js +0 -671
  134. package/dist/infrastructure/storage/project-thread-reader.js +0 -409
  135. package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
  136. package/dist/monitoring.js +0 -212
  137. package/dist/presentation/cli/commands/audit-command.js +0 -201
  138. package/dist/presentation/cli/commands/budget-command.js +0 -79
  139. package/dist/presentation/cli/commands/config-command.js +0 -125
  140. package/dist/presentation/cli/commands/context-source-command.js +0 -217
  141. package/dist/presentation/cli/commands/hook-command.js +0 -265
  142. package/dist/presentation/cli/commands/init-command.js +0 -590
  143. package/dist/presentation/cli/commands/memory-command.js +0 -1031
  144. package/dist/presentation/cli/commands/narrator-command.js +0 -101
  145. package/dist/presentation/cli/commands/permission-command.js +0 -105
  146. package/dist/presentation/cli/commands/protocols-builder.js +0 -254
  147. package/dist/presentation/cli/commands/protocols-command.js +0 -84
  148. package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
  149. package/dist/presentation/cli/commands/report-command.js +0 -403
  150. package/dist/presentation/cli/commands/scan-command.js +0 -52
  151. package/dist/presentation/cli/commands/scan-tool-command.js +0 -110
  152. package/dist/presentation/cli/commands/search-command.js +0 -51
  153. package/dist/presentation/cli/commands/setup-command.js +0 -330
  154. package/dist/presentation/cli/commands/status-command.js +0 -614
  155. package/dist/presentation/cli/commands/team-command.js +0 -256
  156. package/dist/presentation/cli/commands/thread-command.js +0 -370
  157. package/dist/presentation/cli/commands/trust-command.js +0 -328
  158. package/dist/presentation/cli/commands/verify-command.js +0 -298
  159. package/dist/presentation/cli/error-display.js +0 -328
  160. package/dist/presentation/cli/repl.js +0 -805
  161. package/dist/presentation/cli/task-deliverable.js +0 -153
  162. package/dist/testing/cassette.js +0 -125
  163. package/dist/testing/replay-adapter.js +0 -147
@@ -1,130 +0,0 @@
1
- /**
2
- * PM Narration — v0.6 M3 mid-task summary.
3
- *
4
- * While a task is in flight, periodically generates a one-paragraph
5
- * plain-English summary of what the agent has done so far. Fires on
6
- * step-count or elapsed-time thresholds (caller decides when).
7
- *
8
- * Per claim_user_persona HIGH: non-technical users primary. They don't
9
- * read tool calls; they read narration. Mid-task narration tells them
10
- * "the agent is currently editing your auth file and ran the tests"
11
- * instead of forcing them to interpret a list of Bash/Edit/Read steps.
12
- *
13
- * Per feedback_overconfidence_guard.md: narration is an LLM call.
14
- * Hallucination is possible. Surface MUST frame it as "narrator says…"
15
- * not authoritative truth. The PROMPT_TEMPLATE includes the same
16
- * anti-hallucination rule as generate-final-report (ground every claim
17
- * in the structured data).
18
- *
19
- * Provider strategy: env override, else claude (the dead claude-free
20
- * first, fall back to claude). Returns null if neither is installed.
21
- */
22
- import { spawn } from 'child_process';
23
- import { loadTemplate, renderTemplate } from './narrator-prompt-template.js';
24
- import { isMockMode } from '../../infrastructure/orchestration/mocks/resolve-agent-spawn.js';
25
- import { mockNarration } from '../../infrastructure/orchestration/mocks/mock-synthesis.js';
26
- /** v0.6 S6 — prompt template lifted into ~/.codehere/narrator-prompt.md so
27
- * the user can edit the agent's voice. loadTemplate() falls back to the
28
- * baked-in default on missing file or missing required placeholders, so
29
- * the prompt is never silently broken. See narrator-prompt-template.ts. */
30
- function buildPrompt(input) {
31
- const { template } = loadTemplate();
32
- return renderTemplate(template, input);
33
- }
34
- function selectProviderBinary() {
35
- // MED #27 (atomic audit) · the old chain led with 'claude-free' (the dead
36
- // FCC/NIM proxy final-report.ts abandoned) — every narration burned its
37
- // timeout against a down proxy first. Env override → claude, that's it.
38
- const override = process.env.CODEHERE_NARRATOR_BINARY?.trim();
39
- if (override)
40
- return [override];
41
- return ['claude'];
42
- }
43
- export async function generateNarration(input) {
44
- if (isMockMode()) {
45
- const m = mockNarration({ steps: input.steps });
46
- return {
47
- summary: m.summary,
48
- generatedAt: Date.now(),
49
- durationMs: m.durationMs,
50
- stepCountAtSnapshot: input.steps.length,
51
- };
52
- }
53
- const prompt = buildPrompt(input);
54
- const candidates = selectProviderBinary();
55
- for (const binary of candidates) {
56
- const result = await tryProvider(binary, prompt, input.sessionId, input.steps.length);
57
- if (result)
58
- return result;
59
- }
60
- return null;
61
- }
62
- function tryProvider(binary, prompt, sessionId, stepCount) {
63
- return new Promise((resolve) => {
64
- const startedAt = Date.now();
65
- let stdout = '';
66
- let stderr = '';
67
- let resolved = false;
68
- const finish = (val) => {
69
- if (resolved)
70
- return;
71
- resolved = true;
72
- resolve(val);
73
- };
74
- let child;
75
- try {
76
- // Same shape as generate-final-report's tryProvider — claude --bare -p.
77
- child = spawn(binary, ['--bare', '-p', prompt], {
78
- stdio: ['ignore', 'pipe', 'pipe'],
79
- });
80
- }
81
- catch {
82
- finish(null);
83
- return;
84
- }
85
- // 20s timeout — narration should be SNAPPIER than Final Report
86
- // (which is 60s). Mid-task = the user is actively waiting.
87
- const timeout = setTimeout(() => {
88
- try {
89
- child.kill();
90
- }
91
- catch {
92
- /* ignore */
93
- }
94
- finish(null);
95
- }, 20_000);
96
- child.stdout?.on('data', (chunk) => {
97
- stdout += chunk.toString('utf-8');
98
- });
99
- child.stderr?.on('data', (chunk) => {
100
- stderr += chunk.toString('utf-8');
101
- });
102
- child.on('close', (code) => {
103
- clearTimeout(timeout);
104
- if (code !== 0) {
105
- // Non-zero usually means binary missing OR the model refused. Either
106
- // way silent fail; caller treats null as "no narration this cycle".
107
- void stderr;
108
- void sessionId;
109
- finish(null);
110
- return;
111
- }
112
- const summary = stdout.trim();
113
- if (!summary || summary.length < 10) {
114
- finish(null);
115
- return;
116
- }
117
- finish({
118
- summary,
119
- generatedAt: Date.now(),
120
- durationMs: Date.now() - startedAt,
121
- stepCountAtSnapshot: stepCount,
122
- });
123
- });
124
- child.on('error', () => {
125
- clearTimeout(timeout);
126
- finish(null);
127
- });
128
- });
129
- }
130
- //# sourceMappingURL=generate-narration.js.map
@@ -1,181 +0,0 @@
1
- /**
2
- * Hidden Title agent — v0.6.0 M9.
3
- *
4
- * Generates a 4-6 word title for a project thread from its first user prompt.
5
- * Hidden = users don't pick it from any picker; fires automatically when the
6
- * project thread gets its first task entry. The title surfaces in the browser
7
- * tab + future thread switcher UI.
8
- *
9
- * Companion to generate-final-report.ts:
10
- * - Provider: env override → claude → graceful skip (dead claude-free hop removed)
11
- * - Same single-shot, no streaming, returns string
12
- * - Different prompt (terse title generation, NOT 3-paragraph narrative)
13
- * - Cheaper budget (~50 tokens per title vs 200 per Final Report paragraph)
14
- *
15
- * Triggering: project-thread-mirror invokes this when seeding the project-meta
16
- * header for a NEW project (i.e., this cwd's thread.jsonl didn't exist before).
17
- * Idempotent: subsequent task entries do NOT regenerate the title.
18
- *
19
- * Cost: ~1 LLM call per NEW project (not per task). At a typical 1-2 new
20
- * projects per week per user, the cost is negligible. FCC-routed when
21
- * available; degrades silently to "(untitled)" when no provider responds.
22
- */
23
- import { spawn } from 'child_process';
24
- import { isMockMode } from '../../infrastructure/orchestration/mocks/resolve-agent-spawn.js';
25
- import { mockTitle } from '../../infrastructure/orchestration/mocks/mock-synthesis.js';
26
- const TITLE_TIMEOUT_MS = 15_000; // titles are short; abort fast if stuck
27
- const PROMPT_TEMPLATE = (firstPrompt, cwd) => `Generate a 4-6 word project title from this first user prompt.
28
-
29
- Project working directory: ${cwd}
30
- First prompt: ${firstPrompt}
31
-
32
- Rules:
33
- - 4 to 6 words MAX
34
- - No quotes, no punctuation, no trailing period
35
- - Title-case (e.g. "Auth Bug Fix Sprint")
36
- - Ground the title in the prompt + cwd ONLY. Do NOT invent project subject
37
- matter you can't derive from the data above (e.g. don't infer "Thread
38
- Interface Updates" from a "list files" prompt — say what the user
39
- actually asked, not what you imagine the project is about).
40
- - If the prompt is too generic to title meaningfully, prefer naming the
41
- cwd's last path segment (e.g. "Taste V0.6 Workspace") over invention.
42
- - Output ONLY the title — no preamble, no explanation
43
-
44
- Title:`;
45
- function selectProviderBinary() {
46
- // MED #28 (atomic audit) · same dead 'claude-free' first hop as narration —
47
- // removed so a title either comes from claude or degrades fast, not after
48
- // a proxy timeout.
49
- const override = process.env.CODEHERE_TITLE_BINARY;
50
- if (override)
51
- return [override];
52
- return ['claude'];
53
- }
54
- function tryProvider(binary, prompt) {
55
- return new Promise((resolve) => {
56
- let stdout = '';
57
- let settled = false;
58
- const finish = (result) => {
59
- if (settled)
60
- return;
61
- settled = true;
62
- resolve(result);
63
- };
64
- const child = spawn(binary, ['--bare', '-p', prompt], {
65
- stdio: ['ignore', 'pipe', 'pipe'],
66
- });
67
- const timeout = setTimeout(() => {
68
- child.kill('SIGTERM');
69
- if (process.env.CODEHERE_DEBUG === '1') {
70
- console.error(`[title-agent] ${binary} timeout after ${TITLE_TIMEOUT_MS}ms`);
71
- }
72
- finish(null);
73
- }, TITLE_TIMEOUT_MS);
74
- child.on('error', () => {
75
- clearTimeout(timeout);
76
- finish(null); // ENOENT etc. — silent fallback to next provider
77
- });
78
- child.stdout?.on('data', (chunk) => {
79
- stdout += chunk.toString('utf-8');
80
- });
81
- child.on('exit', (code) => {
82
- clearTimeout(timeout);
83
- if (code !== 0) {
84
- finish(null);
85
- return;
86
- }
87
- const title = sanitizeTitle(stdout);
88
- if (!title) {
89
- finish(null);
90
- return;
91
- }
92
- finish(title);
93
- });
94
- });
95
- }
96
- /**
97
- * Strip whitespace / quotes / trailing punctuation. Cap at 80 chars.
98
- *
99
- * Garbage rejection (added 2026-05-06 after dogfood Bug A4): the underlying
100
- * `claude --bare` call can return error-shaped text on stdout with exit 0
101
- * (rate-limit messages, auth errors, refusals). Pre-fix those flowed straight
102
- * into the project sidebar as titles like "Request ID: req_xyz...". We now
103
- * detect obvious error / refusal patterns and return '' so the caller falls
104
- * back to the cwd-derived title.
105
- */
106
- export function sanitizeTitle(raw) {
107
- const lines = raw
108
- .split('\n')
109
- .map((l) => l.trim())
110
- .filter(Boolean);
111
- if (lines.length === 0)
112
- return '';
113
- let title = lines[lines.length - 1]; // last non-empty line is the answer
114
- // Strip surrounding quotes
115
- title = title.replace(/^["'`]+|["'`]+$/g, '');
116
- // Strip trailing punctuation
117
- title = title.replace(/[.!?,;:]+$/, '');
118
- // Cap at 80 chars
119
- if (title.length > 80)
120
- title = title.slice(0, 77) + '...';
121
- title = title.trim();
122
- if (!title)
123
- return '';
124
- // Garbage rejection — patterns that indicate an error response, NOT a title.
125
- // Each pattern matches a real failure mode observed in dogfood:
126
- // - "Request ID: req_..." → API error envelope leaking through
127
- // - "Error:" / "ERROR" / "error " → generic error prefix
128
- // - "I cannot" / "I can't" → model refusal
129
- // - "I apologize" / "I'm sorry" → model refusal
130
- // - "Rate limit" / "rate-limited" → quota error
131
- // - "Authentication" / "Unauthorized" / "401" / "403" → auth failure
132
- // - Long sentences (>10 words) → not a title; model ignored the rules
133
- // - Contains http:// or https:// → URL leakage from error envelope
134
- const lower = title.toLowerCase();
135
- const garbageMarkers = [
136
- /^request\s+id\s*[:=]/i,
137
- /^error\b/i,
138
- /\berror[:\s]/i,
139
- /^i\s+(cannot|can'?t|am\s+unable|won'?t)\b/i,
140
- /^i\s+(apologi[sz]e|am\s+sorry)\b/i,
141
- /^i'?m\s+sorry\b/i,
142
- /\brate\s*[-_]?\s*limit/i,
143
- /\b(authentication|unauthori[sz]ed|forbidden)\b/i,
144
- /\b(401|403|429|500|502|503)\b/i,
145
- /https?:\/\//i,
146
- /api[_-]?key/i,
147
- ];
148
- if (garbageMarkers.some((re) => re.test(lower))) {
149
- if (process.env.CODEHERE_DEBUG === '1') {
150
- console.error(`[title-agent] rejected garbage title: ${title.slice(0, 60)}`);
151
- }
152
- return '';
153
- }
154
- // Length sanity: a real title is 4-6 words per the prompt; allow up to 10
155
- // for slack. Anything longer is the model ignoring instructions.
156
- const wordCount = title.split(/\s+/).filter(Boolean).length;
157
- if (wordCount > 10) {
158
- if (process.env.CODEHERE_DEBUG === '1') {
159
- console.error(`[title-agent] rejected long title (${wordCount} words): ${title.slice(0, 60)}`);
160
- }
161
- return '';
162
- }
163
- return title;
164
- }
165
- /**
166
- * Generate a thread title from the first user prompt + cwd context.
167
- * Returns the title string, or null if no provider is reachable.
168
- * Never throws — failure modes return null.
169
- */
170
- export async function generateThreadTitle(firstPrompt, cwd) {
171
- if (isMockMode())
172
- return sanitizeTitle(mockTitle(firstPrompt, cwd)) || null;
173
- const prompt = PROMPT_TEMPLATE(firstPrompt, cwd);
174
- for (const binary of selectProviderBinary()) {
175
- const result = await tryProvider(binary, prompt);
176
- if (result)
177
- return result;
178
- }
179
- return null;
180
- }
181
- //# sourceMappingURL=generate-thread-title.js.map
@@ -1,158 +0,0 @@
1
- /**
2
- * v0.6 S6 — editable PM narrator prompt template.
3
- *
4
- * The mid-task narration (M3) used to ship a hard-coded prompt baked into
5
- * generate-narration.ts. That made the agent's "voice" un-tunable: a user
6
- * who wanted shorter / longer / more-jargony / less-jargony narration
7
- * had no lever short of forking the source.
8
- *
9
- * S6 lifts the template into ~/.codehere/narrator-prompt.md, a plain
10
- * Markdown file the user edits with whatever editor they like. The file
11
- * uses `{{placeholder}}` substitution for the runtime values:
12
- * {{prompt}} — the user's original task ask (truncated 500ch)
13
- * {{agent}} — which adapter is running ("claude-code" etc.)
14
- * {{elapsed_seconds}} — how long the task has been running
15
- * {{step_count}} — how many steps completed/in-progress
16
- * {{steps}} — last 15 steps, " N. [state] label"
17
- *
18
- * If the file is missing OR the user-edited file is missing required
19
- * placeholders, we fall back to the baked-in DEFAULT_TEMPLATE so a typo
20
- * never breaks narration silently.
21
- *
22
- * Per claim_user_persona HIGH: the narrator IS the product voice for
23
- * non-technical users. Letting them control it is a v1 promise.
24
- *
25
- * Per feedback_overconfidence_guard.md: the DEFAULT_TEMPLATE keeps the
26
- * anti-hallucination rule + "frame as narrator not authority" cue. Users
27
- * editing the template can drop those rules at their own risk; the file
28
- * comment warns about it.
29
- */
30
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs';
31
- import { dirname, join } from 'path';
32
- import { homedir } from 'os';
33
- /** The required placeholders. If a user-edited template is missing ANY of
34
- * these we fall back to the default so the rendered prompt is never
35
- * silently broken. {{step_count}} is omitted from the required list — it's
36
- * derivable from {{steps}} and a custom template might intentionally drop it. */
37
- const REQUIRED_PLACEHOLDERS = ['{{prompt}}', '{{agent}}', '{{elapsed_seconds}}', '{{steps}}'];
38
- export const DEFAULT_TEMPLATE = `<!--
39
- codehere narrator prompt — drives the mid-task summary the user sees as
40
- "narrator says…" while their AI coding agent is working. Edit freely.
41
-
42
- Available placeholders (substituted at render time):
43
- {{prompt}} user's original task ask
44
- {{agent}} which adapter is running
45
- {{elapsed_seconds}} how long the task has been running
46
- {{step_count}} number of steps completed/in-progress
47
- {{steps}} last 15 steps, formatted as " N. [state] label"
48
-
49
- REQUIRED: {{prompt}}, {{agent}}, {{elapsed_seconds}}, {{steps}}.
50
- Missing any of those → codehere falls back to its baked-in default.
51
-
52
- Reset to default any time with: codehere narrator reset
53
- -->
54
-
55
- You are a PM giving a 1-sentence-or-2 mid-task update to a non-technical user
56
- about what their AI coding agent is doing RIGHT NOW. Write ONE short paragraph
57
- (2-3 sentences). No headers, no bullet lists, no markdown.
58
-
59
- CRITICAL anti-hallucination rule: ground every claim in the structured data
60
- below. Do not invent file names, status, or actions not in the steps list.
61
- If you don't know what something does, say "the agent is working on …" with
62
- the literal target. Better to under-claim than to over-claim.
63
-
64
- Tone: like a colleague checking in. "It's reading the auth file and ran the
65
- tests — looks like 2 failed so far." Not robotic, not breathless.
66
-
67
- Reference frame for the user (not for the LLM): the user did NOT see this
68
- list directly; you're translating it for them. The user only sees your
69
- paragraph.
70
-
71
- ────────── Structured data (the only source of truth) ──────────
72
- Task: "{{prompt}}"
73
- Agent: {{agent}}
74
- Elapsed: {{elapsed_seconds}}s
75
- Steps so far ({{step_count}}):
76
- {{steps}}
77
-
78
- Write the paragraph now. Do not preface with "Update:" or anything similar.
79
- Plain prose. No "I'm currently…" — narrate the AGENT, not yourself.
80
- `;
81
- function templateFile() {
82
- return join(process.env.CODEHERE_HOME || homedir(), '.codehere', 'narrator-prompt.md');
83
- }
84
- /** Read the user-customized template if present and valid. Falls back to
85
- * baked-in default on missing file, parse failure, or missing required
86
- * placeholders (so a typo never silently breaks narration). */
87
- export function loadTemplate() {
88
- const path = templateFile();
89
- if (!existsSync(path))
90
- return { source: 'default', template: DEFAULT_TEMPLATE };
91
- let raw;
92
- try {
93
- raw = readFileSync(path, 'utf-8');
94
- }
95
- catch {
96
- return { source: 'default', template: DEFAULT_TEMPLATE };
97
- }
98
- for (const ph of REQUIRED_PLACEHOLDERS) {
99
- if (!raw.includes(ph)) {
100
- return { source: 'default', template: DEFAULT_TEMPLATE };
101
- }
102
- }
103
- return { source: 'user', template: raw };
104
- }
105
- /** Persist the default template to disk so the user has a starting point
106
- * to edit. Used by `codehere narrator edit`. Doesn't overwrite an existing
107
- * user-edited file unless `force` is set. */
108
- export function writeDefaultTemplate(force = false) {
109
- const path = templateFile();
110
- if (!force && existsSync(path))
111
- return { wrote: false, path };
112
- const dir = dirname(path);
113
- if (!existsSync(dir))
114
- mkdirSync(dir, { recursive: true });
115
- writeFileSync(path, DEFAULT_TEMPLATE, 'utf-8');
116
- return { wrote: true, path };
117
- }
118
- /** Delete the user-customized template. Future loads use the baked-in
119
- * default. Idempotent: missing file is a no-op success. */
120
- export function resetTemplate() {
121
- const path = templateFile();
122
- if (!existsSync(path))
123
- return { removed: false, path };
124
- try {
125
- unlinkSync(path);
126
- return { removed: true, path };
127
- }
128
- catch {
129
- return { removed: false, path };
130
- }
131
- }
132
- /** Substitute the runtime values into the template. Same {{placeholder}}
133
- * protocol as the template-file comments document. */
134
- export function renderTemplate(template, input) {
135
- const stepsBlock = input.steps
136
- .slice(-15)
137
- .map((s, idx) => ` ${idx + 1}. [${s.state}] ${(s.label ?? '').slice(0, 120)}`)
138
- .join('\n');
139
- const replacements = {
140
- '{{prompt}}': input.prompt.slice(0, 500),
141
- '{{agent}}': input.agent,
142
- '{{elapsed_seconds}}': String(Math.round(input.elapsedMs / 1000)),
143
- '{{step_count}}': String(input.steps.length),
144
- '{{steps}}': stepsBlock,
145
- };
146
- let out = template;
147
- for (const [k, v] of Object.entries(replacements)) {
148
- // Replace ALL occurrences. Use split/join to avoid regex escaping
149
- // pain on the curly braces.
150
- out = out.split(k).join(v);
151
- }
152
- return out;
153
- }
154
- /** Path to the user-customized template (for CLI status display). */
155
- export function templatePath() {
156
- return templateFile();
157
- }
158
- //# sourceMappingURL=narrator-prompt-template.js.map
@@ -1,57 +0,0 @@
1
- /**
2
- * Tier 2.1 · slice 2b — turn the eligibility decision into a concrete,
3
- * loop-safe plan for the auto cross-vendor review spawn. Still pure: it decides
4
- * WHAT to spawn (vendor, prompt, cwd, tag), not how — the live spawn + the
5
- * real-spend verification are the next slice. Kept pure so the loop guard and
6
- * the refute framing are unit-testable without a daemon or spend.
7
- *
8
- * THE LOOP GUARD is the load-bearing safety here: an auto-review is itself a
9
- * task that completes and flows through the same completion handler. Without a
10
- * guard it would trigger its own auto-review, recursing + burning spend forever.
11
- * A reviewer session is tagged; planAutoReview returns null for tagged sessions.
12
- *
13
- * The reviewer runs in REFUTE mode and READ-ONLY: codehere proves the PROCESS
14
- * (a different vendor independently reviewed + recorded findings), it never
15
- * adjudicates code correctness (assess-cross-vendor honesty note). The prompt
16
- * asks the reviewer to try to disprove "done", not to fix anything.
17
- */
18
- import { shouldAutoReview } from './should-auto-review.js';
19
- /** Tag stamped on an auto-review reviewer session so it never triggers its own
20
- * auto-review (the loop guard) and so surfaces can label it. */
21
- export const AUTO_REVIEW_TAG = 'auto-cross-vendor-review';
22
- /** The refute-mode brief: read-only, adversarial, names the writer's files. */
23
- function buildRefutePrompt(writerAgent, files) {
24
- const fileList = files.length <= 10 ? files.join(', ') : `${files.slice(0, 10).join(', ')} (+${files.length - 10} more)`;
25
- return (`A different agent (${writerAgent}) just changed these files in this repo: ${fileList}. ` +
26
- `Independently review that work READ-ONLY — do not edit anything. ` +
27
- `Try to disprove that the task is correctly done: look for bugs, missed edge cases, ` +
28
- `or claims the diff doesn't actually support. Report what you find (or that it holds up). ` +
29
- `You are the second vendor in a cross-vendor check; your job is to refute, not to fix.`);
30
- }
31
- /**
32
- * Build the auto-review spawn plan, or null if it shouldn't / can't run.
33
- * Returns null (with no side effects) for: the loop guard, or any failed
34
- * eligibility gate. Pure.
35
- */
36
- export function planAutoReview(facts, thresholds) {
37
- // Loop guard FIRST — a reviewer's own completion must never spawn a review.
38
- if (facts.isAutoReviewSession)
39
- return null;
40
- const inputs = {
41
- writerAgent: facts.writerAgent,
42
- installedAgents: facts.installedAgents,
43
- filesChanged: facts.writerFiles.length,
44
- budgetRemainingUsd: facts.budgetRemainingUsd,
45
- };
46
- const decision = shouldAutoReview(inputs, thresholds);
47
- if (!decision.eligible || !decision.reviewerVendor)
48
- return null;
49
- return {
50
- reviewerVendor: decision.reviewerVendor,
51
- prompt: buildRefutePrompt(facts.writerAgent, facts.writerFiles),
52
- cwd: facts.cwd,
53
- tag: AUTO_REVIEW_TAG,
54
- reason: decision.reason,
55
- };
56
- }
57
- //# sourceMappingURL=plan-auto-review.js.map
@@ -1,100 +0,0 @@
1
- /**
2
- * Tier 1.2 (verdict-trust punch list, 2026-06-09) · reconcile the AUDIT against
3
- * the real on-disk effect.
4
- *
5
- * The gap this closes: an audit entry records the agent's DECLARED tool call
6
- * (PreToolUse intent for claude, a post-hoc mirror for the others) — not an
7
- * independent observation that the write actually landed. An agent (or adapter)
8
- * that emits a file-write tool_use which never really changed anything lands that
9
- * fiction in the integrity-checked chain as a first-class entry. The chain then
10
- * faithfully shows the CLAIM was never casually edited — it never checks the claim
11
- * against reality.
12
- *
13
- * This reconciles the audit's file-write tool calls against the SAME git-diff
14
- * ground truth verify-claim already uses for file claims. It does NOT mutate the
15
- * append-only, hash-chained audit (that would break tamper-evidence) — it's a
16
- * read-only layer that produces an honest verdict the surface can show:
17
- * - consistent · writes recorded AND files changed on disk
18
- * - unconfirmed · writes recorded but codehere couldn't tie them to a tracked
19
- * git change. Honest, NOT an accusation: the writes may have
20
- * targeted gitignored / scratch / .codehere paths (which the
21
- * git-diff ground truth excludes), been reverted within the
22
- * run, or — the case worth a look — never really happened.
23
- * "couldn't confirm", never "it's fake" (refuter 2026-06-09:
24
- * a false fabrication accusation on honest work is the worst
25
- * error class on a proof surface).
26
- * - no-writes · nothing claimed, nothing to reconcile
27
- * - unobservable · not a git repo, so codehere can't confirm
28
- *
29
- * Count-based by design: toolInput is truncated/heterogeneous across adapters, so
30
- * per-file path matching is unreliable; the file-write COUNT vs the git-change
31
- * count is robust. Bash/shell tools can also write files but codehere can't tell,
32
- * so they're deliberately NOT counted as declared writes (conservative — never
33
- * fabricates a "declared-not-observed" the user can't act on).
34
- */
35
- /** Tool names that explicitly mutate a file on disk, across every adapter.
36
- * Derived from the real audit's toolName distribution (Write/Edit/write_file/
37
- * edit_file observed) plus the standard variants. Shell tools are excluded — a
38
- * bash `echo > f` can't be distinguished from a read, so counting it would
39
- * manufacture false "declared-not-observed" verdicts. */
40
- // Matched case-INSENSITIVELY (adapters emit varied casings: claude 'Edit',
41
- // codex 'Delete', gemini raw tool_name like 'write_file'/'replace'). A DELETE is
42
- // a real file mutation that shows in git — omitting it made a codex delete-only
43
- // run falsely read "no writes recorded" (self-audit 2026-06-09). Keep this broad;
44
- // over-counting a non-write is far less harmful than a false "nothing happened".
45
- const WRITE_TOOLS = new Set(
46
- // SPECIFIC file-mutation tool names only. Bare generic verbs ('replace',
47
- // 'patch') are deliberately EXCLUDED — a non-file tool named 'replace' (an
48
- // in-memory string replace) would false-count and produce a false 'consistent'
49
- // (worse than under-counting, which is an honest 'unconfirmed'). A real write
50
- // the set misses → 'unconfirmed' (honest), never a fabricated-write laundered
51
- // into green (self-audit round 2, 2026-06-09).
52
- [
53
- 'Write',
54
- 'Edit',
55
- 'MultiEdit',
56
- 'NotebookEdit',
57
- 'Delete',
58
- 'write_file',
59
- 'edit_file',
60
- 'create_file',
61
- 'delete_file',
62
- 'str_replace',
63
- 'str_replace_editor',
64
- 'apply_patch',
65
- ].map((t) => t.toLowerCase()));
66
- export function reconcileAudit(entries, artifacts) {
67
- const writeToolCalls = entries.filter((e) => WRITE_TOOLS.has((e.toolName || '').toLowerCase())).length;
68
- const filesObserved = artifacts?.files?.length ?? 0;
69
- if (artifacts?.noGitTracking) {
70
- return {
71
- writeToolCalls,
72
- filesObserved: 0,
73
- verdict: 'unobservable',
74
- note: `${writeToolCalls} file-write tool call${writeToolCalls === 1 ? '' : 's'} recorded, but this folder isn't a git repo — codehere can't confirm them against disk.`,
75
- };
76
- }
77
- if (writeToolCalls === 0) {
78
- return {
79
- writeToolCalls,
80
- filesObserved,
81
- verdict: 'no-writes',
82
- note: 'No file-write tool calls recorded — nothing to reconcile against disk.',
83
- };
84
- }
85
- if (filesObserved === 0) {
86
- return {
87
- writeToolCalls,
88
- filesObserved,
89
- verdict: 'unconfirmed',
90
- note: `${writeToolCalls} file-write tool call${writeToolCalls === 1 ? '' : 's'} recorded, but codehere couldn't confirm them against tracked git changes — they may have targeted gitignored/scratch paths or been reverted. Worth a look, not proof of a problem.`,
91
- };
92
- }
93
- return {
94
- writeToolCalls,
95
- filesObserved,
96
- verdict: 'consistent',
97
- note: `${writeToolCalls} file-write tool call${writeToolCalls === 1 ? '' : 's'} recorded · ${filesObserved} file${filesObserved === 1 ? '' : 's'} confirmed changed on disk.`,
98
- };
99
- }
100
- //# sourceMappingURL=reconcile-audit.js.map