truecourse 0.5.2 → 0.5.3

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 (2) hide show
  1. package/cli.mjs +57 -37
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -4080,7 +4080,7 @@ __export(helpers_exports, {
4080
4080
  writeConfig: () => writeConfig
4081
4081
  });
4082
4082
  import { exec as exec2 } from "node:child_process";
4083
- import { cpSync, existsSync } from "node:fs";
4083
+ import { cpSync, existsSync, mkdirSync, readdirSync } from "node:fs";
4084
4084
  import fs3 from "node:fs";
4085
4085
  import os2 from "node:os";
4086
4086
  import path3 from "node:path";
@@ -4319,12 +4319,6 @@ function openInBrowser(url) {
4319
4319
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
4320
4320
  exec2(`${cmd} ${url}`);
4321
4321
  }
4322
- function skillDestPath(repoPath) {
4323
- return resolve(repoPath, ".claude", "skills", "truecourse");
4324
- }
4325
- function hasInstalledSkills(repoPath) {
4326
- return existsSync(skillDestPath(repoPath));
4327
- }
4328
4322
  function isInteractive() {
4329
4323
  return !!process.stdin.isTTY;
4330
4324
  }
@@ -4336,35 +4330,61 @@ Running non-interactively with no answer. ${flagGuidance}`
4336
4330
  );
4337
4331
  process.exit(1);
4338
4332
  }
4339
- function copySkillsInto(repoPath) {
4333
+ function resolveSkillsSrcDir() {
4340
4334
  const __dirname4 = dirname(fileURLToPath(import.meta.url));
4341
- const srcPath = resolve(__dirname4, "..", "..", "skills", "truecourse");
4342
- const distPath = resolve(__dirname4, "skills", "truecourse");
4343
- const skillsSrc = existsSync(srcPath) ? srcPath : distPath;
4344
- if (!existsSync(skillsSrc)) {
4335
+ const candidate = resolve(__dirname4, "skills", "truecourse");
4336
+ return existsSync(candidate) ? candidate : null;
4337
+ }
4338
+ function skillDestDir(repoPath) {
4339
+ return resolve(repoPath, ".claude", "skills", "truecourse");
4340
+ }
4341
+ function listSkillDirs(root) {
4342
+ if (!existsSync(root)) return [];
4343
+ return readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
4344
+ }
4345
+ function computeMissingSkills(repoPath) {
4346
+ const src = resolveSkillsSrcDir();
4347
+ if (!src) return [];
4348
+ const shipped = new Set(listSkillDirs(src));
4349
+ const installed = new Set(listSkillDirs(skillDestDir(repoPath)));
4350
+ return [...shipped].filter((name) => !installed.has(name));
4351
+ }
4352
+ function hasInstalledSkills(repoPath) {
4353
+ return computeMissingSkills(repoPath).length === 0;
4354
+ }
4355
+ function copySkills(repoPath, skillNames) {
4356
+ const src = resolveSkillsSrcDir();
4357
+ if (!src) {
4345
4358
  O2.warn("Skills directory not found in package \u2014 skipping.");
4346
4359
  return;
4347
4360
  }
4348
- const skillsDest = resolve(repoPath, ".claude", "skills");
4349
- cpSync(skillsSrc, skillsDest, { recursive: true });
4350
- O2.success("Installed Claude Code skills:");
4351
- O2.message(" - truecourse-analyze (run analysis)");
4352
- O2.message(" - truecourse-list (list violations)");
4353
- O2.message(" - truecourse-fix (apply fixes)");
4361
+ const destParent = skillDestDir(repoPath);
4362
+ mkdirSync(destParent, { recursive: true });
4363
+ for (const name of skillNames) {
4364
+ const skillSrc = resolve(src, name);
4365
+ const skillDest = resolve(destParent, name);
4366
+ if (existsSync(skillDest)) continue;
4367
+ cpSync(skillSrc, skillDest, { recursive: true });
4368
+ }
4369
+ O2.success(
4370
+ `Installed ${skillNames.length} Claude Code skill${skillNames.length === 1 ? "" : "s"}:`
4371
+ );
4372
+ for (const name of skillNames) O2.message(` - ${name}`);
4354
4373
  }
4355
4374
  async function promptInstallSkills(repoPath, { install } = {}) {
4356
- if (hasInstalledSkills(repoPath)) return;
4375
+ const missing = computeMissingSkills(repoPath);
4376
+ if (missing.length === 0) return;
4357
4377
  if (install === true) {
4358
- copySkillsInto(repoPath);
4378
+ copySkills(repoPath, missing);
4359
4379
  return;
4360
4380
  }
4361
4381
  if (install === false) return;
4362
4382
  if (!isInteractive()) return;
4363
- const answer = await ot2({
4364
- message: "Would you like to install Claude Code skills?"
4365
- });
4383
+ const isUpgrade = existsSync(skillDestDir(repoPath));
4384
+ const message = isUpgrade ? `New Claude Code skill${missing.length === 1 ? "" : "s"} available: ${missing.join(", ")}. Install?` : "Would you like to install Claude Code skills?";
4385
+ const answer = await ot2({ message });
4366
4386
  if (q(answer) || !answer) return;
4367
- copySkillsInto(repoPath);
4387
+ copySkills(repoPath, missing);
4368
4388
  }
4369
4389
  var DEFAULT_PORT, DEFAULT_CONFIG;
4370
4390
  var init_helpers = __esm({
@@ -10563,7 +10583,7 @@ var init_language_config = __esm({
10563
10583
  });
10564
10584
 
10565
10585
  // packages/analyzer/dist/file-discovery.js
10566
- import { existsSync as existsSync2, readFileSync, readdirSync, statSync } from "fs";
10586
+ import { existsSync as existsSync2, readFileSync, readdirSync as readdirSync2, statSync } from "fs";
10567
10587
  import { join, relative, resolve as resolve2 } from "path";
10568
10588
  function findAllGitignores(startDir) {
10569
10589
  const gitignores = [];
@@ -10606,7 +10626,7 @@ function discoverFiles(dir) {
10606
10626
  const { ig, rootDir } = loadIgnorePatterns(dir);
10607
10627
  function traverse(currentPath) {
10608
10628
  try {
10609
- const entries = readdirSync(currentPath).sort();
10629
+ const entries = readdirSync2(currentPath).sort();
10610
10630
  for (const entry of entries) {
10611
10631
  const fullPath = join(currentPath, entry);
10612
10632
  const relativePath = relative(rootDir, fullPath);
@@ -10894,7 +10914,7 @@ var init_service_patterns = __esm({
10894
10914
  // packages/analyzer/dist/ts-compiler.js
10895
10915
  import * as ts from "typescript";
10896
10916
  import { dirname as dirname2, join as join2 } from "path";
10897
- import { existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
10917
+ import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
10898
10918
  function buildScopedCompilerOptions(rootPath) {
10899
10919
  const result = [];
10900
10920
  const candidates = [join2(rootPath, "tsconfig.json")];
@@ -10903,7 +10923,7 @@ function buildScopedCompilerOptions(rootPath) {
10903
10923
  if (!existsSync3(dirPath) || !statSync2(dirPath).isDirectory())
10904
10924
  continue;
10905
10925
  try {
10906
- for (const entry of readdirSync2(dirPath).sort()) {
10926
+ for (const entry of readdirSync3(dirPath).sort()) {
10907
10927
  candidates.push(join2(dirPath, entry, "tsconfig.json"));
10908
10928
  }
10909
10929
  } catch {
@@ -13533,7 +13553,7 @@ var init_registry2 = __esm({
13533
13553
 
13534
13554
  // packages/analyzer/dist/dependency-graph.js
13535
13555
  import { resolve as resolve4, dirname as dirname4, join as join3 } from "path";
13536
- import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync3, realpathSync, statSync as statSync3 } from "fs";
13556
+ import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync4, realpathSync, statSync as statSync3 } from "fs";
13537
13557
  function resolveRelativeFallback(importSource, containingFile, analyzedFiles, extensions, indexFiles) {
13538
13558
  const fromDir = dirname4(containingFile);
13539
13559
  const basePath = resolve4(fromDir, importSource);
@@ -13561,7 +13581,7 @@ function buildWorkspacePackageMap(rootPath) {
13561
13581
  if (!existsSync4(dirPath) || !statSync3(dirPath).isDirectory())
13562
13582
  continue;
13563
13583
  try {
13564
- for (const entry of readdirSync3(dirPath).sort()) {
13584
+ for (const entry of readdirSync4(dirPath).sort()) {
13565
13585
  const pkgDir = join3(dirPath, entry);
13566
13586
  const pkgJsonPath = join3(pkgDir, "package.json");
13567
13587
  if (!existsSync4(pkgJsonPath))
@@ -16249,7 +16269,7 @@ var init_registry3 = __esm({
16249
16269
  });
16250
16270
 
16251
16271
  // packages/analyzer/dist/service-detector.js
16252
- import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
16272
+ import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
16253
16273
  import { join as join6, basename, dirname as dirname5 } from "path";
16254
16274
  function detectServices(rootPath, allFiles) {
16255
16275
  const monorepoServices = detectMonorepoServices(rootPath, allFiles);
@@ -16294,7 +16314,7 @@ function detectMonorepoServices(rootPath, allFiles) {
16294
16314
  if (!existsSync7(dirPath))
16295
16315
  continue;
16296
16316
  try {
16297
- const entries = readdirSync4(dirPath).sort();
16317
+ const entries = readdirSync5(dirPath).sort();
16298
16318
  for (const entry of entries) {
16299
16319
  const servicePath = join6(dirPath, entry);
16300
16320
  const stats = statSync4(servicePath);
@@ -17050,7 +17070,7 @@ var init_registry4 = __esm({
17050
17070
  });
17051
17071
 
17052
17072
  // packages/analyzer/dist/database-detector.js
17053
- import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync5 } from "fs";
17073
+ import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync6 } from "fs";
17054
17074
  import { join as join7, resolve as resolve5 } from "path";
17055
17075
  function detectDatabases(rootPath, analyses, services) {
17056
17076
  const detections = [];
@@ -17219,7 +17239,7 @@ function parseDockerCompose(rootPath) {
17219
17239
  function findFiles(dir, fileName, ignoreDirs) {
17220
17240
  const results = [];
17221
17241
  try {
17222
- const entries = readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
17242
+ const entries = readdirSync6(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
17223
17243
  for (const entry of entries) {
17224
17244
  if (ignoreDirs.includes(entry.name))
17225
17245
  continue;
@@ -123658,7 +123678,7 @@ var init_schemas2 = __esm({
123658
123678
 
123659
123679
  // apps/server/dist/services/llm/cli-provider.js
123660
123680
  import { spawn as spawn3 } from "node:child_process";
123661
- import { mkdirSync, writeFileSync } from "node:fs";
123681
+ import { mkdirSync as mkdirSync2, writeFileSync } from "node:fs";
123662
123682
  import { join as join8 } from "node:path";
123663
123683
  import { tmpdir } from "node:os";
123664
123684
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -123721,7 +123741,7 @@ var init_cli_provider = __esm({
123721
123741
  constructor() {
123722
123742
  if (process.env.TRUECOURSE_CLI_DEBUG) {
123723
123743
  this.debugDir = join8(tmpdir(), "truecourse-cli-debug");
123724
- mkdirSync(this.debugDir, { recursive: true });
123744
+ mkdirSync2(this.debugDir, { recursive: true });
123725
123745
  log.info(`[CLI] Debug output: ${this.debugDir}`);
123726
123746
  }
123727
123747
  }
@@ -130710,7 +130730,7 @@ async function runHooksRun() {
130710
130730
 
130711
130731
  // tools/cli/src/index.ts
130712
130732
  var program2 = new Command();
130713
- program2.name("truecourse").version("0.5.2").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
130733
+ program2.name("truecourse").version("0.5.3").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
130714
130734
  var dashboardCmd = program2.command("dashboard").description("Start the TrueCourse dashboard and open it in your browser").option("--reconfigure", "Re-prompt for console vs background service mode").option("--service", "Run as a background service (skips mode prompt)").option("--console", "Run in this terminal (skips mode prompt)").action(async (options) => {
130715
130735
  if (options.service && options.console) {
130716
130736
  console.error("error: --service and --console are mutually exclusive");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "truecourse",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Visualize your codebase architecture as an interactive graph",
5
5
  "type": "module",
6
6
  "bin": {