@allternit/gizzi-code 1.0.0 → 1.0.1
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/bin/gizzi +4 -0
- package/bin/gizzi-ink +5 -0
- package/package.json +137 -31
- package/src/Tool.ts +26 -0
- package/src/bootstrap/state.ts +165 -322
- package/src/commands.ts +209 -0
- package/src/context/QueuedMessageContext.tsx +63 -0
- package/src/context/fpsMetrics.tsx +30 -0
- package/src/context/mailbox.tsx +38 -0
- package/src/context/modalContext.tsx +58 -0
- package/src/context/notifications.tsx +240 -0
- package/src/context/overlayContext.tsx +151 -0
- package/src/context/promptOverlayContext.tsx +125 -0
- package/src/context/stats.tsx +220 -0
- package/src/context/voice.tsx +88 -0
- package/src/hooks/useCanUseTool.ts +11 -0
- package/src/hooks/useExitOnCtrlCD.ts +40 -187
- package/src/hooks/useExitOnCtrlCDWithKeybindings.ts +68 -0
- package/src/hooks/useKeybinding.ts +68 -209
- package/src/hooks/useTerminalSize.ts +31 -99
- package/src/hooks.ts +37 -0
- package/src/ink.ts +204 -0
- package/src/main.ts +7 -0
- package/src/types/command.ts +216 -0
- package/src/types/connectorText.ts +39 -0
- package/src/types/fileSuggestion.ts +15 -0
- package/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +865 -0
- package/src/types/generated/events_mono/common/v1/auth.ts +100 -0
- package/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +223 -0
- package/src/types/generated/google/protobuf/timestamp.ts +187 -0
- package/src/types/hooks.ts +319 -0
- package/src/types/ids.ts +44 -0
- package/src/types/logs.ts +331 -0
- package/src/types/merged/index.ts +5 -0
- package/src/types/merged/message.ts +552 -0
- package/src/types/message.ts +927 -186
- package/src/types/messageQueueTypes.ts +21 -0
- package/src/types/notebook.ts +72 -0
- package/src/types/permissions.ts +447 -0
- package/src/types/plugin.ts +363 -0
- package/src/types/statusLine.ts +15 -0
- package/src/types/textInputTypes.ts +387 -0
- package/src/types/tools.ts +149 -0
- package/src/types/utils.ts +20 -0
- package/src/utils/advisor.ts +12 -0
- package/src/utils/api.ts +29 -0
- package/src/utils/array.ts +7 -0
- package/src/utils/attachments.ts +60 -0
- package/src/utils/auth.ts +3 -0
- package/src/utils/claudeInChrome/chromeNativeHost.ts +15 -0
- package/src/utils/claudeInChrome/common.ts +12 -0
- package/src/utils/claudeInChrome/mcpServer.ts +15 -0
- package/src/utils/computerUse/common.ts +19 -0
- package/src/utils/computerUse/mcpServer.ts +15 -0
- package/src/utils/config.ts +35 -0
- package/src/utils/context.ts +19 -0
- package/src/utils/cwd.ts +3 -0
- package/src/utils/debug.ts +3 -0
- package/src/utils/earlyInput.ts +7 -0
- package/src/utils/effort.ts +13 -0
- package/src/utils/embeddedTools.ts +12 -0
- package/src/utils/envUtils.ts +3 -0
- package/src/utils/errors.ts +3 -0
- package/src/utils/execFileNoThrow.ts +24 -0
- package/src/utils/feature-flags.ts +112 -0
- package/src/utils/file.ts +3 -0
- package/src/utils/fileHistory.ts +17 -0
- package/src/utils/fingerprint.ts +7 -0
- package/src/utils/format.ts +75 -305
- package/src/utils/frontmatterParser.ts +33 -0
- package/src/utils/fsOperations.ts +31 -0
- package/src/utils/fullscreen.ts +40 -350
- package/src/utils/git.ts +15 -0
- package/src/utils/imageResizer.ts +30 -0
- package/src/utils/lazySchema.ts +9 -0
- package/src/utils/log.ts +3 -0
- package/src/utils/markdownConfigLoader.ts +12 -0
- package/src/utils/messages.ts +13 -0
- package/src/utils/migration.ts +137 -0
- package/src/utils/model/providers.ts +15 -0
- package/src/utils/path.ts +3 -0
- package/src/utils/permissions/PermissionResult.ts +14 -0
- package/src/utils/permissions/autoModeState.ts +12 -0
- package/src/utils/permissions/filesystem.ts +12 -0
- package/src/utils/plugins/loadPluginOutputStyles.ts +12 -0
- package/src/utils/plugins/schemas.ts +25 -0
- package/src/utils/process.ts +16 -0
- package/src/utils/sandbox/sandbox-adapter.ts +19 -0
- package/src/utils/sessionStorage.ts +238 -472
- package/src/utils/settings/constants.ts +10 -0
- package/src/utils/settings/settings.ts +19 -0
- package/src/utils/settings/types.ts +18 -0
- package/src/utils/shell/shellToolUtils.ts +9 -0
- package/src/utils/sinks.ts +11 -0
- package/src/utils/sleep.ts +7 -0
- package/src/utils/sliceAnsi.ts +7 -0
- package/src/utils/slowOperations.ts +3 -0
- package/src/utils/startupProfiler.ts +11 -0
- package/src/utils/stringUtils.ts +106 -0
- package/src/utils/systemPromptType.ts +9 -0
- package/src/utils/teleport/api.ts +15 -0
- package/src/utils/textHighlighting.ts +16 -0
- package/src/utils/theme.ts +17 -0
- package/src/utils/thinking.ts +58 -0
- package/src/utils/tokens.ts +11 -0
- package/src/utils/toolResultStorage.ts +17 -0
- package/src/utils/worktreeModeEnabled.ts +7 -0
- package/WORKSPACE_INTEGRATION.md +0 -290
- package/chat-sessions/sessions-index.json +0 -98
- package/package.json.original +0 -31
- package/package.json.publish +0 -47
- package/src/bootstrap/state.d.ts +0 -169
- package/src/bootstrap/state.js +0 -261
- package/src/context/pack-builder.d.ts +0 -24
- package/src/context/pack-builder.js +0 -281
- package/src/hooks/useExitOnCtrlCD.d.ts +0 -86
- package/src/hooks/useExitOnCtrlCD.js +0 -130
- package/src/hooks/useKeybinding.d.ts +0 -89
- package/src/hooks/useKeybinding.js +0 -163
- package/src/hooks/useTerminalSize.d.ts +0 -41
- package/src/hooks/useTerminalSize.js +0 -90
- package/src/index.d.ts +0 -23
- package/src/index.js +0 -24
- package/src/runtime/brand/brand.d.ts +0 -488
- package/src/runtime/brand/brand.js +0 -464
- package/src/runtime/brand/brand.ts +0 -667
- package/src/runtime/services/tokenEstimation.d.ts +0 -187
- package/src/runtime/services/tokenEstimation.js +0 -423
- package/src/runtime/services/tokenEstimation.ts +0 -547
- package/src/runtime/tools/Tool.d.ts +0 -239
- package/src/runtime/tools/Tool.js +0 -285
- package/src/runtime/tools/Tool.ts +0 -524
- package/src/scheduler/TaskScheduler.d.ts +0 -98
- package/src/scheduler/TaskScheduler.js +0 -201
- package/src/scheduler/TaskScheduler.ts +0 -259
- package/src/state/AppStateStore.d.ts +0 -347
- package/src/state/AppStateStore.js +0 -439
- package/src/state/AppStateStore.ts +0 -658
- package/src/state/WorkspaceStateStore.d.ts +0 -43
- package/src/state/WorkspaceStateStore.js +0 -224
- package/src/state/WorkspaceStateStore.ts +0 -297
- package/src/types/message.d.ts +0 -190
- package/src/types/message.js +0 -77
- package/src/utils/format.d.ts +0 -126
- package/src/utils/format.js +0 -230
- package/src/utils/fullscreen.d.ts +0 -161
- package/src/utils/fullscreen.js +0 -277
- package/src/utils/sessionStorage.d.ts +0 -210
- package/src/utils/sessionStorage.js +0 -435
- package/src/watcher/WorkspaceWatcher.d.ts +0 -70
- package/src/watcher/WorkspaceWatcher.js +0 -191
- package/src/watcher/WorkspaceWatcher.ts +0 -251
- package/src/workspace/loader.d.ts +0 -30
- package/src/workspace/loader.js +0 -117
- package/src/workspace/types.d.ts +0 -91
- package/src/workspace/types.js +0 -7
- package/threads/thread_1775361175022.json +0 -9
- package/tsconfig.json +0 -14
package/src/utils/format.ts
CHANGED
|
@@ -1,336 +1,106 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @module utils/format
|
|
4
|
-
*
|
|
5
|
-
* Provides formatting utilities for durations, byte sizes, and numbers.
|
|
6
|
-
* These functions are commonly used in CLI output and display components.
|
|
2
|
+
* Format utilities
|
|
7
3
|
*/
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
second: 1000,
|
|
16
|
-
minute: 60 * 1000,
|
|
17
|
-
hour: 60 * 60 * 1000,
|
|
18
|
-
day: 24 * 60 * 60 * 1000,
|
|
19
|
-
week: 7 * 24 * 60 * 60 * 1000,
|
|
20
|
-
month: 30 * 24 * 60 * 60 * 1000,
|
|
21
|
-
year: 365 * 24 * 60 * 60 * 1000,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Byte unit definitions for size formatting
|
|
26
|
-
* @constant {string[]}
|
|
27
|
-
*/
|
|
28
|
-
const BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Number format options
|
|
32
|
-
* @interface NumberFormatOptions
|
|
33
|
-
*/
|
|
34
|
-
export interface NumberFormatOptions {
|
|
35
|
-
/** Minimum number of decimal places */
|
|
36
|
-
readonly minimumFractionDigits?: number;
|
|
37
|
-
/** Maximum number of decimal places */
|
|
38
|
-
readonly maximumFractionDigits?: number;
|
|
39
|
-
/** Use thousands separator */
|
|
40
|
-
readonly useGrouping?: boolean;
|
|
41
|
-
/** Locale for formatting (default: 'en-US') */
|
|
42
|
-
readonly locale?: string;
|
|
5
|
+
export function formatDuration(ms: number): string {
|
|
6
|
+
if (ms < 1000) return `${ms}ms`
|
|
7
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`
|
|
8
|
+
const minutes = Math.floor(ms / 60000)
|
|
9
|
+
const seconds = ((ms % 60000) / 1000).toFixed(0)
|
|
10
|
+
return `${minutes}m ${seconds}s`
|
|
43
11
|
}
|
|
44
12
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
readonly style?: 'short' | 'long' | 'narrow' | 'auto';
|
|
52
|
-
/** Maximum number of units to display (default: 2) */
|
|
53
|
-
readonly maxUnits?: number;
|
|
54
|
-
/** Include milliseconds in output */
|
|
55
|
-
readonly includeMs?: boolean;
|
|
56
|
-
/** Round to nearest unit */
|
|
57
|
-
readonly round?: boolean;
|
|
13
|
+
export function formatBytes(bytes: number): string {
|
|
14
|
+
if (bytes === 0) return '0 B'
|
|
15
|
+
const k = 1024
|
|
16
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
17
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
18
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`
|
|
58
19
|
}
|
|
59
20
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* @interface ByteFormatOptions
|
|
63
|
-
*/
|
|
64
|
-
export interface ByteFormatOptions {
|
|
65
|
-
/** Number of decimal places (default: 2) */
|
|
66
|
-
readonly decimals?: number;
|
|
67
|
-
/** Use binary units (KiB, MiB) instead of decimal (KB, MB) */
|
|
68
|
-
readonly binary?: boolean;
|
|
69
|
-
/** Include space between value and unit */
|
|
70
|
-
readonly space?: boolean;
|
|
21
|
+
export function formatNumber(num: number): string {
|
|
22
|
+
return new Intl.NumberFormat().format(num)
|
|
71
23
|
}
|
|
72
24
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
*
|
|
76
|
-
* @param {number} ms - Duration in milliseconds
|
|
77
|
-
* @param {DurationFormatOptions} [options] - Format options
|
|
78
|
-
* @returns {string} Formatted duration string
|
|
79
|
-
* @example
|
|
80
|
-
* ```typescript
|
|
81
|
-
* formatDuration(5000); // "5s"
|
|
82
|
-
* formatDuration(65000); // "1m 5s"
|
|
83
|
-
* formatDuration(3600000); // "1h"
|
|
84
|
-
* formatDuration(90000, { style: 'long' }); // "1 minute 30 seconds"
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
export function formatDuration(
|
|
88
|
-
ms: number,
|
|
89
|
-
options: DurationFormatOptions = {}
|
|
90
|
-
): string {
|
|
91
|
-
const {
|
|
92
|
-
style = 'auto',
|
|
93
|
-
maxUnits = 2,
|
|
94
|
-
includeMs = false,
|
|
95
|
-
round = false,
|
|
96
|
-
} = options;
|
|
97
|
-
|
|
98
|
-
// Handle edge cases
|
|
99
|
-
if (!Number.isFinite(ms) || ms < 0) {
|
|
100
|
-
return style === 'long' ? 'unknown duration' : '--';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (ms === 0) {
|
|
104
|
-
return style === 'long' ? '0 seconds' : '0s';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Round if requested
|
|
108
|
-
const duration = round ? Math.round(ms) : ms;
|
|
109
|
-
|
|
110
|
-
// Determine appropriate units
|
|
111
|
-
const units: Array<{ value: number; short: string; long: string }> = [
|
|
112
|
-
{ value: TIME_UNITS.year, short: 'y', long: 'year' },
|
|
113
|
-
{ value: TIME_UNITS.month, short: 'mo', long: 'month' },
|
|
114
|
-
{ value: TIME_UNITS.week, short: 'w', long: 'week' },
|
|
115
|
-
{ value: TIME_UNITS.day, short: 'd', long: 'day' },
|
|
116
|
-
{ value: TIME_UNITS.hour, short: 'h', long: 'hour' },
|
|
117
|
-
{ value: TIME_UNITS.minute, short: 'm', long: 'minute' },
|
|
118
|
-
{ value: TIME_UNITS.second, short: 's', long: 'second' },
|
|
119
|
-
];
|
|
120
|
-
|
|
121
|
-
// Add milliseconds if requested
|
|
122
|
-
if (includeMs || duration < TIME_UNITS.second) {
|
|
123
|
-
units.push({ value: TIME_UNITS.millisecond, short: 'ms', long: 'millisecond' });
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const parts: string[] = [];
|
|
127
|
-
let remaining = Math.abs(duration);
|
|
128
|
-
|
|
129
|
-
for (const unit of units) {
|
|
130
|
-
if (remaining >= unit.value) {
|
|
131
|
-
const count = Math.floor(remaining / unit.value);
|
|
132
|
-
remaining %= unit.value;
|
|
133
|
-
|
|
134
|
-
const useLong = style === 'long';
|
|
135
|
-
const unitStr = useLong
|
|
136
|
-
? `${unit.long}${count !== 1 ? 's' : ''}`
|
|
137
|
-
: unit.short;
|
|
138
|
-
|
|
139
|
-
parts.push(useLong ? `${count} ${unitStr}` : `${count}${unitStr}`);
|
|
140
|
-
|
|
141
|
-
if (parts.length >= maxUnits) {
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (parts.length === 0) {
|
|
148
|
-
return style === 'long' ? '0 seconds' : '0s';
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return parts.join(style === 'long' ? ' ' : ' ');
|
|
25
|
+
export function formatCompact(num: number): string {
|
|
26
|
+
return new Intl.NumberFormat('en', { notation: 'compact' }).format(num)
|
|
152
27
|
}
|
|
153
28
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
*
|
|
157
|
-
* @param {number} bytes - Size in bytes
|
|
158
|
-
* @param {ByteFormatOptions} [options] - Format options
|
|
159
|
-
* @returns {string} Formatted size string
|
|
160
|
-
* @example
|
|
161
|
-
* ```typescript
|
|
162
|
-
* formatBytes(1024); // "1 KB"
|
|
163
|
-
* formatBytes(1536); // "1.50 KB"
|
|
164
|
-
* formatBytes(1048576); // "1 MB"
|
|
165
|
-
* formatBytes(1024, { binary: true }); // "1 KiB"
|
|
166
|
-
* ```
|
|
167
|
-
*/
|
|
168
|
-
export function formatBytes(
|
|
169
|
-
bytes: number,
|
|
170
|
-
options: ByteFormatOptions = {}
|
|
171
|
-
): string {
|
|
172
|
-
const { decimals = 2, binary = false, space = true } = options;
|
|
173
|
-
|
|
174
|
-
// Handle edge cases
|
|
175
|
-
if (!Number.isFinite(bytes)) {
|
|
176
|
-
return '0 B';
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const absBytes = Math.abs(bytes);
|
|
180
|
-
|
|
181
|
-
if (absBytes === 0) {
|
|
182
|
-
return '0 B';
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Use 1024 for binary (KiB, MiB) or 1000 for decimal (KB, MB)
|
|
186
|
-
const base = binary ? 1024 : 1000;
|
|
187
|
-
const binarySuffix = binary ? 'i' : '';
|
|
188
|
-
|
|
189
|
-
// Find appropriate unit
|
|
190
|
-
const exponent = Math.min(
|
|
191
|
-
Math.floor(Math.log(absBytes) / Math.log(base)),
|
|
192
|
-
BYTE_UNITS.length - 1
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
const value = bytes / Math.pow(base, exponent);
|
|
196
|
-
const unit = BYTE_UNITS[exponent] + (exponent > 0 ? binarySuffix : '');
|
|
197
|
-
|
|
198
|
-
// Format with specified decimal places
|
|
199
|
-
const formattedValue = value.toFixed(decimals);
|
|
200
|
-
const trimmedValue = parseFloat(formattedValue).toString();
|
|
201
|
-
|
|
202
|
-
return space ? `${trimmedValue} ${unit}` : `${trimmedValue}${unit}`;
|
|
29
|
+
export function formatPercentage(value: number, total: number): string {
|
|
30
|
+
if (total === 0) return '0%'
|
|
31
|
+
return `${((value / total) * 100).toFixed(1)}%`
|
|
203
32
|
}
|
|
204
33
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
* @param {NumberFormatOptions} [options] - Format options
|
|
210
|
-
* @returns {string} Formatted number string
|
|
211
|
-
* @example
|
|
212
|
-
* ```typescript
|
|
213
|
-
* formatNumber(1234567); // "1,234,567"
|
|
214
|
-
* formatNumber(1234.5678, { maximumFractionDigits: 2 }); // "1,234.57"
|
|
215
|
-
* formatNumber(0.001234, { minimumFractionDigits: 6 }); // "0.001234"
|
|
216
|
-
* ```
|
|
217
|
-
*/
|
|
218
|
-
export function formatNumber(
|
|
219
|
-
num: number,
|
|
220
|
-
options: NumberFormatOptions = {}
|
|
221
|
-
): string {
|
|
222
|
-
const {
|
|
223
|
-
minimumFractionDigits,
|
|
224
|
-
maximumFractionDigits = 2,
|
|
225
|
-
useGrouping = true,
|
|
226
|
-
locale = 'en-US',
|
|
227
|
-
} = options;
|
|
228
|
-
|
|
229
|
-
// Handle edge cases
|
|
230
|
-
if (!Number.isFinite(num)) {
|
|
231
|
-
if (Number.isNaN(num)) return 'NaN';
|
|
232
|
-
return num > 0 ? '∞' : '-∞';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
return new Intl.NumberFormat(locale, {
|
|
237
|
-
minimumFractionDigits,
|
|
238
|
-
maximumFractionDigits,
|
|
239
|
-
useGrouping,
|
|
240
|
-
}).format(num);
|
|
241
|
-
} catch {
|
|
242
|
-
// Fallback for environments without Intl support
|
|
243
|
-
const absNum = Math.abs(num);
|
|
244
|
-
const sign = num < 0 ? '-' : '';
|
|
245
|
-
|
|
246
|
-
// Handle integer part with grouping
|
|
247
|
-
const integerPart = Math.floor(absNum);
|
|
248
|
-
const fractionPart = absNum - integerPart;
|
|
249
|
-
|
|
250
|
-
let result = useGrouping
|
|
251
|
-
? integerPart.toLocaleString(locale)
|
|
252
|
-
: integerPart.toString();
|
|
34
|
+
export function formatDate(date: Date | number | string): string {
|
|
35
|
+
const d = new Date(date)
|
|
36
|
+
return d.toLocaleDateString()
|
|
37
|
+
}
|
|
253
38
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
39
|
+
export function formatDateTime(date: Date | number | string): string {
|
|
40
|
+
const d = new Date(date)
|
|
41
|
+
return d.toLocaleString()
|
|
42
|
+
}
|
|
257
43
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
44
|
+
export function formatRelativeTime(date: Date | number | string): string {
|
|
45
|
+
const now = Date.now()
|
|
46
|
+
const then = new Date(date).getTime()
|
|
47
|
+
const diff = now - then
|
|
48
|
+
|
|
49
|
+
const seconds = Math.floor(diff / 1000)
|
|
50
|
+
const minutes = Math.floor(seconds / 60)
|
|
51
|
+
const hours = Math.floor(minutes / 60)
|
|
52
|
+
const days = Math.floor(hours / 24)
|
|
53
|
+
|
|
54
|
+
if (seconds < 60) return 'just now'
|
|
55
|
+
if (minutes < 60) return `${minutes}m ago`
|
|
56
|
+
if (hours < 24) return `${hours}h ago`
|
|
57
|
+
if (days < 7) return `${days}d ago`
|
|
58
|
+
return formatDate(date)
|
|
59
|
+
}
|
|
272
60
|
|
|
273
|
-
|
|
274
|
-
|
|
61
|
+
export function truncate(str: string, maxLength: number): string {
|
|
62
|
+
if (str.length <= maxLength) return str
|
|
63
|
+
return str.slice(0, maxLength - 3) + '...'
|
|
275
64
|
}
|
|
276
65
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
*
|
|
280
|
-
* @param {number} value - Value to format (0.5 = 50%)
|
|
281
|
-
* @param {number} [decimals=1] - Number of decimal places
|
|
282
|
-
* @returns {string} Formatted percentage string
|
|
283
|
-
* @example
|
|
284
|
-
* ```typescript
|
|
285
|
-
* formatPercentage(0.5); // "50%"
|
|
286
|
-
* formatPercentage(0.1234, 2); // "12.34%"
|
|
287
|
-
* ```
|
|
288
|
-
*/
|
|
289
|
-
export function formatPercentage(value: number, decimals: number = 1): string {
|
|
290
|
-
if (!Number.isFinite(value)) {
|
|
291
|
-
return '--%';
|
|
292
|
-
}
|
|
293
|
-
return `${(value * 100).toFixed(decimals)}%`;
|
|
66
|
+
export function capitalize(str: string): string {
|
|
67
|
+
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
294
68
|
}
|
|
295
69
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
* @param {number} num - Number to format
|
|
300
|
-
* @param {number} [decimals=1] - Number of decimal places
|
|
301
|
-
* @returns {string} Compact formatted string
|
|
302
|
-
* @example
|
|
303
|
-
* ```typescript
|
|
304
|
-
* formatCompact(1234); // "1.2K"
|
|
305
|
-
* formatCompact(1000000); // "1M"
|
|
306
|
-
* formatCompact(1234567890); // "1.2B"
|
|
307
|
-
* ```
|
|
308
|
-
*/
|
|
309
|
-
export function formatCompact(num: number, decimals: number = 1): string {
|
|
310
|
-
if (!Number.isFinite(num) || num === 0) {
|
|
311
|
-
return '0';
|
|
312
|
-
}
|
|
70
|
+
export function camelCase(str: string): string {
|
|
71
|
+
return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase())
|
|
72
|
+
}
|
|
313
73
|
|
|
314
|
-
|
|
315
|
-
|
|
74
|
+
export function kebabCase(str: string): string {
|
|
75
|
+
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')
|
|
76
|
+
}
|
|
316
77
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
units.length - 1
|
|
321
|
-
);
|
|
78
|
+
export function snakeCase(str: string): string {
|
|
79
|
+
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '')
|
|
80
|
+
}
|
|
322
81
|
|
|
323
|
-
|
|
324
|
-
|
|
82
|
+
export function padLeft(str: string, length: number, char = ' '): string {
|
|
83
|
+
return char.repeat(Math.max(0, length - str.length)) + str
|
|
84
|
+
}
|
|
325
85
|
|
|
326
|
-
|
|
86
|
+
export function padRight(str: string, length: number, char = ' '): string {
|
|
87
|
+
return str + char.repeat(Math.max(0, length - str.length))
|
|
327
88
|
}
|
|
328
89
|
|
|
329
|
-
// Default export
|
|
330
90
|
export default {
|
|
331
91
|
formatDuration,
|
|
332
92
|
formatBytes,
|
|
333
93
|
formatNumber,
|
|
334
|
-
formatPercentage,
|
|
335
94
|
formatCompact,
|
|
336
|
-
|
|
95
|
+
formatPercentage,
|
|
96
|
+
formatDate,
|
|
97
|
+
formatDateTime,
|
|
98
|
+
formatRelativeTime,
|
|
99
|
+
truncate,
|
|
100
|
+
capitalize,
|
|
101
|
+
camelCase,
|
|
102
|
+
kebabCase,
|
|
103
|
+
snakeCase,
|
|
104
|
+
padLeft,
|
|
105
|
+
padRight,
|
|
106
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontmatter Parser
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface Frontmatter {
|
|
6
|
+
[key: string]: unknown
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function parseFrontmatter(content: string): { frontmatter: Frontmatter; body: string } {
|
|
10
|
+
const lines = content.split('\n')
|
|
11
|
+
if (lines[0] !== '---') {
|
|
12
|
+
return { frontmatter: {}, body: content }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const endIndex = lines.findIndex((line, i) => i > 0 && line === '---')
|
|
16
|
+
if (endIndex === -1) {
|
|
17
|
+
return { frontmatter: {}, body: content }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const frontmatterText = lines.slice(1, endIndex).join('\n')
|
|
21
|
+
const body = lines.slice(endIndex + 1).join('\n')
|
|
22
|
+
|
|
23
|
+
// Simple YAML-like parsing
|
|
24
|
+
const frontmatter: Frontmatter = {}
|
|
25
|
+
for (const line of frontmatterText.split('\n')) {
|
|
26
|
+
const match = line.match(/^(\w+):\s*(.*)$/)
|
|
27
|
+
if (match) {
|
|
28
|
+
frontmatter[match[1]] = match[2]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { frontmatter, body }
|
|
33
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File System Operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { readFile, writeFile, mkdir } from 'fs/promises'
|
|
6
|
+
|
|
7
|
+
export async function readFileSafe(path: string): Promise<string | null> {
|
|
8
|
+
try {
|
|
9
|
+
return await readFile(path, 'utf-8')
|
|
10
|
+
} catch {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function writeFileSafe(path: string, content: string): Promise<boolean> {
|
|
16
|
+
try {
|
|
17
|
+
await writeFile(path, content)
|
|
18
|
+
return true
|
|
19
|
+
} catch {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function mkdirSafe(path: string): Promise<boolean> {
|
|
25
|
+
try {
|
|
26
|
+
await mkdir(path, { recursive: true })
|
|
27
|
+
return true
|
|
28
|
+
} catch {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
}
|