codehere 0.7.1 → 1.0.1

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 (139) hide show
  1. package/README.md +22 -13
  2. package/dist/application/services/verdict-service.js +154 -0
  3. package/dist/application/use-cases/assess-cross-vendor.js +126 -0
  4. package/dist/application/use-cases/build-cross-vendor-verdict.js +118 -0
  5. package/dist/application/use-cases/export-aat.js +107 -0
  6. package/dist/application/use-cases/generate-acceptance-criteria.js +223 -0
  7. package/dist/application/use-cases/generate-final-report.js +140 -15
  8. package/dist/application/use-cases/generate-narration.js +5 -3
  9. package/dist/application/use-cases/generate-thread-title.js +5 -2
  10. package/dist/application/use-cases/narrator-prompt-template.js +1 -1
  11. package/dist/application/use-cases/plan-auto-review.js +57 -0
  12. package/dist/application/use-cases/reconcile-audit.js +100 -0
  13. package/dist/application/use-cases/rerun-tests.js +226 -0
  14. package/dist/application/use-cases/search-sessions.js +70 -0
  15. package/dist/application/use-cases/should-auto-review.js +71 -0
  16. package/dist/application/use-cases/thread-export.js +90 -0
  17. package/dist/application/use-cases/verify-claim.js +187 -5
  18. package/dist/domain/audit.js +11 -0
  19. package/dist/domain/services/codebase-detector.js +0 -6
  20. package/dist/domain/task.js +91 -0
  21. package/dist/error-handler.js +3 -115
  22. package/dist/index.js +279 -31
  23. package/dist/infrastructure/completion/bash-completion.js +7 -3
  24. package/dist/infrastructure/completion/fish-completion.js +7 -12
  25. package/dist/infrastructure/completion/zsh-completion.js +7 -12
  26. package/dist/infrastructure/config/config-manager.js +4 -3
  27. package/dist/infrastructure/config/product-context.js +1 -19
  28. package/dist/infrastructure/context/adapters/figma-source.js +37 -2
  29. package/dist/infrastructure/context/adapters/github-issue-source.js +3 -2
  30. package/dist/infrastructure/context/github-api.js +110 -0
  31. package/dist/infrastructure/context/github-device-flow.js +65 -0
  32. package/dist/infrastructure/context/oauth-store.js +5 -2
  33. package/dist/infrastructure/context/registry-bootstrap.js +0 -4
  34. package/dist/infrastructure/cost/budget-config.js +4 -3
  35. package/dist/infrastructure/cost/cost-router.js +16 -23
  36. package/dist/infrastructure/cost/spend-aggregator.js +91 -16
  37. package/dist/infrastructure/cost/team-ledger.js +355 -0
  38. package/dist/infrastructure/discovery/discovery-log.js +85 -0
  39. package/dist/infrastructure/hooks/audit-tip-signature.js +336 -0
  40. package/dist/infrastructure/hooks/claude-sdk-hook.js +139 -3
  41. package/dist/infrastructure/hooks/hook-mode.js +20 -4
  42. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +8 -2
  43. package/dist/infrastructure/hooks/pre-prompt-scan.js +3 -3
  44. package/dist/infrastructure/observability/execution-tracer.js +1 -1
  45. package/dist/infrastructure/orchestration/agents-config-seed.js +23 -11
  46. package/dist/infrastructure/orchestration/aider-adapter.js +188 -24
  47. package/dist/infrastructure/orchestration/artifacts-extractor.js +60 -2
  48. package/dist/infrastructure/orchestration/cassette-recorder.js +1 -1
  49. package/dist/infrastructure/orchestration/claude-code-adapter.js +117 -3
  50. package/dist/infrastructure/orchestration/codex-adapter.js +52 -16
  51. package/dist/infrastructure/orchestration/conductor-adapter.js +46 -7
  52. package/dist/infrastructure/orchestration/context-handoff.js +32 -14
  53. package/dist/infrastructure/orchestration/detect-ollama.js +75 -0
  54. package/dist/infrastructure/orchestration/failover-config.js +1 -11
  55. package/dist/infrastructure/orchestration/gemini-adapter.js +92 -12
  56. package/dist/infrastructure/orchestration/generic-cli-adapter.js +134 -3
  57. package/dist/infrastructure/orchestration/graphify-context.js +14 -59
  58. package/dist/infrastructure/orchestration/memory-injector.js +4 -1
  59. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +167 -9
  60. package/dist/infrastructure/orchestration/opencode-adapter.js +84 -14
  61. package/dist/infrastructure/orchestration/progress-aggregator.js +275 -23
  62. package/dist/infrastructure/orchestration/session-manager.js +593 -94
  63. package/dist/infrastructure/orchestration/session-persistence.js +177 -41
  64. package/dist/infrastructure/orchestration/thread-key-store.js +1 -1
  65. package/dist/infrastructure/orchestration/write-pass-store.js +0 -8
  66. package/dist/infrastructure/protocols/cloud-sync.js +2 -2
  67. package/dist/infrastructure/protocols/mcp-helpers.js +1 -1
  68. package/dist/infrastructure/protocols/mcp-server-impl.js +1498 -354
  69. package/dist/infrastructure/protocols/mcp-tools.js +401 -0
  70. package/dist/infrastructure/protocols/ui/app-script-artifacts.js +121 -0
  71. package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +44 -0
  72. package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +56 -0
  73. package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +588 -0
  74. package/dist/infrastructure/protocols/ui/app-script-context-sources.js +168 -0
  75. package/dist/infrastructure/protocols/ui/app-script-conversation.js +67 -0
  76. package/dist/infrastructure/protocols/ui/app-script-drawer.js +115 -0
  77. package/dist/infrastructure/protocols/ui/app-script-failover.js +133 -0
  78. package/dist/infrastructure/protocols/ui/app-script-github.js +113 -0
  79. package/dist/infrastructure/protocols/ui/app-script-observer.js +104 -0
  80. package/dist/infrastructure/protocols/ui/app-script-onboarding.js +80 -0
  81. package/dist/infrastructure/protocols/ui/app-script-overlay.js +203 -0
  82. package/dist/infrastructure/protocols/ui/app-script-recovery.js +136 -0
  83. package/dist/infrastructure/protocols/ui/app-script-render.js +166 -0
  84. package/dist/infrastructure/protocols/ui/app-script-share.js +78 -0
  85. package/dist/infrastructure/protocols/ui/app-script-sidebar.js +194 -0
  86. package/dist/infrastructure/protocols/ui/app-script-tour.js +78 -0
  87. package/dist/infrastructure/protocols/ui/app-script-wpass.js +312 -0
  88. package/dist/infrastructure/protocols/ui/app-script.js +2998 -0
  89. package/dist/infrastructure/protocols/ui/font-faces.js +7 -0
  90. package/dist/infrastructure/protocols/ui/styles.js +2147 -0
  91. package/dist/infrastructure/protocols/ui/tokens.js +96 -0
  92. package/dist/infrastructure/protocols/ui-page-v2.js +116 -4126
  93. package/dist/infrastructure/protocols/verify-page.js +884 -148
  94. package/dist/infrastructure/security/fix-code.js +144 -0
  95. package/dist/infrastructure/security/fix-secret.js +89 -0
  96. package/dist/infrastructure/security/permissions-config.js +3 -2
  97. package/dist/infrastructure/security/scan-types.js +10 -0
  98. package/dist/infrastructure/security/ship-scan.js +195 -0
  99. package/dist/infrastructure/security/trust-scorer.js +70 -3
  100. package/dist/infrastructure/security/vibe-checks.js +99 -0
  101. package/dist/infrastructure/storage/atomic-write.js +86 -0
  102. package/dist/infrastructure/storage/project-thread-mirror.js +151 -4
  103. package/dist/infrastructure/storage/project-thread-reader.js +262 -25
  104. package/dist/infrastructure/storage/project-thread-title-backfill.js +1 -1
  105. package/dist/monitoring.js +2 -2
  106. package/dist/presentation/cli/commands/audit-command.js +79 -4
  107. package/dist/presentation/cli/commands/budget-command.js +2 -2
  108. package/dist/presentation/cli/commands/check-command.js +96 -0
  109. package/dist/presentation/cli/commands/context-source-command.js +20 -1
  110. package/dist/presentation/cli/commands/help-command.js +5 -5
  111. package/dist/presentation/cli/commands/hook-command.js +5 -5
  112. package/dist/presentation/cli/commands/init-command.js +89 -66
  113. package/dist/presentation/cli/commands/memory-command.js +28 -28
  114. package/dist/presentation/cli/commands/permission-command.js +1 -12
  115. package/dist/presentation/cli/commands/protocols-builder.js +2 -2
  116. package/dist/presentation/cli/commands/protocols-command.js +4 -4
  117. package/dist/presentation/cli/commands/repo-map-builder.js +1 -1
  118. package/dist/presentation/cli/commands/report-command.js +48 -32
  119. package/dist/presentation/cli/commands/scan-command.js +52 -0
  120. package/dist/presentation/cli/commands/scan-tool-command.js +24 -8
  121. package/dist/presentation/cli/commands/search-command.js +51 -0
  122. package/dist/presentation/cli/commands/setup-command.js +31 -8
  123. package/dist/presentation/cli/commands/status-command.js +39 -86
  124. package/dist/presentation/cli/commands/team-command.js +256 -0
  125. package/dist/presentation/cli/commands/thread-command.js +87 -5
  126. package/dist/presentation/cli/commands/trust-command.js +53 -31
  127. package/dist/presentation/cli/commands/verify-command.js +74 -9
  128. package/dist/presentation/cli/error-display.js +0 -8
  129. package/dist/presentation/cli/repl.js +15 -7
  130. package/dist/presentation/cli/task-deliverable.js +36 -10
  131. package/dist/testing/replay-adapter.js +0 -19
  132. package/dist/ui.js +51 -239
  133. package/dist/utils/version.js +0 -6
  134. package/package.json +30 -10
  135. package/dist/domain/entities/task.js +0 -61
  136. package/dist/infrastructure/protocols/ui-page.js +0 -2377
  137. package/dist/infrastructure/security/input-validator.js +0 -152
  138. package/dist/infrastructure/storage/embeddings-path.js +0 -37
  139. package/dist/infrastructure/storage/task-repository.js +0 -206
