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 +31 -13
- package/db/migrations/0009_sticky_blizzard.sql +16 -0
- package/db/migrations/meta/0009_snapshot.json +2062 -0
- package/db/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/public/assets/{index-DYIYjwei.js → index-CVwZeppe.js} +163 -153
- package/public/assets/index-JxEVjRt1.css +1 -0
- package/public/index.html +2 -2
- package/server.mjs +148561 -144650
- package/public/assets/index-CFKYSTp1.css +0 -1
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: "
|
|
13077
|
-
{ value: "
|
|
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
|
-
|
|
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
|
-
|
|
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;
|