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.
Files changed (119) hide show
  1. package/README.md +37 -184
  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 +329 -0
  5. package/dist/index.js +74 -1004
  6. package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -265
  7. package/dist/presentation/cli/commands/check-command.js +251 -0
  8. package/dist/presentation/cli/commands/help-command.js +22 -286
  9. package/dist/ui.js +19 -438
  10. package/dist/utils/version.js +0 -12
  11. package/package.json +18 -27
  12. package/dist/application/use-cases/domain-trust.js +0 -110
  13. package/dist/application/use-cases/generate-final-report.js +0 -134
  14. package/dist/application/use-cases/generate-narration.js +0 -128
  15. package/dist/application/use-cases/generate-thread-title.js +0 -178
  16. package/dist/application/use-cases/narrator-prompt-template.js +0 -158
  17. package/dist/application/use-cases/thread-export.js +0 -155
  18. package/dist/application/use-cases/verify-claim.js +0 -274
  19. package/dist/application/use-cases/write-pass.js +0 -277
  20. package/dist/domain/entities/task.js +0 -61
  21. package/dist/domain/services/codebase-detector.js +0 -91
  22. package/dist/error-handler.js +0 -251
  23. package/dist/infrastructure/completion/bash-completion.js +0 -25
  24. package/dist/infrastructure/completion/fish-completion.js +0 -22
  25. package/dist/infrastructure/completion/zsh-completion.js +0 -30
  26. package/dist/infrastructure/config/config-manager.js +0 -173
  27. package/dist/infrastructure/config/product-context.js +0 -67
  28. package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
  29. package/dist/infrastructure/context/adapters/figma-source.js +0 -163
  30. package/dist/infrastructure/context/adapters/github-issue-source.js +0 -159
  31. package/dist/infrastructure/context/adapters/linear-source.js +0 -190
  32. package/dist/infrastructure/context/context-resolver.js +0 -144
  33. package/dist/infrastructure/context/context-source.js +0 -114
  34. package/dist/infrastructure/context/oauth-flow.js +0 -207
  35. package/dist/infrastructure/context/oauth-store.js +0 -119
  36. package/dist/infrastructure/context/registry-bootstrap.js +0 -99
  37. package/dist/infrastructure/context/write-pass-resolver.js +0 -106
  38. package/dist/infrastructure/cost/budget-config.js +0 -113
  39. package/dist/infrastructure/cost/cost-router.js +0 -104
  40. package/dist/infrastructure/cost/spend-aggregator.js +0 -147
  41. package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -888
  42. package/dist/infrastructure/hooks/hook-mode.js +0 -71
  43. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -43
  44. package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
  45. package/dist/infrastructure/hooks/session-analyzer.js +0 -177
  46. package/dist/infrastructure/observability/execution-tracer.js +0 -227
  47. package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
  48. package/dist/infrastructure/orchestration/agent-installer.js +0 -101
  49. package/dist/infrastructure/orchestration/agents-config-seed.js +0 -56
  50. package/dist/infrastructure/orchestration/aider-adapter.js +0 -447
  51. package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
  52. package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -478
  53. package/dist/infrastructure/orchestration/codex-adapter.js +0 -538
  54. package/dist/infrastructure/orchestration/conductor-adapter.js +0 -377
  55. package/dist/infrastructure/orchestration/context-handoff.js +0 -144
  56. package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
  57. package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
  58. package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
  59. package/dist/infrastructure/orchestration/failover-config.js +0 -77
  60. package/dist/infrastructure/orchestration/failover-policy.js +0 -106
  61. package/dist/infrastructure/orchestration/gemini-adapter.js +0 -583
  62. package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -558
  63. package/dist/infrastructure/orchestration/graphify-context.js +0 -254
  64. package/dist/infrastructure/orchestration/memory-injector.js +0 -380
  65. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -233
  66. package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
  67. package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
  68. package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
  69. package/dist/infrastructure/orchestration/opencode-adapter.js +0 -510
  70. package/dist/infrastructure/orchestration/progress-aggregator.js +0 -689
  71. package/dist/infrastructure/orchestration/readiness.js +0 -103
  72. package/dist/infrastructure/orchestration/session-manager.js +0 -1091
  73. package/dist/infrastructure/orchestration/session-persistence.js +0 -258
  74. package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
  75. package/dist/infrastructure/orchestration/write-pass-store.js +0 -46
  76. package/dist/infrastructure/protocols/cloud-sync.js +0 -207
  77. package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
  78. package/dist/infrastructure/protocols/mcp-server-impl.js +0 -2853
  79. package/dist/infrastructure/protocols/probe-port.js +0 -36
  80. package/dist/infrastructure/protocols/thread-phase.js +0 -105
  81. package/dist/infrastructure/protocols/ui-page-v2.js +0 -4418
  82. package/dist/infrastructure/protocols/ui-page.js +0 -2377
  83. package/dist/infrastructure/protocols/verify-page.js +0 -983
  84. package/dist/infrastructure/security/file-collection.js +0 -118
  85. package/dist/infrastructure/security/input-validator.js +0 -152
  86. package/dist/infrastructure/security/permissions-config.js +0 -234
  87. package/dist/infrastructure/security/trust-scorer.js +0 -657
  88. package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
  89. package/dist/infrastructure/storage/embeddings-path.js +0 -37
  90. package/dist/infrastructure/storage/project-thread-migration.js +0 -237
  91. package/dist/infrastructure/storage/project-thread-mirror.js +0 -524
  92. package/dist/infrastructure/storage/project-thread-reader.js +0 -172
  93. package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
  94. package/dist/infrastructure/storage/task-repository.js +0 -206
  95. package/dist/monitoring.js +0 -212
  96. package/dist/presentation/cli/commands/audit-command.js +0 -126
  97. package/dist/presentation/cli/commands/budget-command.js +0 -79
  98. package/dist/presentation/cli/commands/config-command.js +0 -125
  99. package/dist/presentation/cli/commands/context-source-command.js +0 -198
  100. package/dist/presentation/cli/commands/hook-command.js +0 -265
  101. package/dist/presentation/cli/commands/init-command.js +0 -578
  102. package/dist/presentation/cli/commands/memory-command.js +0 -1031
  103. package/dist/presentation/cli/commands/narrator-command.js +0 -101
  104. package/dist/presentation/cli/commands/permission-command.js +0 -116
  105. package/dist/presentation/cli/commands/protocols-builder.js +0 -254
  106. package/dist/presentation/cli/commands/protocols-command.js +0 -84
  107. package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
  108. package/dist/presentation/cli/commands/report-command.js +0 -387
  109. package/dist/presentation/cli/commands/scan-tool-command.js +0 -94
  110. package/dist/presentation/cli/commands/setup-command.js +0 -307
  111. package/dist/presentation/cli/commands/status-command.js +0 -661
  112. package/dist/presentation/cli/commands/thread-command.js +0 -288
  113. package/dist/presentation/cli/commands/trust-command.js +0 -306
  114. package/dist/presentation/cli/commands/verify-command.js +0 -233
  115. package/dist/presentation/cli/error-display.js +0 -336
  116. package/dist/presentation/cli/repl.js +0 -797
  117. package/dist/presentation/cli/task-deliverable.js +0 -127
  118. package/dist/testing/cassette.js +0 -125
  119. package/dist/testing/replay-adapter.js +0 -166
package/dist/ui.js CHANGED
@@ -1,50 +1,8 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
3
- import cliProgress from 'cli-progress';
4
- import boxen from 'boxen';
5
- import Table from 'cli-table3';
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
- // Professional status symbols (ASCII only - enterprise-ready)
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
@@ -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.8.0",
4
- "description": "A PM for your AI coding agents. Delegate, orchestrate, and audit Claude Code, Codex, Aider, OpenCode, Gemini, and any user-configured CLI agent from one local web UI — every AI action traced, every file scored, every spawn warmed with project memory.",
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
- "agent-orchestration",
41
- "audit-trail",
42
- "trust-scoring",
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.uk",
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
- "cli-progress": "^3.12.0",
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
- "playwright": "^1.60.0",
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",