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
package/dist/ui.js
CHANGED
|
@@ -1,50 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { existsSync } from 'fs';
|
|
7
|
-
import { join, dirname } from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
let cachedCliStyle = null;
|
|
10
|
-
export function getCliStyle() {
|
|
11
|
-
if (cachedCliStyle)
|
|
12
|
-
return cachedCliStyle;
|
|
13
|
-
const envStyle = process.env.CODEHERE_CLI_STYLE?.toLowerCase();
|
|
14
|
-
cachedCliStyle = envStyle === 'verbose' ? 'verbose' : 'minimal';
|
|
15
|
-
return cachedCliStyle;
|
|
16
|
-
}
|
|
17
|
-
export function isMinimalStyle() {
|
|
18
|
-
return getCliStyle() === 'minimal';
|
|
19
|
-
}
|
|
20
|
-
// Minimal header for commands (used in minimal style)
|
|
21
|
-
export function printMinimalHeader(command, query) {
|
|
22
|
-
if (query) {
|
|
23
|
-
console.log(colors.cyan(`codehere ${command}`) + colors.dim(' ▸ ') + query);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
console.log(colors.cyan(`codehere ${command}`));
|
|
27
|
-
}
|
|
28
|
-
console.log();
|
|
29
|
-
}
|
|
30
|
-
// Minimal safety note (used at end of AI responses)
|
|
31
|
-
export function printSafetyNote() {
|
|
32
|
-
console.log(colors.dim('Note: AI output may be inaccurate. Review before committing.'));
|
|
33
|
-
}
|
|
34
|
-
// Minimal context summary
|
|
35
|
-
export function printContextSummary(files, maxShow = 3) {
|
|
36
|
-
if (files.length === 0)
|
|
37
|
-
return;
|
|
38
|
-
const unique = [...new Set(files)];
|
|
39
|
-
const shown = unique.slice(0, maxShow);
|
|
40
|
-
const more = unique.length - maxShow;
|
|
41
|
-
console.log(colors.dim('Context:'));
|
|
42
|
-
shown.forEach((f) => console.log(colors.dim(` - ${f}`)));
|
|
43
|
-
if (more > 0) {
|
|
44
|
-
console.log(colors.dim(` ... and ${more} more file${more > 1 ? 's' : ''}`));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Professional color scheme - subtle and enterprise-ready
|
|
2
|
+
// Color roles (DESIGN.md §1): color carries meaning.
|
|
3
|
+
// verified = green (independently verified ONLY) caught = red (a contradiction caught ONLY)
|
|
4
|
+
// warn = amber (attention) evidence = dim (machine facts, metadata)
|
|
5
|
+
// identity = cyan (an id, sparingly) heading = bold (the one thing that matters)
|
|
48
6
|
export const colors = {
|
|
49
7
|
success: chalk.green,
|
|
50
8
|
error: chalk.red,
|
|
@@ -59,414 +17,37 @@ export const colors = {
|
|
|
59
17
|
green: chalk.green,
|
|
60
18
|
gray: chalk.gray,
|
|
61
19
|
blue: chalk.blue,
|
|
20
|
+
verified: chalk.green,
|
|
21
|
+
caught: chalk.red,
|
|
22
|
+
warn: chalk.yellow,
|
|
23
|
+
evidence: chalk.dim,
|
|
24
|
+
identity: chalk.cyan,
|
|
25
|
+
heading: chalk.bold,
|
|
62
26
|
};
|
|
63
|
-
//
|
|
27
|
+
// Glyph language (DESIGN.md): the sanctioned geometric set plus ANSI color,
|
|
28
|
+
// never emoji-as-icon.
|
|
64
29
|
export const symbols = {
|
|
65
30
|
success: '✓',
|
|
66
|
-
error: '
|
|
67
|
-
warning: '
|
|
68
|
-
info: '
|
|
69
|
-
processing: '
|
|
70
|
-
arrow: '
|
|
71
|
-
dot: '
|
|
31
|
+
error: '✕',
|
|
32
|
+
warning: '!',
|
|
33
|
+
info: '›',
|
|
34
|
+
processing: '›',
|
|
35
|
+
arrow: '›',
|
|
36
|
+
dot: '·',
|
|
72
37
|
check: '✓',
|
|
73
|
-
cross: '
|
|
38
|
+
cross: '✕',
|
|
74
39
|
pipe: '│',
|
|
75
40
|
dash: '─',
|
|
76
41
|
plus: '+',
|
|
77
42
|
minus: '-',
|
|
78
43
|
bullet: '•',
|
|
79
44
|
};
|
|
80
|
-
// Spinner helper - minimal text only with smooth transitions
|
|
81
|
-
export function createSpinner(text) {
|
|
82
|
-
return ora({
|
|
83
|
-
text: colors.dim(text),
|
|
84
|
-
spinner: 'dots', // Smooth animated dots
|
|
85
|
-
color: 'cyan',
|
|
86
|
-
interval: 80, // Faster animation for better perceived performance
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
// Progress bar helper - clean and minimal with smooth transitions
|
|
90
|
-
export function createProgressBar(total, format) {
|
|
91
|
-
const bar = new cliProgress.SingleBar({
|
|
92
|
-
format: format || colors.dim('Progress') + ' |{bar}| ' + colors.cyan('{percentage}%') + ' | {value}/{total}',
|
|
93
|
-
barCompleteChar: '\u2588', // Full block for smooth appearance
|
|
94
|
-
barIncompleteChar: '\u2591', // Light shade for incomplete
|
|
95
|
-
hideCursor: true,
|
|
96
|
-
clearOnComplete: true,
|
|
97
|
-
etaBuffer: 10, // Smooth ETA calculation
|
|
98
|
-
forceRedraw: true, // Force redraw for smooth updates
|
|
99
|
-
}, cliProgress.Presets.shades_classic);
|
|
100
|
-
bar.start(total, 0);
|
|
101
|
-
return bar;
|
|
102
|
-
}
|
|
103
|
-
// Professional box helper - minimal borders
|
|
104
|
-
export function createBox(content, options) {
|
|
105
|
-
return boxen(content, {
|
|
106
|
-
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
107
|
-
margin: { top: 0, bottom: 1, left: 0, right: 0 },
|
|
108
|
-
borderStyle: 'single',
|
|
109
|
-
borderColor: 'gray',
|
|
110
|
-
...options,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
// Professional banner - clean and minimal
|
|
114
|
-
export function createBanner(title, subtitle) {
|
|
115
|
-
const width = Math.max(title.length, subtitle?.length || 0) + 4;
|
|
116
|
-
const top = '┌' + '─'.repeat(width - 2) + '┐';
|
|
117
|
-
const bottom = '└' + '─'.repeat(width - 2) + '┘';
|
|
118
|
-
const titleLine = '│ ' + colors.bold(title) + ' '.repeat(width - title.length - 3) + '│';
|
|
119
|
-
let banner = `\n${colors.gray(top)}\n${colors.gray(titleLine)}\n`;
|
|
120
|
-
if (subtitle) {
|
|
121
|
-
const subtitleLine = '│ ' + colors.dim(subtitle) + ' '.repeat(width - subtitle.length - 3) + '│';
|
|
122
|
-
banner += `${colors.gray(subtitleLine)}\n`;
|
|
123
|
-
}
|
|
124
|
-
banner += `${colors.gray(bottom)}\n`;
|
|
125
|
-
return banner;
|
|
126
|
-
}
|
|
127
|
-
// Separator - clean line
|
|
128
|
-
export function separator(char = '─', length = 60) {
|
|
129
|
-
return colors.dim(char.repeat(length));
|
|
130
|
-
}
|
|
131
|
-
// Success message - professional
|
|
132
|
-
export function success(message) {
|
|
133
|
-
return colors.green(symbols.success + ' ' + message);
|
|
134
|
-
}
|
|
135
|
-
// Error message - professional
|
|
136
45
|
export function error(message) {
|
|
137
46
|
return colors.red(symbols.error + ' ' + message);
|
|
138
47
|
}
|
|
139
|
-
// Warning message - professional
|
|
140
|
-
export function warning(message) {
|
|
141
|
-
return colors.yellow(symbols.warning + ' ' + message);
|
|
142
|
-
}
|
|
143
|
-
// Info message - professional
|
|
144
|
-
export function info(message) {
|
|
145
|
-
return colors.blue(symbols.info + ' ' + message);
|
|
146
|
-
}
|
|
147
|
-
// Create professional table - minimal styling
|
|
148
|
-
export function createTable(headers, rows) {
|
|
149
|
-
const table = new Table({
|
|
150
|
-
head: headers.map((h) => colors.bold(h)),
|
|
151
|
-
style: {
|
|
152
|
-
head: [],
|
|
153
|
-
border: ['gray'],
|
|
154
|
-
compact: false,
|
|
155
|
-
},
|
|
156
|
-
chars: {
|
|
157
|
-
top: '─',
|
|
158
|
-
'top-mid': '┬',
|
|
159
|
-
'top-left': '┌',
|
|
160
|
-
'top-right': '┐',
|
|
161
|
-
bottom: '─',
|
|
162
|
-
'bottom-mid': '┴',
|
|
163
|
-
'bottom-left': '└',
|
|
164
|
-
'bottom-right': '┘',
|
|
165
|
-
left: '│',
|
|
166
|
-
'left-mid': '├',
|
|
167
|
-
mid: '─',
|
|
168
|
-
'mid-mid': '┼',
|
|
169
|
-
right: '│',
|
|
170
|
-
'right-mid': '┤',
|
|
171
|
-
middle: '│',
|
|
172
|
-
},
|
|
173
|
-
colWidths: headers.map((_, i) => {
|
|
174
|
-
const maxWidth = Math.max(headers[i].length, ...rows.map((row) => (row[i] || '').length));
|
|
175
|
-
return Math.min(maxWidth + 2, 50);
|
|
176
|
-
}),
|
|
177
|
-
});
|
|
178
|
-
rows.forEach((row) => table.push(row));
|
|
179
|
-
return table;
|
|
180
|
-
}
|
|
181
|
-
// Format file path - subtle
|
|
182
|
-
export function formatPath(path) {
|
|
183
|
-
return colors.cyan(path);
|
|
184
|
-
}
|
|
185
|
-
// Format number - bold
|
|
186
|
-
export function formatNumber(num) {
|
|
187
|
-
return colors.bold(num.toString());
|
|
188
|
-
}
|
|
189
|
-
// Format percentage - subtle
|
|
190
|
-
export function formatPercent(value, total) {
|
|
191
|
-
if (total !== undefined) {
|
|
192
|
-
const percent = Math.round((value / total) * 100);
|
|
193
|
-
return colors.dim(`${percent}%`);
|
|
194
|
-
}
|
|
195
|
-
// If just a percentage value (0-100)
|
|
196
|
-
return colors.dim(`${value.toFixed(1)}%`);
|
|
197
|
-
}
|
|
198
|
-
// Format score (for search results) - color by relevance
|
|
199
|
-
export function formatScore(score) {
|
|
200
|
-
const percent = Math.round(score * 100);
|
|
201
|
-
if (percent >= 50)
|
|
202
|
-
return colors.green(`${percent}%`);
|
|
203
|
-
if (percent >= 30)
|
|
204
|
-
return colors.yellow(`${percent}%`);
|
|
205
|
-
return colors.dim(`${percent}%`);
|
|
206
|
-
}
|
|
207
|
-
// Professional section header
|
|
208
|
-
export function sectionHeader(title) {
|
|
209
|
-
console.log(colors.bold(title));
|
|
210
|
-
console.log(separator());
|
|
211
|
-
}
|
|
212
|
-
// Print empty line
|
|
213
48
|
export function newline(count = 1) {
|
|
214
49
|
for (let i = 0; i < count; i++) {
|
|
215
50
|
console.log();
|
|
216
51
|
}
|
|
217
52
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Show a human-voice "you need an API key" message and exit.
|
|
220
|
-
* Covers all supported providers — not just Cohere.
|
|
221
|
-
*/
|
|
222
|
-
export function hasAnyApiKey() {
|
|
223
|
-
return !!(process.env.ANTHROPIC_API_KEY ||
|
|
224
|
-
process.env.OPENAI_API_KEY ||
|
|
225
|
-
process.env.COHERE_API_KEY ||
|
|
226
|
-
process.env.OPENROUTER_API_KEY ||
|
|
227
|
-
process.env.CODEHERE_AI_PROVIDER === 'local' ||
|
|
228
|
-
process.env.CODEHERE_FAKE_AI === '1');
|
|
229
|
-
}
|
|
230
|
-
export function requireApiKey() {
|
|
231
|
-
newline();
|
|
232
|
-
console.log(error('You need an API key to use this command.'));
|
|
233
|
-
newline();
|
|
234
|
-
console.log(' Fastest options:');
|
|
235
|
-
console.log(colors.cyan(' export ANTHROPIC_API_KEY=sk-ant-...') + colors.dim(' (Claude models — recommended)'));
|
|
236
|
-
console.log(colors.cyan(' export OPENAI_API_KEY=sk-...'));
|
|
237
|
-
console.log(colors.cyan(' export COHERE_API_KEY=...'));
|
|
238
|
-
console.log(colors.cyan(' export CODEHERE_AI_PROVIDER=local') + colors.dim(' (Ollama — no key needed)'));
|
|
239
|
-
newline();
|
|
240
|
-
console.log(colors.dim(' These work right now, no key needed:'));
|
|
241
|
-
console.log(colors.dim(' codehere trust .'));
|
|
242
|
-
console.log(colors.dim(' codehere hook status'));
|
|
243
|
-
console.log(colors.dim(' codehere serve'));
|
|
244
|
-
newline();
|
|
245
|
-
process.exit(1);
|
|
246
|
-
}
|
|
247
|
-
// Status indicator
|
|
248
|
-
export function statusIndicator(status) {
|
|
249
|
-
const map = {
|
|
250
|
-
success: colors.green(symbols.success),
|
|
251
|
-
error: colors.red(symbols.error),
|
|
252
|
-
warning: colors.yellow(symbols.warning),
|
|
253
|
-
info: colors.blue(symbols.info),
|
|
254
|
-
processing: colors.cyan(symbols.processing),
|
|
255
|
-
};
|
|
256
|
-
return map[status];
|
|
257
|
-
}
|
|
258
|
-
// Gradient logo for "codehere" - coral → purple → blue
|
|
259
|
-
export function createCodehereLogo() {
|
|
260
|
-
const text = 'codehere';
|
|
261
|
-
const letters = text.split('');
|
|
262
|
-
// Color stops: coral → blue (matches landing page #ff9a76 → #4a90e2)
|
|
263
|
-
const colorStops = [
|
|
264
|
-
{ r: 255, g: 154, b: 118 }, // #ff9a76 coral
|
|
265
|
-
{ r: 255, g: 148, b: 110 },
|
|
266
|
-
{ r: 230, g: 148, b: 130 },
|
|
267
|
-
{ r: 200, g: 150, b: 155 },
|
|
268
|
-
{ r: 160, g: 155, b: 190 },
|
|
269
|
-
{ r: 120, g: 158, b: 218 },
|
|
270
|
-
{ r: 85, g: 150, b: 232 },
|
|
271
|
-
{ r: 74, g: 144, b: 226 }, // #4a90e2 blue
|
|
272
|
-
];
|
|
273
|
-
// Map each letter to a color
|
|
274
|
-
const coloredLetters = letters.map((letter, index) => {
|
|
275
|
-
const colorIndex = Math.floor((index / (letters.length - 1)) * (colorStops.length - 1));
|
|
276
|
-
const color = colorStops[colorIndex];
|
|
277
|
-
// Use chalk's rgb for gradient effect
|
|
278
|
-
return chalk.rgb(color.r, color.g, color.b)(letter);
|
|
279
|
-
});
|
|
280
|
-
return coloredLetters.join('');
|
|
281
|
-
}
|
|
282
|
-
// Import centralized version utility
|
|
283
|
-
import { getVersionWithPrefix } from './utils/version.js';
|
|
284
|
-
// Welcome message with logo
|
|
285
|
-
export function createWelcomeMessage() {
|
|
286
|
-
const logo = createCodehereLogo();
|
|
287
|
-
const version = getVersionWithPrefix();
|
|
288
|
-
// Matches the positioning in `codehere --help` and `codehere help`. codehere
|
|
289
|
-
// is the LAYER over your coding agents, not itself an agent — the old
|
|
290
|
-
// "AI coding agent with built-in safety" line implied the opposite.
|
|
291
|
-
const tagline = 'A PM for your AI coding agents';
|
|
292
|
-
return `
|
|
293
|
-
${colors.bold(logo)} ${colors.dim(version)}
|
|
294
|
-
${colors.dim(tagline)}
|
|
295
|
-
`;
|
|
296
|
-
}
|
|
297
|
-
// Helper to get visual length (strip ANSI codes)
|
|
298
|
-
function visualLength(str) {
|
|
299
|
-
// Remove ANSI escape codes
|
|
300
|
-
return str.replace(/\u001b\[[0-9;]*m/g, '').length;
|
|
301
|
-
}
|
|
302
|
-
// Enhanced welcome message for interactive session
|
|
303
|
-
export function createSessionWelcome() {
|
|
304
|
-
const logo = createCodehereLogo();
|
|
305
|
-
const version = getVersionWithPrefix();
|
|
306
|
-
// Check if indexed (legacy check - uses global path for backward compatibility)
|
|
307
|
-
// Note: Active CLI flows use per-repo embeddings via getEmbeddingsDbPath()
|
|
308
|
-
let isIndexed = false;
|
|
309
|
-
try {
|
|
310
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
311
|
-
const __dirname = dirname(__filename);
|
|
312
|
-
const agentDir = join(__dirname, '..');
|
|
313
|
-
const dbPath = join(agentDir, 'data', 'embeddings.sqlite');
|
|
314
|
-
isIndexed = existsSync(dbPath);
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
// Ignore errors - will default to not indexed
|
|
318
|
-
}
|
|
319
|
-
const width = 54;
|
|
320
|
-
const greeting = 'Hello there, code here!';
|
|
321
|
-
// Use subtle blue-gray for borders (like Claude Code)
|
|
322
|
-
const borderColor = chalk.hex('#6B7280'); // Subtle gray-blue
|
|
323
|
-
// Helper to create a line with proper padding
|
|
324
|
-
const createLine = (content) => {
|
|
325
|
-
const contentVisual = visualLength(content);
|
|
326
|
-
// Total width = left border (2) + content + padding + right border (2)
|
|
327
|
-
// So: width = 2 + contentVisual + padding + 2
|
|
328
|
-
// padding = width - contentVisual - 4
|
|
329
|
-
const padding = Math.max(0, width - contentVisual - 4);
|
|
330
|
-
return borderColor('│ ') + content + ' '.repeat(padding) + borderColor(' │\n');
|
|
331
|
-
};
|
|
332
|
-
let welcomeBox = '';
|
|
333
|
-
welcomeBox += borderColor('┌' + '─'.repeat(width - 2) + '┐\n');
|
|
334
|
-
// Header line with logo and version
|
|
335
|
-
const headerContent = colors.bold(logo) + ' ' + colors.dim(version);
|
|
336
|
-
welcomeBox += createLine(headerContent);
|
|
337
|
-
welcomeBox += borderColor('│') + ' '.repeat(width - 2) + borderColor('│\n');
|
|
338
|
-
// Greeting line
|
|
339
|
-
welcomeBox += createLine(greeting);
|
|
340
|
-
welcomeBox += borderColor('│') + ' '.repeat(width - 2) + borderColor('│\n');
|
|
341
|
-
// Tips section
|
|
342
|
-
const tipsHeader = 'Tips for getting started:';
|
|
343
|
-
welcomeBox += createLine(colors.yellow(tipsHeader));
|
|
344
|
-
if (!isIndexed) {
|
|
345
|
-
const tip1 = ' Run "index" to build your codebase search index';
|
|
346
|
-
welcomeBox += createLine(colors.dim(tip1));
|
|
347
|
-
}
|
|
348
|
-
else {
|
|
349
|
-
const tip1 = ' Try asking: "How does authentication work?"';
|
|
350
|
-
welcomeBox += createLine(colors.dim(tip1));
|
|
351
|
-
}
|
|
352
|
-
const tip2 = ' Type "help" to see all available commands';
|
|
353
|
-
welcomeBox += createLine(colors.dim(tip2));
|
|
354
|
-
welcomeBox += borderColor('│') + ' '.repeat(width - 2) + borderColor('│\n');
|
|
355
|
-
// Quick examples
|
|
356
|
-
const examplesHeader = 'Quick start:';
|
|
357
|
-
welcomeBox += createLine(colors.cyan(examplesHeader));
|
|
358
|
-
const example1 = ' • codehere hook install — activate pre-execution scanning';
|
|
359
|
-
welcomeBox += createLine(colors.dim(example1));
|
|
360
|
-
const example2 = ' • codehere trust . — score this codebase (no API key needed)';
|
|
361
|
-
welcomeBox += createLine(colors.dim(example2));
|
|
362
|
-
const example3 = ' • codehere report — generate shareable audit report';
|
|
363
|
-
welcomeBox += createLine(colors.dim(example3));
|
|
364
|
-
welcomeBox += borderColor('└' + '─'.repeat(width - 2) + '┘');
|
|
365
|
-
return welcomeBox;
|
|
366
|
-
}
|
|
367
|
-
// ── Delight utilities ─────────────────────────────────────────────────────────
|
|
368
|
-
const THINKING_MESSAGES = [
|
|
369
|
-
'On it...',
|
|
370
|
-
'Let me look...',
|
|
371
|
-
'Thinking...',
|
|
372
|
-
'One sec...',
|
|
373
|
-
'Reading your code...',
|
|
374
|
-
'Working through this...',
|
|
375
|
-
'Bear with me...',
|
|
376
|
-
'Pulling it together...',
|
|
377
|
-
];
|
|
378
|
-
const FAREWELL_MESSAGES = [
|
|
379
|
-
'See you later! 👋',
|
|
380
|
-
'Happy shipping!',
|
|
381
|
-
'Good luck out there.',
|
|
382
|
-
'Back to building.',
|
|
383
|
-
'See you on the next one.',
|
|
384
|
-
'Later! Go build something great.',
|
|
385
|
-
'Until next time.',
|
|
386
|
-
];
|
|
387
|
-
const CLEAN_SCAN_CELEBRATIONS = [
|
|
388
|
-
'Perfect score. Nothing to worry about.',
|
|
389
|
-
'All clear — clean scan.',
|
|
390
|
-
'Zero findings. Enjoy the green.',
|
|
391
|
-
'Nothing suspicious. Carry on.',
|
|
392
|
-
'Clean as a whistle.',
|
|
393
|
-
];
|
|
394
|
-
export function randomThinkingMessage() {
|
|
395
|
-
return colors.dim(THINKING_MESSAGES[Math.floor(Math.random() * THINKING_MESSAGES.length)]);
|
|
396
|
-
}
|
|
397
|
-
export function randomFarewell() {
|
|
398
|
-
return info(FAREWELL_MESSAGES[Math.floor(Math.random() * FAREWELL_MESSAGES.length)]);
|
|
399
|
-
}
|
|
400
|
-
export function randomCleanScan() {
|
|
401
|
-
return CLEAN_SCAN_CELEBRATIONS[Math.floor(Math.random() * CLEAN_SCAN_CELEBRATIONS.length)];
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* v0.6.2 sync — every non-replOnly entry MUST correspond to a real
|
|
405
|
-
* `program.command('<name>')` registration in src/index.ts. Drift is
|
|
406
|
-
* blocked by test/cli/slash-commands-sync.test.ts (UAT-001 CI guard).
|
|
407
|
-
*
|
|
408
|
-
* Pre-fix (v0.6.1 and earlier): this list carried 16 ghost commands
|
|
409
|
-
* (ask/explain/fix/review/plan/suggest/test/docs/refactor/orchestrate/run/
|
|
410
|
-
* git-review/index/cost/models/undo) removed in v0.3 — and was missing
|
|
411
|
-
* 8 real commands (init/memory/permission/narrator/budget/start/task/kill).
|
|
412
|
-
* Catastrophic first-impression bug found by UAT 2026-05-19.
|
|
413
|
-
*/
|
|
414
|
-
export const SLASH_COMMANDS = [
|
|
415
|
-
// Setup + config (no key)
|
|
416
|
-
{ name: 'setup', args: '', description: 'Interactive first-run wizard', noKey: true },
|
|
417
|
-
{ name: 'init', args: '', description: 'Scaffold .codehere/ in this repo', noKey: true },
|
|
418
|
-
{ name: 'memory', args: '<sub>', description: 'Project memory · init / repo-map / show', noKey: true },
|
|
419
|
-
{ name: 'config', args: '[key] [value]', description: 'Manage preferences', noKey: true },
|
|
420
|
-
{ name: 'permission', args: '<sub>', description: 'Manage .codehere/permissions.yaml allow/deny', noKey: true },
|
|
421
|
-
{ name: 'narrator', args: '', description: 'Customize the PM narrator prompt', noKey: true },
|
|
422
|
-
{ name: 'budget', args: '[set <amount>]', description: 'Daily spend budget', noKey: true },
|
|
423
|
-
// Safety + observability (no key)
|
|
424
|
-
{ name: 'hook', args: '[install|status]', description: 'Safety hook management', noKey: true },
|
|
425
|
-
{ name: 'trust', args: '[path]', description: 'Scan for vulnerabilities', noKey: true },
|
|
426
|
-
{ name: 'report', args: '[path]', description: 'Shareable security audit', noKey: true },
|
|
427
|
-
{ name: 'status', args: '', description: 'Security dashboard — hook activity', noKey: true },
|
|
428
|
-
{
|
|
429
|
-
name: 'verify',
|
|
430
|
-
args: '[session-id]',
|
|
431
|
-
description: "Verify a session's Final Report against recorded reality",
|
|
432
|
-
noKey: true,
|
|
433
|
-
},
|
|
434
|
-
{ name: 'audit', args: '[verify|show]', description: 'Inspect the hash-chained audit log', noKey: true },
|
|
435
|
-
{
|
|
436
|
-
name: 'context-source',
|
|
437
|
-
args: '[list|connect|disconnect]',
|
|
438
|
-
description: 'Connect Linear/Figma via OAuth',
|
|
439
|
-
noKey: true,
|
|
440
|
-
},
|
|
441
|
-
{ name: 'thread', args: '<sub> [arg]', description: 'Share or import a signed session bundle', noKey: true },
|
|
442
|
-
{ name: 'health', args: '', description: 'System health + metrics', noKey: true },
|
|
443
|
-
// Orchestration
|
|
444
|
-
{ name: 'start', args: '', description: 'Open the dashboard at localhost:3773' },
|
|
445
|
-
{ name: 'serve', args: '', description: 'Run headless MCP server (no UI)', noKey: true },
|
|
446
|
-
{ name: 'task', args: '<prompt>', description: 'Delegate a task to a coding agent' },
|
|
447
|
-
{ name: 'kill', args: '<sessionId>', description: 'Kill a running task' },
|
|
448
|
-
// Utility (no key)
|
|
449
|
-
{ name: 'help', args: '', description: 'Command reference', noKey: true },
|
|
450
|
-
// REPL-only meta-commands (handled in repl.ts, not in Commander).
|
|
451
|
-
// Marked replOnly so the CI sync guard skips them.
|
|
452
|
-
{ name: 'agents', args: '', description: 'List installed specialists', noKey: true, replOnly: true },
|
|
453
|
-
{ name: 'history', args: '', description: 'Recent REPL session history', noKey: true, replOnly: true },
|
|
454
|
-
{ name: 'clear', args: '', description: 'Clear the screen', noKey: true, replOnly: true },
|
|
455
|
-
{ name: 'exit', args: '', description: 'Leave the session', noKey: true, replOnly: true },
|
|
456
|
-
];
|
|
457
|
-
export function showSlashCommandMenu() {
|
|
458
|
-
newline();
|
|
459
|
-
console.log(colors.bold(' Slash commands'));
|
|
460
|
-
newline();
|
|
461
|
-
const maxNameLen = Math.max(...SLASH_COMMANDS.map((c) => c.name.length + c.args.length)) + 1;
|
|
462
|
-
for (const cmd of SLASH_COMMANDS) {
|
|
463
|
-
const signature = `/${cmd.name}${cmd.args ? ' ' + cmd.args : ''}`;
|
|
464
|
-
const pad = ' '.repeat(Math.max(0, maxNameLen + 2 - signature.length + 8));
|
|
465
|
-
const badge = cmd.noKey ? colors.dim(' (no key)') : '';
|
|
466
|
-
console.log(` ${colors.cyan(signature)}${pad}${colors.dim(cmd.description)}${badge}`);
|
|
467
|
-
}
|
|
468
|
-
newline();
|
|
469
|
-
console.log(colors.dim(' Type any command with / prefix, or just ask a question directly.'));
|
|
470
|
-
newline();
|
|
471
|
-
}
|
|
472
53
|
//# sourceMappingURL=ui.js.map
|
package/dist/utils/version.js
CHANGED
|
@@ -37,16 +37,4 @@ export function getVersion() {
|
|
|
37
37
|
cachedVersion = '0.3.0';
|
|
38
38
|
return cachedVersion;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Get version with 'v' prefix (e.g., "v0.2.0")
|
|
42
|
-
*/
|
|
43
|
-
export function getVersionWithPrefix() {
|
|
44
|
-
return `v${getVersion()}`;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Reset version cache (useful for testing)
|
|
48
|
-
*/
|
|
49
|
-
export function resetVersionCache() {
|
|
50
|
-
cachedVersion = null;
|
|
51
|
-
}
|
|
52
40
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codehere",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Re-runs the tests an AI says passed, and tells you whether they did. Flags weakened tests and test files that do not exist.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -16,38 +16,36 @@
|
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=20"
|
|
18
18
|
},
|
|
19
|
+
"os": [
|
|
20
|
+
"darwin",
|
|
21
|
+
"linux"
|
|
22
|
+
],
|
|
19
23
|
"scripts": {
|
|
20
24
|
"prepare": "bash ../scripts/install-hooks.sh || true",
|
|
21
25
|
"prebuild": "rm -rf dist",
|
|
22
26
|
"build": "tsc",
|
|
23
27
|
"postbuild": "chmod +x dist/index.js",
|
|
24
|
-
"repomap": "node scripts/gen-repo-map.mjs",
|
|
25
|
-
"pattern-counts": "node scripts/print-pattern-counts.mjs",
|
|
26
28
|
"prepublishOnly": "npm run build && find dist -name '*.map' -delete && find dist -name '*.d.ts' -delete && find dist -name '*.d.ts.map' -delete",
|
|
27
29
|
"start": "node dist/index.js",
|
|
28
30
|
"dev": "tsx src/index.ts",
|
|
29
31
|
"test": "npm run build && vitest run",
|
|
30
32
|
"test:watch": "vitest",
|
|
31
33
|
"lint": "eslint src/ --ext .ts",
|
|
34
|
+
"knip": "knip",
|
|
35
|
+
"knip:gate": "node scripts/knip-gate.mjs",
|
|
36
|
+
"arch:gate": "tsc --noEmit && eslint src/ --ext .ts && node scripts/knip-gate.mjs",
|
|
32
37
|
"format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
|
|
33
38
|
"format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'",
|
|
34
39
|
"sbom": "npm sbom --sbom-format=spdx --omit=dev",
|
|
35
|
-
"pretag:check": "../scripts/pretag-npm-check.sh"
|
|
36
|
-
"cassette:record": "../scripts/capture-cassette.sh"
|
|
40
|
+
"pretag:check": "../scripts/pretag-npm-check.sh"
|
|
37
41
|
},
|
|
38
42
|
"keywords": [
|
|
39
43
|
"ai-coding-agents",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"ai-safety",
|
|
44
|
-
"ai-governance",
|
|
44
|
+
"test-verification",
|
|
45
|
+
"ci",
|
|
46
|
+
"github-action",
|
|
45
47
|
"claude-code",
|
|
46
48
|
"codex",
|
|
47
|
-
"aider",
|
|
48
|
-
"opencode",
|
|
49
|
-
"hook-system",
|
|
50
|
-
"sast",
|
|
51
49
|
"cli-tool",
|
|
52
50
|
"typescript"
|
|
53
51
|
],
|
|
@@ -60,25 +58,18 @@
|
|
|
60
58
|
"bugs": {
|
|
61
59
|
"url": "https://github.com/muhammadegaa/codehere/issues"
|
|
62
60
|
},
|
|
63
|
-
"homepage": "https://codehere
|
|
61
|
+
"homepage": "https://github.com/muhammadegaa/codehere",
|
|
64
62
|
"dependencies": {
|
|
65
|
-
"@mohammednagy/graphify-ts": "^0.22.3",
|
|
66
|
-
"boxen": "^8.0.1",
|
|
67
63
|
"chalk": "^5.3.0",
|
|
68
|
-
"
|
|
69
|
-
"cli-table3": "^0.6.5",
|
|
70
|
-
"commander": "^11.1.0",
|
|
71
|
-
"dotenv": "^16.3.1",
|
|
72
|
-
"gray-matter": "^4.0.3",
|
|
73
|
-
"ora": "^7.0.1",
|
|
74
|
-
"yaml": "^2.8.4"
|
|
64
|
+
"commander": "^11.1.0"
|
|
75
65
|
},
|
|
76
66
|
"devDependencies": {
|
|
77
67
|
"@eslint/js": "^10.0.1",
|
|
78
|
-
"@types/cli-progress": "^3.11.5",
|
|
79
68
|
"@types/node": "^20.19.25",
|
|
80
69
|
"eslint": "^10.2.0",
|
|
81
|
-
"
|
|
70
|
+
"eslint-import-resolver-typescript": "^4.4.5",
|
|
71
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
72
|
+
"knip": "^6.16.1",
|
|
82
73
|
"prettier": "^3.8.3",
|
|
83
74
|
"tsx": "^4.21.0",
|
|
84
75
|
"typescript": "^5.9.3",
|