@towles/tool 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/index.mjs +99 -281
- package/package.json +3 -12
package/README.md
CHANGED
|
@@ -70,11 +70,16 @@ if that works, then you need to add the pnpm global bin directory to your PATH.
|
|
|
70
70
|
- [@anthropic-ai/claude-code](https://github.com/anthropic-ai/claude-code) - A library for interacting with the Claude code
|
|
71
71
|
- [zod](https://github.com/colinhacks/zod) - TypeScript-first schema validation
|
|
72
72
|
- [Consola](https://github.com/unjs/consola) console wrapper and colors
|
|
73
|
-
- [c12](https://github.com/unjs/c12) configuration loader and utilities
|
|
73
|
+
- ~~[c12](https://github.com/unjs/c12) configuration loader and utilities~~
|
|
74
|
+
- referted stayed to json config
|
|
74
75
|
- [rolldown-vite](https://voidzero.dev/posts/announcing-rolldown-vite) - A Vite plugin for rolling down your code
|
|
75
76
|
- ~~[zx](https://github.com/google/zx) google created library to write shell scripts in a more powerful and expressive way via the Anthropic API.~~
|
|
76
77
|
- [prompts](https://github.com/terkelg/prompts) - A library for creating beautiful command-line prompts, with fuzzy search and other features.
|
|
77
78
|
- [yargs](https://github.com/yargs/yargs) - A modern, feature-rich command-line argument parser with enhanced error handling, TypeScript support, and flexible command configuration.
|
|
79
|
+
- ~~[ink](https://github.com/vadimdemedes/ink) - React for interactive command-line apps~~
|
|
80
|
+
- wanted hotkey support and more complex UI but this was overkill for this project.
|
|
81
|
+
- [publint](https://publint.dev/)
|
|
82
|
+
- [e18e.dev](https://e18e.dev/guide/resources.html)
|
|
78
83
|
|
|
79
84
|
## Document verbose and debug options
|
|
80
85
|
|
package/dist/index.mjs
CHANGED
|
@@ -2,312 +2,119 @@
|
|
|
2
2
|
import process$1 from 'node:process';
|
|
3
3
|
import yargs from 'yargs';
|
|
4
4
|
import { hideBin } from 'yargs/helpers';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import consola from 'consola';
|
|
6
|
+
import prompts from 'prompts';
|
|
7
7
|
import { execSync, exec } from 'node:child_process';
|
|
8
8
|
import * as fs from 'node:fs';
|
|
9
9
|
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
10
10
|
import * as path from 'node:path';
|
|
11
11
|
import path__default from 'node:path';
|
|
12
12
|
import { promisify } from 'node:util';
|
|
13
|
-
import consola from 'consola';
|
|
14
13
|
import { colors } from 'consola/utils';
|
|
15
14
|
import { DateTime } from 'luxon';
|
|
16
15
|
import { z } from 'zod/v4';
|
|
17
16
|
import { homedir } from 'node:os';
|
|
18
17
|
import stripJsonComments from 'strip-json-comments';
|
|
19
18
|
|
|
20
|
-
const version = "0.0.
|
|
21
|
-
|
|
22
|
-
const AppContext = createContext(null);
|
|
23
|
-
function AppProvider({ children, initialCommandContext }) {
|
|
24
|
-
const [appState, setAppState] = useState({
|
|
25
|
-
isLoading: false,
|
|
26
|
-
error: null,
|
|
27
|
-
currentCommand: null
|
|
28
|
-
});
|
|
29
|
-
const [commandContext, setCommandContext] = useState({
|
|
30
|
-
mode: "interactive",
|
|
31
|
-
exitCode: 0,
|
|
32
|
-
onExit: (code = 0) => process.exit(code),
|
|
33
|
-
...initialCommandContext
|
|
34
|
-
});
|
|
35
|
-
const updateAppState = (updates) => {
|
|
36
|
-
setAppState((prev) => ({ ...prev, ...updates }));
|
|
37
|
-
};
|
|
38
|
-
const updateCommandContext = (updates) => {
|
|
39
|
-
setCommandContext((prev) => ({ ...prev, ...updates }));
|
|
40
|
-
};
|
|
41
|
-
return /* @__PURE__ */ React.createElement(AppContext.Provider, { value: {
|
|
42
|
-
appState,
|
|
43
|
-
updateAppState,
|
|
44
|
-
commandContext,
|
|
45
|
-
updateCommandContext
|
|
46
|
-
} }, children);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const ConfigContext = createContext(null);
|
|
50
|
-
function ConfigProvider({ children, context }) {
|
|
51
|
-
return /* @__PURE__ */ React.createElement(ConfigContext.Provider, { value: { context } }, children);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const AppInfo = {
|
|
55
|
-
toolName: "towles-tool"
|
|
56
|
-
};
|
|
57
|
-
const DEFAULT_THEME = {
|
|
58
|
-
primary: "cyan",
|
|
59
|
-
warning: "yellow",
|
|
60
|
-
error: "red",
|
|
61
|
-
dim: "dim"
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
class ErrorBoundary extends Component {
|
|
65
|
-
constructor(props) {
|
|
66
|
-
super(props);
|
|
67
|
-
this.state = { hasError: false };
|
|
68
|
-
}
|
|
69
|
-
static getDerivedStateFromError(error) {
|
|
70
|
-
return { hasError: true, error };
|
|
71
|
-
}
|
|
72
|
-
componentDidCatch(error, errorInfo) {
|
|
73
|
-
}
|
|
74
|
-
render() {
|
|
75
|
-
if (this.state.hasError) {
|
|
76
|
-
if (this.props.fallback) {
|
|
77
|
-
return this.props.fallback;
|
|
78
|
-
}
|
|
79
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: DEFAULT_THEME.error }, "Application Error"), /* @__PURE__ */ React.createElement(Text, { color: DEFAULT_THEME.error }, this.state.error?.message || "An unexpected error occurred"), /* @__PURE__ */ React.createElement(Text, { color: DEFAULT_THEME.dim }, "Press ESC to exit"));
|
|
80
|
-
}
|
|
81
|
-
return this.props.children;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
19
|
+
const version = "0.0.13";
|
|
84
20
|
|
|
85
21
|
function execCommand(cmd, cwd) {
|
|
86
22
|
return execSync(cmd, { encoding: "utf8", cwd }).trim();
|
|
87
23
|
}
|
|
88
24
|
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
setLoading(true);
|
|
95
|
-
setError(null);
|
|
96
|
-
const statusOutput = execCommand("git status --porcelain", cwd);
|
|
97
|
-
const lines = statusOutput.trim().split("\n").filter((line) => line.length > 0);
|
|
98
|
-
const staged = lines.filter((line) => line[0] !== " " && line[0] !== "?").map((line) => line.slice(3));
|
|
99
|
-
const unstaged = lines.filter((line) => line[1] !== " " && line[1] !== "?").map((line) => line.slice(3));
|
|
100
|
-
const untracked = lines.filter((line) => line.startsWith("??")).map((line) => line.slice(3));
|
|
101
|
-
return { staged, unstaged, untracked };
|
|
102
|
-
} catch (err) {
|
|
103
|
-
setError("Failed to get git status");
|
|
104
|
-
return null;
|
|
105
|
-
} finally {
|
|
106
|
-
setLoading(false);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
const stageFiles = async (files) => {
|
|
110
|
-
try {
|
|
111
|
-
setLoading(true);
|
|
112
|
-
setError(null);
|
|
113
|
-
if (files.length === 0) return false;
|
|
114
|
-
const command = files.includes(".") ? "git add ." : `git add ${files.map((f) => `"${f}"`).join(" ")}`;
|
|
115
|
-
execCommand(command, cwd);
|
|
116
|
-
return true;
|
|
117
|
-
} catch (err) {
|
|
118
|
-
setError("Failed to stage files");
|
|
119
|
-
return false;
|
|
120
|
-
} finally {
|
|
121
|
-
setLoading(false);
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
const commit = async (message) => {
|
|
125
|
-
try {
|
|
126
|
-
setLoading(true);
|
|
127
|
-
setError(null);
|
|
128
|
-
const escapedMessage = message.replace(/"/g, '\\"');
|
|
129
|
-
execCommand(`git commit -m "${escapedMessage}"`, cwd);
|
|
130
|
-
return true;
|
|
131
|
-
} catch (err) {
|
|
132
|
-
setError("Failed to commit changes");
|
|
133
|
-
return false;
|
|
134
|
-
} finally {
|
|
135
|
-
setLoading(false);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
return {
|
|
139
|
-
getGitStatus,
|
|
140
|
-
stageFiles,
|
|
141
|
-
commit,
|
|
142
|
-
loading,
|
|
143
|
-
error,
|
|
144
|
-
clearError: () => setError(null)
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function GitCommit({ context, messageArgs, onExit }) {
|
|
149
|
-
const { getGitStatus, stageFiles, commit, loading, error } = useGitOperations(context.cwd);
|
|
150
|
-
const [step, setStep] = useState("loading");
|
|
151
|
-
const [gitStatus, setGitStatus] = useState(null);
|
|
152
|
-
const [commitMessage, setCommitMessage] = useState(messageArgs?.join(" ") || "");
|
|
153
|
-
const [userInput, setUserInput] = useState("");
|
|
154
|
-
const [waitingForInput, setWaitingForInput] = useState(false);
|
|
155
|
-
useEffect(() => {
|
|
156
|
-
async function init() {
|
|
157
|
-
const status = await getGitStatus();
|
|
158
|
-
if (status) {
|
|
159
|
-
setGitStatus(status);
|
|
160
|
-
if (status.staged.length === 0 && status.unstaged.length === 0 && status.untracked.length === 0) {
|
|
161
|
-
setStep("success");
|
|
162
|
-
} else if (status.staged.length === 0) {
|
|
163
|
-
setStep("staging");
|
|
164
|
-
setWaitingForInput(true);
|
|
165
|
-
} else if (messageArgs && messageArgs.length > 0) {
|
|
166
|
-
setStep("commit");
|
|
167
|
-
setCommitMessage(messageArgs.join(" "));
|
|
168
|
-
} else {
|
|
169
|
-
setStep("message");
|
|
170
|
-
setWaitingForInput(true);
|
|
171
|
-
}
|
|
172
|
-
} else {
|
|
173
|
-
setStep("error");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
init();
|
|
177
|
-
}, []);
|
|
178
|
-
useInput((input, key) => {
|
|
179
|
-
if (key.escape) {
|
|
180
|
-
onExit();
|
|
25
|
+
async function gitCommitCommand(context, messageArgs) {
|
|
26
|
+
try {
|
|
27
|
+
const status = await getGitStatus(context.cwd);
|
|
28
|
+
if (!status || status.staged.length === 0 && status.unstaged.length === 0 && status.untracked.length === 0) {
|
|
29
|
+
consola.success("\u2713 Working tree clean - nothing to commit");
|
|
181
30
|
return;
|
|
182
31
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
} else if (key.backspace || key.delete) {
|
|
195
|
-
setUserInput((prev) => prev.slice(0, -1));
|
|
196
|
-
} else if (input && !key.ctrl && !key.meta) {
|
|
197
|
-
setUserInput((prev) => prev + input);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
const handleStageFiles = async () => {
|
|
202
|
-
setWaitingForInput(false);
|
|
203
|
-
const success = await stageFiles(["."]);
|
|
204
|
-
if (success) {
|
|
205
|
-
const newStatus = await getGitStatus();
|
|
206
|
-
if (newStatus) {
|
|
207
|
-
setGitStatus(newStatus);
|
|
208
|
-
if (messageArgs && messageArgs.length > 0) {
|
|
209
|
-
setStep("commit");
|
|
210
|
-
} else {
|
|
211
|
-
setStep("message");
|
|
212
|
-
setWaitingForInput(true);
|
|
213
|
-
}
|
|
32
|
+
displayGitStatus(status);
|
|
33
|
+
if (status.staged.length === 0) {
|
|
34
|
+
const shouldStage = await prompts({
|
|
35
|
+
type: "confirm",
|
|
36
|
+
name: "stage",
|
|
37
|
+
message: "No files are staged. Add all modified and untracked files?",
|
|
38
|
+
initial: true
|
|
39
|
+
});
|
|
40
|
+
if (!shouldStage.stage) {
|
|
41
|
+
consola.info("Cancelled");
|
|
42
|
+
return;
|
|
214
43
|
}
|
|
215
|
-
|
|
216
|
-
|
|
44
|
+
consola.start("Staging files...");
|
|
45
|
+
await execCommand("git add .", context.cwd);
|
|
46
|
+
consola.success("Files staged");
|
|
217
47
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
48
|
+
let commitMessage = messageArgs?.join(" ") || "";
|
|
49
|
+
if (!commitMessage) {
|
|
50
|
+
const response = await prompts({
|
|
51
|
+
type: "text",
|
|
52
|
+
name: "message",
|
|
53
|
+
message: "Enter commit message:",
|
|
54
|
+
validate: (value) => value.trim().length > 0 || "Commit message cannot be empty"
|
|
55
|
+
});
|
|
56
|
+
if (!response.message) {
|
|
57
|
+
consola.info("Cancelled");
|
|
58
|
+
return;
|
|
228
59
|
}
|
|
229
|
-
|
|
60
|
+
commitMessage = response.message;
|
|
230
61
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
62
|
+
consola.start("Creating commit...");
|
|
63
|
+
await execCommand(`git commit -m "${commitMessage}"`, context.cwd);
|
|
64
|
+
consola.success("\u2713 Commit created successfully!");
|
|
65
|
+
} catch (error) {
|
|
66
|
+
consola.error("Git commit failed:", error instanceof Error ? error.message : String(error));
|
|
67
|
+
process.exit(1);
|
|
237
68
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
69
|
+
}
|
|
70
|
+
async function getGitStatus(cwd) {
|
|
71
|
+
try {
|
|
72
|
+
const output = await execCommand("git status --porcelain", cwd);
|
|
73
|
+
const lines = output.trim().split("\n").filter((line) => line.trim());
|
|
74
|
+
const staged = [];
|
|
75
|
+
const unstaged = [];
|
|
76
|
+
const untracked = [];
|
|
77
|
+
for (const line of lines) {
|
|
78
|
+
const status = line.substring(0, 2);
|
|
79
|
+
const file = line.substring(3);
|
|
80
|
+
if (status[0] !== " " && status[0] !== "?") {
|
|
81
|
+
staged.push(file);
|
|
82
|
+
}
|
|
83
|
+
if (status[1] !== " " && status[1] !== "?") {
|
|
84
|
+
unstaged.push(file);
|
|
85
|
+
}
|
|
86
|
+
if (status === "??") {
|
|
87
|
+
untracked.push(file);
|
|
88
|
+
}
|
|
243
89
|
}
|
|
90
|
+
return { staged, unstaged, untracked };
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
244
93
|
}
|
|
245
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, "Git Commit"), gitStatus && /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Current Status:"), gitStatus.staged.length > 0 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "green" }, "\u2713 Staged files (", gitStatus.staged.length, "):"), gitStatus.staged.slice(0, 5).map((file) => /* @__PURE__ */ React.createElement(Text, { key: file, color: "green" }, " ", file)), gitStatus.staged.length > 5 && /* @__PURE__ */ React.createElement(Text, { color: "green" }, " ... and ", gitStatus.staged.length - 5, " more")), gitStatus.unstaged.length > 0 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "M Modified files (", gitStatus.unstaged.length, "):"), gitStatus.unstaged.slice(0, 3).map((file) => /* @__PURE__ */ React.createElement(Text, { key: file, color: "yellow" }, " ", file)), gitStatus.unstaged.length > 3 && /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, " ... and ", gitStatus.unstaged.length - 3, " more")), gitStatus.untracked.length > 0 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "red" }, "? Untracked files (", gitStatus.untracked.length, "):"), gitStatus.untracked.slice(0, 3).map((file) => /* @__PURE__ */ React.createElement(Text, { key: file, color: "red" }, " ", file)), gitStatus.untracked.length > 3 && /* @__PURE__ */ React.createElement(Text, { color: "red" }, " ... and ", gitStatus.untracked.length - 3, " more"))), /* @__PURE__ */ React.createElement(Box, { marginTop: 2, flexDirection: "column" }, step === "staging" && waitingForInput && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "No files are staged. Add all modified and untracked files? (y/N)"), /* @__PURE__ */ React.createElement(Text, { color: "dim" }, "Press y for yes, n for no, or ESC to cancel")), step === "message" && waitingForInput && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Enter commit message:"), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "> "), /* @__PURE__ */ React.createElement(Text, null, userInput), /* @__PURE__ */ React.createElement(Text, { color: "dim" }, "\u2588")), /* @__PURE__ */ React.createElement(Text, { color: "dim" }, "Press Enter to commit, ESC to cancel")), step === "commit" && /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Committing changes...")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "dim" }, "Press ESC to cancel")));
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function ConfigDisplay({ context }) {
|
|
249
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "green" }, "Configuration"), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "Settings File: "), /* @__PURE__ */ React.createElement(Text, null, context.settingsFile.path)), /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "yellow" }, "User Config:"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "Daily Path Template: "), /* @__PURE__ */ React.createElement(Text, null, context.settingsFile.settings.journalSettings.dailyPathTemplate)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "Meeting Path Template: "), /* @__PURE__ */ React.createElement(Text, null, context.settingsFile.settings.journalSettings.meetingPathTemplate)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "Note Path Template: "), /* @__PURE__ */ React.createElement(Text, null, context.settingsFile.settings.journalSettings.notePathTemplate)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "Editor: "), /* @__PURE__ */ React.createElement(Text, null, context.settingsFile.settings.preferredEditor)))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "yellow" }, "Working Directory:"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, context.cwd))));
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function useTerminalSize() {
|
|
253
|
-
const [size, setSize] = useState({
|
|
254
|
-
columns: process.stdout.columns || 80,
|
|
255
|
-
rows: process.stdout.rows || 24
|
|
256
|
-
});
|
|
257
|
-
useEffect(() => {
|
|
258
|
-
const updateSize = () => {
|
|
259
|
-
setSize({
|
|
260
|
-
columns: process.stdout.columns || 80,
|
|
261
|
-
rows: process.stdout.rows || 24
|
|
262
|
-
});
|
|
263
|
-
};
|
|
264
|
-
process.stdout.on("resize", updateSize);
|
|
265
|
-
return () => {
|
|
266
|
-
process.stdout.off("resize", updateSize);
|
|
267
|
-
};
|
|
268
|
-
}, []);
|
|
269
|
-
return size;
|
|
270
94
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if (isExiting) {
|
|
280
|
-
return null;
|
|
95
|
+
function displayGitStatus(status) {
|
|
96
|
+
consola.info("Current git status:");
|
|
97
|
+
if (status.staged.length > 0) {
|
|
98
|
+
consola.success(`\u2713 Staged files (${status.staged.length}):`);
|
|
99
|
+
status.staged.slice(0, 5).forEach((file) => consola.log(` ${file}`));
|
|
100
|
+
if (status.staged.length > 5) {
|
|
101
|
+
consola.log(` ... and ${status.staged.length - 5} more`);
|
|
102
|
+
}
|
|
281
103
|
}
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
onExit: handleExit
|
|
289
|
-
}
|
|
290
|
-
);
|
|
104
|
+
if (status.unstaged.length > 0) {
|
|
105
|
+
consola.warn(`M Modified files (${status.unstaged.length}):`);
|
|
106
|
+
status.unstaged.slice(0, 3).forEach((file) => consola.log(` ${file}`));
|
|
107
|
+
if (status.unstaged.length > 3) {
|
|
108
|
+
consola.log(` ... and ${status.unstaged.length - 3} more`);
|
|
109
|
+
}
|
|
291
110
|
}
|
|
292
|
-
if (
|
|
293
|
-
|
|
111
|
+
if (status.untracked.length > 0) {
|
|
112
|
+
consola.error(`? Untracked files (${status.untracked.length}):`);
|
|
113
|
+
status.untracked.slice(0, 3).forEach((file) => consola.log(` ${file}`));
|
|
114
|
+
if (status.untracked.length > 3) {
|
|
115
|
+
consola.log(` ... and ${status.untracked.length - 3} more`);
|
|
116
|
+
}
|
|
294
117
|
}
|
|
295
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: DEFAULT_THEME.primary }, "Towles Tool"), /* @__PURE__ */ React.createElement(Text, { color: DEFAULT_THEME.dim }, "Terminal size: ", terminalSize.columns, "x", terminalSize.rows), /* @__PURE__ */ React.createElement(Text, { color: DEFAULT_THEME.warning }, "No command specified"));
|
|
296
|
-
}
|
|
297
|
-
function App(props) {
|
|
298
|
-
return /* @__PURE__ */ React.createElement(ErrorBoundary, null, /* @__PURE__ */ React.createElement(AppProvider, null, /* @__PURE__ */ React.createElement(ConfigProvider, { context: props.context }, /* @__PURE__ */ React.createElement(AppContent, { ...props }))));
|
|
299
|
-
}
|
|
300
|
-
function renderApp(props) {
|
|
301
|
-
return render(/* @__PURE__ */ React.createElement(App, { ...props }));
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
async function gitCommitCommand(context, messageArgs) {
|
|
305
|
-
const { waitUntilExit } = renderApp({
|
|
306
|
-
context,
|
|
307
|
-
command: "git-commit",
|
|
308
|
-
commandArgs: messageArgs
|
|
309
|
-
});
|
|
310
|
-
await waitUntilExit();
|
|
311
118
|
}
|
|
312
119
|
|
|
313
120
|
function getMondayOfWeek(date) {
|
|
@@ -516,12 +323,23 @@ async function loadTowlesToolContext({
|
|
|
516
323
|
};
|
|
517
324
|
}
|
|
518
325
|
|
|
326
|
+
const AppInfo = {
|
|
327
|
+
toolName: "towles-tool"
|
|
328
|
+
};
|
|
329
|
+
|
|
519
330
|
async function configCommand(context) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
331
|
+
consola.info("Configuration");
|
|
332
|
+
consola.log("");
|
|
333
|
+
consola.info(`Settings File: ${context.settingsFile.path}`);
|
|
334
|
+
consola.log("");
|
|
335
|
+
consola.warn("User Config:");
|
|
336
|
+
consola.log(` Daily Path Template: ${context.settingsFile.settings.journalSettings.dailyPathTemplate}`);
|
|
337
|
+
consola.log(` Meeting Path Template: ${context.settingsFile.settings.journalSettings.meetingPathTemplate}`);
|
|
338
|
+
consola.log(` Note Path Template: ${context.settingsFile.settings.journalSettings.notePathTemplate}`);
|
|
339
|
+
consola.log(` Editor: ${context.settingsFile.settings.preferredEditor}`);
|
|
340
|
+
consola.log("");
|
|
341
|
+
consola.warn("Working Directory:");
|
|
342
|
+
consola.log(` ${context.cwd}`);
|
|
525
343
|
}
|
|
526
344
|
|
|
527
345
|
const USER_SETTINGS_DIR = path.join(homedir(), ".config", AppInfo.toolName);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@towles/tool",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.13",
|
|
5
5
|
"description": "One off quality of life scripts that I use on a daily basis.",
|
|
6
6
|
"author": "Chris Towles <Chris.Towles.Dev@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -35,32 +35,22 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@anthropic-ai/claude-code": "^1.0.51",
|
|
37
37
|
"@anthropic-ai/sdk": "^0.56.0",
|
|
38
|
-
"@clack/prompts": "^0.11.0",
|
|
39
|
-
"@inkjs/ui": "^2.0.0",
|
|
40
|
-
"c12": "^3.0.4",
|
|
41
|
-
"changelogen": "^0.6.2",
|
|
42
38
|
"consola": "^3.4.2",
|
|
43
39
|
"fzf": "^0.5.2",
|
|
44
|
-
"ink": "^5.0.1",
|
|
45
40
|
"luxon": "^3.7.1",
|
|
46
|
-
"magicast": "^0.3.5",
|
|
47
41
|
"neverthrow": "^8.2.0",
|
|
48
42
|
"prompts": "^2.4.2",
|
|
49
|
-
"react": "^18.3.1",
|
|
50
43
|
"strip-json-comments": "^5.0.2",
|
|
51
44
|
"yargs": "^17.7.2",
|
|
52
45
|
"zod": "^4.0.5"
|
|
53
46
|
},
|
|
54
47
|
"devDependencies": {
|
|
55
48
|
"@antfu/ni": "^25.0.0",
|
|
56
|
-
"@antfu/utils": "^9.2.0",
|
|
57
49
|
"@types/luxon": "^3.6.2",
|
|
58
50
|
"@types/node": "^22.16.3",
|
|
59
51
|
"@types/prompts": "^2.4.9",
|
|
60
|
-
"@types/react": "^18.3.12",
|
|
61
52
|
"@types/yargs": "^17.0.32",
|
|
62
53
|
"bumpp": "^10.2.0",
|
|
63
|
-
"ink-testing-library": "^4.0.0",
|
|
64
54
|
"lint-staged": "^15.5.2",
|
|
65
55
|
"oxlint": "^1.7.0",
|
|
66
56
|
"simple-git-hooks": "^2.13.0",
|
|
@@ -88,9 +78,10 @@
|
|
|
88
78
|
"lint": "oxlint",
|
|
89
79
|
"lint:fix": "oxlint --fix",
|
|
90
80
|
"lint:fix_all": "oxlint --fix .",
|
|
81
|
+
"lint:package": "pnpm dlx publint --fix && pnpm dlx knip",
|
|
91
82
|
"release:local": "bumpp && pnpm publish --no-git-checks -r --access public",
|
|
92
83
|
"release": "bumpp && echo \"github action will run and publish to npm\"",
|
|
93
|
-
"start": "tsx src/index.
|
|
84
|
+
"start": "tsx src/index.ts",
|
|
94
85
|
"test": "vitest --run",
|
|
95
86
|
"test:watch": "CI=DisableCallingClaude vitest --watch",
|
|
96
87
|
"typecheck": "tsc --noEmit"
|