truecourse 0.1.12 → 0.1.13

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/cli.mjs CHANGED
@@ -12662,8 +12662,9 @@ async function startServiceMode(openBrowser) {
12662
12662
  v2.info("Check logs with: truecourse service logs");
12663
12663
  }
12664
12664
  }
12665
- function startConsoleMode() {
12665
+ function startConsoleMode(openBrowser) {
12666
12666
  const serverPath = getServerPath();
12667
+ const url2 = getServerUrl();
12667
12668
  v2.step("Starting server (embedded PostgreSQL starts automatically)...");
12668
12669
  const serverProcess = spawn2(
12669
12670
  process.execPath,
@@ -12687,6 +12688,11 @@ function startConsoleMode() {
12687
12688
  };
12688
12689
  process.on("SIGINT", cleanup);
12689
12690
  process.on("SIGTERM", cleanup);
12691
+ if (openBrowser) {
12692
+ healthcheck().then((healthy) => {
12693
+ if (healthy) openInBrowser(url2);
12694
+ });
12695
+ }
12690
12696
  }
12691
12697
  async function runStart({ openBrowser = true } = {}) {
12692
12698
  we("Starting TrueCourse");
@@ -12697,10 +12703,10 @@ async function runStart({ openBrowser = true } = {}) {
12697
12703
  } catch (error) {
12698
12704
  v2.error(`Service mode failed: ${error.message}`);
12699
12705
  v2.info("Falling back to console mode. Reconfigure with: truecourse setup");
12700
- startConsoleMode();
12706
+ startConsoleMode(openBrowser);
12701
12707
  }
12702
12708
  } else {
12703
- startConsoleMode();
12709
+ startConsoleMode(openBrowser);
12704
12710
  }
12705
12711
  }
12706
12712
  var __dirname;
@@ -12995,6 +13001,7 @@ function renderDiffResultsSummary(result) {
12995
13001
  v2.info("Run `truecourse list --diff` to see full details.");
12996
13002
  }
12997
13003
  function openInBrowser(url2) {
13004
+ console.log(` Opening ${url2}`);
12998
13005
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
12999
13006
  exec(`${cmd} ${url2}`);
13000
13007
  }
@@ -13034,6 +13041,7 @@ import os6 from "node:os";
13034
13041
 
13035
13042
  // tools/cli/src/commands/setup.ts
13036
13043
  init_dist2();
13044
+ import { execSync as execSync4 } from "node:child_process";
13037
13045
  import fs6 from "node:fs";
13038
13046
  import path6 from "node:path";
13039
13047
  import os5 from "node:os";
@@ -13073,8 +13081,9 @@ async function runSetup() {
13073
13081
  const provider = await de({
13074
13082
  message: "Which LLM provider would you like to use?",
13075
13083
  options: [
13076
- { value: "anthropic", label: "Anthropic (Claude)" },
13077
- { value: "openai", label: "OpenAI (GPT)" },
13084
+ { value: "claude-code", label: "Claude Code CLI \u2014 no API key needed (Recommended)" },
13085
+ { value: "anthropic", label: "Anthropic (Claude API)" },
13086
+ { value: "openai", label: "OpenAI (GPT API)" },
13078
13087
  { value: "skip", label: "Skip for now" }
13079
13088
  ]
13080
13089
  });
@@ -13083,9 +13092,18 @@ async function runSetup() {
13083
13092
  process.exit(0);
13084
13093
  }
13085
13094
  const config = {};
13086
- if (provider === "anthropic" || provider === "openai") {
13095
+ if (provider === "anthropic" || provider === "openai" || provider === "claude-code") {
13087
13096
  config.provider = provider;
13088
13097
  }
13098
+ if (provider === "claude-code") {
13099
+ try {
13100
+ execSync4("which claude", { stdio: "ignore" });
13101
+ } catch {
13102
+ v2.error("Claude Code CLI not found on PATH. Install it first: https://docs.anthropic.com/en/docs/claude-code");
13103
+ process.exit(1);
13104
+ }
13105
+ v2.success("Claude Code CLI detected.");
13106
+ }
13089
13107
  if (provider === "anthropic") {
13090
13108
  const anthropicKey = await ue({
13091
13109
  message: "Enter your Anthropic API key:",
@@ -13130,7 +13148,7 @@ async function runSetup() {
13130
13148
  }
13131
13149
  config.model = model?.trim() || defaultModel;
13132
13150
  }
13133
- const useLangfuse = await me({
13151
+ const useLangfuse = provider !== "claude-code" && await me({
13134
13152
  message: "Would you like to enable Langfuse tracing?",
13135
13153
  initialValue: false
13136
13154
  });
@@ -13233,8 +13251,7 @@ async function runAdd() {
13233
13251
  message: "Would you like to install Claude Code skills?"
13234
13252
  });
13235
13253
  if (BD(installSkills)) {
13236
- openInBrowser(repoUrl);
13237
- fe("Opened in browser");
13254
+ fe(`Open ${repoUrl}`);
13238
13255
  return;
13239
13256
  }
13240
13257
  if (installSkills) {
@@ -13251,8 +13268,7 @@ async function runAdd() {
13251
13268
  v2.message(" - truecourse-fix (apply fixes)");
13252
13269
  }
13253
13270
  }
13254
- openInBrowser(repoUrl);
13255
- fe("Opened in browser");
13271
+ fe(`Open ${repoUrl}`);
13256
13272
  } catch (err) {
13257
13273
  const message = err instanceof Error ? err.message : String(err);
13258
13274
  if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
@@ -13336,11 +13352,13 @@ async function runAnalyze() {
13336
13352
  }
13337
13353
  const violations = await res.json();
13338
13354
  renderViolationsSummary(violations);
13355
+ const repoUrl = `${serverUrl}/repos/${repo.id}`;
13339
13356
  if (firstRun) {
13340
- const repoUrl = `${serverUrl}/repos/${repo.id}`;
13341
13357
  openInBrowser(repoUrl);
13358
+ fe("Analysis complete \u2014 opened in browser");
13359
+ } else {
13360
+ fe(`Analysis complete \u2014 open ${repoUrl}`);
13342
13361
  }
13343
- fe("Analysis complete");
13344
13362
  } catch (err) {
13345
13363
  spinner.stop("Analysis failed");
13346
13364
  const message = err instanceof Error ? err.message : String(err);
@@ -0,0 +1,16 @@
1
+ CREATE TABLE "analysis_usage" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "analysis_id" uuid NOT NULL,
4
+ "provider" text NOT NULL,
5
+ "call_type" text NOT NULL,
6
+ "input_tokens" integer DEFAULT 0 NOT NULL,
7
+ "output_tokens" integer DEFAULT 0 NOT NULL,
8
+ "cache_read_tokens" integer DEFAULT 0 NOT NULL,
9
+ "cache_write_tokens" integer DEFAULT 0 NOT NULL,
10
+ "total_tokens" integer DEFAULT 0 NOT NULL,
11
+ "cost_usd" text,
12
+ "duration_ms" integer DEFAULT 0 NOT NULL,
13
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
14
+ );
15
+ --> statement-breakpoint
16
+ ALTER TABLE "analysis_usage" ADD CONSTRAINT "analysis_usage_analysis_id_analyses_id_fk" FOREIGN KEY ("analysis_id") REFERENCES "public"."analyses"("id") ON DELETE cascade ON UPDATE no action;