roguelike-cli 1.0.0
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/INSTALL.md +108 -0
- package/bin/rlc +4 -0
- package/dist/ai/claude.js +115 -0
- package/dist/commands/init.js +175 -0
- package/dist/config/config.js +85 -0
- package/dist/index.js +29 -0
- package/dist/interactive/commands.js +552 -0
- package/dist/interactive/index.js +180 -0
- package/dist/interactive/startup.js +38 -0
- package/dist/storage/nodeConfig.js +109 -0
- package/dist/storage/storage.js +155 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/schemaParser.js +217 -0
- package/package.json +45 -0
- package/src/ai/claude.ts +139 -0
- package/src/commands/init.ts +159 -0
- package/src/config/config.ts +69 -0
- package/src/index.ts +37 -0
- package/src/interactive/commands.ts +625 -0
- package/src/interactive/index.ts +174 -0
- package/src/interactive/startup.ts +38 -0
- package/src/storage/nodeConfig.ts +109 -0
- package/src/storage/storage.ts +143 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/schemaParser.ts +259 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.startInteractive = startInteractive;
|
|
37
|
+
const readline = __importStar(require("readline"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const startup_1 = require("./startup");
|
|
40
|
+
const commands_1 = require("./commands");
|
|
41
|
+
const config_1 = require("../config/config");
|
|
42
|
+
function getCompletions(currentPath) {
|
|
43
|
+
if (!fs.existsSync(currentPath)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
47
|
+
const completions = [];
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
if (entry.name.startsWith('.'))
|
|
50
|
+
continue;
|
|
51
|
+
completions.push(entry.name);
|
|
52
|
+
}
|
|
53
|
+
return completions;
|
|
54
|
+
}
|
|
55
|
+
async function startInteractive(initialConfig) {
|
|
56
|
+
await (0, startup_1.showStartupAnimation)();
|
|
57
|
+
let config = initialConfig;
|
|
58
|
+
// Use object to hold currentPath so closures always get the current value
|
|
59
|
+
const state = {
|
|
60
|
+
currentPath: config.currentPath
|
|
61
|
+
};
|
|
62
|
+
// Completer function that uses state.currentPath
|
|
63
|
+
const completer = (line) => {
|
|
64
|
+
try {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (!trimmed) {
|
|
67
|
+
return [[], ''];
|
|
68
|
+
}
|
|
69
|
+
// Find the last word using regex to get exact position
|
|
70
|
+
const lastWordMatch = line.match(/(\S+)$/);
|
|
71
|
+
if (!lastWordMatch) {
|
|
72
|
+
return [[], line];
|
|
73
|
+
}
|
|
74
|
+
const lastWord = lastWordMatch[1];
|
|
75
|
+
const lastWordStart = lastWordMatch.index;
|
|
76
|
+
const prefix = line.substring(lastWordStart);
|
|
77
|
+
const parts = trimmed.split(/\s+/);
|
|
78
|
+
const command = parts[0]?.toLowerCase() || '';
|
|
79
|
+
// Only autocomplete if we're in a command that takes a path argument
|
|
80
|
+
const commandsThatNeedCompletion = ['cd', 'open', 'cp', 'rm', 'mkdir'];
|
|
81
|
+
if (commandsThatNeedCompletion.includes(command) && parts.length > 1) {
|
|
82
|
+
const completions = getCompletions(state.currentPath);
|
|
83
|
+
const hits = completions.filter((c) => c.toLowerCase().startsWith(lastWord.toLowerCase()));
|
|
84
|
+
return [hits.length > 0 ? hits : [], prefix];
|
|
85
|
+
}
|
|
86
|
+
// If we're typing a command name itself
|
|
87
|
+
if (parts.length === 1) {
|
|
88
|
+
const commandCompletions = ['ls', 'cd', 'mkdir', 'open', 'cp', 'rm', 'tree', 'pwd', 'init', 'config', 'help', 'save', 'cancel', 'clean', 'exit', 'quit', '..', '...'];
|
|
89
|
+
const hits = commandCompletions.filter((c) => c.toLowerCase().startsWith(lastWord.toLowerCase()));
|
|
90
|
+
return [hits.length > 0 ? hits : commandCompletions, prefix];
|
|
91
|
+
}
|
|
92
|
+
return [[], line];
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
// Return empty completion on any error to prevent crash
|
|
96
|
+
return [[], line];
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const rl = readline.createInterface({
|
|
100
|
+
input: process.stdin,
|
|
101
|
+
output: process.stdout,
|
|
102
|
+
prompt: '> ',
|
|
103
|
+
completer: completer,
|
|
104
|
+
});
|
|
105
|
+
let isProcessingCommand = false;
|
|
106
|
+
let currentCommandAbortController = null;
|
|
107
|
+
// Override SIGINT to cancel commands instead of exiting
|
|
108
|
+
process.on('SIGINT', () => {
|
|
109
|
+
if (isProcessingCommand) {
|
|
110
|
+
// Cancel current command but stay in program
|
|
111
|
+
if (currentCommandAbortController) {
|
|
112
|
+
currentCommandAbortController.abort();
|
|
113
|
+
currentCommandAbortController = null;
|
|
114
|
+
}
|
|
115
|
+
isProcessingCommand = false;
|
|
116
|
+
console.log('\n^C');
|
|
117
|
+
rl.prompt();
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Clear the line if not processing
|
|
121
|
+
rl.write('\x1B[2K\r> ');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
rl.on('line', async (input) => {
|
|
125
|
+
const trimmed = input.trim();
|
|
126
|
+
if (trimmed === 'exit' || trimmed === 'quit') {
|
|
127
|
+
rl.close();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (trimmed === '') {
|
|
131
|
+
rl.prompt();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Create abort controller for this command
|
|
135
|
+
currentCommandAbortController = new AbortController();
|
|
136
|
+
isProcessingCommand = true;
|
|
137
|
+
const abortController = currentCommandAbortController;
|
|
138
|
+
try {
|
|
139
|
+
const result = await (0, commands_1.processCommand)(trimmed, state.currentPath, config, abortController.signal);
|
|
140
|
+
if (abortController.signal.aborted) {
|
|
141
|
+
rl.prompt();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (result.reloadConfig) {
|
|
145
|
+
const newConfig = await (0, config_1.initConfig)();
|
|
146
|
+
if (newConfig) {
|
|
147
|
+
config = newConfig;
|
|
148
|
+
state.currentPath = config.currentPath;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (result.newPath) {
|
|
152
|
+
state.currentPath = result.newPath;
|
|
153
|
+
}
|
|
154
|
+
if (result.output) {
|
|
155
|
+
console.log(result.output);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error.name === 'AbortError' || abortController.signal.aborted) {
|
|
160
|
+
console.log('\nCommand cancelled.');
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.error(`Error: ${error.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
isProcessingCommand = false;
|
|
168
|
+
currentCommandAbortController = null;
|
|
169
|
+
}
|
|
170
|
+
rl.prompt();
|
|
171
|
+
});
|
|
172
|
+
rl.on('close', () => {
|
|
173
|
+
if (process.stdin.isTTY) {
|
|
174
|
+
process.stdin.setRawMode(false);
|
|
175
|
+
}
|
|
176
|
+
console.log('\nGoodbye!');
|
|
177
|
+
process.exit(0);
|
|
178
|
+
});
|
|
179
|
+
rl.prompt();
|
|
180
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.showStartupAnimation = showStartupAnimation;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const ASCII_ART = [
|
|
6
|
+
'',
|
|
7
|
+
' |',
|
|
8
|
+
' |',
|
|
9
|
+
' + \\',
|
|
10
|
+
' \\.G_.*=.',
|
|
11
|
+
' `(#\'/.\|',
|
|
12
|
+
' .>\' (_--.',
|
|
13
|
+
' _=/d ,^\\',
|
|
14
|
+
'~~ \\)-\' \'',
|
|
15
|
+
' / |',
|
|
16
|
+
' \' \'',
|
|
17
|
+
'',
|
|
18
|
+
'╔═════════════════════════╗',
|
|
19
|
+
'║ Roguelike CLI v1.0 ║',
|
|
20
|
+
'║ www.rlc.rocks ║',
|
|
21
|
+
'╚═════════════════════════╝',
|
|
22
|
+
'',
|
|
23
|
+
' Commands: ls, cd, mkdir, open, cp, mv, rm, tree, pwd, clean',
|
|
24
|
+
' TAB to autocomplete, | pbcopy to copy output',
|
|
25
|
+
'',
|
|
26
|
+
' Workflow: <description> -> refine -> save',
|
|
27
|
+
' init - setup, config - settings, help - examples',
|
|
28
|
+
'',
|
|
29
|
+
' Ready...',
|
|
30
|
+
'',
|
|
31
|
+
];
|
|
32
|
+
async function showStartupAnimation() {
|
|
33
|
+
for (const line of ASCII_ART) {
|
|
34
|
+
console.log(line);
|
|
35
|
+
await (0, utils_1.sleep)(15);
|
|
36
|
+
}
|
|
37
|
+
await (0, utils_1.sleep)(100);
|
|
38
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readNodeConfig = readNodeConfig;
|
|
37
|
+
exports.writeNodeConfig = writeNodeConfig;
|
|
38
|
+
exports.createNode = createNode;
|
|
39
|
+
exports.saveSchemaFile = saveSchemaFile;
|
|
40
|
+
exports.readSchemaFile = readSchemaFile;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const CONFIG_FILE = '.rlc.json';
|
|
44
|
+
function readNodeConfig(nodePath) {
|
|
45
|
+
const configPath = path.join(nodePath, CONFIG_FILE);
|
|
46
|
+
if (!fs.existsSync(configPath)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const data = fs.readFileSync(configPath, 'utf-8');
|
|
51
|
+
return JSON.parse(data);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function writeNodeConfig(nodePath, config) {
|
|
58
|
+
if (!fs.existsSync(nodePath)) {
|
|
59
|
+
fs.mkdirSync(nodePath, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
const configPath = path.join(nodePath, CONFIG_FILE);
|
|
62
|
+
const existing = readNodeConfig(nodePath);
|
|
63
|
+
const updated = {
|
|
64
|
+
...existing,
|
|
65
|
+
...config,
|
|
66
|
+
updatedAt: new Date().toISOString(),
|
|
67
|
+
createdAt: existing?.createdAt || new Date().toISOString(),
|
|
68
|
+
};
|
|
69
|
+
fs.writeFileSync(configPath, JSON.stringify(updated, null, 2), 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
function createNode(parentPath, name, options) {
|
|
72
|
+
const safeName = name
|
|
73
|
+
.toLowerCase()
|
|
74
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
75
|
+
.replace(/^-+|-+$/g, '');
|
|
76
|
+
const nodePath = path.join(parentPath, safeName);
|
|
77
|
+
const config = {
|
|
78
|
+
name,
|
|
79
|
+
deadline: options?.deadline,
|
|
80
|
+
branch: options?.branch,
|
|
81
|
+
zone: options?.zone,
|
|
82
|
+
description: options?.description,
|
|
83
|
+
createdAt: new Date().toISOString(),
|
|
84
|
+
updatedAt: new Date().toISOString(),
|
|
85
|
+
metadata: options?.metadata,
|
|
86
|
+
};
|
|
87
|
+
writeNodeConfig(nodePath, config);
|
|
88
|
+
return nodePath;
|
|
89
|
+
}
|
|
90
|
+
// Save schema content to .rlc.schema file
|
|
91
|
+
function saveSchemaFile(dirPath, filename, content) {
|
|
92
|
+
if (!fs.existsSync(dirPath)) {
|
|
93
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
const safeName = filename
|
|
96
|
+
.toLowerCase()
|
|
97
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
98
|
+
.replace(/^-+|-+$/g, '');
|
|
99
|
+
const schemaPath = path.join(dirPath, `${safeName}.rlc.schema`);
|
|
100
|
+
fs.writeFileSync(schemaPath, content, 'utf-8');
|
|
101
|
+
return schemaPath;
|
|
102
|
+
}
|
|
103
|
+
// Read schema file
|
|
104
|
+
function readSchemaFile(filePath) {
|
|
105
|
+
if (!fs.existsSync(filePath)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
109
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listSchemas = listSchemas;
|
|
37
|
+
exports.navigateToNode = navigateToNode;
|
|
38
|
+
exports.readSchema = readSchema;
|
|
39
|
+
exports.getTree = getTree;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const nodeConfig_1 = require("./nodeConfig");
|
|
43
|
+
function listSchemas(dirPath) {
|
|
44
|
+
if (!fs.existsSync(dirPath)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const items = [];
|
|
48
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
51
|
+
// Skip hidden files
|
|
52
|
+
if (entry.name.startsWith('.')) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
const config = (0, nodeConfig_1.readNodeConfig)(fullPath);
|
|
57
|
+
items.push({
|
|
58
|
+
name: entry.name,
|
|
59
|
+
path: fullPath,
|
|
60
|
+
config,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return items.sort((a, b) => a.name.localeCompare(b.name));
|
|
65
|
+
}
|
|
66
|
+
function navigateToNode(currentPath, nodeName) {
|
|
67
|
+
const schemas = listSchemas(currentPath);
|
|
68
|
+
const node = schemas.find(s => s.name.toLowerCase() === nodeName.toLowerCase());
|
|
69
|
+
if (!node) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (fs.statSync(node.path).isDirectory()) {
|
|
73
|
+
return node.path;
|
|
74
|
+
}
|
|
75
|
+
return node.path;
|
|
76
|
+
}
|
|
77
|
+
function readSchema(nodePath) {
|
|
78
|
+
// Read node config and return its info
|
|
79
|
+
const config = (0, nodeConfig_1.readNodeConfig)(nodePath);
|
|
80
|
+
if (!config) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
let output = `${config.name}`;
|
|
84
|
+
if (config.deadline)
|
|
85
|
+
output += `\nDeadline: ${config.deadline}`;
|
|
86
|
+
if (config.branch)
|
|
87
|
+
output += `\nBranch: ${config.branch}`;
|
|
88
|
+
if (config.zone)
|
|
89
|
+
output += `\nZone: ${config.zone}`;
|
|
90
|
+
if (config.description)
|
|
91
|
+
output += `\n${config.description}`;
|
|
92
|
+
return output;
|
|
93
|
+
}
|
|
94
|
+
function getTree(dirPath, prefix = '', isLast = true, maxDepth = 10, currentDepth = 0, showFiles = false) {
|
|
95
|
+
if (currentDepth >= maxDepth) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const lines = [];
|
|
99
|
+
// Get items - either just folders or all entries
|
|
100
|
+
let items = [];
|
|
101
|
+
if (showFiles) {
|
|
102
|
+
// Show all files and folders
|
|
103
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
if (entry.name.startsWith('.'))
|
|
106
|
+
continue;
|
|
107
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
108
|
+
const config = entry.isDirectory() ? (0, nodeConfig_1.readNodeConfig)(fullPath) : null;
|
|
109
|
+
items.push({
|
|
110
|
+
name: entry.name,
|
|
111
|
+
path: fullPath,
|
|
112
|
+
isDir: entry.isDirectory(),
|
|
113
|
+
config
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Sort: folders first, then files
|
|
117
|
+
items.sort((a, b) => {
|
|
118
|
+
if (a.isDir !== b.isDir)
|
|
119
|
+
return a.isDir ? -1 : 1;
|
|
120
|
+
return a.name.localeCompare(b.name);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Only folders (original behavior)
|
|
125
|
+
const schemas = listSchemas(dirPath);
|
|
126
|
+
items = schemas.map(s => ({
|
|
127
|
+
name: s.name,
|
|
128
|
+
path: s.path,
|
|
129
|
+
isDir: true,
|
|
130
|
+
config: s.config
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
items.forEach((item, index) => {
|
|
134
|
+
const isItemLast = index === items.length - 1;
|
|
135
|
+
const connector = isItemLast ? '└──' : '├──';
|
|
136
|
+
const currentPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
137
|
+
let displayName = item.name;
|
|
138
|
+
// Add file indicator
|
|
139
|
+
if (!item.isDir) {
|
|
140
|
+
displayName = `* ${displayName}`;
|
|
141
|
+
}
|
|
142
|
+
if (item.config?.deadline) {
|
|
143
|
+
displayName += ` [${item.config.deadline}]`;
|
|
144
|
+
}
|
|
145
|
+
if (item.config?.branch) {
|
|
146
|
+
displayName += ` (${item.config.branch})`;
|
|
147
|
+
}
|
|
148
|
+
lines.push(`${prefix}${connector} ${displayName}`);
|
|
149
|
+
if (item.isDir) {
|
|
150
|
+
const childLines = getTree(item.path, currentPrefix, isItemLast, maxDepth, currentDepth + 1, showFiles);
|
|
151
|
+
lines.push(...childLines);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
return lines;
|
|
155
|
+
}
|