@towles/tool 0.0.20 → 0.0.41
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/LICENSE +21 -0
- package/LICENSE.md +9 -10
- package/README.md +121 -78
- package/bin/run.ts +5 -0
- package/package.json +63 -53
- package/patches/prompts.patch +34 -0
- package/src/commands/base.ts +42 -0
- package/src/commands/config.test.ts +15 -0
- package/src/commands/config.ts +43 -0
- package/src/commands/doctor.ts +133 -0
- package/src/commands/gh/branch-clean.ts +110 -0
- package/src/commands/gh/branch.test.ts +124 -0
- package/src/commands/gh/branch.ts +132 -0
- package/src/commands/gh/pr.ts +168 -0
- package/src/commands/index.ts +55 -0
- package/src/commands/install.ts +148 -0
- package/src/commands/journal/daily-notes.ts +66 -0
- package/src/commands/journal/meeting.ts +83 -0
- package/src/commands/journal/note.ts +83 -0
- package/src/commands/journal/utils.ts +399 -0
- package/src/commands/observe/graph.test.ts +89 -0
- package/src/commands/observe/graph.ts +1640 -0
- package/src/commands/observe/report.ts +166 -0
- package/src/commands/observe/session.ts +385 -0
- package/src/commands/observe/setup.ts +180 -0
- package/src/commands/observe/status.ts +146 -0
- package/src/commands/ralph/lib/execution.ts +302 -0
- package/src/commands/ralph/lib/formatter.ts +298 -0
- package/src/commands/ralph/lib/index.ts +4 -0
- package/src/commands/ralph/lib/marker.ts +108 -0
- package/src/commands/ralph/lib/state.ts +191 -0
- package/src/commands/ralph/marker/create.ts +23 -0
- package/src/commands/ralph/plan.ts +73 -0
- package/src/commands/ralph/progress.ts +44 -0
- package/src/commands/ralph/ralph.test.ts +673 -0
- package/src/commands/ralph/run.ts +408 -0
- package/src/commands/ralph/task/add.ts +105 -0
- package/src/commands/ralph/task/done.ts +73 -0
- package/src/commands/ralph/task/list.test.ts +48 -0
- package/src/commands/ralph/task/list.ts +110 -0
- package/src/commands/ralph/task/remove.ts +62 -0
- package/src/config/context.ts +7 -0
- package/src/config/settings.ts +155 -0
- package/src/constants.ts +3 -0
- package/src/types/journal.ts +16 -0
- package/src/utils/anthropic/types.ts +158 -0
- package/src/utils/date-utils.test.ts +96 -0
- package/src/utils/date-utils.ts +54 -0
- package/src/utils/exec.ts +8 -0
- package/src/utils/git/gh-cli-wrapper.test.ts +14 -0
- package/src/utils/git/gh-cli-wrapper.ts +54 -0
- package/src/utils/git/git-wrapper.test.ts +26 -0
- package/src/utils/git/git-wrapper.ts +15 -0
- package/src/utils/git/git.ts +25 -0
- package/src/utils/render.test.ts +71 -0
- package/src/utils/render.ts +34 -0
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +0 -805
package/dist/index.mjs
DELETED
|
@@ -1,805 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import process$1 from 'node:process';
|
|
3
|
-
import consola from 'consola';
|
|
4
|
-
import { z } from 'zod/v4';
|
|
5
|
-
import * as fs from 'node:fs';
|
|
6
|
-
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
7
|
-
import * as path from 'node:path';
|
|
8
|
-
import path__default from 'node:path';
|
|
9
|
-
import { homedir } from 'node:os';
|
|
10
|
-
import * as commentJson from 'comment-json';
|
|
11
|
-
import { colors } from 'consola/utils';
|
|
12
|
-
import yargs from 'yargs';
|
|
13
|
-
import { hideBin } from 'yargs/helpers';
|
|
14
|
-
import prompts from 'prompts';
|
|
15
|
-
import { execSync, exec } from 'node:child_process';
|
|
16
|
-
import { promisify } from 'node:util';
|
|
17
|
-
import { DateTime } from 'luxon';
|
|
18
|
-
import { Fzf } from 'fzf';
|
|
19
|
-
import stripAnsi from 'strip-ansi';
|
|
20
|
-
import { exec as exec$1 } from 'tinyexec';
|
|
21
|
-
|
|
22
|
-
async function loadTowlesToolContext({
|
|
23
|
-
cwd,
|
|
24
|
-
settingsFile,
|
|
25
|
-
debug = false
|
|
26
|
-
}) {
|
|
27
|
-
return {
|
|
28
|
-
cwd,
|
|
29
|
-
settingsFile,
|
|
30
|
-
args: [],
|
|
31
|
-
// TODO: Load args from yargs
|
|
32
|
-
debug
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const AppInfo = {
|
|
37
|
-
toolName: "towles-tool"
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const USER_SETTINGS_DIR = path.join(homedir(), ".config", AppInfo.toolName);
|
|
41
|
-
const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, `${AppInfo.toolName}.settings.json`);
|
|
42
|
-
const JournalSettingsSchema = z.object({
|
|
43
|
-
// Base folder where all journal files are stored
|
|
44
|
-
baseFolder: z.string().default(path.join(homedir())),
|
|
45
|
-
// https://moment.github.io/luxon/#/formatting?id=table-of-tokens
|
|
46
|
-
dailyPathTemplate: z.string().default(path.join("journal/{monday:yyyy}/{monday:MM}/daily-notes/{monday:yyyy}-{monday:MM}-{monday:dd}-daily-notes.md")),
|
|
47
|
-
meetingPathTemplate: z.string().default(path.join("journal/{yyyy}/{MM}/meetings/{yyyy}-{MM}-{dd}-{title}.md")),
|
|
48
|
-
notePathTemplate: z.string().default(path.join("journal/{yyyy}/{MM}/notes/{yyyy}-{MM}-{dd}-{title}.md"))
|
|
49
|
-
});
|
|
50
|
-
const UserSettingsSchema = z.object({
|
|
51
|
-
preferredEditor: z.string().default("code"),
|
|
52
|
-
journalSettings: JournalSettingsSchema
|
|
53
|
-
});
|
|
54
|
-
class LoadedSettings {
|
|
55
|
-
constructor(settingsFile) {
|
|
56
|
-
this.settingsFile = settingsFile;
|
|
57
|
-
}
|
|
58
|
-
settingsFile;
|
|
59
|
-
}
|
|
60
|
-
function createDefaultSettings() {
|
|
61
|
-
return UserSettingsSchema.parse({
|
|
62
|
-
// NOTE: yes its odd zod can't use defaults from objects nested but it appears to be the case.
|
|
63
|
-
journalSettings: JournalSettingsSchema.parse({})
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
function createSettingsFile() {
|
|
67
|
-
let userSettings = createDefaultSettings();
|
|
68
|
-
if (fs.existsSync(USER_SETTINGS_PATH)) {
|
|
69
|
-
const userContent = fs.readFileSync(USER_SETTINGS_PATH, "utf-8");
|
|
70
|
-
const parsedUserSettings = commentJson.parse(userContent);
|
|
71
|
-
userSettings = UserSettingsSchema.parse(parsedUserSettings);
|
|
72
|
-
} else {
|
|
73
|
-
saveSettings({
|
|
74
|
-
path: USER_SETTINGS_PATH,
|
|
75
|
-
settings: userSettings
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return userSettings;
|
|
79
|
-
}
|
|
80
|
-
function saveSettings(settingsFile) {
|
|
81
|
-
try {
|
|
82
|
-
const dirPath = path.dirname(settingsFile.path);
|
|
83
|
-
if (!fs.existsSync(dirPath)) {
|
|
84
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
85
|
-
}
|
|
86
|
-
fs.writeFileSync(
|
|
87
|
-
settingsFile.path,
|
|
88
|
-
commentJson.stringify(settingsFile.settings, null, 2),
|
|
89
|
-
"utf-8"
|
|
90
|
-
);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
consola.error("Error saving user settings file:", error);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
async function loadSettings() {
|
|
96
|
-
let userSettings = null;
|
|
97
|
-
if (fs.existsSync(USER_SETTINGS_PATH)) {
|
|
98
|
-
const userContent = fs.readFileSync(USER_SETTINGS_PATH, "utf-8");
|
|
99
|
-
const parsedUserSettings = commentJson.parse(userContent);
|
|
100
|
-
userSettings = UserSettingsSchema.parse(parsedUserSettings);
|
|
101
|
-
if (JSON.stringify(parsedUserSettings) !== JSON.stringify(userSettings)) {
|
|
102
|
-
consola.warn(`Settings file ${USER_SETTINGS_PATH} has been updated with default values.`);
|
|
103
|
-
const tempSettingsFile = {
|
|
104
|
-
path: USER_SETTINGS_PATH,
|
|
105
|
-
settings: userSettings
|
|
106
|
-
};
|
|
107
|
-
saveSettings(tempSettingsFile);
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
const confirmed = await consola.prompt(`Settings file not found. Create ${colors.cyan(USER_SETTINGS_PATH)}?`, {
|
|
111
|
-
type: "confirm"
|
|
112
|
-
});
|
|
113
|
-
if (!confirmed) {
|
|
114
|
-
throw new Error(`Settings file not found and user chose not to create it.`);
|
|
115
|
-
}
|
|
116
|
-
userSettings = createSettingsFile();
|
|
117
|
-
}
|
|
118
|
-
return new LoadedSettings(
|
|
119
|
-
{
|
|
120
|
-
path: USER_SETTINGS_PATH,
|
|
121
|
-
settings: userSettings
|
|
122
|
-
}
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const version = "0.0.20";
|
|
127
|
-
|
|
128
|
-
const JOURNAL_TYPES = {
|
|
129
|
-
DAILY_NOTES: "daily-notes",
|
|
130
|
-
MEETING: "meeting",
|
|
131
|
-
NOTE: "note"
|
|
132
|
-
};
|
|
133
|
-
async function parseArguments(argv) {
|
|
134
|
-
let parsedResult = null;
|
|
135
|
-
const parser = yargs(hideBin(argv)).scriptName(AppInfo.toolName).usage("Usage: $0 <command> [options]").version(version).demandCommand(1, "You need at least one command").recommendCommands().strict().help().wrap(yargs().terminalWidth());
|
|
136
|
-
parser.command(
|
|
137
|
-
["journal", "j"],
|
|
138
|
-
"quickly create md files from templates files like daily-notes, meeting, notes, etc.",
|
|
139
|
-
(yargs2) => {
|
|
140
|
-
return yargs2.command(
|
|
141
|
-
["daily-notes", "today"],
|
|
142
|
-
"Weekly files with daily sections for ongoing work and notes",
|
|
143
|
-
{},
|
|
144
|
-
(argv2) => {
|
|
145
|
-
parsedResult = { command: "journal", args: { jouralType: "daily-notes", title: "" } };
|
|
146
|
-
}
|
|
147
|
-
).command(
|
|
148
|
-
["meeting [title]", "m"],
|
|
149
|
-
"Structured meeting notes with agenda and action items",
|
|
150
|
-
{
|
|
151
|
-
title: {
|
|
152
|
-
type: "string",
|
|
153
|
-
describe: "Meeting title"
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
(argv2) => {
|
|
157
|
-
parsedResult = { command: "journal", args: { jouralType: "meeting", title: argv2.title || "" } };
|
|
158
|
-
}
|
|
159
|
-
).command(
|
|
160
|
-
["note [title]", "n"],
|
|
161
|
-
"General-purpose notes with structured sections",
|
|
162
|
-
{
|
|
163
|
-
title: {
|
|
164
|
-
type: "string",
|
|
165
|
-
describe: "Note title"
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
(argv2) => {
|
|
169
|
-
parsedResult = { command: "journal", args: { jouralType: "note", title: argv2.title || "" } };
|
|
170
|
-
}
|
|
171
|
-
).demandCommand(1, "You need to specify a journal subcommand").help();
|
|
172
|
-
},
|
|
173
|
-
() => {
|
|
174
|
-
parser.showHelp();
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
parser.command(
|
|
178
|
-
["git-commit [message...]", "gc"],
|
|
179
|
-
"Git commit command with optional message",
|
|
180
|
-
{
|
|
181
|
-
message: {
|
|
182
|
-
type: "string",
|
|
183
|
-
array: true,
|
|
184
|
-
describe: "Commit message words"
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
(argv2) => {
|
|
188
|
-
parsedResult = { command: "git-commit", args: { message: argv2.message } };
|
|
189
|
-
}
|
|
190
|
-
);
|
|
191
|
-
parser.command(
|
|
192
|
-
["gh-branch [assignedToMe...]", "branch", "br"],
|
|
193
|
-
"Create git branch from github issue",
|
|
194
|
-
{
|
|
195
|
-
assignedToMe: {
|
|
196
|
-
type: "boolean",
|
|
197
|
-
describe: "filter issues based on if assigned to you by default",
|
|
198
|
-
default: false
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
(argv2) => {
|
|
202
|
-
parsedResult = { command: "gh-branch", args: { assignedToMe: argv2.assignedToMe } };
|
|
203
|
-
}
|
|
204
|
-
);
|
|
205
|
-
parser.command(
|
|
206
|
-
["config", "cfg"],
|
|
207
|
-
"set or show configuration file.",
|
|
208
|
-
{},
|
|
209
|
-
() => {
|
|
210
|
-
parsedResult = { command: "config", args: {} };
|
|
211
|
-
}
|
|
212
|
-
);
|
|
213
|
-
parser.command(
|
|
214
|
-
["weather", "w"],
|
|
215
|
-
"Show current weather for Cincinnati, OH",
|
|
216
|
-
{},
|
|
217
|
-
() => {
|
|
218
|
-
parsedResult = { command: "weather", args: {} };
|
|
219
|
-
}
|
|
220
|
-
);
|
|
221
|
-
await parser.parse();
|
|
222
|
-
if (!parsedResult) {
|
|
223
|
-
throw new Error("No command was parsed");
|
|
224
|
-
}
|
|
225
|
-
return parsedResult;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function execCommand(cmd, cwd) {
|
|
229
|
-
return execSync(cmd, { encoding: "utf8", cwd }).trim();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async function gitCommitCommand(context, commitMessage) {
|
|
233
|
-
try {
|
|
234
|
-
const status = await getGitStatus(context.cwd);
|
|
235
|
-
if (!status || status.staged.length === 0 && status.unstaged.length === 0 && status.untracked.length === 0) {
|
|
236
|
-
consola.success("\u2713 Working tree clean - nothing to commit");
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
displayGitStatus(status);
|
|
240
|
-
if (status.staged.length === 0) {
|
|
241
|
-
const shouldStage = await prompts({
|
|
242
|
-
type: "confirm",
|
|
243
|
-
name: "stage",
|
|
244
|
-
message: "No files are staged. Add all modified and untracked files?",
|
|
245
|
-
initial: true
|
|
246
|
-
});
|
|
247
|
-
if (!shouldStage.stage) {
|
|
248
|
-
consola.info("Cancelled");
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
consola.start("Staging files...");
|
|
252
|
-
await execCommand("git add .", context.cwd);
|
|
253
|
-
consola.success("Files staged");
|
|
254
|
-
}
|
|
255
|
-
if (!commitMessage) {
|
|
256
|
-
const response = await prompts({
|
|
257
|
-
type: "text",
|
|
258
|
-
name: "message",
|
|
259
|
-
message: "Enter commit message:",
|
|
260
|
-
validate: (value) => value.trim().length > 0 || "Commit message cannot be empty"
|
|
261
|
-
});
|
|
262
|
-
if (!response.message) {
|
|
263
|
-
consola.info("Cancelled");
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
commitMessage = response.message;
|
|
267
|
-
}
|
|
268
|
-
consola.start("Creating commit...");
|
|
269
|
-
await execCommand(`git commit -m "${commitMessage}"`, context.cwd);
|
|
270
|
-
consola.success("\u2713 Commit created successfully!");
|
|
271
|
-
} catch (error) {
|
|
272
|
-
consola.error("Git commit failed:", error instanceof Error ? error.message : String(error));
|
|
273
|
-
process.exit(1);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
async function getGitStatus(cwd) {
|
|
277
|
-
try {
|
|
278
|
-
const output = await execCommand("git status --porcelain", cwd);
|
|
279
|
-
const lines = output.trim().split("\n").filter((line) => line.trim());
|
|
280
|
-
const staged = [];
|
|
281
|
-
const unstaged = [];
|
|
282
|
-
const untracked = [];
|
|
283
|
-
for (const line of lines) {
|
|
284
|
-
const status = line.substring(0, 2);
|
|
285
|
-
const file = line.substring(3);
|
|
286
|
-
if (status[0] !== " " && status[0] !== "?") {
|
|
287
|
-
staged.push(file);
|
|
288
|
-
}
|
|
289
|
-
if (status[1] !== " " && status[1] !== "?") {
|
|
290
|
-
unstaged.push(file);
|
|
291
|
-
}
|
|
292
|
-
if (status === "??") {
|
|
293
|
-
untracked.push(file);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return { staged, unstaged, untracked };
|
|
297
|
-
} catch {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function displayGitStatus(status) {
|
|
302
|
-
consola.info("Current git status:");
|
|
303
|
-
if (status.staged.length > 0) {
|
|
304
|
-
consola.success(`\u2713 Staged files (${status.staged.length}):`);
|
|
305
|
-
status.staged.slice(0, 5).forEach((file) => consola.log(` ${file}`));
|
|
306
|
-
if (status.staged.length > 5) {
|
|
307
|
-
consola.log(` ... and ${status.staged.length - 5} more`);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if (status.unstaged.length > 0) {
|
|
311
|
-
consola.warn(`M Modified files (${status.unstaged.length}):`);
|
|
312
|
-
status.unstaged.slice(0, 3).forEach((file) => consola.log(` ${file}`));
|
|
313
|
-
if (status.unstaged.length > 3) {
|
|
314
|
-
consola.log(` ... and ${status.unstaged.length - 3} more`);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
if (status.untracked.length > 0) {
|
|
318
|
-
consola.error(`? Untracked files (${status.untracked.length}):`);
|
|
319
|
-
status.untracked.slice(0, 3).forEach((file) => consola.log(` ${file}`));
|
|
320
|
-
if (status.untracked.length > 3) {
|
|
321
|
-
consola.log(` ... and ${status.untracked.length - 3} more`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function getMondayOfWeek(date) {
|
|
327
|
-
const newDate = new Date(date);
|
|
328
|
-
const day = newDate.getDay();
|
|
329
|
-
const diff = newDate.getDate() - day + (day === 0 ? -6 : 1);
|
|
330
|
-
newDate.setDate(diff);
|
|
331
|
-
newDate.setHours(0, 0, 0, 0);
|
|
332
|
-
return newDate;
|
|
333
|
-
}
|
|
334
|
-
function getWeekInfo(mondayDate) {
|
|
335
|
-
const tuesdayDate = new Date(mondayDate);
|
|
336
|
-
tuesdayDate.setDate(mondayDate.getDate() + 1);
|
|
337
|
-
const wednesdayDate = new Date(mondayDate);
|
|
338
|
-
wednesdayDate.setDate(mondayDate.getDate() + 2);
|
|
339
|
-
const thursdayDate = new Date(mondayDate);
|
|
340
|
-
thursdayDate.setDate(mondayDate.getDate() + 3);
|
|
341
|
-
const fridayDate = new Date(mondayDate);
|
|
342
|
-
fridayDate.setDate(mondayDate.getDate() + 4);
|
|
343
|
-
return {
|
|
344
|
-
mondayDate,
|
|
345
|
-
tuesdayDate,
|
|
346
|
-
wednesdayDate,
|
|
347
|
-
thursdayDate,
|
|
348
|
-
fridayDate
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
function formatDate(date) {
|
|
352
|
-
return date.toISOString().split("T")[0];
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const execAsync = promisify(exec);
|
|
356
|
-
function ensureDirectoryExists(folderPath) {
|
|
357
|
-
if (!existsSync(folderPath)) {
|
|
358
|
-
consola.info(`Creating journal directory: ${colors.cyan(folderPath)}`);
|
|
359
|
-
mkdirSync(folderPath, { recursive: true });
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function createJournalContent({ mondayDate }) {
|
|
363
|
-
const weekInfo = getWeekInfo(mondayDate);
|
|
364
|
-
const content = [`# Journal for Week ${formatDate(mondayDate)}`];
|
|
365
|
-
content.push(``);
|
|
366
|
-
content.push(`## ${formatDate(weekInfo.mondayDate)} Monday`);
|
|
367
|
-
content.push(``);
|
|
368
|
-
content.push(`## ${formatDate(weekInfo.tuesdayDate)} Tuesday`);
|
|
369
|
-
content.push(``);
|
|
370
|
-
content.push(`## ${formatDate(weekInfo.wednesdayDate)} Wednesday`);
|
|
371
|
-
content.push(``);
|
|
372
|
-
content.push(`## ${formatDate(weekInfo.thursdayDate)} Thursday`);
|
|
373
|
-
content.push(``);
|
|
374
|
-
content.push(`## ${formatDate(weekInfo.fridayDate)} Friday`);
|
|
375
|
-
content.push(``);
|
|
376
|
-
return content.join("\n");
|
|
377
|
-
}
|
|
378
|
-
function createMeetingContent({ title, date }) {
|
|
379
|
-
const dateStr = formatDate(date);
|
|
380
|
-
const timeStr = date.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit" });
|
|
381
|
-
const content = [`# Meeting: ${title || "Meeting"}`];
|
|
382
|
-
content.push(``);
|
|
383
|
-
content.push(`**Date:** ${dateStr}`);
|
|
384
|
-
content.push(`**Time:** ${timeStr}`);
|
|
385
|
-
content.push(`**Attendees:** `);
|
|
386
|
-
content.push(``);
|
|
387
|
-
content.push(`## Agenda`);
|
|
388
|
-
content.push(``);
|
|
389
|
-
content.push(`- `);
|
|
390
|
-
content.push(``);
|
|
391
|
-
content.push(`## Notes`);
|
|
392
|
-
content.push(``);
|
|
393
|
-
content.push(`## Action Items`);
|
|
394
|
-
content.push(``);
|
|
395
|
-
content.push(`- [ ] `);
|
|
396
|
-
content.push(``);
|
|
397
|
-
content.push(`## Follow-up`);
|
|
398
|
-
content.push(``);
|
|
399
|
-
return content.join("\n");
|
|
400
|
-
}
|
|
401
|
-
function createNoteContent({ title, date }) {
|
|
402
|
-
const dateStr = formatDate(date);
|
|
403
|
-
const timeStr = date.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit" });
|
|
404
|
-
const content = [`# ${title || "Note"}`];
|
|
405
|
-
content.push(``);
|
|
406
|
-
content.push(`**Created:** ${dateStr} ${timeStr}`);
|
|
407
|
-
content.push(``);
|
|
408
|
-
content.push(`## Summary`);
|
|
409
|
-
content.push(``);
|
|
410
|
-
content.push(`## Details`);
|
|
411
|
-
content.push(``);
|
|
412
|
-
content.push(`## References`);
|
|
413
|
-
content.push(``);
|
|
414
|
-
return content.join("\n");
|
|
415
|
-
}
|
|
416
|
-
async function openInEditor({ editor, filePath, folderPath }) {
|
|
417
|
-
try {
|
|
418
|
-
if (folderPath) {
|
|
419
|
-
await execAsync(`"${editor}" "${folderPath}" "${filePath}"`);
|
|
420
|
-
} else {
|
|
421
|
-
await execAsync(`"${editor}" "${filePath}"`);
|
|
422
|
-
}
|
|
423
|
-
} catch (ex) {
|
|
424
|
-
consola.warn(`Could not open in editor : '${editor}'. Modify your editor in the config: examples include 'code', 'code-insiders', etc...`, ex);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
function resolvePathTemplate(template, title, date, mondayDate) {
|
|
428
|
-
const dateTime = DateTime.fromJSDate(date, { zone: "utc" });
|
|
429
|
-
return template.replace(/\{([^}]+)\}/g, (match, token) => {
|
|
430
|
-
try {
|
|
431
|
-
if (token === "title") {
|
|
432
|
-
return title.toLowerCase().replace(/\s+/g, "-");
|
|
433
|
-
}
|
|
434
|
-
if (token.startsWith("monday:")) {
|
|
435
|
-
const mondayToken = token.substring(7);
|
|
436
|
-
const mondayDateTime = DateTime.fromJSDate(mondayDate, { zone: "utc" });
|
|
437
|
-
return mondayDateTime.toFormat(mondayToken);
|
|
438
|
-
}
|
|
439
|
-
const result = dateTime.toFormat(token);
|
|
440
|
-
const isLikelyInvalid = token.includes("invalid") || result.length > 20 || // Very long results are likely garbage
|
|
441
|
-
result.length > token.length * 2 && /\d{10,}/.test(result) || // Contains very long numbers
|
|
442
|
-
result.includes("UTC");
|
|
443
|
-
if (isLikelyInvalid) {
|
|
444
|
-
consola.warn(`Invalid date format token: ${token}`);
|
|
445
|
-
return match;
|
|
446
|
-
}
|
|
447
|
-
return result;
|
|
448
|
-
} catch (error) {
|
|
449
|
-
consola.warn(`Invalid date format token: ${token}`);
|
|
450
|
-
return match;
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
function generateJournalFileInfoByType({ journalSettings, date = /* @__PURE__ */ new Date(), type, title }) {
|
|
455
|
-
const currentDate = new Date(date);
|
|
456
|
-
let templatePath = "";
|
|
457
|
-
let mondayDate = getMondayOfWeek(currentDate);
|
|
458
|
-
switch (type) {
|
|
459
|
-
case JOURNAL_TYPES.DAILY_NOTES: {
|
|
460
|
-
const monday = getMondayOfWeek(currentDate);
|
|
461
|
-
templatePath = journalSettings.dailyPathTemplate;
|
|
462
|
-
mondayDate = monday;
|
|
463
|
-
break;
|
|
464
|
-
}
|
|
465
|
-
case JOURNAL_TYPES.MEETING: {
|
|
466
|
-
templatePath = journalSettings.meetingPathTemplate;
|
|
467
|
-
mondayDate = currentDate;
|
|
468
|
-
break;
|
|
469
|
-
}
|
|
470
|
-
case JOURNAL_TYPES.NOTE: {
|
|
471
|
-
templatePath = journalSettings.notePathTemplate;
|
|
472
|
-
mondayDate = currentDate;
|
|
473
|
-
break;
|
|
474
|
-
}
|
|
475
|
-
default:
|
|
476
|
-
throw new Error(`Unknown JournalType: ${type}`);
|
|
477
|
-
}
|
|
478
|
-
const resolvedPath = resolvePathTemplate(templatePath, title, currentDate, mondayDate);
|
|
479
|
-
const fullPath = path__default.join(journalSettings.baseFolder, resolvedPath);
|
|
480
|
-
return {
|
|
481
|
-
currentDate,
|
|
482
|
-
fullPath,
|
|
483
|
-
mondayDate
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
async function createJournalFile({ context, type, title }) {
|
|
487
|
-
try {
|
|
488
|
-
if (title.trim().length === 0 && (type === JOURNAL_TYPES.MEETING || type === JOURNAL_TYPES.NOTE)) {
|
|
489
|
-
title = await consola.prompt(`Enter ${type} title:`, {
|
|
490
|
-
type: "text"
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
const currentDate = /* @__PURE__ */ new Date();
|
|
494
|
-
const fileInfo = generateJournalFileInfoByType({
|
|
495
|
-
journalSettings: context.settingsFile.settings.journalSettings,
|
|
496
|
-
date: currentDate,
|
|
497
|
-
type,
|
|
498
|
-
title
|
|
499
|
-
});
|
|
500
|
-
ensureDirectoryExists(path__default.dirname(fileInfo.fullPath));
|
|
501
|
-
if (existsSync(fileInfo.fullPath)) {
|
|
502
|
-
consola.info(`Opening existing ${type} file: ${colors.cyan(fileInfo.fullPath)}`);
|
|
503
|
-
} else {
|
|
504
|
-
let content;
|
|
505
|
-
switch (type) {
|
|
506
|
-
case JOURNAL_TYPES.DAILY_NOTES:
|
|
507
|
-
content = createJournalContent({ mondayDate: fileInfo.mondayDate });
|
|
508
|
-
break;
|
|
509
|
-
case JOURNAL_TYPES.MEETING:
|
|
510
|
-
content = createMeetingContent({ title, date: currentDate });
|
|
511
|
-
break;
|
|
512
|
-
case JOURNAL_TYPES.NOTE:
|
|
513
|
-
content = createNoteContent({ title, date: currentDate });
|
|
514
|
-
break;
|
|
515
|
-
default:
|
|
516
|
-
throw new Error(`Unknown journal type: ${type}`);
|
|
517
|
-
}
|
|
518
|
-
consola.info(`Creating new ${type} file: ${colors.cyan(fileInfo.fullPath)}`);
|
|
519
|
-
writeFileSync(fileInfo.fullPath, content, "utf8");
|
|
520
|
-
}
|
|
521
|
-
await openInEditor({
|
|
522
|
-
editor: context.settingsFile.settings.preferredEditor,
|
|
523
|
-
filePath: fileInfo.fullPath,
|
|
524
|
-
folderPath: context.settingsFile.settings.journalSettings.baseFolder
|
|
525
|
-
});
|
|
526
|
-
} catch (error) {
|
|
527
|
-
consola.warn(`Error creating ${type} file:`, error);
|
|
528
|
-
process$1.exit(1);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
async function configCommand(context) {
|
|
533
|
-
consola.info("Configuration");
|
|
534
|
-
consola.log("");
|
|
535
|
-
consola.info(`Settings File: ${context.settingsFile.path}`);
|
|
536
|
-
consola.log("");
|
|
537
|
-
consola.warn("User Config:");
|
|
538
|
-
consola.log(` Daily Path Template: ${context.settingsFile.settings.journalSettings.dailyPathTemplate}`);
|
|
539
|
-
consola.log(` Meeting Path Template: ${context.settingsFile.settings.journalSettings.meetingPathTemplate}`);
|
|
540
|
-
consola.log(` Note Path Template: ${context.settingsFile.settings.journalSettings.notePathTemplate}`);
|
|
541
|
-
consola.log(` Editor: ${context.settingsFile.settings.preferredEditor}`);
|
|
542
|
-
consola.log("");
|
|
543
|
-
consola.warn("Working Directory:");
|
|
544
|
-
consola.log(` ${context.cwd}`);
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
const isGithubCliInstalled = async () => {
|
|
548
|
-
try {
|
|
549
|
-
const proc = await exec$1(`gh`, ["--version"]);
|
|
550
|
-
return proc.stdout.indexOf("https://github.com/cli/cli") > 0;
|
|
551
|
-
} catch (e) {
|
|
552
|
-
return false;
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
const getIssues = async ({ assignedToMe, cwd }) => {
|
|
556
|
-
let issues = [];
|
|
557
|
-
const flags = [
|
|
558
|
-
"issue",
|
|
559
|
-
"list",
|
|
560
|
-
"--json",
|
|
561
|
-
"labels,number,title,state"
|
|
562
|
-
];
|
|
563
|
-
if (assignedToMe) {
|
|
564
|
-
flags.push("--assignee");
|
|
565
|
-
flags.push("@me");
|
|
566
|
-
}
|
|
567
|
-
const result = await exec$1(`gh`, flags);
|
|
568
|
-
const striped = stripAnsi(result.stdout);
|
|
569
|
-
issues = JSON.parse(striped);
|
|
570
|
-
return issues;
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
const createBranch = async ({ branchName }) => {
|
|
574
|
-
const result = await exec$1(`git`, ["checkout", "-b", branchName]);
|
|
575
|
-
return result.stdout;
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
const getTerminalColumns = () => process.stdout?.columns || 80;
|
|
579
|
-
const limitText = (text, maxWidth) => {
|
|
580
|
-
if (text.length <= maxWidth)
|
|
581
|
-
return text;
|
|
582
|
-
return `${text.slice(0, maxWidth - 1)}${colors.dim("\u2026")}`;
|
|
583
|
-
};
|
|
584
|
-
function hexToRgb(hex) {
|
|
585
|
-
const cleanHex = hex.replace("#", "");
|
|
586
|
-
const r = Number.parseInt(cleanHex.slice(0, 2), 16);
|
|
587
|
-
const g = Number.parseInt(cleanHex.slice(2, 4), 16);
|
|
588
|
-
const b = Number.parseInt(cleanHex.slice(4, 6), 16);
|
|
589
|
-
return { r, g, b };
|
|
590
|
-
}
|
|
591
|
-
function printWithHexColor({ msg, hex }) {
|
|
592
|
-
const colorWithHex = hex.startsWith("#") ? hex : `#${hex}`;
|
|
593
|
-
const { r, g, b } = hexToRgb(colorWithHex);
|
|
594
|
-
const colorStart = `\x1B[38;2;${r};${g};${b}m`;
|
|
595
|
-
const colorEnd = "\x1B[0m";
|
|
596
|
-
return `${colorStart}${msg}${colorEnd}`;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
const checkPreqrequisites = async () => {
|
|
600
|
-
const cliInstalled = await isGithubCliInstalled();
|
|
601
|
-
if (!cliInstalled) {
|
|
602
|
-
consola.log("Github CLI not installed");
|
|
603
|
-
process.exit(1);
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
function customTrimEnd(str, charsToTrim) {
|
|
607
|
-
let i = str.length - 1;
|
|
608
|
-
while (i >= 0 && charsToTrim.includes(str[i])) {
|
|
609
|
-
i--;
|
|
610
|
-
}
|
|
611
|
-
return str.substring(0, i + 1);
|
|
612
|
-
}
|
|
613
|
-
const createBranchNameFromIssue = (selectedIssue) => {
|
|
614
|
-
let slug = selectedIssue.title.toLowerCase();
|
|
615
|
-
slug = slug.trim();
|
|
616
|
-
slug = slug.replaceAll(" ", "-");
|
|
617
|
-
slug = slug.replace(/[^0-9a-zA-Z_]/g, "-");
|
|
618
|
-
slug = slug.replaceAll("--", "-");
|
|
619
|
-
slug = slug.replaceAll("--", "-");
|
|
620
|
-
slug = slug.replaceAll("--", "-");
|
|
621
|
-
slug = customTrimEnd(slug, ["-"]);
|
|
622
|
-
const branchName = `feature/${selectedIssue.number}-${slug}`;
|
|
623
|
-
return branchName;
|
|
624
|
-
};
|
|
625
|
-
async function githubBranchCommand(context, args) {
|
|
626
|
-
await checkPreqrequisites();
|
|
627
|
-
const assignedToMe = Boolean(args.assignedToMe);
|
|
628
|
-
consola.log("Assigned to me:", assignedToMe);
|
|
629
|
-
const currentIssues = await getIssues({ assignedToMe, cwd: context.cwd });
|
|
630
|
-
if (currentIssues.length === 0) {
|
|
631
|
-
consola.log(colors.yellow("No issues found, check assignments"));
|
|
632
|
-
process.exit(1);
|
|
633
|
-
} else {
|
|
634
|
-
consola.log(colors.green(`${currentIssues.length} Issues found assigned to you`));
|
|
635
|
-
}
|
|
636
|
-
let lineMaxLength = getTerminalColumns();
|
|
637
|
-
const longestNumber = Math.max(...currentIssues.map((i) => i.number.toString().length));
|
|
638
|
-
const longestLabels = Math.max(...currentIssues.map((i) => i.labels.map((x) => x.name).join(", ").length));
|
|
639
|
-
lineMaxLength = lineMaxLength > 130 ? 130 : lineMaxLength;
|
|
640
|
-
const descriptionLength = lineMaxLength - longestNumber - longestLabels - 15;
|
|
641
|
-
const choices = currentIssues.map(
|
|
642
|
-
(i) => {
|
|
643
|
-
const labelText = i.labels.map((l) => printWithHexColor({ msg: l.name, hex: l.color })).join(", ");
|
|
644
|
-
const labelTextNoColor = i.labels.map((l) => l.name).join(", ");
|
|
645
|
-
const labelStartpad = longestLabels - labelTextNoColor.length;
|
|
646
|
-
return {
|
|
647
|
-
title: i.number.toString(),
|
|
648
|
-
value: i.number,
|
|
649
|
-
description: `${limitText(i.title, descriptionLength).padEnd(descriptionLength)} ${"".padStart(labelStartpad)}${labelText}`
|
|
650
|
-
// pads to make sure the labels are aligned, no diea why padStart doesn't work on labelText
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
);
|
|
654
|
-
choices.push({ title: "Cancel", value: "cancel" });
|
|
655
|
-
const fzf = new Fzf(choices, {
|
|
656
|
-
selector: (item) => `${item.value} ${item.description}`,
|
|
657
|
-
casing: "case-insensitive"
|
|
658
|
-
});
|
|
659
|
-
try {
|
|
660
|
-
const result = await prompts({
|
|
661
|
-
name: "issueNumber",
|
|
662
|
-
message: "Github issue to create branch for:",
|
|
663
|
-
type: "autocomplete",
|
|
664
|
-
choices,
|
|
665
|
-
async suggest(input, choices2) {
|
|
666
|
-
consola.log(input);
|
|
667
|
-
const results = fzf.find(input);
|
|
668
|
-
return results.map((r) => choices2.find((c) => c.value === r.item.value));
|
|
669
|
-
}
|
|
670
|
-
}, {
|
|
671
|
-
// when escape is used just cancel
|
|
672
|
-
onCancel: () => {
|
|
673
|
-
consola.info(colors.dim("Canceled"));
|
|
674
|
-
process.exit(0);
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
if (result.issueNumber === "cancel") {
|
|
678
|
-
consola.log(colors.dim("Canceled"));
|
|
679
|
-
process.exit(0);
|
|
680
|
-
}
|
|
681
|
-
const selectedIssue = currentIssues.find((i) => i.number === result.issueNumber);
|
|
682
|
-
consola.log(`Selected issue ${colors.green(selectedIssue.number)} - ${colors.green(selectedIssue.title)}`);
|
|
683
|
-
const branchName = createBranchNameFromIssue(selectedIssue);
|
|
684
|
-
createBranch({ branchName });
|
|
685
|
-
} catch (e) {
|
|
686
|
-
process.exit(1);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
const CINCINNATI_LATITUDE = 39.1031;
|
|
691
|
-
const CINCINNATI_LONGITUDE = -84.512;
|
|
692
|
-
const WEATHER_DESCRIPTIONS = {
|
|
693
|
-
0: { description: "Clear sky", emoji: "\u2600\uFE0F" },
|
|
694
|
-
1: { description: "Mainly clear", emoji: "\u{1F324}\uFE0F" },
|
|
695
|
-
2: { description: "Partly cloudy", emoji: "\u26C5" },
|
|
696
|
-
3: { description: "Overcast", emoji: "\u2601\uFE0F" },
|
|
697
|
-
45: { description: "Fog", emoji: "\u{1F32B}\uFE0F" },
|
|
698
|
-
48: { description: "Depositing rime fog", emoji: "\u{1F32B}\uFE0F" },
|
|
699
|
-
51: { description: "Light drizzle", emoji: "\u{1F326}\uFE0F" },
|
|
700
|
-
53: { description: "Moderate drizzle", emoji: "\u{1F326}\uFE0F" },
|
|
701
|
-
55: { description: "Dense drizzle", emoji: "\u{1F327}\uFE0F" },
|
|
702
|
-
56: { description: "Light freezing drizzle", emoji: "\u{1F328}\uFE0F" },
|
|
703
|
-
57: { description: "Dense freezing drizzle", emoji: "\u{1F328}\uFE0F" },
|
|
704
|
-
61: { description: "Slight rain", emoji: "\u{1F327}\uFE0F" },
|
|
705
|
-
63: { description: "Moderate rain", emoji: "\u{1F327}\uFE0F" },
|
|
706
|
-
65: { description: "Heavy rain", emoji: "\u{1F327}\uFE0F" },
|
|
707
|
-
66: { description: "Light freezing rain", emoji: "\u{1F328}\uFE0F" },
|
|
708
|
-
67: { description: "Heavy freezing rain", emoji: "\u{1F328}\uFE0F" },
|
|
709
|
-
71: { description: "Slight snow fall", emoji: "\u{1F328}\uFE0F" },
|
|
710
|
-
73: { description: "Moderate snow fall", emoji: "\u2744\uFE0F" },
|
|
711
|
-
75: { description: "Heavy snow fall", emoji: "\u2744\uFE0F" },
|
|
712
|
-
77: { description: "Snow grains", emoji: "\u{1F328}\uFE0F" },
|
|
713
|
-
80: { description: "Slight rain showers", emoji: "\u{1F326}\uFE0F" },
|
|
714
|
-
81: { description: "Moderate rain showers", emoji: "\u{1F327}\uFE0F" },
|
|
715
|
-
82: { description: "Violent rain showers", emoji: "\u26C8\uFE0F" },
|
|
716
|
-
85: { description: "Slight snow showers", emoji: "\u{1F328}\uFE0F" },
|
|
717
|
-
86: { description: "Heavy snow showers", emoji: "\u2744\uFE0F" },
|
|
718
|
-
95: { description: "Thunderstorm", emoji: "\u26C8\uFE0F" },
|
|
719
|
-
96: { description: "Thunderstorm with slight hail", emoji: "\u26C8\uFE0F" },
|
|
720
|
-
99: { description: "Thunderstorm with heavy hail", emoji: "\u26C8\uFE0F" }
|
|
721
|
-
};
|
|
722
|
-
function getWindDirection(degrees) {
|
|
723
|
-
const directions = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"];
|
|
724
|
-
const index = Math.round(degrees / 22.5) % 16;
|
|
725
|
-
return directions[index];
|
|
726
|
-
}
|
|
727
|
-
function formatWeatherData(data) {
|
|
728
|
-
const { current_weather: weather, current_weather_units: units } = data;
|
|
729
|
-
const weatherInfo = WEATHER_DESCRIPTIONS[weather.weathercode] || {
|
|
730
|
-
description: "Unknown",
|
|
731
|
-
emoji: "\u2753"
|
|
732
|
-
};
|
|
733
|
-
const windDirection = getWindDirection(weather.winddirection);
|
|
734
|
-
const timeOfDay = weather.is_day ? "Day" : "Night";
|
|
735
|
-
consola.info("\u{1F30E} Current Weather in Cincinnati, OH");
|
|
736
|
-
consola.log("");
|
|
737
|
-
consola.log(`${weatherInfo.emoji} ${weatherInfo.description}`);
|
|
738
|
-
consola.log(`\u{1F321}\uFE0F Temperature: ${weather.temperature}${units.temperature}`);
|
|
739
|
-
consola.log(`\u{1F4A8} Wind: ${weather.windspeed} ${units.windspeed} ${windDirection}`);
|
|
740
|
-
consola.log(`\u{1F550} Time: ${new Date(weather.time).toLocaleTimeString()} (${timeOfDay})`);
|
|
741
|
-
}
|
|
742
|
-
async function weatherCommand(context) {
|
|
743
|
-
try {
|
|
744
|
-
consola.start("Fetching current weather for Cincinnati...");
|
|
745
|
-
const url = `https://api.open-meteo.com/v1/forecast?latitude=${CINCINNATI_LATITUDE}&longitude=${CINCINNATI_LONGITUDE}¤t_weather=true&temperature_unit=fahrenheit&windspeed_unit=mph&timezone=America/New_York`;
|
|
746
|
-
const response = await fetch(url);
|
|
747
|
-
if (!response.ok) {
|
|
748
|
-
throw new Error(`Weather API request failed: ${response.status} ${response.statusText}`);
|
|
749
|
-
}
|
|
750
|
-
const data = await response.json();
|
|
751
|
-
if (!data.current_weather) {
|
|
752
|
-
throw new Error("No weather data received from API");
|
|
753
|
-
}
|
|
754
|
-
consola.success("Weather data retrieved successfully!");
|
|
755
|
-
consola.log("");
|
|
756
|
-
formatWeatherData(data);
|
|
757
|
-
} catch (error) {
|
|
758
|
-
consola.error("Failed to fetch weather data:", error instanceof Error ? error.message : String(error));
|
|
759
|
-
process.exit(1);
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
async function executeCommand(parsedArgs, context) {
|
|
764
|
-
switch (parsedArgs.command) {
|
|
765
|
-
case "journal": {
|
|
766
|
-
await createJournalFile({ context, type: parsedArgs.args.jouralType, title: parsedArgs.args.title || "" });
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
case "git-commit":
|
|
770
|
-
await gitCommitCommand(context, parsedArgs.args.message);
|
|
771
|
-
break;
|
|
772
|
-
case "gh-branch":
|
|
773
|
-
await githubBranchCommand(context, parsedArgs.args);
|
|
774
|
-
break;
|
|
775
|
-
case "config":
|
|
776
|
-
await configCommand(context);
|
|
777
|
-
break;
|
|
778
|
-
case "weather":
|
|
779
|
-
await weatherCommand();
|
|
780
|
-
break;
|
|
781
|
-
default:
|
|
782
|
-
throw new Error(`Unknown command: ${parsedArgs.command}`);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
async function main() {
|
|
786
|
-
const settings = await loadSettings();
|
|
787
|
-
const context = await loadTowlesToolContext({
|
|
788
|
-
cwd: process$1.cwd(),
|
|
789
|
-
settingsFile: settings.settingsFile,
|
|
790
|
-
debug: true
|
|
791
|
-
// later can be set to false in production or when not debugging
|
|
792
|
-
});
|
|
793
|
-
consola.info(`Using configuration from ${settings.settingsFile.path}`);
|
|
794
|
-
const parsedArgs = await parseArguments(process$1.argv);
|
|
795
|
-
await executeCommand(parsedArgs, context);
|
|
796
|
-
}
|
|
797
|
-
main().catch((error) => {
|
|
798
|
-
consola.error("An unexpected critical error occurred:");
|
|
799
|
-
if (error instanceof Error) {
|
|
800
|
-
consola.error(error.stack);
|
|
801
|
-
} else {
|
|
802
|
-
consola.error(String(error));
|
|
803
|
-
}
|
|
804
|
-
process$1.exit(1);
|
|
805
|
-
});
|