codehere 0.8.0 → 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.
- package/README.md +37 -184
- package/dist/application/use-cases/check-claimed-tests.js +81 -0
- package/dist/application/use-cases/detect-test-weakening.js +237 -0
- package/dist/application/use-cases/rerun-tests.js +329 -0
- package/dist/index.js +74 -1004
- package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -265
- package/dist/presentation/cli/commands/check-command.js +251 -0
- package/dist/presentation/cli/commands/help-command.js +22 -286
- package/dist/ui.js +19 -438
- package/dist/utils/version.js +0 -12
- package/package.json +18 -27
- package/dist/application/use-cases/domain-trust.js +0 -110
- package/dist/application/use-cases/generate-final-report.js +0 -134
- package/dist/application/use-cases/generate-narration.js +0 -128
- package/dist/application/use-cases/generate-thread-title.js +0 -178
- package/dist/application/use-cases/narrator-prompt-template.js +0 -158
- package/dist/application/use-cases/thread-export.js +0 -155
- package/dist/application/use-cases/verify-claim.js +0 -274
- package/dist/application/use-cases/write-pass.js +0 -277
- package/dist/domain/entities/task.js +0 -61
- package/dist/domain/services/codebase-detector.js +0 -91
- package/dist/error-handler.js +0 -251
- package/dist/infrastructure/completion/bash-completion.js +0 -25
- package/dist/infrastructure/completion/fish-completion.js +0 -22
- package/dist/infrastructure/completion/zsh-completion.js +0 -30
- package/dist/infrastructure/config/config-manager.js +0 -173
- package/dist/infrastructure/config/product-context.js +0 -67
- package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
- package/dist/infrastructure/context/adapters/figma-source.js +0 -163
- package/dist/infrastructure/context/adapters/github-issue-source.js +0 -159
- package/dist/infrastructure/context/adapters/linear-source.js +0 -190
- package/dist/infrastructure/context/context-resolver.js +0 -144
- package/dist/infrastructure/context/context-source.js +0 -114
- package/dist/infrastructure/context/oauth-flow.js +0 -207
- package/dist/infrastructure/context/oauth-store.js +0 -119
- package/dist/infrastructure/context/registry-bootstrap.js +0 -99
- package/dist/infrastructure/context/write-pass-resolver.js +0 -106
- package/dist/infrastructure/cost/budget-config.js +0 -113
- package/dist/infrastructure/cost/cost-router.js +0 -104
- package/dist/infrastructure/cost/spend-aggregator.js +0 -147
- package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -888
- package/dist/infrastructure/hooks/hook-mode.js +0 -71
- package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -43
- package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
- package/dist/infrastructure/hooks/session-analyzer.js +0 -177
- package/dist/infrastructure/observability/execution-tracer.js +0 -227
- package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
- package/dist/infrastructure/orchestration/agent-installer.js +0 -101
- package/dist/infrastructure/orchestration/agents-config-seed.js +0 -56
- package/dist/infrastructure/orchestration/aider-adapter.js +0 -447
- package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
- package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -478
- package/dist/infrastructure/orchestration/codex-adapter.js +0 -538
- package/dist/infrastructure/orchestration/conductor-adapter.js +0 -377
- package/dist/infrastructure/orchestration/context-handoff.js +0 -144
- package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
- package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
- package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
- package/dist/infrastructure/orchestration/failover-config.js +0 -77
- package/dist/infrastructure/orchestration/failover-policy.js +0 -106
- package/dist/infrastructure/orchestration/gemini-adapter.js +0 -583
- package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -558
- package/dist/infrastructure/orchestration/graphify-context.js +0 -254
- package/dist/infrastructure/orchestration/memory-injector.js +0 -380
- package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -233
- package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
- package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
- package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
- package/dist/infrastructure/orchestration/opencode-adapter.js +0 -510
- package/dist/infrastructure/orchestration/progress-aggregator.js +0 -689
- package/dist/infrastructure/orchestration/readiness.js +0 -103
- package/dist/infrastructure/orchestration/session-manager.js +0 -1091
- package/dist/infrastructure/orchestration/session-persistence.js +0 -258
- package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
- package/dist/infrastructure/orchestration/write-pass-store.js +0 -46
- package/dist/infrastructure/protocols/cloud-sync.js +0 -207
- package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
- package/dist/infrastructure/protocols/mcp-server-impl.js +0 -2853
- package/dist/infrastructure/protocols/probe-port.js +0 -36
- package/dist/infrastructure/protocols/thread-phase.js +0 -105
- package/dist/infrastructure/protocols/ui-page-v2.js +0 -4418
- package/dist/infrastructure/protocols/ui-page.js +0 -2377
- package/dist/infrastructure/protocols/verify-page.js +0 -983
- package/dist/infrastructure/security/file-collection.js +0 -118
- package/dist/infrastructure/security/input-validator.js +0 -152
- package/dist/infrastructure/security/permissions-config.js +0 -234
- package/dist/infrastructure/security/trust-scorer.js +0 -657
- package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
- package/dist/infrastructure/storage/embeddings-path.js +0 -37
- package/dist/infrastructure/storage/project-thread-migration.js +0 -237
- package/dist/infrastructure/storage/project-thread-mirror.js +0 -524
- package/dist/infrastructure/storage/project-thread-reader.js +0 -172
- package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
- package/dist/infrastructure/storage/task-repository.js +0 -206
- package/dist/monitoring.js +0 -212
- package/dist/presentation/cli/commands/audit-command.js +0 -126
- package/dist/presentation/cli/commands/budget-command.js +0 -79
- package/dist/presentation/cli/commands/config-command.js +0 -125
- package/dist/presentation/cli/commands/context-source-command.js +0 -198
- package/dist/presentation/cli/commands/hook-command.js +0 -265
- package/dist/presentation/cli/commands/init-command.js +0 -578
- package/dist/presentation/cli/commands/memory-command.js +0 -1031
- package/dist/presentation/cli/commands/narrator-command.js +0 -101
- package/dist/presentation/cli/commands/permission-command.js +0 -116
- package/dist/presentation/cli/commands/protocols-builder.js +0 -254
- package/dist/presentation/cli/commands/protocols-command.js +0 -84
- package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
- package/dist/presentation/cli/commands/report-command.js +0 -387
- package/dist/presentation/cli/commands/scan-tool-command.js +0 -94
- package/dist/presentation/cli/commands/setup-command.js +0 -307
- package/dist/presentation/cli/commands/status-command.js +0 -661
- package/dist/presentation/cli/commands/thread-command.js +0 -288
- package/dist/presentation/cli/commands/trust-command.js +0 -306
- package/dist/presentation/cli/commands/verify-command.js +0 -233
- package/dist/presentation/cli/error-display.js +0 -336
- package/dist/presentation/cli/repl.js +0 -797
- package/dist/presentation/cli/task-deliverable.js +0 -127
- package/dist/testing/cassette.js +0 -125
- package/dist/testing/replay-adapter.js +0 -166
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI command: verify
|
|
3
|
-
*
|
|
4
|
-
* v0.7 verifier-agent · Slice 2 (CLI surface for the pure verify-claim use case).
|
|
5
|
-
*
|
|
6
|
-
* Compares what the agent's Final Report TEXT claims against the structured
|
|
7
|
-
* reality (artifacts + steps) captured during the session. Catches the
|
|
8
|
-
* easy lies before they reach a PR description.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* codehere verify <session-id> # run verifier on a completed session
|
|
12
|
-
* codehere verify <session-id> --json # machine-readable output for CI
|
|
13
|
-
* codehere verify # list recent sessions to pick from
|
|
14
|
-
*
|
|
15
|
-
* Exit codes:
|
|
16
|
-
* 0 = verified OR partial (warnings only · unverifiable claims)
|
|
17
|
-
* 0 = no-report (nothing to verify; not a failure)
|
|
18
|
-
* 1 = broken (at least one claim contradicts recorded reality)
|
|
19
|
-
* 2 = session not found / invalid input
|
|
20
|
-
*
|
|
21
|
-
* The verifier is intentionally conservative: only claims that map to
|
|
22
|
-
* structured data are checked. Prose claims pass through silently.
|
|
23
|
-
*/
|
|
24
|
-
import { colors, symbols } from '../../../ui.js';
|
|
25
|
-
import { loadSessionById, loadRecent, } from '../../../infrastructure/orchestration/session-persistence.js';
|
|
26
|
-
import { verifyClaim } from '../../../application/use-cases/verify-claim.js';
|
|
27
|
-
export async function executeVerifyCommand(sessionId, options = {}) {
|
|
28
|
-
// No session id: show a picker list and exit gracefully.
|
|
29
|
-
if (!sessionId) {
|
|
30
|
-
return showSessionPicker(options.json ?? false);
|
|
31
|
-
}
|
|
32
|
-
const session = loadSessionById(sessionId);
|
|
33
|
-
if (!session) {
|
|
34
|
-
if (options.json) {
|
|
35
|
-
process.stdout.write(JSON.stringify({
|
|
36
|
-
error: 'session-not-found',
|
|
37
|
-
sessionId,
|
|
38
|
-
hint: 'Run `codehere verify` (no args) to list recent sessions.',
|
|
39
|
-
}, null, 2) + '\n');
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
process.stderr.write(colors.error(`${symbols.error} No completed session found matching "${sessionId}".\n`) +
|
|
43
|
-
colors.dim(' Tip: run `codehere verify` (no args) to see recent sessions.\n'));
|
|
44
|
-
}
|
|
45
|
-
return 2;
|
|
46
|
-
}
|
|
47
|
-
const result = verifyClaim({
|
|
48
|
-
summary: session.finalReport?.summary,
|
|
49
|
-
artifacts: session.artifacts,
|
|
50
|
-
steps: session.steps,
|
|
51
|
-
});
|
|
52
|
-
if (options.json) {
|
|
53
|
-
process.stdout.write(JSON.stringify(serializeResult(session, result), null, 2) + '\n');
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
printHumanReadable(session, result);
|
|
57
|
-
}
|
|
58
|
-
// Exit code: only `broken` is a hard failure (CI-friendly).
|
|
59
|
-
return result.status === 'broken' ? 1 : 0;
|
|
60
|
-
}
|
|
61
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
62
|
-
/* Picker mode · no session id given */
|
|
63
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
64
|
-
function showSessionPicker(json) {
|
|
65
|
-
const recent = loadRecent(15);
|
|
66
|
-
if (recent.length === 0) {
|
|
67
|
-
if (json) {
|
|
68
|
-
process.stdout.write(JSON.stringify({ sessions: [], note: 'No completed sessions found.' }, null, 2) + '\n');
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
process.stdout.write(colors.dim('No completed sessions found. Run a task first, then verify it:\n') +
|
|
72
|
-
colors.dim(' codehere task "describe what you want done"\n'));
|
|
73
|
-
}
|
|
74
|
-
return 0;
|
|
75
|
-
}
|
|
76
|
-
if (json) {
|
|
77
|
-
const items = recent.map((s) => ({
|
|
78
|
-
sessionId: s.sessionId,
|
|
79
|
-
agent: s.agent,
|
|
80
|
-
prompt: s.prompt,
|
|
81
|
-
completedAt: s.completedAt,
|
|
82
|
-
hasFinalReport: Boolean(s.finalReport),
|
|
83
|
-
}));
|
|
84
|
-
process.stdout.write(JSON.stringify({ sessions: items }, null, 2) + '\n');
|
|
85
|
-
return 0;
|
|
86
|
-
}
|
|
87
|
-
process.stdout.write('\n' + colors.bold('Recent sessions') + colors.dim(' (pass --json for machine output)\n\n'));
|
|
88
|
-
for (const s of recent) {
|
|
89
|
-
const shortId = s.sessionId.slice(0, 8);
|
|
90
|
-
const when = formatRelativeTime(s.completedAt);
|
|
91
|
-
const reportTag = s.finalReport ? colors.gray('· report ✓') : colors.gray('· no report');
|
|
92
|
-
const promptLine = truncate(s.prompt.replace(/\s+/g, ' ').trim(), 70);
|
|
93
|
-
process.stdout.write(` ${colors.cyan(shortId)} ${colors.gray(s.agent.padEnd(11))}${colors.dim(when.padEnd(14))} ${reportTag}\n` +
|
|
94
|
-
` ${colors.dim(promptLine)}\n\n`);
|
|
95
|
-
}
|
|
96
|
-
process.stdout.write(colors.dim('To verify one of these: ') + colors.bold('codehere verify <id>') + '\n\n');
|
|
97
|
-
return 0;
|
|
98
|
-
}
|
|
99
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
100
|
-
/* Human-readable output */
|
|
101
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
102
|
-
function printHumanReadable(session, result) {
|
|
103
|
-
const shortId = session.sessionId.slice(0, 8);
|
|
104
|
-
const when = formatRelativeTime(session.completedAt);
|
|
105
|
-
// Header
|
|
106
|
-
process.stdout.write('\n' +
|
|
107
|
-
colors.dim('session ') +
|
|
108
|
-
colors.cyan(shortId) +
|
|
109
|
-
colors.dim(' · ') +
|
|
110
|
-
colors.gray(session.agent) +
|
|
111
|
-
colors.dim(' · ') +
|
|
112
|
-
colors.gray(when) +
|
|
113
|
-
'\n' +
|
|
114
|
-
colors.dim('task: ') +
|
|
115
|
-
truncate(session.prompt.replace(/\s+/g, ' ').trim(), 80) +
|
|
116
|
-
'\n\n');
|
|
117
|
-
// What the agent did — lead with the deliverable, not the audit. A
|
|
118
|
-
// non-technical user opening this wants "what happened" first, then "does
|
|
119
|
-
// it check out". Both come straight from recorded state (no screen lies).
|
|
120
|
-
if (session.finalReport?.summary) {
|
|
121
|
-
process.stdout.write(session.finalReport.summary.trim() + '\n\n');
|
|
122
|
-
}
|
|
123
|
-
// Files changed + trust, or the honest can't-track note.
|
|
124
|
-
const files = session.artifacts?.files ?? [];
|
|
125
|
-
if (session.artifacts?.noGitTracking) {
|
|
126
|
-
process.stdout.write(colors.dim("Files: codehere couldn't track changes here (this folder isn't a git repository).\n\n"));
|
|
127
|
-
}
|
|
128
|
-
else if (files.length > 0) {
|
|
129
|
-
process.stdout.write(colors.bold('Files changed:\n'));
|
|
130
|
-
for (const f of files) {
|
|
131
|
-
const trust = typeof f.trust === 'number' ? colors.dim(` · trust ${f.trust}/100`) : '';
|
|
132
|
-
process.stdout.write(` • ${f.path} ${colors.success('+' + f.added)}/${colors.error('-' + f.removed)}${trust}\n`);
|
|
133
|
-
}
|
|
134
|
-
process.stdout.write('\n');
|
|
135
|
-
}
|
|
136
|
-
// Verdict line · color-coded by status
|
|
137
|
-
const verdict = verdictLine(result);
|
|
138
|
-
process.stdout.write(colors.bold('Fact-check: ') + verdict + '\n\n');
|
|
139
|
-
// Findings detail
|
|
140
|
-
if (result.findings.length > 0 && result.status !== 'no-report') {
|
|
141
|
-
process.stdout.write(colors.bold('Findings:\n\n'));
|
|
142
|
-
for (let i = 0; i < result.findings.length; i++) {
|
|
143
|
-
const f = result.findings[i];
|
|
144
|
-
const num = colors.dim(` ${(i + 1).toString().padStart(2)}. `);
|
|
145
|
-
const sev = severityTag(f.severity);
|
|
146
|
-
const kind = colors.gray(`[${f.kind}]`);
|
|
147
|
-
process.stdout.write(`${num}${sev} ${kind} ${f.message}\n`);
|
|
148
|
-
process.stdout.write(` ${colors.dim('claim:')} ${colors.gray(f.claim)}\n`);
|
|
149
|
-
process.stdout.write(` ${colors.dim('reality:')} ${colors.gray(f.reality)}\n\n`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
// What was checked (so users know the verifier's scope)
|
|
153
|
-
process.stdout.write(colors.dim('What was checked:\n'));
|
|
154
|
-
process.stdout.write(colors.dim(' · numeric test claims (X tests passed, X of Y, etc) vs artifacts.tests\n'));
|
|
155
|
-
process.stdout.write(colors.dim(' · universal claims (all tests pass, no failures) vs artifacts.tests.failed\n'));
|
|
156
|
-
process.stdout.write(colors.dim(' · file claims (X files changed, no files changed) vs artifacts.files\n'));
|
|
157
|
-
process.stdout.write(colors.dim('Not checked: prose claims, intent, semantic correctness of changes.\n\n'));
|
|
158
|
-
}
|
|
159
|
-
function verdictLine(result) {
|
|
160
|
-
switch (result.status) {
|
|
161
|
-
case 'verified':
|
|
162
|
-
return colors.green(`${symbols.success} Verified`) + colors.dim(' ' + result.summary);
|
|
163
|
-
case 'partial':
|
|
164
|
-
return colors.warning(`${symbols.warning} Partial`) + colors.dim(' ' + result.summary);
|
|
165
|
-
case 'broken':
|
|
166
|
-
return colors.error(`${symbols.error} Broken`) + colors.dim(' ' + result.summary);
|
|
167
|
-
case 'no-report':
|
|
168
|
-
return colors.gray(`${symbols.dot} No report`) + colors.dim(' ' + result.summary);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function severityTag(sev) {
|
|
172
|
-
switch (sev) {
|
|
173
|
-
case 'fail':
|
|
174
|
-
return colors.error('fail');
|
|
175
|
-
case 'warn':
|
|
176
|
-
return colors.warning('warn');
|
|
177
|
-
case 'info':
|
|
178
|
-
return colors.info('info');
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
182
|
-
/* JSON serialization */
|
|
183
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
184
|
-
function serializeResult(session, result) {
|
|
185
|
-
return {
|
|
186
|
-
sessionId: session.sessionId,
|
|
187
|
-
agent: session.agent,
|
|
188
|
-
prompt: session.prompt,
|
|
189
|
-
completedAt: session.completedAt,
|
|
190
|
-
durationMs: session.durationMs,
|
|
191
|
-
hasFinalReport: Boolean(session.finalReport),
|
|
192
|
-
verdict: {
|
|
193
|
-
status: result.status,
|
|
194
|
-
summary: result.summary,
|
|
195
|
-
findings: result.findings.map((f) => ({
|
|
196
|
-
severity: f.severity,
|
|
197
|
-
kind: f.kind,
|
|
198
|
-
claim: f.claim,
|
|
199
|
-
reality: f.reality,
|
|
200
|
-
message: f.message,
|
|
201
|
-
})),
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
206
|
-
/* Small utilities */
|
|
207
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
208
|
-
function formatRelativeTime(ts) {
|
|
209
|
-
if (!ts || ts <= 0)
|
|
210
|
-
return 'unknown';
|
|
211
|
-
const deltaMs = Date.now() - ts;
|
|
212
|
-
if (deltaMs < 0)
|
|
213
|
-
return 'just now';
|
|
214
|
-
const seconds = Math.floor(deltaMs / 1000);
|
|
215
|
-
if (seconds < 60)
|
|
216
|
-
return `${seconds}s ago`;
|
|
217
|
-
const minutes = Math.floor(seconds / 60);
|
|
218
|
-
if (minutes < 60)
|
|
219
|
-
return `${minutes}m ago`;
|
|
220
|
-
const hours = Math.floor(minutes / 60);
|
|
221
|
-
if (hours < 24)
|
|
222
|
-
return `${hours}h ago`;
|
|
223
|
-
const days = Math.floor(hours / 24);
|
|
224
|
-
if (days < 30)
|
|
225
|
-
return `${days}d ago`;
|
|
226
|
-
return new Date(ts).toISOString().split('T')[0];
|
|
227
|
-
}
|
|
228
|
-
function truncate(s, max) {
|
|
229
|
-
if (s.length <= max)
|
|
230
|
-
return s;
|
|
231
|
-
return s.slice(0, max - 1).trimEnd() + '…';
|
|
232
|
-
}
|
|
233
|
-
//# sourceMappingURL=verify-command.js.map
|
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Centralized Error Display Utility
|
|
3
|
-
* Provides consistent, helpful error messages with recovery suggestions
|
|
4
|
-
*
|
|
5
|
-
* Clean Architecture: Presentation Layer
|
|
6
|
-
*/
|
|
7
|
-
import { ErrorType, classifyError, EnterpriseError } from '../../error-handler.js';
|
|
8
|
-
import { colors, separator, newline, symbols } from '../../ui.js';
|
|
9
|
-
/**
|
|
10
|
-
* Determine error severity based on error type
|
|
11
|
-
*/
|
|
12
|
-
function getErrorSeverity(errorType) {
|
|
13
|
-
switch (errorType) {
|
|
14
|
-
case ErrorType.FATAL:
|
|
15
|
-
case ErrorType.POLICY:
|
|
16
|
-
return 'critical';
|
|
17
|
-
case ErrorType.RATE_LIMIT:
|
|
18
|
-
case ErrorType.API_ERROR:
|
|
19
|
-
case ErrorType.VALIDATION:
|
|
20
|
-
return 'warning';
|
|
21
|
-
case ErrorType.NETWORK:
|
|
22
|
-
case ErrorType.RETRYABLE:
|
|
23
|
-
return 'info';
|
|
24
|
-
default:
|
|
25
|
-
return 'warning';
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Get severity label (text-based, enterprise-grade)
|
|
30
|
-
*/
|
|
31
|
-
function getSeverityLabel(severity) {
|
|
32
|
-
switch (severity) {
|
|
33
|
-
case 'critical':
|
|
34
|
-
return colors.red('[CRITICAL] Error:');
|
|
35
|
-
case 'warning':
|
|
36
|
-
return colors.yellow('[WARNING] Error:');
|
|
37
|
-
case 'info':
|
|
38
|
-
return colors.cyan('[INFO] Error:');
|
|
39
|
-
default:
|
|
40
|
-
return colors.red('Error:');
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Extract file path from error message
|
|
45
|
-
*/
|
|
46
|
-
function extractFilePath(errorMessage) {
|
|
47
|
-
// Patterns: "File not found: path/to/file", "in path/to/file", "at path/to/file"
|
|
48
|
-
const patterns = [
|
|
49
|
-
/(?:File|file)\s+(?:not found|error|issue)[:\s]+([^\s]+)/i,
|
|
50
|
-
/(?:in|at)\s+([^\s]+\.(ts|js|py|json|md|yaml|yml))/i,
|
|
51
|
-
/([^\s]+\.(ts|js|py|json|md|yaml|yml)(?::\d+)?)/i,
|
|
52
|
-
];
|
|
53
|
-
for (const pattern of patterns) {
|
|
54
|
-
const match = errorMessage.match(pattern);
|
|
55
|
-
if (match && match[1]) {
|
|
56
|
-
return match[1].replace(/^["']|["']$/g, ''); // Remove quotes
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Extract line number from error message
|
|
63
|
-
*/
|
|
64
|
-
function extractLineNumber(errorMessage) {
|
|
65
|
-
// Patterns: "line 42", ":42", "at line 42"
|
|
66
|
-
const patterns = [/(?:line|Line)\s+(\d+)/i, /:(\d+):/, /\((\d+)\)/];
|
|
67
|
-
for (const pattern of patterns) {
|
|
68
|
-
const match = errorMessage.match(pattern);
|
|
69
|
-
if (match && match[1]) {
|
|
70
|
-
const line = parseInt(match[1], 10);
|
|
71
|
-
if (!isNaN(line) && line > 0) {
|
|
72
|
-
return line;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Get recovery commands based on error type and context
|
|
80
|
-
*/
|
|
81
|
-
function getRecoveryCommands(errorType, errorMessage, context) {
|
|
82
|
-
const commands = [];
|
|
83
|
-
const lowerMessage = errorMessage.toLowerCase();
|
|
84
|
-
switch (errorType) {
|
|
85
|
-
case ErrorType.VALIDATION:
|
|
86
|
-
if (lowerMessage.includes('file') || lowerMessage.includes('not found')) {
|
|
87
|
-
if (context.filepath) {
|
|
88
|
-
commands.push(`codehere trust ${context.filepath}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
case ErrorType.API_ERROR:
|
|
93
|
-
if (lowerMessage.includes('api') || lowerMessage.includes('key')) {
|
|
94
|
-
commands.push('codehere setup');
|
|
95
|
-
commands.push('codehere config --help');
|
|
96
|
-
}
|
|
97
|
-
break;
|
|
98
|
-
case ErrorType.POLICY:
|
|
99
|
-
if (context.filepath) {
|
|
100
|
-
commands.push(`codehere trust ${context.filepath}`);
|
|
101
|
-
commands.push('codehere config policies');
|
|
102
|
-
}
|
|
103
|
-
break;
|
|
104
|
-
case ErrorType.RATE_LIMIT:
|
|
105
|
-
commands.push('codehere config --help');
|
|
106
|
-
break;
|
|
107
|
-
default:
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
return commands;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Get help command for operation (Task 7.3: Contextual Help Integration)
|
|
114
|
-
*/
|
|
115
|
-
function getHelpCommandForOperation(operation) {
|
|
116
|
-
const operationLower = operation.toLowerCase();
|
|
117
|
-
// Map operations to help commands
|
|
118
|
-
if (operationLower.includes('ask') || operationLower.includes('question')) {
|
|
119
|
-
return 'ask';
|
|
120
|
-
}
|
|
121
|
-
if (operationLower.includes('explain')) {
|
|
122
|
-
return 'explain';
|
|
123
|
-
}
|
|
124
|
-
if (operationLower.includes('plan')) {
|
|
125
|
-
return 'plan';
|
|
126
|
-
}
|
|
127
|
-
if (operationLower.includes('orchestrate')) {
|
|
128
|
-
return 'orchestrate';
|
|
129
|
-
}
|
|
130
|
-
if (operationLower.includes('react')) {
|
|
131
|
-
return 'react';
|
|
132
|
-
}
|
|
133
|
-
if (operationLower.includes('index')) {
|
|
134
|
-
return 'index';
|
|
135
|
-
}
|
|
136
|
-
if (operationLower.includes('setup') || operationLower.includes('config')) {
|
|
137
|
-
return 'setup';
|
|
138
|
-
}
|
|
139
|
-
if (operationLower.includes('undo')) {
|
|
140
|
-
return 'undo';
|
|
141
|
-
}
|
|
142
|
-
if (operationLower.includes('trace')) {
|
|
143
|
-
return 'trace';
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Get documentation link for error type
|
|
149
|
-
*/
|
|
150
|
-
function getDocumentationLink(errorType) {
|
|
151
|
-
const baseUrl = 'https://docs.codehere.dev';
|
|
152
|
-
switch (errorType) {
|
|
153
|
-
case ErrorType.POLICY:
|
|
154
|
-
return `${baseUrl}/security-policies`;
|
|
155
|
-
case ErrorType.API_ERROR:
|
|
156
|
-
case ErrorType.RATE_LIMIT:
|
|
157
|
-
return `${baseUrl}/setup/api-keys`;
|
|
158
|
-
case ErrorType.VALIDATION:
|
|
159
|
-
return `${baseUrl}/troubleshooting`;
|
|
160
|
-
case ErrorType.NETWORK:
|
|
161
|
-
return `${baseUrl}/troubleshooting/network`;
|
|
162
|
-
default:
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Generate error code for troubleshooting
|
|
168
|
-
*/
|
|
169
|
-
function generateErrorCode(errorType, errorMessage) {
|
|
170
|
-
const prefix = errorType.toUpperCase().substring(0, 3);
|
|
171
|
-
const hash = errorMessage.split('').reduce((acc, char) => {
|
|
172
|
-
return (acc << 5) - acc + char.charCodeAt(0);
|
|
173
|
-
}, 0);
|
|
174
|
-
const code = Math.abs(hash).toString(16).substring(0, 4).toUpperCase();
|
|
175
|
-
return `${prefix}-${code}`;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Display error with helpful context and recovery suggestions
|
|
179
|
-
*/
|
|
180
|
-
export function displayError(error, options = {}) {
|
|
181
|
-
const { operation = 'operation', query, showSuggestions = true, showStack = false } = options;
|
|
182
|
-
const errorType = classifyError(error);
|
|
183
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
184
|
-
const isEnterpriseError = error instanceof EnterpriseError;
|
|
185
|
-
// Generate error code for troubleshooting
|
|
186
|
-
const errorCode = generateErrorCode(errorType, errorMessage);
|
|
187
|
-
// Determine error severity (based on error type)
|
|
188
|
-
const severity = getErrorSeverity(errorType);
|
|
189
|
-
// Extract file/line context from error message or options
|
|
190
|
-
const fileContext = options.filepath || extractFilePath(errorMessage);
|
|
191
|
-
const lineContext = options.lineNumber || extractLineNumber(errorMessage);
|
|
192
|
-
// Display error header
|
|
193
|
-
newline();
|
|
194
|
-
console.log(separator('═', 80));
|
|
195
|
-
// Show severity indicator (text-based, no emojis for enterprise)
|
|
196
|
-
const severityLabel = getSeverityLabel(severity);
|
|
197
|
-
if (severityLabel) {
|
|
198
|
-
console.log(severityLabel + ` ${errorMessage}`);
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
console.log(colors.red(`Error: ${errorMessage}`));
|
|
202
|
-
}
|
|
203
|
-
if (errorCode) {
|
|
204
|
-
console.log(colors.dim(`Error Code: ${errorCode}`));
|
|
205
|
-
}
|
|
206
|
-
// Show file/line context if available
|
|
207
|
-
if (fileContext) {
|
|
208
|
-
console.log(colors.dim(`File: ${fileContext}${lineContext ? `:${lineContext}` : ''}`));
|
|
209
|
-
}
|
|
210
|
-
console.log(separator('═', 80));
|
|
211
|
-
newline();
|
|
212
|
-
// Show error type if it's an EnterpriseError
|
|
213
|
-
if (isEnterpriseError) {
|
|
214
|
-
console.log(colors.dim(`Type: ${errorType}`));
|
|
215
|
-
if (error.context?.attempt !== undefined) {
|
|
216
|
-
console.log(colors.dim(`Attempt: ${error.context.attempt + 1}/${error.context.maxRetries || '?'}`));
|
|
217
|
-
}
|
|
218
|
-
newline();
|
|
219
|
-
}
|
|
220
|
-
// Show suggestions based on error type
|
|
221
|
-
if (showSuggestions) {
|
|
222
|
-
const suggestions = getErrorSuggestions(errorType, errorMessage, { operation, query, filepath: fileContext });
|
|
223
|
-
if (suggestions.length > 0) {
|
|
224
|
-
console.log(colors.bold('Suggestions:'));
|
|
225
|
-
suggestions.forEach((suggestion) => {
|
|
226
|
-
console.log(colors.dim(` ${symbols.bullet} ${suggestion}`));
|
|
227
|
-
});
|
|
228
|
-
newline();
|
|
229
|
-
}
|
|
230
|
-
// Show recovery commands for certain error types
|
|
231
|
-
const recoveryCommands = getRecoveryCommands(errorType, errorMessage, {
|
|
232
|
-
operation,
|
|
233
|
-
query,
|
|
234
|
-
filepath: fileContext,
|
|
235
|
-
lineNumber: lineContext,
|
|
236
|
-
});
|
|
237
|
-
if (recoveryCommands.length > 0) {
|
|
238
|
-
console.log(colors.bold('Recovery Commands:'));
|
|
239
|
-
recoveryCommands.forEach((cmd) => {
|
|
240
|
-
console.log(colors.cyan(` $ ${cmd}`));
|
|
241
|
-
});
|
|
242
|
-
newline();
|
|
243
|
-
}
|
|
244
|
-
// Show documentation link for complex errors
|
|
245
|
-
const docLink = getDocumentationLink(errorType);
|
|
246
|
-
if (docLink) {
|
|
247
|
-
console.log(colors.dim(`Learn More: ${docLink}`));
|
|
248
|
-
newline();
|
|
249
|
-
}
|
|
250
|
-
// Contextual help suggestion (Task 7.3: Contextual Help Integration)
|
|
251
|
-
if (operation) {
|
|
252
|
-
const helpCommand = getHelpCommandForOperation(operation);
|
|
253
|
-
if (helpCommand) {
|
|
254
|
-
console.log(colors.dim(`Get help: ${colors.cyan(`codehere help ${helpCommand}`)}`));
|
|
255
|
-
newline();
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
// Show stack trace if requested (for debugging)
|
|
260
|
-
if (showStack && error instanceof Error && error.stack) {
|
|
261
|
-
console.log(colors.dim('Stack trace:'));
|
|
262
|
-
console.log(colors.dim(error.stack));
|
|
263
|
-
newline();
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Get recovery suggestions based on error type
|
|
268
|
-
*/
|
|
269
|
-
function getErrorSuggestions(errorType, errorMessage, _context) {
|
|
270
|
-
const suggestions = [];
|
|
271
|
-
const lowerMessage = errorMessage.toLowerCase();
|
|
272
|
-
switch (errorType) {
|
|
273
|
-
case ErrorType.RATE_LIMIT:
|
|
274
|
-
suggestions.push("You've reached the API rate limit or monthly quota");
|
|
275
|
-
suggestions.push('Wait a moment and try again');
|
|
276
|
-
suggestions.push('Check your API key limits at: https://dashboard.cohere.com/api-keys');
|
|
277
|
-
suggestions.push('Consider upgrading your API key for higher limits');
|
|
278
|
-
break;
|
|
279
|
-
case ErrorType.API_ERROR:
|
|
280
|
-
case ErrorType.VALIDATION:
|
|
281
|
-
if (lowerMessage.includes('api') || lowerMessage.includes('key')) {
|
|
282
|
-
suggestions.push('Check your COHERE_API_KEY is set correctly');
|
|
283
|
-
suggestions.push('Verify your API key at: https://dashboard.cohere.com/api-keys');
|
|
284
|
-
suggestions.push('Make sure .env file exists in your project root');
|
|
285
|
-
suggestions.push('Run "codehere setup" to configure your API key');
|
|
286
|
-
suggestions.push('For troubleshooting, include the error code when reporting issues');
|
|
287
|
-
}
|
|
288
|
-
else if (lowerMessage.includes('not found') || lowerMessage.includes('missing')) {
|
|
289
|
-
suggestions.push("Make sure you're in the correct directory");
|
|
290
|
-
suggestions.push('Run "codehere trust ." to verify the path is scanned');
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
suggestions.push('Check the error message above for specific details');
|
|
294
|
-
suggestions.push('Run "codehere setup" to verify your configuration');
|
|
295
|
-
}
|
|
296
|
-
break;
|
|
297
|
-
case ErrorType.NETWORK:
|
|
298
|
-
suggestions.push('Check your internet connection');
|
|
299
|
-
suggestions.push('Verify the API service is accessible');
|
|
300
|
-
suggestions.push('Try again in a few moments');
|
|
301
|
-
break;
|
|
302
|
-
case ErrorType.POLICY:
|
|
303
|
-
suggestions.push('The operation was blocked by safety policies');
|
|
304
|
-
suggestions.push('Review the policy reason above');
|
|
305
|
-
suggestions.push('Modify your request to comply with safety rules');
|
|
306
|
-
break;
|
|
307
|
-
case ErrorType.FATAL:
|
|
308
|
-
suggestions.push('This is a fatal error that cannot be recovered');
|
|
309
|
-
suggestions.push('Check the error message for details');
|
|
310
|
-
suggestions.push('If this persists, please report the issue');
|
|
311
|
-
break;
|
|
312
|
-
default:
|
|
313
|
-
// Generic suggestions for retryable errors
|
|
314
|
-
if (lowerMessage.includes('file') || lowerMessage.includes('path')) {
|
|
315
|
-
suggestions.push('Verify the file path is correct');
|
|
316
|
-
suggestions.push('Check file permissions');
|
|
317
|
-
}
|
|
318
|
-
else if (lowerMessage.includes('memory') || lowerMessage.includes('database')) {
|
|
319
|
-
suggestions.push('Run "codehere health" to inspect runtime state');
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
suggestions.push('This error may be temporary - try again');
|
|
323
|
-
suggestions.push('Check the error message for specific details');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
return suggestions;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Display error and exit with appropriate code
|
|
330
|
-
*/
|
|
331
|
-
export function displayErrorAndExit(error, options = {}) {
|
|
332
|
-
const { exitCode = 1, ...displayOptions } = options;
|
|
333
|
-
displayError(error, displayOptions);
|
|
334
|
-
process.exit(exitCode);
|
|
335
|
-
}
|
|
336
|
-
//# sourceMappingURL=error-display.js.map
|