truecourse 0.2.1 → 0.2.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 +33 -0
- package/cli.mjs +132 -42
- package/package.json +3 -1
- package/server.mjs +41029 -32184
package/README.md
CHANGED
|
@@ -178,6 +178,39 @@ All rules are visible in the **Rules** tab in the web UI. Custom rule generation
|
|
|
178
178
|
| Rust | Planned |
|
|
179
179
|
| PHP | Planned |
|
|
180
180
|
|
|
181
|
+
## Telemetry
|
|
182
|
+
|
|
183
|
+
TrueCourse collects anonymous usage data to help us understand adoption and improve the product. Telemetry is **enabled by default** and can be disabled at any time.
|
|
184
|
+
|
|
185
|
+
### What is collected
|
|
186
|
+
|
|
187
|
+
- Event type (`analyze` or `diff-check`)
|
|
188
|
+
- Tool version
|
|
189
|
+
- Languages detected (e.g., TypeScript, Python)
|
|
190
|
+
- File count range (bucketed: 1-50, 50-200, etc.)
|
|
191
|
+
- Service count
|
|
192
|
+
- Analysis duration range (bucketed)
|
|
193
|
+
- OS and architecture (e.g., `darwin-arm64`)
|
|
194
|
+
- Random anonymous session ID (not tied to user identity)
|
|
195
|
+
|
|
196
|
+
### What is NOT collected
|
|
197
|
+
|
|
198
|
+
- Source code, file paths, repo names, or git URLs
|
|
199
|
+
- Violation details, rule results, or LLM outputs
|
|
200
|
+
- IP addresses, user identity, or machine hostname
|
|
201
|
+
|
|
202
|
+
### Opt out
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npx truecourse telemetry disable # Disable telemetry
|
|
206
|
+
npx truecourse telemetry enable # Re-enable telemetry
|
|
207
|
+
npx truecourse telemetry status # Check current status
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Telemetry is automatically disabled in CI environments (`CI=true`) and can also be disabled by setting `TRUECOURSE_TELEMETRY=0`.
|
|
211
|
+
|
|
212
|
+
Data is sent to [PostHog](https://posthog.com) for aggregation.
|
|
213
|
+
|
|
181
214
|
## License
|
|
182
215
|
|
|
183
216
|
MIT
|
package/cli.mjs
CHANGED
|
@@ -972,8 +972,8 @@ var require_command = __commonJS({
|
|
|
972
972
|
"node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
973
973
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
974
974
|
var childProcess = __require("node:child_process");
|
|
975
|
-
var
|
|
976
|
-
var
|
|
975
|
+
var path10 = __require("node:path");
|
|
976
|
+
var fs9 = __require("node:fs");
|
|
977
977
|
var process2 = __require("node:process");
|
|
978
978
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
979
979
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1905,11 +1905,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1905
1905
|
let launchWithNode = false;
|
|
1906
1906
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1907
1907
|
function findFile(baseDir, baseName) {
|
|
1908
|
-
const localBin =
|
|
1909
|
-
if (
|
|
1910
|
-
if (sourceExt.includes(
|
|
1908
|
+
const localBin = path10.resolve(baseDir, baseName);
|
|
1909
|
+
if (fs9.existsSync(localBin)) return localBin;
|
|
1910
|
+
if (sourceExt.includes(path10.extname(baseName))) return void 0;
|
|
1911
1911
|
const foundExt = sourceExt.find(
|
|
1912
|
-
(ext) =>
|
|
1912
|
+
(ext) => fs9.existsSync(`${localBin}${ext}`)
|
|
1913
1913
|
);
|
|
1914
1914
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1915
1915
|
return void 0;
|
|
@@ -1921,21 +1921,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1921
1921
|
if (this._scriptPath) {
|
|
1922
1922
|
let resolvedScriptPath;
|
|
1923
1923
|
try {
|
|
1924
|
-
resolvedScriptPath =
|
|
1924
|
+
resolvedScriptPath = fs9.realpathSync(this._scriptPath);
|
|
1925
1925
|
} catch (err) {
|
|
1926
1926
|
resolvedScriptPath = this._scriptPath;
|
|
1927
1927
|
}
|
|
1928
|
-
executableDir =
|
|
1929
|
-
|
|
1928
|
+
executableDir = path10.resolve(
|
|
1929
|
+
path10.dirname(resolvedScriptPath),
|
|
1930
1930
|
executableDir
|
|
1931
1931
|
);
|
|
1932
1932
|
}
|
|
1933
1933
|
if (executableDir) {
|
|
1934
1934
|
let localFile = findFile(executableDir, executableFile);
|
|
1935
1935
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1936
|
-
const legacyName =
|
|
1936
|
+
const legacyName = path10.basename(
|
|
1937
1937
|
this._scriptPath,
|
|
1938
|
-
|
|
1938
|
+
path10.extname(this._scriptPath)
|
|
1939
1939
|
);
|
|
1940
1940
|
if (legacyName !== this._name) {
|
|
1941
1941
|
localFile = findFile(
|
|
@@ -1946,7 +1946,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1946
1946
|
}
|
|
1947
1947
|
executableFile = localFile || executableFile;
|
|
1948
1948
|
}
|
|
1949
|
-
launchWithNode = sourceExt.includes(
|
|
1949
|
+
launchWithNode = sourceExt.includes(path10.extname(executableFile));
|
|
1950
1950
|
let proc;
|
|
1951
1951
|
if (process2.platform !== "win32") {
|
|
1952
1952
|
if (launchWithNode) {
|
|
@@ -2786,7 +2786,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2786
2786
|
* @return {Command}
|
|
2787
2787
|
*/
|
|
2788
2788
|
nameFromFilename(filename) {
|
|
2789
|
-
this._name =
|
|
2789
|
+
this._name = path10.basename(filename, path10.extname(filename));
|
|
2790
2790
|
return this;
|
|
2791
2791
|
}
|
|
2792
2792
|
/**
|
|
@@ -2800,9 +2800,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2800
2800
|
* @param {string} [path]
|
|
2801
2801
|
* @return {(string|null|Command)}
|
|
2802
2802
|
*/
|
|
2803
|
-
executableDir(
|
|
2804
|
-
if (
|
|
2805
|
-
this._executableDir =
|
|
2803
|
+
executableDir(path11) {
|
|
2804
|
+
if (path11 === void 0) return this._executableDir;
|
|
2805
|
+
this._executableDir = path11;
|
|
2806
2806
|
return this;
|
|
2807
2807
|
}
|
|
2808
2808
|
/**
|
|
@@ -3766,7 +3766,7 @@ ${import_picocolors2.default.gray(m2)} ${s}
|
|
|
3766
3766
|
// node_modules/.pnpm/xmlhttprequest-ssl@2.1.2/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js
|
|
3767
3767
|
var require_XMLHttpRequest = __commonJS({
|
|
3768
3768
|
"node_modules/.pnpm/xmlhttprequest-ssl@2.1.2/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js"(exports, module) {
|
|
3769
|
-
var
|
|
3769
|
+
var fs9 = __require("fs");
|
|
3770
3770
|
var Url = __require("url");
|
|
3771
3771
|
var spawn3 = __require("child_process").spawn;
|
|
3772
3772
|
module.exports = XMLHttpRequest3;
|
|
@@ -3924,7 +3924,7 @@ var require_XMLHttpRequest = __commonJS({
|
|
|
3924
3924
|
throw new Error("XMLHttpRequest: Only GET method is supported");
|
|
3925
3925
|
}
|
|
3926
3926
|
if (settings.async) {
|
|
3927
|
-
|
|
3927
|
+
fs9.readFile(unescape(url2.pathname), function(error, data2) {
|
|
3928
3928
|
if (error) {
|
|
3929
3929
|
self.handleError(error, error.errno || -1);
|
|
3930
3930
|
} else {
|
|
@@ -3936,7 +3936,7 @@ var require_XMLHttpRequest = __commonJS({
|
|
|
3936
3936
|
});
|
|
3937
3937
|
} else {
|
|
3938
3938
|
try {
|
|
3939
|
-
this.response =
|
|
3939
|
+
this.response = fs9.readFileSync(unescape(url2.pathname));
|
|
3940
3940
|
this.responseText = this.response.toString("utf8");
|
|
3941
3941
|
this.status = 200;
|
|
3942
3942
|
setState(self.DONE);
|
|
@@ -4062,15 +4062,15 @@ var require_XMLHttpRequest = __commonJS({
|
|
|
4062
4062
|
} else {
|
|
4063
4063
|
var contentFile = ".node-xmlhttprequest-content-" + process.pid;
|
|
4064
4064
|
var syncFile = ".node-xmlhttprequest-sync-" + process.pid;
|
|
4065
|
-
|
|
4065
|
+
fs9.writeFileSync(syncFile, "", "utf8");
|
|
4066
4066
|
var execString = "var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http" + (ssl ? "s" : "") + ".request;var options = " + JSON.stringify(options) + ";var responseText = '';var responseData = Buffer.alloc(0);var req = doRequest(options, function(response) {response.on('data', function(chunk) { var data = Buffer.from(chunk); responseText += data.toString('utf8'); responseData = Buffer.concat([responseData, data]);});response.on('end', function() {fs.writeFileSync('" + contentFile + "', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText, data: responseData.toString('base64')}}), 'utf8');fs.unlinkSync('" + syncFile + "');});response.on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});}).on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});" + (data ? "req.write('" + JSON.stringify(data).slice(1, -1).replace(/'/g, "\\'") + "');" : "") + "req.end();";
|
|
4067
4067
|
var syncProc = spawn3(process.argv[0], ["-e", execString]);
|
|
4068
4068
|
var statusText;
|
|
4069
|
-
while (
|
|
4069
|
+
while (fs9.existsSync(syncFile)) {
|
|
4070
4070
|
}
|
|
4071
|
-
self.responseText =
|
|
4071
|
+
self.responseText = fs9.readFileSync(contentFile, "utf8");
|
|
4072
4072
|
syncProc.stdin.end();
|
|
4073
|
-
|
|
4073
|
+
fs9.unlinkSync(contentFile);
|
|
4074
4074
|
if (self.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) {
|
|
4075
4075
|
var errorObj = JSON.parse(self.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, ""));
|
|
4076
4076
|
self.handleError(errorObj, 503);
|
|
@@ -9762,12 +9762,12 @@ function parse2(str) {
|
|
|
9762
9762
|
uri.queryKey = queryKey(uri, uri["query"]);
|
|
9763
9763
|
return uri;
|
|
9764
9764
|
}
|
|
9765
|
-
function pathNames(obj,
|
|
9766
|
-
const regx = /\/{2,9}/g, names =
|
|
9767
|
-
if (
|
|
9765
|
+
function pathNames(obj, path10) {
|
|
9766
|
+
const regx = /\/{2,9}/g, names = path10.replace(regx, "/").split("/");
|
|
9767
|
+
if (path10.slice(0, 1) == "/" || path10.length === 0) {
|
|
9768
9768
|
names.splice(0, 1);
|
|
9769
9769
|
}
|
|
9770
|
-
if (
|
|
9770
|
+
if (path10.slice(-1) == "/") {
|
|
9771
9771
|
names.splice(names.length - 1, 1);
|
|
9772
9772
|
}
|
|
9773
9773
|
return names;
|
|
@@ -10441,7 +10441,7 @@ var init_esm_debug = __esm({
|
|
|
10441
10441
|
});
|
|
10442
10442
|
|
|
10443
10443
|
// node_modules/.pnpm/socket.io-client@4.8.3/node_modules/socket.io-client/build/esm-debug/url.js
|
|
10444
|
-
function url(uri,
|
|
10444
|
+
function url(uri, path10 = "", loc) {
|
|
10445
10445
|
let obj = uri;
|
|
10446
10446
|
loc = loc || typeof location !== "undefined" && location;
|
|
10447
10447
|
if (null == uri)
|
|
@@ -10475,7 +10475,7 @@ function url(uri, path9 = "", loc) {
|
|
|
10475
10475
|
obj.path = obj.path || "/";
|
|
10476
10476
|
const ipv6 = obj.host.indexOf(":") !== -1;
|
|
10477
10477
|
const host = ipv6 ? "[" + obj.host + "]" : obj.host;
|
|
10478
|
-
obj.id = obj.protocol + "://" + host + ":" + obj.port +
|
|
10478
|
+
obj.id = obj.protocol + "://" + host + ":" + obj.port + path10;
|
|
10479
10479
|
obj.href = obj.protocol + "://" + host + (loc && loc.port === obj.port ? "" : ":" + obj.port);
|
|
10480
10480
|
return obj;
|
|
10481
10481
|
}
|
|
@@ -12146,8 +12146,8 @@ function lookup(uri, opts) {
|
|
|
12146
12146
|
const parsed = url(uri, opts.path || "/socket.io");
|
|
12147
12147
|
const source = parsed.source;
|
|
12148
12148
|
const id = parsed.id;
|
|
12149
|
-
const
|
|
12150
|
-
const sameNamespace = cache[id] &&
|
|
12149
|
+
const path10 = parsed.path;
|
|
12150
|
+
const sameNamespace = cache[id] && path10 in cache[id]["nsps"];
|
|
12151
12151
|
const newConnection = opts.forceNew || opts["force new connection"] || false === opts.multiplex || sameNamespace;
|
|
12152
12152
|
let io;
|
|
12153
12153
|
if (newConnection) {
|
|
@@ -12683,10 +12683,16 @@ function startConsoleMode(openBrowser) {
|
|
|
12683
12683
|
process.execPath,
|
|
12684
12684
|
[serverPath],
|
|
12685
12685
|
{
|
|
12686
|
-
stdio: "
|
|
12686
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
12687
12687
|
env: { ...process.env }
|
|
12688
12688
|
}
|
|
12689
12689
|
);
|
|
12690
|
+
const forwardOutput = (data) => {
|
|
12691
|
+
process.stdout.write("\r\x1B[K");
|
|
12692
|
+
process.stderr.write(data);
|
|
12693
|
+
};
|
|
12694
|
+
serverProcess.stdout?.on("data", forwardOutput);
|
|
12695
|
+
serverProcess.stderr?.on("data", forwardOutput);
|
|
12690
12696
|
serverProcess.on("error", (error) => {
|
|
12691
12697
|
v2.error(`Failed to start server: ${error.message}`);
|
|
12692
12698
|
process.exit(1);
|
|
@@ -13364,9 +13370,9 @@ var {
|
|
|
13364
13370
|
init_dist2();
|
|
13365
13371
|
init_setup();
|
|
13366
13372
|
init_start();
|
|
13367
|
-
import
|
|
13368
|
-
import
|
|
13369
|
-
import
|
|
13373
|
+
import fs8 from "node:fs";
|
|
13374
|
+
import path9 from "node:path";
|
|
13375
|
+
import os7 from "node:os";
|
|
13370
13376
|
|
|
13371
13377
|
// tools/cli/src/commands/add.ts
|
|
13372
13378
|
init_dist2();
|
|
@@ -13415,9 +13421,73 @@ async function runAdd() {
|
|
|
13415
13421
|
// tools/cli/src/commands/analyze.ts
|
|
13416
13422
|
init_dist2();
|
|
13417
13423
|
init_helpers();
|
|
13424
|
+
|
|
13425
|
+
// tools/cli/src/telemetry.ts
|
|
13426
|
+
init_dist2();
|
|
13427
|
+
import fs7 from "node:fs";
|
|
13428
|
+
import path7 from "node:path";
|
|
13429
|
+
import os6 from "node:os";
|
|
13430
|
+
import crypto from "node:crypto";
|
|
13431
|
+
var DEFAULT_CONFIG2 = {
|
|
13432
|
+
enabled: true,
|
|
13433
|
+
anonymousId: "",
|
|
13434
|
+
noticeShown: false
|
|
13435
|
+
};
|
|
13436
|
+
function getTelemetryConfigPath() {
|
|
13437
|
+
return path7.join(os6.homedir(), ".truecourse", "telemetry.json");
|
|
13438
|
+
}
|
|
13439
|
+
function readTelemetryConfig() {
|
|
13440
|
+
const configPath = getTelemetryConfigPath();
|
|
13441
|
+
try {
|
|
13442
|
+
const raw = fs7.readFileSync(configPath, "utf-8");
|
|
13443
|
+
const parsed = JSON.parse(raw);
|
|
13444
|
+
const config = { ...DEFAULT_CONFIG2, ...parsed };
|
|
13445
|
+
if (!config.anonymousId) {
|
|
13446
|
+
config.anonymousId = crypto.randomUUID();
|
|
13447
|
+
writeTelemetryConfig(config);
|
|
13448
|
+
}
|
|
13449
|
+
return config;
|
|
13450
|
+
} catch {
|
|
13451
|
+
const config = {
|
|
13452
|
+
enabled: true,
|
|
13453
|
+
anonymousId: crypto.randomUUID(),
|
|
13454
|
+
noticeShown: false
|
|
13455
|
+
};
|
|
13456
|
+
writeTelemetryConfig(config);
|
|
13457
|
+
return config;
|
|
13458
|
+
}
|
|
13459
|
+
}
|
|
13460
|
+
function writeTelemetryConfig(partial) {
|
|
13461
|
+
const configPath = getTelemetryConfigPath();
|
|
13462
|
+
const dir = path7.dirname(configPath);
|
|
13463
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
13464
|
+
let current;
|
|
13465
|
+
try {
|
|
13466
|
+
const raw = fs7.readFileSync(configPath, "utf-8");
|
|
13467
|
+
current = { ...DEFAULT_CONFIG2, ...JSON.parse(raw) };
|
|
13468
|
+
} catch {
|
|
13469
|
+
current = { ...DEFAULT_CONFIG2 };
|
|
13470
|
+
}
|
|
13471
|
+
const merged = { ...current, ...partial };
|
|
13472
|
+
fs7.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
13473
|
+
}
|
|
13474
|
+
function showFirstRunNotice() {
|
|
13475
|
+
try {
|
|
13476
|
+
const config = readTelemetryConfig();
|
|
13477
|
+
if (!config.enabled || config.noticeShown) return;
|
|
13478
|
+
v2.info(
|
|
13479
|
+
"TrueCourse collects anonymous usage data to improve the product. Run `npx truecourse telemetry disable` to opt out."
|
|
13480
|
+
);
|
|
13481
|
+
writeTelemetryConfig({ noticeShown: true });
|
|
13482
|
+
} catch {
|
|
13483
|
+
}
|
|
13484
|
+
}
|
|
13485
|
+
|
|
13486
|
+
// tools/cli/src/commands/analyze.ts
|
|
13418
13487
|
var TIMEOUT_MS = 15 * 60 * 1e3;
|
|
13419
13488
|
async function runAnalyze({ noAutostart = false, codeReview = false, deterministicOnly = false } = {}) {
|
|
13420
13489
|
we("Analyzing repository");
|
|
13490
|
+
showFirstRunNotice();
|
|
13421
13491
|
if (noAutostart) {
|
|
13422
13492
|
const url2 = getServerUrl();
|
|
13423
13493
|
try {
|
|
@@ -13535,6 +13605,7 @@ async function runAnalyze({ noAutostart = false, codeReview = false, determinist
|
|
|
13535
13605
|
}
|
|
13536
13606
|
async function runAnalyzeDiff({ noAutostart = false } = {}) {
|
|
13537
13607
|
we("Running diff check");
|
|
13608
|
+
showFirstRunNotice();
|
|
13538
13609
|
if (noAutostart) {
|
|
13539
13610
|
const url2 = getServerUrl();
|
|
13540
13611
|
try {
|
|
@@ -13629,11 +13700,11 @@ init_dist2();
|
|
|
13629
13700
|
init_platform();
|
|
13630
13701
|
init_logs();
|
|
13631
13702
|
init_helpers();
|
|
13632
|
-
import
|
|
13703
|
+
import path8 from "node:path";
|
|
13633
13704
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
13634
|
-
var __dirname2 =
|
|
13705
|
+
var __dirname2 = path8.dirname(fileURLToPath3(import.meta.url));
|
|
13635
13706
|
function getServerPath2() {
|
|
13636
|
-
return
|
|
13707
|
+
return path8.join(__dirname2, "..", "server.mjs");
|
|
13637
13708
|
}
|
|
13638
13709
|
async function healthcheck2() {
|
|
13639
13710
|
const url2 = getServerUrl();
|
|
@@ -13788,7 +13859,7 @@ function registerServiceCommand(program3) {
|
|
|
13788
13859
|
init_helpers();
|
|
13789
13860
|
init_platform();
|
|
13790
13861
|
var program2 = new Command();
|
|
13791
|
-
program2.name("truecourse").version("0.2.
|
|
13862
|
+
program2.name("truecourse").version("0.2.2").description("TrueCourse CLI - Setup and manage your TrueCourse instance");
|
|
13792
13863
|
program2.command("setup").description("Run the setup wizard to configure TrueCourse").action(async () => {
|
|
13793
13864
|
await runSetup();
|
|
13794
13865
|
});
|
|
@@ -13834,10 +13905,29 @@ program2.command("stop").description("Stop the TrueCourse background service").a
|
|
|
13834
13905
|
v2.info("Press Ctrl+C in the terminal where TrueCourse is running.");
|
|
13835
13906
|
}
|
|
13836
13907
|
});
|
|
13908
|
+
var telemetryCmd = program2.command("telemetry").description("Manage anonymous usage telemetry");
|
|
13909
|
+
telemetryCmd.command("enable").description("Enable anonymous usage telemetry").action(() => {
|
|
13910
|
+
writeTelemetryConfig({ enabled: true });
|
|
13911
|
+
v2.success("Telemetry enabled. Thank you for helping improve TrueCourse!");
|
|
13912
|
+
});
|
|
13913
|
+
telemetryCmd.command("disable").description("Disable anonymous usage telemetry").action(() => {
|
|
13914
|
+
writeTelemetryConfig({ enabled: false });
|
|
13915
|
+
v2.success("Telemetry disabled. No data will be collected.");
|
|
13916
|
+
});
|
|
13917
|
+
telemetryCmd.command("status").description("Show current telemetry status").action(() => {
|
|
13918
|
+
const config = readTelemetryConfig();
|
|
13919
|
+
if (process.env.CI === "true") {
|
|
13920
|
+
v2.info("Telemetry is automatically disabled in CI environments.");
|
|
13921
|
+
} else if (config.enabled) {
|
|
13922
|
+
v2.info("Telemetry is enabled.");
|
|
13923
|
+
} else {
|
|
13924
|
+
v2.info("Telemetry is disabled.");
|
|
13925
|
+
}
|
|
13926
|
+
});
|
|
13837
13927
|
program2.action(async () => {
|
|
13838
|
-
const configDir =
|
|
13839
|
-
const envPath =
|
|
13840
|
-
const isFirstRun = !
|
|
13928
|
+
const configDir = path9.join(os7.homedir(), ".truecourse");
|
|
13929
|
+
const envPath = path9.join(configDir, ".env");
|
|
13930
|
+
const isFirstRun = !fs8.existsSync(envPath);
|
|
13841
13931
|
if (isFirstRun) {
|
|
13842
13932
|
await runSetup();
|
|
13843
13933
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "truecourse",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Visualize your codebase architecture as an interactive graph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
"dotenv": "^16.4.0",
|
|
16
16
|
"embedded-postgres": "18.3.0-beta.16",
|
|
17
17
|
"postgres": "^3.4.0",
|
|
18
|
+
"pyright": "^1.1.408",
|
|
18
19
|
"tree-sitter": "^0.25.0",
|
|
19
20
|
"tree-sitter-javascript": "^0.25.0",
|
|
21
|
+
"tree-sitter-python": "^0.25.0",
|
|
20
22
|
"tree-sitter-typescript": "^0.23.2"
|
|
21
23
|
},
|
|
22
24
|
"optionalDependencies": {
|