package/dist/ui.js CHANGED
@@ -1,11 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
3
- import cliProgress from 'cli-progress';
4
- import boxen from 'boxen';
5
2
  import Table from 'cli-table3';
6
- import { existsSync } from 'fs';
7
- import { join, dirname } from 'path';
8
- import { fileURLToPath } from 'url';
9
3
  let cachedCliStyle = null;
10
4
  export function getCliStyle() {
11
5
  if (cachedCliStyle)
@@ -27,24 +21,16 @@ export function printMinimalHeader(command, query) {
27
21
  }
28
22
  console.log();
29
23
  }
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
24
  // Professional color scheme - subtle and enterprise-ready
25
+ // CLI color economy (DESIGN.md §5.2) — color carries MEANING, not decoration,
26
+ // and is always redundant with a glyph + word so NO_COLOR / piped output stays
27
+ // legible (chalk auto-disables on non-TTY and when NO_COLOR is set). The
28
+ // semantic names below are the vocabulary CLI output should use; the raw chalk
29
+ // names are kept for back-compat but new output uses meaning:
30
+ // verified = green (independently verified ONLY) caught = red (a contradiction caught ONLY)
31
+ // warn = amber (budget/attention) evidence = dim (machine facts, metadata)
32
+ // identity = cyan (an agent/session id, sparingly) heading = bold (the one thing that matters)
33
+ // Retired: magenta as decoration.
48
34
  export const colors = {
49
35
  success: chalk.green,
50
36
  error: chalk.red,
@@ -59,57 +45,33 @@ export const colors = {
59
45
  green: chalk.green,
60
46
  gray: chalk.gray,
61
47
  blue: chalk.blue,
48
+ // semantic economy — prefer these in new CLI output
49
+ verified: chalk.green,
50
+ caught: chalk.red,
51
+ warn: chalk.yellow,
52
+ evidence: chalk.dim,
53
+ identity: chalk.cyan,
54
+ heading: chalk.bold,
62
55
  };
63
- // Professional status symbols (ASCII only - enterprise-ready)
56
+ // S19 glyph language (BINDING, shared with the web design tokens in
57
+ // ui-page-v2): status = the sanctioned geometric set + ANSI color —
58
+ // ✓ ✕ · — › ● ○ ⊘ — never emoji-as-icon, never pictographs in stdout/stderr.
64
59
  export const symbols = {
65
60
  success: '✓',
66
- error: '✗',
67
- warning: '⚠',
68
- info: '→',
69
- processing: '⟳',
70
- arrow: '→',
71
- dot: '•',
61
+ error: '✕',
62
+ warning: '!',
63
+ info: '›',
64
+ processing: '›',
65
+ arrow: '›',
66
+ dot: '·',
72
67
  check: '✓',
73
- cross: '✗',
68
+ cross: '✕',
74
69
  pipe: '│',
75
70
  dash: '─',
76
71
  plus: '+',
77
72
  minus: '-',
78
73
  bullet: '•',
79
74
  };
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
75
  // Professional banner - clean and minimal
114
76
  export function createBanner(title, subtitle) {
115
77
  const width = Math.max(title.length, subtitle?.length || 0) + 4;
@@ -144,6 +106,13 @@ export function warning(message) {
144
106
  export function info(message) {
145
107
  return colors.blue(symbols.info + ' ' + message);
146
108
  }
109
+ // Section heading (DESIGN.md §5.2) — the one structural line per block. Bold,
110
+ // no color: color is reserved for meaning (verdict/identity), so a heading
111
+ // earns emphasis from weight, not decoration. Legible with NO_COLOR (bold is
112
+ // the fallback; the words carry it regardless).
113
+ export function heading(message) {
114
+ return colors.heading(message);
115
+ }
147
116
  // Create professional table - minimal styling
148
117
  export function createTable(headers, rows) {
149
118
  const table = new Table({
@@ -178,32 +147,10 @@ export function createTable(headers, rows) {
178
147
  rows.forEach((row) => table.push(row));
179
148
  return table;
180
149
  }
181
- // Format file path - subtle
182
- export function formatPath(path) {
183
- return colors.cyan(path);
184
- }
185
150
  // Format number - bold
186
151
  export function formatNumber(num) {
187
152
  return colors.bold(num.toString());
188
153
  }
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
154
  // Professional section header
208
155
  export function sectionHeader(title) {
209
156
  console.log(colors.bold(title));
@@ -215,46 +162,6 @@ export function newline(count = 1) {
215
162
  console.log();
216
163
  }
217
164
  }
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
165
  // Gradient logo for "codehere" - coral → purple → blue
259
166
  export function createCodehereLogo() {
260
167
  const text = 'codehere';
@@ -288,115 +195,20 @@ export function createWelcomeMessage() {
288
195
  // Matches the positioning in `codehere --help` and `codehere help`. codehere
289
196
  // is the LAYER over your coding agents, not itself an agent — the old
290
197
  // "AI coding agent with built-in safety" line implied the opposite.
291
- const tagline = 'A PM for your AI coding agents';
198
+ const tagline = 'Your AI coding agents: audited, cost-bounded, cross-vendor';
292
199
  return `
293
200
  ${colors.bold(logo)} ${colors.dim(version)}
294
201
  ${colors.dim(tagline)}
295
202
  `;
296
203
  }
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
204
  // ── 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
205
  const CLEAN_SCAN_CELEBRATIONS = [
388
206
  'Perfect score. Nothing to worry about.',
389
- 'All clear — clean scan.',
207
+ 'All clear · clean scan.',
390
208
  'Zero findings. Enjoy the green.',
391
209
  'Nothing suspicious. Carry on.',
392
210
  'Clean as a whistle.',
393
211
  ];
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
212
  export function randomCleanScan() {
401
213
  return CLEAN_SCAN_CELEBRATIONS[Math.floor(Math.random() * CLEAN_SCAN_CELEBRATIONS.length)];
402
214
  }
@@ -420,11 +232,24 @@ export const SLASH_COMMANDS = [
420
232
  { name: 'permission', args: '<sub>', description: 'Manage .codehere/permissions.yaml allow/deny', noKey: true },
421
233
  { name: 'narrator', args: '', description: 'Customize the PM narrator prompt', noKey: true },
422
234
  { name: 'budget', args: '[set <amount>]', description: 'Daily spend budget', noKey: true },
235
+ {
236
+ name: 'team',
237
+ args: '[set-dir <path>|budget <usd>]',
238
+ description: "Merge each machine's spend into one team total · local-first",
239
+ noKey: true,
240
+ },
423
241
  // Safety + observability (no key)
424
242
  { name: 'hook', args: '[install|status]', description: 'Safety hook management', noKey: true },
425
243
  { name: 'trust', args: '[path]', description: 'Scan for vulnerabilities', noKey: true },
244
+ {
245
+ name: 'scan',
246
+ args: '[path]',
247
+ description: 'Is your app safe to ship? — the 1 thing that gets you hacked',
248
+ noKey: true,
249
+ },
250
+ { name: 'check', args: '[path]', description: 'Re-run your tests — proof, not the AI’s claim', noKey: true },
426
251
  { name: 'report', args: '[path]', description: 'Shareable security audit', noKey: true },
427
- { name: 'status', args: '', description: 'Security dashboard — hook activity', noKey: true },
252
+ { name: 'status', args: '', description: 'Security dashboard · hook activity', noKey: true },
428
253
  {
429
254
  name: 'verify',
430
255
  args: '[session-id]',
@@ -432,6 +257,7 @@ export const SLASH_COMMANDS = [
432
257
  noKey: true,
433
258
  },
434
259
  { name: 'audit', args: '[verify|show]', description: 'Inspect the hash-chained audit log', noKey: true },
260
+ { name: 'search', args: '<query>', description: 'Search past sessions · every hit cites its evidence', noKey: true },
435
261
  {
436
262
  name: 'context-source',
437
263
  args: '[list|connect|disconnect]',
@@ -444,6 +270,7 @@ export const SLASH_COMMANDS = [
444
270
  { name: 'start', args: '', description: 'Open the dashboard at localhost:3773' },
445
271
  { name: 'serve', args: '', description: 'Run headless MCP server (no UI)', noKey: true },
446
272
  { name: 'task', args: '<prompt>', description: 'Delegate a task to a coding agent' },
273
+ { name: 'reply', args: '<id> <text>', description: 'Continue a goal · send a follow-up to a session' },
447
274
  { name: 'kill', args: '<sessionId>', description: 'Kill a running task' },
448
275
  // Utility (no key)
449
276
  { name: 'help', args: '', description: 'Command reference', noKey: true },
@@ -454,19 +281,4 @@ export const SLASH_COMMANDS = [
454
281
  { name: 'clear', args: '', description: 'Clear the screen', noKey: true, replOnly: true },
455
282
  { name: 'exit', args: '', description: 'Leave the session', noKey: true, replOnly: true },
456
283
  ];
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
284
  //# sourceMappingURL=ui.js.map
@@ -43,10 +43,4 @@ export function getVersion() {
43
43
  export function getVersionWithPrefix() {
44
44
  return `v${getVersion()}`;
45
45
  }
46
- /**
47
- * Reset version cache (useful for testing)
48
- */
49
- export function resetVersionCache() {
50
- cachedVersion = null;
51
- }
52
46
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "codehere",
3
- "version": "0.7.1",
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.1",
4
+ "description": "See what your AI coding agents cost, and prove what they actually did. Runs Claude Code, Codex, Aider, Gemini and OpenCode on your machine, records every action in a hash-chained log, and re-runs your tests instead of taking an agent's word for it.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -16,6 +16,10 @@
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",
@@ -29,15 +33,26 @@
29
33
  "test": "npm run build && vitest run",
30
34
  "test:watch": "vitest",
31
35
  "lint": "eslint src/ --ext .ts",
36
+ "knip": "knip",
37
+ "knip:gate": "node scripts/knip-gate.mjs",
38
+ "lint:tokens": "node scripts/ui-token-gate.mjs",
39
+ "arch:gate": "tsc --noEmit && eslint src/ --ext .ts && node scripts/knip-gate.mjs && node scripts/ui-token-gate.mjs",
32
40
  "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
33
41
  "format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'",
34
42
  "sbom": "npm sbom --sbom-format=spdx --omit=dev",
35
43
  "pretag:check": "../scripts/pretag-npm-check.sh",
36
- "cassette:record": "../scripts/capture-cassette.sh"
44
+ "cassette:record": "../scripts/capture-cassette.sh",
45
+ "e2e": "node test/e2e/run.mjs",
46
+ "e2e:live": "CODEHERE_E2E_LIVE=1 node test/e2e/run.mjs",
47
+ "degraded": "node scripts/degraded-matrix.mjs",
48
+ "inventory": "node scripts/inventory-drift.mjs"
37
49
  },
38
50
  "keywords": [
39
51
  "ai-coding-agents",
40
- "agent-orchestration",
52
+ "verification",
53
+ "agent-audit",
54
+ "llm-cost",
55
+ "ai-cost-tracking",
41
56
  "audit-trail",
42
57
  "trust-scoring",
43
58
  "ai-safety",
@@ -62,27 +77,32 @@
62
77
  },
63
78
  "homepage": "https://codehere.uk",
64
79
  "dependencies": {
65
- "@mohammednagy/graphify-ts": "^0.22.3",
66
- "boxen": "^8.0.1",
67
80
  "chalk": "^5.3.0",
68
- "cli-progress": "^3.12.0",
69
81
  "cli-table3": "^0.6.5",
70
82
  "commander": "^11.1.0",
71
83
  "dotenv": "^16.3.1",
72
- "gray-matter": "^4.0.3",
73
- "ora": "^7.0.1",
74
84
  "yaml": "^2.8.4"
75
85
  },
76
86
  "devDependencies": {
77
87
  "@eslint/js": "^10.0.1",
78
- "@types/cli-progress": "^3.11.5",
79
88
  "@types/node": "^20.19.25",
80
89
  "eslint": "^10.2.0",
90
+ "eslint-import-resolver-typescript": "^4.4.5",
91
+ "eslint-plugin-import-x": "^4.16.2",
92
+ "knip": "^6.16.1",
81
93
  "playwright": "^1.60.0",
82
94
  "prettier": "^3.8.3",
83
95
  "tsx": "^4.21.0",
84
96
  "typescript": "^5.9.3",
85
97
  "typescript-eslint": "^8.58.2",
86
98
  "vitest": "^4.1.4"
99
+ },
100
+ "peerDependencies": {
101
+ "@mohammednagy/graphify-ts": "^0.22.3"
102
+ },
103
+ "peerDependenciesMeta": {
104
+ "@mohammednagy/graphify-ts": {
105
+ "optional": true
106
+ }
87
107
  }
88
108
  }
@@ -1,61 +0,0 @@
1
- /**
2
- * Domain Entity: CodehereTask
3
- * Task and workflow entities for the 4-mode interaction model
4
- *
5
- * Phase 1: v0.5.0-alpha
6
- * See: .internal/ARCHITECTURE.md (internal docs)
7
- */
8
- /**
9
- * Task Mode - The interaction mode that created this task
10
- */
11
- export var TaskMode;
12
- (function (TaskMode) {
13
- TaskMode["SUGGEST"] = "suggest";
14
- TaskMode["PLAN"] = "plan";
15
- TaskMode["RUN"] = "run";
16
- TaskMode["REVIEW"] = "review";
17
- })(TaskMode || (TaskMode = {}));
18
- /**
19
- * Task Status - Current lifecycle state
20
- */
21
- export var TaskStatus;
22
- (function (TaskStatus) {
23
- TaskStatus["CREATED"] = "created";
24
- TaskStatus["PLANNED"] = "planned";
25
- TaskStatus["RUNNING"] = "running";
26
- TaskStatus["COMPLETED"] = "completed";
27
- TaskStatus["FAILED"] = "failed";
28
- TaskStatus["NEEDS_REVIEW"] = "needs_review";
29
- TaskStatus["APPROVED"] = "approved";
30
- TaskStatus["REJECTED"] = "rejected";
31
- TaskStatus["CANCELLED"] = "cancelled";
32
- })(TaskStatus || (TaskStatus = {}));
33
- /**
34
- * Risk Tier - Risk level for operation
35
- */
36
- export var RiskTier;
37
- (function (RiskTier) {
38
- RiskTier["T1"] = "t1";
39
- RiskTier["T2"] = "t2";
40
- RiskTier["T3"] = "t3";
41
- })(RiskTier || (RiskTier = {}));
42
- /**
43
- * Environment Mode - Data access boundaries
44
- */
45
- export var EnvironmentMode;
46
- (function (EnvironmentMode) {
47
- EnvironmentMode["LOCAL"] = "local";
48
- EnvironmentMode["ORG"] = "org";
49
- EnvironmentMode["INTERNET"] = "internet";
50
- })(EnvironmentMode || (EnvironmentMode = {}));
51
- /**
52
- * Review Status
53
- */
54
- export var ReviewStatus;
55
- (function (ReviewStatus) {
56
- ReviewStatus["NOT_REQUIRED"] = "not_required";
57
- ReviewStatus["PENDING"] = "pending";
58
- ReviewStatus["APPROVED"] = "approved";
59
- ReviewStatus["REJECTED"] = "rejected";
60
- })(ReviewStatus || (ReviewStatus = {}));
61
- //# sourceMappingURL=task.js.map