sheldonify 0.1.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/.claude-plugin/plugin.json +8 -0
- package/.clinerules +24 -0
- package/.cursor/rules/sheldonify.md +24 -0
- package/.github/copilot-instructions.md +16 -0
- package/.kiro/steering/sheldonify.md +24 -0
- package/.openclaw/skills/sheldonify +83 -0
- package/.windsurf/rules/sheldonify.md +24 -0
- package/AGENTS.md +56 -0
- package/LICENSE +191 -0
- package/README.md +388 -0
- package/bin/sheldonify.js +2 -0
- package/codex.md +32 -0
- package/dist/classifier.d.ts +7 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +19 -0
- package/dist/classifier.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +158 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +121 -0
- package/dist/config.js.map +1 -0
- package/dist/duplicates.d.ts +3 -0
- package/dist/duplicates.d.ts.map +1 -0
- package/dist/duplicates.js +59 -0
- package/dist/duplicates.js.map +1 -0
- package/dist/executor.d.ts +3 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +99 -0
- package/dist/executor.js.map +1 -0
- package/dist/index-generator.d.ts +3 -0
- package/dist/index-generator.d.ts.map +1 -0
- package/dist/index-generator.js +22 -0
- package/dist/index-generator.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +7 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +129 -0
- package/dist/output.js.map +1 -0
- package/dist/planner.d.ts +3 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +83 -0
- package/dist/planner.js.map +1 -0
- package/dist/protected.d.ts +4 -0
- package/dist/protected.d.ts.map +1 -0
- package/dist/protected.js +74 -0
- package/dist/protected.js.map +1 -0
- package/dist/scanner.d.ts +8 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +65 -0
- package/dist/scanner.js.map +1 -0
- package/dist/strategies/by-context.d.ts +9 -0
- package/dist/strategies/by-context.d.ts.map +1 -0
- package/dist/strategies/by-context.js +104 -0
- package/dist/strategies/by-context.js.map +1 -0
- package/dist/strategies/by-date.d.ts +6 -0
- package/dist/strategies/by-date.d.ts.map +1 -0
- package/dist/strategies/by-date.js +23 -0
- package/dist/strategies/by-date.js.map +1 -0
- package/dist/strategies/by-type.d.ts +6 -0
- package/dist/strategies/by-type.d.ts.map +1 -0
- package/dist/strategies/by-type.js +65 -0
- package/dist/strategies/by-type.js.map +1 -0
- package/dist/strategies/custom.d.ts +7 -0
- package/dist/strategies/custom.d.ts.map +1 -0
- package/dist/strategies/custom.js +31 -0
- package/dist/strategies/custom.js.map +1 -0
- package/dist/strategies/index.d.ts +3 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +18 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/types.d.ts +125 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/undo-generator.d.ts +4 -0
- package/dist/undo-generator.d.ts.map +1 -0
- package/dist/undo-generator.js +65 -0
- package/dist/undo-generator.js.map +1 -0
- package/dist/utils/fs-helpers.d.ts +6 -0
- package/dist/utils/fs-helpers.d.ts.map +1 -0
- package/dist/utils/fs-helpers.js +54 -0
- package/dist/utils/fs-helpers.js.map +1 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +12 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/media.d.ts +6 -0
- package/dist/utils/media.d.ts.map +1 -0
- package/dist/utils/media.js +63 -0
- package/dist/utils/media.js.map +1 -0
- package/dist/utils/platform.d.ts +5 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +15 -0
- package/dist/utils/platform.js.map +1 -0
- package/hooks/check-install.js +32 -0
- package/hooks/hooks.json +17 -0
- package/package.json +67 -0
- package/skills/sheldonify/SKILL.md +110 -0
- package/skills/sheldonify/references/config-format.md +55 -0
- package/skills/sheldonify-scan/SKILL.md +87 -0
- package/skills/sheldonify-undo/SKILL.md +45 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export interface SheldonifyConfig {
|
|
2
|
+
strategy: StrategyName;
|
|
3
|
+
depth: number;
|
|
4
|
+
dryRun: boolean;
|
|
5
|
+
verbose: boolean;
|
|
6
|
+
jsonOutput: boolean;
|
|
7
|
+
targetDir: string;
|
|
8
|
+
configPath?: string;
|
|
9
|
+
protected: ProtectedConfig;
|
|
10
|
+
typeStrategy: TypeStrategyConfig;
|
|
11
|
+
contextStrategy: ContextStrategyConfig;
|
|
12
|
+
dateStrategy: DateStrategyConfig;
|
|
13
|
+
customRules: CustomRule[];
|
|
14
|
+
}
|
|
15
|
+
export type StrategyName = 'type' | 'context' | 'date' | 'custom';
|
|
16
|
+
export interface ProtectedConfig {
|
|
17
|
+
useDefaults: boolean;
|
|
18
|
+
include: string[];
|
|
19
|
+
exclude: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface TypeStrategyConfig {
|
|
22
|
+
extraMappings: Record<string, string>;
|
|
23
|
+
categoryRenames: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
export interface ContextStrategyConfig {
|
|
26
|
+
extraKeywords: Record<string, string[]>;
|
|
27
|
+
}
|
|
28
|
+
export interface DateStrategyConfig {
|
|
29
|
+
dateSource: 'modified' | 'created';
|
|
30
|
+
}
|
|
31
|
+
export interface CustomRule {
|
|
32
|
+
name: string;
|
|
33
|
+
match: {
|
|
34
|
+
extensions?: string[];
|
|
35
|
+
patterns?: string[];
|
|
36
|
+
regex?: string;
|
|
37
|
+
};
|
|
38
|
+
priority?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface FileEntry {
|
|
41
|
+
absolutePath: string;
|
|
42
|
+
relativePath: string;
|
|
43
|
+
name: string;
|
|
44
|
+
extension: string;
|
|
45
|
+
size: number;
|
|
46
|
+
modifiedAt: Date;
|
|
47
|
+
createdAt: Date;
|
|
48
|
+
hash?: string;
|
|
49
|
+
isDirectory: boolean;
|
|
50
|
+
media?: MediaMetadata;
|
|
51
|
+
}
|
|
52
|
+
export interface MediaMetadata {
|
|
53
|
+
width?: number;
|
|
54
|
+
height?: number;
|
|
55
|
+
duration?: number;
|
|
56
|
+
bitrate?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface Classification {
|
|
59
|
+
category: string;
|
|
60
|
+
confidence: number;
|
|
61
|
+
reason: string;
|
|
62
|
+
}
|
|
63
|
+
export interface MoveOperation {
|
|
64
|
+
source: string;
|
|
65
|
+
destination: string;
|
|
66
|
+
reason: string;
|
|
67
|
+
type: 'organize' | 'duplicate';
|
|
68
|
+
}
|
|
69
|
+
export interface DuplicateGroup {
|
|
70
|
+
hash: string;
|
|
71
|
+
kept: string;
|
|
72
|
+
duplicates: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface MovePlan {
|
|
75
|
+
operations: MoveOperation[];
|
|
76
|
+
duplicateGroups: DuplicateGroup[];
|
|
77
|
+
skippedPaths: string[];
|
|
78
|
+
uncertainFiles: UncertainFile[];
|
|
79
|
+
warnings: string[];
|
|
80
|
+
stats: PlanStats;
|
|
81
|
+
}
|
|
82
|
+
export interface UncertainFile {
|
|
83
|
+
file: FileEntry;
|
|
84
|
+
candidates: Classification[];
|
|
85
|
+
}
|
|
86
|
+
export interface PlanStats {
|
|
87
|
+
totalFiles: number;
|
|
88
|
+
filesToMove: number;
|
|
89
|
+
duplicatesFound: number;
|
|
90
|
+
foldersToCreate: number;
|
|
91
|
+
protectedSkipped: number;
|
|
92
|
+
uncertainCount: number;
|
|
93
|
+
}
|
|
94
|
+
export interface ExecutionResult {
|
|
95
|
+
success: boolean;
|
|
96
|
+
operationsExecuted: number;
|
|
97
|
+
errors: string[];
|
|
98
|
+
indexPath: string;
|
|
99
|
+
undoShPath: string;
|
|
100
|
+
undoPs1Path: string;
|
|
101
|
+
}
|
|
102
|
+
export interface SheldonifyIndex {
|
|
103
|
+
version: number;
|
|
104
|
+
timestamp: string;
|
|
105
|
+
strategy: StrategyName;
|
|
106
|
+
targetDir: string;
|
|
107
|
+
stats: PlanStats;
|
|
108
|
+
operations: MoveOperation[];
|
|
109
|
+
undo: {
|
|
110
|
+
from: string;
|
|
111
|
+
to: string;
|
|
112
|
+
}[];
|
|
113
|
+
uncertainResolutions: UncertainResolution[];
|
|
114
|
+
}
|
|
115
|
+
export interface UncertainResolution {
|
|
116
|
+
file: string;
|
|
117
|
+
options: string[];
|
|
118
|
+
resolved: string;
|
|
119
|
+
resolvedBy: 'user' | 'agent' | 'heuristic';
|
|
120
|
+
}
|
|
121
|
+
export interface SortStrategy {
|
|
122
|
+
name: string;
|
|
123
|
+
categorize(file: FileEntry, config: SheldonifyConfig): Classification;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MoveOperation } from './types.js';
|
|
2
|
+
export declare function generateUndoSh(operations: MoveOperation[], targetDir: string): string;
|
|
3
|
+
export declare function generateUndoPs1(operations: MoveOperation[], targetDir: string): string;
|
|
4
|
+
//# sourceMappingURL=undo-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo-generator.d.ts","sourceRoot":"","sources":["../src/undo-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,wBAAgB,cAAc,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAuCrF;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAmCtF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { normalizePath } from './utils/platform.js';
|
|
3
|
+
export function generateUndoSh(operations, targetDir) {
|
|
4
|
+
const lines = [
|
|
5
|
+
'#!/bin/bash',
|
|
6
|
+
'set -euo pipefail',
|
|
7
|
+
'echo "Undoing sheldonify organization..."',
|
|
8
|
+
'',
|
|
9
|
+
];
|
|
10
|
+
const createdDirs = new Set();
|
|
11
|
+
// Reverse operations in LIFO order
|
|
12
|
+
for (const op of [...operations].reverse()) {
|
|
13
|
+
const from = normalizePath(path.relative(targetDir, op.destination));
|
|
14
|
+
const to = normalizePath(path.relative(targetDir, op.source));
|
|
15
|
+
const toDir = normalizePath(path.dirname(to));
|
|
16
|
+
if (toDir !== '.') {
|
|
17
|
+
lines.push(`mkdir -p "${toDir}"`);
|
|
18
|
+
}
|
|
19
|
+
lines.push(`mv "${from}" "${to}"`);
|
|
20
|
+
const destDir = normalizePath(path.relative(targetDir, path.dirname(op.destination)));
|
|
21
|
+
if (destDir !== '.') {
|
|
22
|
+
createdDirs.add(destDir);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
lines.push('');
|
|
26
|
+
lines.push('# Remove created directories (only if empty)');
|
|
27
|
+
// Sort dirs by depth descending so children are removed before parents
|
|
28
|
+
const sortedDirs = [...createdDirs].sort((a, b) => b.split('/').length - a.split('/').length);
|
|
29
|
+
for (const dir of sortedDirs) {
|
|
30
|
+
lines.push(`rmdir "${dir}" 2>/dev/null || true`);
|
|
31
|
+
}
|
|
32
|
+
lines.push('');
|
|
33
|
+
lines.push('echo "Undo complete."');
|
|
34
|
+
return lines.join('\n') + '\n';
|
|
35
|
+
}
|
|
36
|
+
export function generateUndoPs1(operations, targetDir) {
|
|
37
|
+
const lines = [
|
|
38
|
+
'Write-Host "Undoing sheldonify organization..."',
|
|
39
|
+
'',
|
|
40
|
+
];
|
|
41
|
+
const createdDirs = new Set();
|
|
42
|
+
for (const op of [...operations].reverse()) {
|
|
43
|
+
const from = path.relative(targetDir, op.destination);
|
|
44
|
+
const to = path.relative(targetDir, op.source);
|
|
45
|
+
const toDir = path.dirname(to);
|
|
46
|
+
if (toDir !== '.') {
|
|
47
|
+
lines.push(`New-Item -ItemType Directory -Force -Path "${toDir}" | Out-Null`);
|
|
48
|
+
}
|
|
49
|
+
lines.push(`Move-Item -Path "${from}" -Destination "${to}"`);
|
|
50
|
+
const destDir = path.relative(targetDir, path.dirname(op.destination));
|
|
51
|
+
if (destDir !== '.') {
|
|
52
|
+
createdDirs.add(destDir);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push('# Remove created directories (only if empty)');
|
|
57
|
+
const sortedDirs = [...createdDirs].sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
|
|
58
|
+
for (const dir of sortedDirs) {
|
|
59
|
+
lines.push(`if ((Test-Path "${dir}") -and @(Get-ChildItem "${dir}" -Force).Count -eq 0) { Remove-Item "${dir}" }`);
|
|
60
|
+
}
|
|
61
|
+
lines.push('');
|
|
62
|
+
lines.push('Write-Host "Undo complete."');
|
|
63
|
+
return lines.join('\r\n') + '\r\n';
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=undo-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo-generator.js","sourceRoot":"","sources":["../src/undo-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
2
|
+
export declare function safeMove(source: string, destination: string): Promise<void>;
|
|
3
|
+
export declare function pathExists(p: string): Promise<boolean>;
|
|
4
|
+
export declare function isDirectory(p: string): Promise<boolean>;
|
|
5
|
+
export declare function resolveConflict(destPath: string, existingDests: Set<string>): string;
|
|
6
|
+
//# sourceMappingURL=fs-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/fs-helpers.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYjF;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAYpF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export async function ensureDir(dirPath) {
|
|
4
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
5
|
+
}
|
|
6
|
+
export async function safeMove(source, destination) {
|
|
7
|
+
await ensureDir(path.dirname(destination));
|
|
8
|
+
try {
|
|
9
|
+
await fs.rename(source, destination);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
if (isNodeError(err) && err.code === 'EXDEV') {
|
|
13
|
+
await fs.copyFile(source, destination);
|
|
14
|
+
await fs.unlink(source);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function pathExists(p) {
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(p);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function isDirectory(p) {
|
|
31
|
+
try {
|
|
32
|
+
const stat = await fs.stat(p);
|
|
33
|
+
return stat.isDirectory();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function resolveConflict(destPath, existingDests) {
|
|
40
|
+
if (!existingDests.has(destPath))
|
|
41
|
+
return destPath;
|
|
42
|
+
const dir = path.dirname(destPath);
|
|
43
|
+
const ext = path.extname(destPath);
|
|
44
|
+
const stem = path.basename(destPath, ext);
|
|
45
|
+
let counter = 2;
|
|
46
|
+
while (existingDests.has(path.join(dir, `${stem} (${counter})${ext}`))) {
|
|
47
|
+
counter++;
|
|
48
|
+
}
|
|
49
|
+
return path.join(dir, `${stem} (${counter})${ext}`);
|
|
50
|
+
}
|
|
51
|
+
function isNodeError(err) {
|
|
52
|
+
return err instanceof Error && 'code' in err;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=fs-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-helpers.js","sourceRoot":"","sources":["../../src/utils/fs-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe;IAC7C,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,WAAmB;IAChE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC7C,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YACvC,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAS;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,CAAS;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,aAA0B;IAC1E,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAElD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,OAAO,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAGA,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
export function hashFile(filePath) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const hash = createHash('sha256');
|
|
6
|
+
const stream = createReadStream(filePath);
|
|
7
|
+
stream.on('data', (chunk) => hash.update(chunk));
|
|
8
|
+
stream.on('end', () => resolve(hash.digest('hex')));
|
|
9
|
+
stream.on('error', reject);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { MediaMetadata } from '../types.js';
|
|
2
|
+
export declare function isImageExtension(ext: string): boolean;
|
|
3
|
+
export declare function isVideoExtension(ext: string): boolean;
|
|
4
|
+
export declare function isAudioExtension(ext: string): boolean;
|
|
5
|
+
export declare function extractMediaMetadata(filePath: string, extension: string): Promise<MediaMetadata | undefined>;
|
|
6
|
+
//# sourceMappingURL=media.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/utils/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAM5C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CASlH"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const IMAGE_EXTENSIONS = new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'tiff', 'svg', 'ico', 'heic', 'raw']);
|
|
2
|
+
const VIDEO_EXTENSIONS = new Set(['mp4', 'avi', 'mkv', 'mov', 'wmv', 'flv', 'webm']);
|
|
3
|
+
const AUDIO_EXTENSIONS = new Set(['mp3', 'wav', 'flac', 'aac', 'ogg', 'wma', 'm4a']);
|
|
4
|
+
export function isImageExtension(ext) {
|
|
5
|
+
return IMAGE_EXTENSIONS.has(ext);
|
|
6
|
+
}
|
|
7
|
+
export function isVideoExtension(ext) {
|
|
8
|
+
return VIDEO_EXTENSIONS.has(ext);
|
|
9
|
+
}
|
|
10
|
+
export function isAudioExtension(ext) {
|
|
11
|
+
return AUDIO_EXTENSIONS.has(ext);
|
|
12
|
+
}
|
|
13
|
+
export async function extractMediaMetadata(filePath, extension) {
|
|
14
|
+
// Optional dependency — graceful fallback
|
|
15
|
+
if (isImageExtension(extension)) {
|
|
16
|
+
return extractImageMetadata(filePath);
|
|
17
|
+
}
|
|
18
|
+
if (isVideoExtension(extension) || isAudioExtension(extension)) {
|
|
19
|
+
return extractAVMetadata(filePath);
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
async function extractImageMetadata(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
// Dynamic import — sharp is an optional dependency
|
|
26
|
+
const sharp = (await Function('return import("sharp")')());
|
|
27
|
+
const metadata = await sharp.default(filePath).metadata();
|
|
28
|
+
return {
|
|
29
|
+
width: metadata.width,
|
|
30
|
+
height: metadata.height,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function extractAVMetadata(_filePath) {
|
|
38
|
+
// ffprobe integration — optional, returns undefined if not available
|
|
39
|
+
try {
|
|
40
|
+
const { execFile } = await import('node:child_process');
|
|
41
|
+
const { promisify } = await import('node:util');
|
|
42
|
+
const execFileAsync = promisify(execFile);
|
|
43
|
+
const { stdout } = await execFileAsync('ffprobe', [
|
|
44
|
+
'-v', 'quiet',
|
|
45
|
+
'-print_format', 'json',
|
|
46
|
+
'-show_format', '-show_streams',
|
|
47
|
+
_filePath,
|
|
48
|
+
]);
|
|
49
|
+
const data = JSON.parse(stdout);
|
|
50
|
+
const stream = data.streams?.[0];
|
|
51
|
+
const format = data.format;
|
|
52
|
+
return {
|
|
53
|
+
width: stream?.width,
|
|
54
|
+
height: stream?.height,
|
|
55
|
+
duration: format?.duration ? parseFloat(format.duration) : undefined,
|
|
56
|
+
bitrate: format?.bit_rate ? parseInt(format.bit_rate, 10) : undefined,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/utils/media.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function isWindows(): boolean;
|
|
2
|
+
export declare function normalizePath(p: string): string;
|
|
3
|
+
export declare function getExtension(filename: string): string;
|
|
4
|
+
export declare function getStem(filename: string): string;
|
|
5
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
export function isWindows() {
|
|
3
|
+
return process.platform === 'win32';
|
|
4
|
+
}
|
|
5
|
+
export function normalizePath(p) {
|
|
6
|
+
return p.split(path.sep).join('/');
|
|
7
|
+
}
|
|
8
|
+
export function getExtension(filename) {
|
|
9
|
+
const ext = path.extname(filename);
|
|
10
|
+
return ext ? ext.slice(1).toLowerCase() : '';
|
|
11
|
+
}
|
|
12
|
+
export function getStem(filename) {
|
|
13
|
+
return path.basename(filename, path.extname(filename));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// PreToolUse hook: checks if sheldonify CLI is installed when a sheldonify command is about to run.
|
|
4
|
+
// If not installed, nudges the agent to install it first.
|
|
5
|
+
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
let input = '';
|
|
9
|
+
process.stdin.setEncoding('utf-8');
|
|
10
|
+
process.stdin.on('data', chunk => { input += chunk; });
|
|
11
|
+
process.stdin.on('end', () => {
|
|
12
|
+
try {
|
|
13
|
+
const data = JSON.parse(input);
|
|
14
|
+
const toolInput = data.tool_input ?? '';
|
|
15
|
+
|
|
16
|
+
if (typeof toolInput !== 'string' || !toolInput.includes('sheldonify')) {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
execSync('sheldonify --version', { stdio: 'ignore' });
|
|
22
|
+
} catch {
|
|
23
|
+
const msg = {
|
|
24
|
+
systemMessage: 'sheldonify is not installed. Run: npm install -g sheldonify'
|
|
25
|
+
};
|
|
26
|
+
process.stdout.write(JSON.stringify(msg));
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// never block due to hook errors
|
|
30
|
+
}
|
|
31
|
+
process.exit(0);
|
|
32
|
+
});
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Sheldonify lifecycle hooks — ensures sheldonify is available and validates operations",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Bash",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/check-install.js\"",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sheldonify",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool to organize files and folders by type, context, date, or custom rules",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"sheldonify": "./bin/sheldonify.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"dist/",
|
|
15
|
+
"docs/",
|
|
16
|
+
".claude-plugin/",
|
|
17
|
+
"skills/",
|
|
18
|
+
"hooks/",
|
|
19
|
+
"AGENTS.md",
|
|
20
|
+
".github/",
|
|
21
|
+
".cursor/",
|
|
22
|
+
".windsurf/",
|
|
23
|
+
".clinerules",
|
|
24
|
+
".kiro/",
|
|
25
|
+
".openclaw/",
|
|
26
|
+
"codex.md"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.json",
|
|
33
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"lint": "tsc --noEmit",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"file-organizer",
|
|
41
|
+
"cli",
|
|
42
|
+
"file-management",
|
|
43
|
+
"directory-organizer",
|
|
44
|
+
"sheldonify"
|
|
45
|
+
],
|
|
46
|
+
"author": "Dhananjay Gupta <dhananjay.gupta.dj@gmail.com>",
|
|
47
|
+
"license": "Apache-2.0",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/maxdj007/sheldonify"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/maxdj007/sheldonify#readme",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/maxdj007/sheldonify/issues"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"chalk": "^5.3.0",
|
|
58
|
+
"commander": "^12.1.0",
|
|
59
|
+
"minimatch": "^10.0.1",
|
|
60
|
+
"zod": "^3.23.8"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^20.14.0",
|
|
64
|
+
"typescript": "^5.5.0",
|
|
65
|
+
"vitest": "^2.0.0"
|
|
66
|
+
}
|
|
67
|
+
}
|