@lakindu_perera/toren 1.0.8 → 1.0.9

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 (64) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cli/toren.d.ts +24 -0
  3. package/dist/cli/toren.js +254 -0
  4. package/dist/cli/toren.js.map +1 -0
  5. package/dist/detectors/config-detector.d.ts +3 -0
  6. package/dist/detectors/config-detector.js +58 -0
  7. package/dist/detectors/config-detector.js.map +1 -0
  8. package/dist/detectors/health-detector.d.ts +12 -0
  9. package/dist/detectors/health-detector.js +53 -0
  10. package/dist/detectors/health-detector.js.map +1 -0
  11. package/dist/detectors/important-files-detector.d.ts +51 -0
  12. package/dist/detectors/important-files-detector.js +455 -0
  13. package/dist/detectors/important-files-detector.js.map +1 -0
  14. package/dist/detectors/package-manager-detector.d.ts +7 -0
  15. package/dist/detectors/package-manager-detector.js +35 -0
  16. package/dist/detectors/package-manager-detector.js.map +1 -0
  17. package/dist/detectors/project-info-detector.d.ts +13 -0
  18. package/dist/detectors/project-info-detector.js +97 -0
  19. package/dist/detectors/project-info-detector.js.map +1 -0
  20. package/dist/detectors/script-detector.d.ts +42 -0
  21. package/dist/detectors/script-detector.js +199 -0
  22. package/dist/detectors/script-detector.js.map +1 -0
  23. package/dist/focused-output.d.ts +27 -0
  24. package/dist/focused-output.js +201 -0
  25. package/dist/focused-output.js.map +1 -0
  26. package/dist/lifecycle.d.ts +2 -0
  27. package/dist/lifecycle.js +114 -0
  28. package/dist/lifecycle.js.map +1 -0
  29. package/dist/renderers/console-renderer.d.ts +19 -0
  30. package/dist/renderers/console-renderer.js +361 -0
  31. package/dist/renderers/console-renderer.js.map +1 -0
  32. package/dist/renderers/html-renderer.d.ts +14 -0
  33. package/{src → dist}/renderers/html-renderer.js +181 -241
  34. package/dist/renderers/html-renderer.js.map +1 -0
  35. package/dist/renderers/index.d.ts +6 -0
  36. package/dist/renderers/index.js +12 -0
  37. package/dist/renderers/index.js.map +1 -0
  38. package/dist/renderers/json-renderer.d.ts +10 -0
  39. package/dist/renderers/json-renderer.js +127 -0
  40. package/dist/renderers/json-renderer.js.map +1 -0
  41. package/dist/renderers/markdown-renderer.d.ts +13 -0
  42. package/dist/renderers/markdown-renderer.js +360 -0
  43. package/dist/renderers/markdown-renderer.js.map +1 -0
  44. package/dist/scanner/scan.d.ts +2 -0
  45. package/dist/scanner/scan.js +573 -0
  46. package/dist/scanner/scan.js.map +1 -0
  47. package/dist/types/index.d.ts +85 -0
  48. package/dist/types/index.js +2 -0
  49. package/dist/types/index.js.map +1 -0
  50. package/package.json +11 -6
  51. package/bin/toren.js +0 -311
  52. package/src/detectors/config-detector.js +0 -81
  53. package/src/detectors/health-detector.js +0 -72
  54. package/src/detectors/important-files-detector.js +0 -515
  55. package/src/detectors/package-manager-detector.js +0 -112
  56. package/src/detectors/project-info-detector.js +0 -89
  57. package/src/detectors/script-detector.js +0 -248
  58. package/src/focused-output.js +0 -216
  59. package/src/lifecycle.js +0 -124
  60. package/src/renderers/console-renderer.js +0 -399
  61. package/src/renderers/index.js +0 -41
  62. package/src/renderers/json-renderer.js +0 -168
  63. package/src/renderers/markdown-renderer.js +0 -397
  64. package/src/scanner/scan.js +0 -554
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview Toren — Script Detector with Intelligence Layer
3
+ *
4
+ * Reads package.json scripts and enriches each entry with:
5
+ * - category — functional grouping (development, build, testing, etc.)
6
+ * - description — human-readable purpose string
7
+ * - usage — ready-to-run command string for the detected package manager
8
+ *
9
+ * Design contract:
10
+ * - Backward compatible: name and command are always present and unchanged.
11
+ * - category and description are null when no deterministic match exists.
12
+ * - usage is always a string — derived from packageManager or falls back to
13
+ * "npm run <name>" when packageManager is null.
14
+ * - Descriptions are never fabricated. Only canonical mappings and known
15
+ * command-keyword inferences are used.
16
+ * - Deterministic: same input always produces the same output.
17
+ * - Graceful: malformed or missing package.json returns an empty array.
18
+ *
19
+ * @module detectors/script-detector
20
+ */
21
+ /**
22
+ * @typedef {Object} ScriptItem
23
+ * @property {string} name - Script name as declared in package.json
24
+ * @property {string} command - Raw script command string
25
+ * @property {string|null} category - Functional category, or null when unknown
26
+ * @property {string|null} description - Human-readable purpose, or null when unknown
27
+ * @property {string} usage - Ready-to-run invocation string
28
+ */
29
+ /**
30
+ * Detect and enrich npm/package scripts from package.json.
31
+ *
32
+ * The `packageManager` parameter is optional for backward compatibility.
33
+ * When omitted (or null), usage strings fall back to `npm run <name>`.
34
+ *
35
+ * @param {string} rootPath - Absolute path of the scanned root
36
+ * @param {string|null} [packageManager=null] - Detected package manager name
37
+ * @returns {{ scripts: ScriptItem[] }}
38
+ */
39
+ import type { ScriptInfo, PackageManager } from "../types/index.js";
40
+ export declare function detectScripts(rootPath: string, packageManager?: PackageManager | null): {
41
+ scripts: ScriptInfo[];
42
+ };
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @fileoverview Toren — Script Detector with Intelligence Layer
3
+ *
4
+ * Reads package.json scripts and enriches each entry with:
5
+ * - category — functional grouping (development, build, testing, etc.)
6
+ * - description — human-readable purpose string
7
+ * - usage — ready-to-run command string for the detected package manager
8
+ *
9
+ * Design contract:
10
+ * - Backward compatible: name and command are always present and unchanged.
11
+ * - category and description are null when no deterministic match exists.
12
+ * - usage is always a string — derived from packageManager or falls back to
13
+ * "npm run <name>" when packageManager is null.
14
+ * - Descriptions are never fabricated. Only canonical mappings and known
15
+ * command-keyword inferences are used.
16
+ * - Deterministic: same input always produces the same output.
17
+ * - Graceful: malformed or missing package.json returns an empty array.
18
+ *
19
+ * @module detectors/script-detector
20
+ */
21
+ import fs from 'node:fs';
22
+ import path from 'node:path';
23
+ // ---------------------------------------------------------------------------
24
+ // Description and category tables — keyed by exact script name (lowercase)
25
+ // ---------------------------------------------------------------------------
26
+ /**
27
+ * Maps a known script name to its canonical human-readable description.
28
+ * @type {Map<string, string>}
29
+ */
30
+ const NAME_DESCRIPTIONS = new Map([
31
+ ['dev', 'Start the development server'],
32
+ ['develop', 'Start the development server'],
33
+ ['start', 'Start the application'],
34
+ ['serve', 'Serve the application'],
35
+ ['preview', 'Preview the production build'],
36
+ ['build', 'Create a production build'],
37
+ ['test', 'Run the test suite'],
38
+ ['test:watch', 'Run tests in watch mode'],
39
+ ['test:e2e', 'Run end-to-end tests'],
40
+ ['lint', 'Run code-quality checks'],
41
+ ['lint:fix', 'Run code-quality checks and fix supported issues'],
42
+ ['format', 'Format the codebase'],
43
+ ['typecheck', 'Run static type checks'],
44
+ ['check', 'Run project checks'],
45
+ ['clean', 'Remove generated build artifacts'],
46
+ ['generate', 'Generate project files or code'],
47
+ ['migrate', 'Run database migrations'],
48
+ ['seed', 'Seed the database'],
49
+ ['deploy', 'Deploy the application'],
50
+ ]);
51
+ /**
52
+ * Maps a known script name to its functional category.
53
+ * @type {Map<string, string>}
54
+ */
55
+ const NAME_CATEGORIES = new Map([
56
+ ['dev', 'development'],
57
+ ['develop', 'development'],
58
+ ['start', 'development'],
59
+ ['serve', 'development'],
60
+ ['preview', 'development'],
61
+ ['build', 'build'],
62
+ ['test', 'testing'],
63
+ ['test:watch', 'testing'],
64
+ ['test:e2e', 'testing'],
65
+ ['lint', 'quality'],
66
+ ['lint:fix', 'quality'],
67
+ ['format', 'quality'],
68
+ ['typecheck', 'quality'],
69
+ ['check', 'quality'],
70
+ ['clean', 'utility'],
71
+ ['generate', 'utility'],
72
+ ['migrate', 'database'],
73
+ ['seed', 'database'],
74
+ ['deploy', 'deployment'],
75
+ ]);
76
+ // ---------------------------------------------------------------------------
77
+ // Command-keyword inference — ordered most-specific first
78
+ // ---------------------------------------------------------------------------
79
+ /**
80
+ * Ordered list of command-keyword → { description, category } inferences.
81
+ * Evaluated only when a script name has no entry in NAME_DESCRIPTIONS.
82
+ * More specific patterns (e.g. "playwright test") must appear before broader
83
+ * ones (e.g. "jest") to prevent false matches.
84
+ *
85
+ * @type {Array<{ keyword: string, description: string, category: string }>}
86
+ */
87
+ const COMMAND_INFERENCE = [
88
+ { keyword: 'playwright test', description: 'Run end-to-end tests', category: 'testing' },
89
+ { keyword: 'cypress run', description: 'Run end-to-end tests', category: 'testing' },
90
+ { keyword: 'vitest', description: 'Run the test suite', category: 'testing' },
91
+ { keyword: 'jest', description: 'Run the test suite', category: 'testing' },
92
+ { keyword: 'tsc --noEmit', description: 'Run static type checks', category: 'quality' },
93
+ { keyword: 'eslint', description: 'Run code-quality checks', category: 'quality' },
94
+ { keyword: 'prettier', description: 'Format the codebase', category: 'quality' },
95
+ ];
96
+ // ---------------------------------------------------------------------------
97
+ // Usage builder
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Script names that npm treats as built-in lifecycle commands.
101
+ * These do NOT need the "run" subcommand: `npm test`, `npm start`, etc.
102
+ * @type {Set<string>}
103
+ */
104
+ const NPM_LIFECYCLE = new Set(['test', 'start', 'stop', 'restart']);
105
+ /**
106
+ * Script names that bun exposes as direct subcommands (no "run" needed).
107
+ * @type {Set<string>}
108
+ */
109
+ const BUN_LIFECYCLE = new Set(['test', 'start']);
110
+ /**
111
+ * Build the ready-to-run usage string for a script.
112
+ *
113
+ * Rules:
114
+ * npm: lifecycle commands (test, start…) → `npm <name>`
115
+ * all others → `npm run <name>`
116
+ * pnpm: all scripts → `pnpm <name>` (pnpm forwards directly)
117
+ * yarn: all scripts → `yarn <name>`
118
+ * bun: lifecycle commands (test, start) → `bun <name>`
119
+ * all others → `bun run <name>`
120
+ * null: conservative fallback → `npm run <name>` (always valid)
121
+ *
122
+ * @param {string} name - Script name
123
+ * @param {string|null} packageManager - Detected package manager or null
124
+ * @returns {string}
125
+ */
126
+ function buildUsage(name, packageManager) {
127
+ switch (packageManager) {
128
+ case 'npm':
129
+ return NPM_LIFECYCLE.has(name) ? `npm ${name}` : `npm run ${name}`;
130
+ case 'pnpm':
131
+ // pnpm forwards all script names without requiring the 'run' sub-command.
132
+ return `pnpm ${name}`;
133
+ case 'yarn':
134
+ // yarn similarly runs scripts directly without 'run'.
135
+ return `yarn ${name}`;
136
+ case 'bun':
137
+ return BUN_LIFECYCLE.has(name) ? `bun ${name}` : `bun run ${name}`;
138
+ default:
139
+ // null or unknown — conservative: `npm run <name>` is always valid even
140
+ // for lifecycle names, so we keep it unconditionally safe.
141
+ return `npm run ${name}`;
142
+ }
143
+ }
144
+ // ---------------------------------------------------------------------------
145
+ // Description + category resolver
146
+ // ---------------------------------------------------------------------------
147
+ /**
148
+ * Resolve description and category for a single script entry.
149
+ * Priority: exact name match → command-keyword inference → null.
150
+ *
151
+ * @param {string} name
152
+ * @param {string} command
153
+ * @returns {{ description: string|null, category: string|null }}
154
+ */
155
+ function resolveIntelligence(name, command) {
156
+ // 1. Exact name match (canonical mapping — highest confidence).
157
+ const nameDescription = NAME_DESCRIPTIONS.get(name) ?? null;
158
+ const nameCategory = NAME_CATEGORIES.get(name) ?? null;
159
+ if (nameDescription !== null || nameCategory !== null) {
160
+ return { description: nameDescription, category: nameCategory };
161
+ }
162
+ // 2. Command-keyword inference (fallback — only for unknown names).
163
+ for (const { keyword, description, category } of COMMAND_INFERENCE) {
164
+ if (command.includes(keyword)) {
165
+ return { description, category };
166
+ }
167
+ }
168
+ // 3. Unknown — do not fabricate.
169
+ return { description: null, category: null };
170
+ }
171
+ export function detectScripts(rootPath, packageManager = null) {
172
+ const scripts = [];
173
+ const pkgPath = path.join(rootPath, 'package.json');
174
+ try {
175
+ if (fs.existsSync(pkgPath)) {
176
+ const content = fs.readFileSync(pkgPath, 'utf8');
177
+ const pkg = JSON.parse(content);
178
+ if (pkg.scripts && typeof pkg.scripts === 'object') {
179
+ for (const [name, command] of Object.entries(pkg.scripts)) {
180
+ if (typeof command !== 'string')
181
+ continue;
182
+ const { description, category } = resolveIntelligence(name, command);
183
+ scripts.push({
184
+ name,
185
+ command,
186
+ category,
187
+ description,
188
+ usage: buildUsage(name, packageManager),
189
+ });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ catch {
195
+ // Return empty scripts on malformed or unreadable package.json
196
+ }
197
+ return { scripts };
198
+ }
199
+ //# sourceMappingURL=script-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-detector.js","sourceRoot":"","sources":["../../src/detectors/script-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ScanResult } from "./types/index.js";
2
+ export declare const FOCUSED_FLAGS: string[];
3
+ /**
4
+ * Validates focused flags in the provided arguments.
5
+ *
6
+ * @param {string[]} args Process arguments
7
+ * @returns {{ error: boolean, message?: string, mode?: string|null }}
8
+ */
9
+ type FocusedModeResult = {
10
+ error: true;
11
+ title: string;
12
+ message: string;
13
+ detailLabel: string;
14
+ detailValue: string;
15
+ } | {
16
+ error: false;
17
+ mode: string | null;
18
+ };
19
+ export declare function getFocusedModeInfo(args: string[]): FocusedModeResult;
20
+ /**
21
+ * Renders the scan result based on the active focused mode.
22
+ *
23
+ * @param {string} mode Active focused mode flag
24
+ * @param {import('./scanner/scan.js').ScanResult} result
25
+ */
26
+ export declare function renderFocusedMode(mode: string, result: ScanResult): void;
27
+ export {};
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @fileoverview Toren — Focused Output Mode Handler
3
+ *
4
+ * Handles the six focused output flags:
5
+ * --project-type --frameworks --entry-points
6
+ * --structure --configs --scripts
7
+ *
8
+ * Design contract:
9
+ * - Each flag renders exactly one section to stdout using the console visual
10
+ * style (ANSI colours, section header + divider).
11
+ * - Empty-state messages are canonical strings declared in EMPTY below.
12
+ * They must end with a period and stay in sync with console-renderer.js.
13
+ * - No business logic. All data comes from the ScanResult passed in.
14
+ * - Stateless: renderFocusedMode() may be called multiple times safely.
15
+ */
16
+ import { renderStructure } from './renderers/console-renderer.js';
17
+ // ---------------------------------------------------------------------------
18
+ // Canonical empty-state messages
19
+ // Keep these in sync with the equivalent strings in console-renderer.js.
20
+ // ---------------------------------------------------------------------------
21
+ const EMPTY = {
22
+ frameworks: 'No frameworks detected.',
23
+ entryPoints: 'No entry points detected.',
24
+ configs: 'No configuration files detected.',
25
+ scripts: 'No package scripts detected.',
26
+ importantFiles: 'No important files detected.',
27
+ health: 'No project health observations available.',
28
+ };
29
+ export const FOCUSED_FLAGS = [
30
+ '--project-type',
31
+ '--frameworks',
32
+ '--entry-points',
33
+ '--structure',
34
+ '--configs',
35
+ '--scripts',
36
+ '--summary',
37
+ '--important-files',
38
+ '--health'
39
+ ];
40
+ export function getFocusedModeInfo(args) {
41
+ const activeFlags = FOCUSED_FLAGS.filter(flag => args.includes(flag));
42
+ if (activeFlags.length > 1) {
43
+ return {
44
+ error: true,
45
+ title: 'Conflicting options',
46
+ message: 'Focused output flags are mutually exclusive.',
47
+ detailLabel: 'Provided flags',
48
+ detailValue: activeFlags.join(', ')
49
+ };
50
+ }
51
+ return {
52
+ error: false,
53
+ mode: activeFlags[0] || null
54
+ };
55
+ }
56
+ /**
57
+ * Print a bold-white section title followed by a dim matched-length divider
58
+ * and a blank line — same visual pattern as console-renderer.js's section().
59
+ *
60
+ * @param {string} title
61
+ */
62
+ function printSectionHeader(title) {
63
+ console.log(`\x1b[1m\x1b[97m${title}\x1b[0m`);
64
+ console.log(`\x1b[2m${'─'.repeat(title.length)}\x1b[0m`);
65
+ console.log('');
66
+ }
67
+ /**
68
+ * Print a focused section: header, then items or an empty-state message.
69
+ *
70
+ * @param {string} title - Section heading
71
+ * @param {string[]} items - Pre-formatted lines to print
72
+ * @param {string} emptyMsg - Canonical empty-state message (ends with '.')
73
+ */
74
+ function section(title, items, emptyMsg) {
75
+ printSectionHeader(title);
76
+ if (!items || items.length === 0) {
77
+ console.log(`\x1b[2m${emptyMsg}\x1b[0m`);
78
+ }
79
+ else {
80
+ for (const item of items) {
81
+ console.log(item);
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Renders the scan result based on the active focused mode.
87
+ *
88
+ * @param {string} mode Active focused mode flag
89
+ * @param {import('./scanner/scan.js').ScanResult} result
90
+ */
91
+ export function renderFocusedMode(mode, result) {
92
+ switch (mode) {
93
+ case '--project-type': {
94
+ // projectType is always a string; 'Unknown' when undetected.
95
+ section('Project Type', [result.projectType], 'Unknown');
96
+ break;
97
+ }
98
+ case '--frameworks': {
99
+ const frameworks = (!result.projectType || result.projectType === 'Unknown')
100
+ ? []
101
+ : [result.projectType];
102
+ section('Frameworks', frameworks, EMPTY.frameworks);
103
+ break;
104
+ }
105
+ case '--entry-points': {
106
+ section('Entry Points', result.entryPoints || [], EMPTY.entryPoints);
107
+ break;
108
+ }
109
+ case '--structure': {
110
+ renderStructure(result);
111
+ break;
112
+ }
113
+ case '--configs': {
114
+ section('Configuration Files', result.configs || [], EMPTY.configs);
115
+ break;
116
+ }
117
+ case '--scripts': {
118
+ const scriptsList = [];
119
+ if (result.scripts && result.scripts.length > 0) {
120
+ for (const s of result.scripts) {
121
+ const usage = s.usage || `npm run ${s.name}`;
122
+ scriptsList.push(`\x1b[97m${usage}\x1b[0m`);
123
+ if (s.description) {
124
+ scriptsList.push(` \x1b[2m${s.description}\x1b[0m\n`);
125
+ }
126
+ else {
127
+ scriptsList.push(` \x1b[2m${s.command}\x1b[0m\n`);
128
+ }
129
+ }
130
+ }
131
+ // Remove trailing newline from last element if it exists
132
+ if (scriptsList.length > 0) {
133
+ scriptsList[scriptsList.length - 1] = scriptsList[scriptsList.length - 1].replace(/\n$/, '');
134
+ }
135
+ section('Package Scripts', scriptsList, EMPTY.scripts);
136
+ break;
137
+ }
138
+ case '--summary': {
139
+ const p = result.projectInfo || {};
140
+ const lines = [
141
+ `Name ${p.name || 'Unknown'}`,
142
+ `Type ${result.projectType || 'Unknown'}`,
143
+ ];
144
+ if (p.runtime)
145
+ lines.push(`Runtime ${p.runtime}`);
146
+ if (p.language)
147
+ lines.push(`Language ${p.language}`);
148
+ if (p.framework)
149
+ lines.push(`Framework ${p.framework}`);
150
+ if (p.architecture)
151
+ lines.push(`Architecture ${p.architecture}`);
152
+ if (result.packageManager)
153
+ lines.push(`Package Manager ${result.packageManager}`);
154
+ if (p.entryPoint)
155
+ lines.push(`Entry Point ${p.entryPoint}`);
156
+ if (p.sourceDirectory)
157
+ lines.push(`Source Directory ${p.sourceDirectory}`);
158
+ lines.push(`Files ${result.flatFiles ? result.flatFiles.length : 0}`);
159
+ lines.push(`Folders ${result.totalFolders || 0}`);
160
+ section('Project Summary', lines, 'No summary available.');
161
+ break;
162
+ }
163
+ case '--important-files': {
164
+ const items = [];
165
+ if (result.importantFiles && result.importantFiles.length > 0) {
166
+ const top10 = result.importantFiles.slice(0, 10);
167
+ top10.forEach((f, idx) => {
168
+ items.push(`${idx + 1}. \x1b[97m${f.path}\x1b[0m`);
169
+ items.push(` \x1b[2m${f.reason}\x1b[0m\n`);
170
+ });
171
+ // Remove trailing newline
172
+ if (items.length > 0) {
173
+ items[items.length - 1] = items[items.length - 1].replace(/\n$/, '');
174
+ }
175
+ }
176
+ section('Important Files', items, EMPTY.importantFiles);
177
+ break;
178
+ }
179
+ case '--health': {
180
+ const items = [];
181
+ if (result.health && result.health.length > 0) {
182
+ for (const h of result.health) {
183
+ let icon = 'ℹ';
184
+ if (h.status === 'pass')
185
+ icon = '✓';
186
+ else if (h.status === 'warning')
187
+ icon = '⚠';
188
+ let color = '\x1b[97m';
189
+ if (h.status === 'pass')
190
+ color = '\x1b[32m';
191
+ else if (h.status === 'warning')
192
+ color = '\x1b[33m';
193
+ items.push(`${color}${icon}\x1b[0m ${h.message}`);
194
+ }
195
+ }
196
+ section('Project Health', items, EMPTY.health);
197
+ break;
198
+ }
199
+ }
200
+ }
201
+ //# sourceMappingURL=focused-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focused-output.js","sourceRoot":"","sources":["../src/focused-output.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,8EAA8E;AAC9E,iCAAiC;AACjC,yEAAyE;AACzE,8EAA8E;AAE9E,MAAM,KAAK,GAAG;IACZ,UAAU,EAAM,yBAAyB;IACzC,WAAW,EAAK,2BAA2B;IAC3C,OAAO,EAAS,kCAAkC;IAClD,OAAO,EAAS,8BAA8B;IAC9C,cAAc,EAAE,8BAA8B;IAC9C,MAAM,EAAU,2CAA2C;CAC5D,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,aAAa;IACb,WAAW;IACX,WAAW;IACX,WAAW;IACX,mBAAmB;IACnB,UAAU;CACX,CAAC;AAYF,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,qBAAqB;YAC5B,OAAO,EAAE,8CAA8C;YACvD,WAAW,EAAE,gBAAgB;YAC7B,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;SACpC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI;KAC7B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,KAAa,EAAE,KAAe,EAAE,QAAgB;IAC/D,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAE1B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,SAAS,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,MAAkB;IAChE,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,gBAAgB,EAAE,CAAC;YACtB,6DAA6D;YAC7D,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,CAAC;YACzD,MAAM;QACR,CAAC;QAED,KAAK,cAAc,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC;gBAC1E,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACzB,OAAO,CAAC,YAAY,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YACpD,MAAM;QACR,CAAC;QAED,KAAK,gBAAgB,EAAE,CAAC;YACtB,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;YACrE,MAAM;QACR,CAAC;QAED,KAAK,aAAa,EAAE,CAAC;YACnB,eAAe,CAAC,MAAM,CAAC,CAAC;YACxB,MAAM;QACR,CAAC;QAED,KAAK,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACpE,MAAM;QACR,CAAC;QAED,KAAK,WAAW,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,EAAE,CAAC;YACvB,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBAC/B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC7C,WAAW,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC;oBAC5C,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;wBAClB,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC;oBACzD,CAAC;yBAAM,CAAC;wBACN,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC;oBACrD,CAAC;gBACH,CAAC;YACH,CAAC;YACD,yDAAyD;YACzD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC/F,CAAC;YACD,OAAO,CAAC,iBAAiB,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM;QACR,CAAC;QAED,KAAK,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG;gBACZ,oBAAoB,CAAC,CAAC,IAAI,IAAI,SAAS,EAAE;gBACzC,oBAAoB,MAAM,CAAC,WAAW,IAAI,SAAS,EAAE;aACtD,CAAC;YACF,IAAI,CAAC,CAAC,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,CAAC,QAAQ;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,CAAC,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,CAAC,YAAY;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;YACrE,IAAI,MAAM,CAAC,cAAc;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;YACnF,IAAI,CAAC,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,CAAC,eAAe;gBAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YAE3E,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACjF,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC;YAE3D,OAAO,CAAC,iBAAiB,EAAE,KAAK,EAAE,uBAAuB,CAAC,CAAC;YAC3D,MAAM;QACR,CAAC;QAED,KAAK,mBAAmB,EAAE,CAAC;YACzB,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9D,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACjD,KAAK,CAAC,OAAO,CAAC,CAAC,CAAgB,EAAE,GAAW,EAAE,EAAE;oBAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;oBACnD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,WAAW,CAAC,CAAC;gBAC/C,CAAC,CAAC,CAAC;gBACH,0BAA0B;gBAC1B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;YACD,OAAO,CAAC,iBAAiB,EAAE,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YACxD,MAAM;QACR,CAAC;QAED,KAAK,UAAU,EAAE,CAAC;YAChB,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAC9B,IAAI,IAAI,GAAG,GAAG,CAAC;oBACf,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;wBAAE,IAAI,GAAG,GAAG,CAAC;yBAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;wBAAE,IAAI,GAAG,GAAG,CAAC;oBAE5C,IAAI,KAAK,GAAG,UAAU,CAAC;oBACvB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;wBAAE,KAAK,GAAG,UAAU,CAAC;yBACvC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;wBAAE,KAAK,GAAG,UAAU,CAAC;oBAEpD,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,gBAAgB,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runDoctor(pkgVersion: string): void;
2
+ export declare function runUninstall(): void;
@@ -0,0 +1,114 @@
1
+ import fs from 'node:fs';
2
+ import { execSync } from 'node:child_process';
3
+ import readline from 'node:readline';
4
+ const C = {
5
+ reset: '\x1b[0m',
6
+ cyan: '\x1b[36m',
7
+ green: '\x1b[32m',
8
+ yellow: '\x1b[33m',
9
+ red: '\x1b[31m',
10
+ };
11
+ function paint(text, ...codes) {
12
+ return `${codes.join('')}${text}${C.reset}`;
13
+ }
14
+ function getGlobalNpmRoot() {
15
+ try {
16
+ return execSync('npm root -g', { encoding: 'utf8', stdio: 'pipe' }).trim();
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ function getInstallStatus() {
23
+ const status = {
24
+ isGlobal: false,
25
+ method: 'unknown',
26
+ binaryPath: process.argv[1] || 'unknown',
27
+ isBroken: false,
28
+ };
29
+ try {
30
+ if (!status.binaryPath || !fs.existsSync(status.binaryPath)) {
31
+ status.isBroken = true;
32
+ return status;
33
+ }
34
+ const realPath = fs.realpathSync(status.binaryPath);
35
+ const globalRoot = getGlobalNpmRoot();
36
+ if (globalRoot) {
37
+ if (realPath.includes(globalRoot)) {
38
+ status.isGlobal = true;
39
+ status.method = 'npm install -g';
40
+ }
41
+ else if (status.binaryPath !== realPath) {
42
+ status.isGlobal = true;
43
+ status.method = 'npm link';
44
+ }
45
+ else {
46
+ status.isGlobal = false;
47
+ status.method = 'local';
48
+ }
49
+ }
50
+ else {
51
+ if (status.binaryPath !== realPath) {
52
+ status.isGlobal = true;
53
+ status.method = 'npm link';
54
+ }
55
+ else {
56
+ status.isGlobal = false;
57
+ }
58
+ }
59
+ }
60
+ catch (err) {
61
+ status.isBroken = true;
62
+ }
63
+ return status;
64
+ }
65
+ export function runDoctor(pkgVersion) {
66
+ const status = getInstallStatus();
67
+ if (status.isBroken) {
68
+ console.log(paint('⚠ Broken installation detected', C.red));
69
+ console.log(`→ Run: ${paint('npm uninstall -g toren', C.cyan)}`);
70
+ console.log('');
71
+ return;
72
+ }
73
+ if (status.isGlobal) {
74
+ console.log(`${paint('✔', C.green)} Toren installed globally`);
75
+ }
76
+ else {
77
+ console.log(`${paint('✔', C.green)} Toren installed locally`);
78
+ }
79
+ console.log(`${paint('✔', C.green)} Binary path valid`);
80
+ console.log(`${paint('✔', C.green)} Version match confirmed`);
81
+ console.log('');
82
+ }
83
+ export function runUninstall() {
84
+ const status = getInstallStatus();
85
+ if (status.isBroken) {
86
+ console.log(paint('⚠ Toren installation is corrupted. Please reinstall using npm install -g toren', C.yellow));
87
+ process.exit(0);
88
+ }
89
+ const rl = readline.createInterface({
90
+ input: process.stdin,
91
+ output: process.stdout
92
+ });
93
+ rl.question('Are you sure you want to remove Toren from global environment? (y/n) ', (answer) => {
94
+ rl.close();
95
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
96
+ process.exit(0);
97
+ }
98
+ console.log('');
99
+ console.log('Uninstalling Toren...');
100
+ try {
101
+ execSync('npm uninstall -g toren', { stdio: 'inherit' });
102
+ console.log('');
103
+ console.log(paint('✔ Successfully removed Toren from the global environment.', C.green));
104
+ }
105
+ catch (err) {
106
+ console.log('');
107
+ console.log(paint('❌ Failed to uninstall Toren.', C.red));
108
+ console.log('Please try manually: npm uninstall -g toren');
109
+ }
110
+ console.log('');
111
+ process.exit(0);
112
+ });
113
+ }
114
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { ScanResult } from "../types/index.js";
2
+ /**
3
+ * Render a ScanResult to the terminal.
4
+ *
5
+ * All sections read from the ScanResult. Presentation-level derivations
6
+ * (e.g. frameworks list) are computed here; no business logic is added.
7
+ *
8
+ * @param {import('../scanner/scan.js').ScanResult} result
9
+ * @param {{ cwd?: string }} [options]
10
+ */
11
+ export declare function render(result: ScanResult, options?: {
12
+ cwd?: string;
13
+ }): void;
14
+ /**
15
+ * Render only the project structure for the --structure flag.
16
+ *
17
+ * @param {import('../scanner/scan.js').ScanResult} result
18
+ */
19
+ export declare function renderStructure(result: ScanResult): void;