foldermaker 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,16 @@
1
+ """
2
+ folderforge
3
+
4
+ Create folders and files automatically from an AI-generated
5
+ text folder-tree structure.
6
+
7
+ Example:
8
+ import folderforge
9
+ folderforge.build("structure.txt")
10
+
11
+ """
12
+
13
+ from .builder import build, build_from_text
14
+
15
+ __version__ = "1.0.0"
16
+ __all__ = ["build", "build_from_text"]
foldermaker/builder.py ADDED
@@ -0,0 +1,122 @@
1
+ from pathlib import Path
2
+
3
+ from .parser import parse_tree
4
+
5
+
6
+ def build_from_text(
7
+ tree_text: str,
8
+ output_dir: str | Path = ".",
9
+ dry_run: bool = False,
10
+ ) -> list[str]:
11
+ output_path = Path(output_dir).expanduser().resolve()
12
+ nodes = parse_tree(tree_text)
13
+
14
+ created: list[str] = []
15
+ node_map = {node.name: node for node in nodes}
16
+
17
+ for node in nodes:
18
+ relative_path = _get_relative_path(node, node_map)
19
+ target = output_path / relative_path
20
+
21
+ if node.is_folder:
22
+ _create_folder(target, dry_run, created)
23
+ else:
24
+ _create_file(target, dry_run, created)
25
+
26
+ return created
27
+
28
+
29
+ def build(
30
+ structure_file: str | Path,
31
+ output_dir: str | Path = ".",
32
+ dry_run: bool = False,
33
+ ) -> list[str]:
34
+ """
35
+ Reads a .txt file containing a folder tree and creates it.
36
+
37
+ Example:
38
+ import folderforge
39
+ folderforge.build("structure.txt", output_dir="D:/MY_AGENT")
40
+ """
41
+ structure_path = Path(structure_file).expanduser().resolve()
42
+
43
+ if not structure_path.exists():
44
+ raise FileNotFoundError(f"Structure file not found: {structure_path}")
45
+
46
+ tree_text = structure_path.read_text(encoding="utf-8")
47
+ return build_from_text(tree_text, output_dir=output_dir, dry_run=dry_run)
48
+
49
+
50
+ def _get_relative_path(node, node_map) -> Path:
51
+ """
52
+ Builds the full relative path, such as:
53
+ core/ollama_client.py
54
+ """
55
+ parts = [node.name]
56
+ current = node
57
+
58
+ while current.parent:
59
+ parent = node_map.get(current.parent)
60
+
61
+ if parent is None:
62
+ break
63
+
64
+ parts.append(parent.name)
65
+ current = parent
66
+
67
+ return Path(*reversed(parts))
68
+
69
+
70
+ def _create_folder(path: Path, dry_run: bool, created: list[str]) -> None:
71
+ if dry_run:
72
+ print(f"[DRY RUN] Would create folder: {path}")
73
+ created.append(str(path))
74
+ return
75
+
76
+ path.mkdir(parents=True, exist_ok=True)
77
+ print(f"Created folder: {path}")
78
+ created.append(str(path))
79
+
80
+
81
+ def _create_file(path: Path, dry_run: bool, created: list[str]) -> None:
82
+ if dry_run:
83
+ print(f"[DRY RUN] Would create file: {path}")
84
+ created.append(str(path))
85
+ return
86
+
87
+ path.parent.mkdir(parents=True, exist_ok=True)
88
+
89
+ if not path.exists():
90
+ path.touch()
91
+ print(f"Created file: {path}")
92
+ else:
93
+ print(f"File already exists: {path}")
94
+
95
+ created.append(str(path))
96
+
97
+
98
+ def cli():
99
+ import argparse
100
+
101
+ parser = argparse.ArgumentParser(
102
+ description="Create folders and files from a text folder-tree structure."
103
+ )
104
+ parser.add_argument("structure_file", help="Path to the .txt tree file")
105
+ parser.add_argument(
106
+ "-o", "--output",
107
+ default=".",
108
+ help="Output directory where the structure will be created"
109
+ )
110
+ parser.add_argument(
111
+ "--dry-run",
112
+ action="store_true",
113
+ help="Show what would be created without creating anything"
114
+ )
115
+
116
+ args = parser.parse_args()
117
+
118
+ build(
119
+ structure_file=args.structure_file,
120
+ output_dir=args.output,
121
+ dry_run=args.dry_run,
122
+ )
foldermaker/parser.py ADDED
@@ -0,0 +1,117 @@
1
+ import re
2
+ from dataclasses import dataclass, field
3
+ from pathlib import PureWindowsPath, PurePosixPath
4
+
5
+
6
+ TREE_NAME_PATTERN = re.compile(r"(?:├──|└──|--)\s*(.+)$")
7
+ CLEAN_NAME_PATTERN = re.compile(r"[\u2500-\u257F│├└─]")
8
+
9
+
10
+ @dataclass
11
+ class Node:
12
+ name: str
13
+ depth: int
14
+ parent: str | None = None
15
+ is_folder: bool = False
16
+ children: list["Node"] = field(default_factory=list)
17
+
18
+
19
+ def _get_indent_depth(prefix: str) -> int:
20
+ """
21
+ Calculates nesting depth from the space before a file/folder name.
22
+
23
+ Examples:
24
+ "│ " -> depth 1
25
+ "│ ├── " -> depth 1
26
+ "│ │ " -> depth 2
27
+ """
28
+ cleaned = CLEAN_NAME_PATTERN.sub(" ", prefix)
29
+ cleaned = cleaned.replace("\t", " ")
30
+
31
+ leading_spaces = len(cleaned) - len(cleaned.lstrip(" "))
32
+ return leading_spaces // 4
33
+
34
+
35
+ def _extract_name(line: str) -> tuple[str, int]:
36
+ """
37
+ Returns (name, depth) from one tree line.
38
+ """
39
+ match = TREE_NAME_PATTERN.search(line)
40
+
41
+ if match:
42
+ name = match.group(1).strip()
43
+ prefix = line[: match.start()]
44
+ else:
45
+ name = line.strip()
46
+ prefix = ""
47
+
48
+ if not name:
49
+ raise ValueError(f"Could not find a folder or file name in line: {line!r}")
50
+
51
+ depth = _get_indent_depth(prefix)
52
+ return name, depth
53
+
54
+
55
+ def _is_folder(name: str, has_children: bool) -> bool:
56
+ """
57
+ Folder detection rules:
58
+
59
+ 1. `config\\` or `config/` is always a folder.
60
+ 2. `script.py`, `README.md`, `image.png` are files.
61
+ 3. Names without an extension are folders if they have children.
62
+ This correctly treats `Modelfile` as a file and `logs\\` as a folder.
63
+ """
64
+ if name.endswith("\\") or name.endswith("/"):
65
+ return True
66
+
67
+ if "." in PureWindowsPath(name).name or "." in PurePosixPath(name).name:
68
+ return False
69
+
70
+ return has_children
71
+
72
+
73
+ def parse_tree(text: str) -> list[Node]:
74
+ """
75
+ Converts tree text into a list of nested Node objects.
76
+ """
77
+ lines = [line.rstrip() for line in text.splitlines()]
78
+ lines = [line for line in lines if line.strip()]
79
+
80
+ if not lines:
81
+ raise ValueError("The structure file is empty.")
82
+
83
+ nodes: list[Node] = []
84
+ stack: list[Node] = []
85
+
86
+ for line in lines:
87
+ name, depth = _extract_name(line)
88
+
89
+
90
+ clean_name = name.rstrip("\\/").strip()
91
+
92
+ if not clean_name:
93
+ continue
94
+
95
+ node = Node(
96
+ name=clean_name,
97
+ depth=depth,
98
+ )
99
+
100
+
101
+ while stack and stack[-1].depth >= depth:
102
+ stack.pop()
103
+
104
+ if stack:
105
+ node.parent = stack[-1].name
106
+ stack[-1].children.append(node)
107
+ else:
108
+
109
+ node.parent = None
110
+
111
+ stack.append(node)
112
+ nodes.append(node)
113
+
114
+ for node in nodes:
115
+ node.is_folder = _is_folder(node.name, bool(node.children))
116
+
117
+ return nodes
@@ -0,0 +1,274 @@
1
+ Metadata-Version: 2.4
2
+ Name: foldermaker
3
+ Version: 1.0.0
4
+ Summary: Create folders and files automatically from AI-generated text folder trees.
5
+ Author: Aniruddha Singh
6
+ License: MIT
7
+ Keywords: folder,tree,scaffold,project-generator,ai
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Dynamic: license-file
12
+
13
+ # FolderMaker
14
+
15
+ **FolderMaker** is a free and open-source Python library that creates complete project folder and file structures from a text tree copied from AI assistant.
16
+
17
+ Instead of manually creating every folder and file, paste the AI-generated structure into a `.txt` file and run one Python command. FolderForge will create the full structure automatically.
18
+
19
+ ## Features
20
+
21
+ - Creates folders and files from an AI-generated text tree
22
+ - Supports nested folders and files
23
+ - Understands tree symbols such as `│`, `├──`, and `└──`
24
+ - Supports Windows paths such as `D:\MY_AGENT\`
25
+ - Detects folders with trailing `\` or `/`
26
+ - Detects files such as `main.py`, `README.md`, and `Modelfile`
27
+ - Creates empty folders such as `logs\`, `workspace\`, and `venv\`
28
+ - Includes a dry-run mode to preview the result
29
+ - No external dependencies
30
+ - MIT licensed
31
+
32
+ ## Installation
33
+
34
+ ### Install from source
35
+
36
+ 1. Download or clone this repository.
37
+
38
+ ```powershell
39
+ git clone [https://github.com/your-username/foldermaker.git]
40
+ cd foldermaker
41
+ ```
42
+
43
+ 2. Install the library:
44
+
45
+ ```powershell
46
+ pip install foldermaker.
47
+ ```
48
+ ### 1. Create a structure file
49
+
50
+ Create a file named `structure.txt`.
51
+
52
+ Paste your AI-generated folder tree into it exactly as shown by the AI assistant.
53
+
54
+ Example:
55
+
56
+ ```text
57
+ D:\MY_AGENT\
58
+ │
59
+ ├── Modelfile
60
+ ├── main.py
61
+ ├── config\
62
+ │ └── settings.py
63
+ │
64
+ ├── core\
65
+ │ ├── ollama_client.py
66
+ │ ├── agent.py
67
+ │ ├── planner.py
68
+ │ └── tool_executor.py
69
+ │
70
+ ├── tools\
71
+ │ ├── web_search.py
72
+ │ ├── browser.py
73
+ │ ├── file_manager.py
74
+ │ └── code_executor.py
75
+ │
76
+ ├── memory\
77
+ │ ├── database.py
78
+ │ ├── long_term_memory.py
79
+ │ └── feedback.py
80
+ │
81
+ ├── knowledge\
82
+ │ └── document_reader.py
83
+ │
84
+ ├── task_manager\
85
+ │ └── queue.py
86
+ │
87
+ ├── logs\
88
+ ├── generated_tools\
89
+ ├── workspace\
90
+ └── venv\
91
+ ```
92
+
93
+ ### 2. Create a Python runner file
94
+
95
+ Create a file named `main.py`:
96
+
97
+ ```python
98
+ import foldermaker
99
+
100
+ folderforge.build(
101
+ structure_file="structure.txt",
102
+ output_dir=r"D:\MY_AGENT"
103
+ )
104
+ ```
105
+
106
+ ### 3. Run the script
107
+
108
+ ```powershell
109
+ python main.py
110
+ ```
111
+
112
+ FolderMaker will create this structure:
113
+
114
+ ```text
115
+ D:\MY_AGENT\
116
+ ├── Modelfile
117
+ ├── main.py
118
+ ├── config\settings.py
119
+ ├── core\ollama_client.py
120
+ ├── core\agent.py
121
+ ├── core\planner.py
122
+ ├── core\tool_executor.py
123
+ ├── tools\web_search.py
124
+ ├── tools\browser.py
125
+ ├── tools\file_manager.py
126
+ ├── tools\code_executor.py
127
+ ├── memory\database.py
128
+ ├── memory\long_term_memory.py
129
+ ├── memory\feedback.py
130
+ ├── knowledge\document_reader.py
131
+ ├── task_manager\queue.py
132
+ ├── logs\
133
+ ├── generated_tools\
134
+ ├── workspace\
135
+ └── venv\
136
+ ```
137
+
138
+ ## Command-Line Usage
139
+
140
+ After installing FolderForge, you can also use it from the terminal:
141
+
142
+ ```powershell
143
+ foldermaker structure.txt -o D:\MY_AGENT
144
+ ```
145
+
146
+ To preview what will be created without creating anything:
147
+
148
+ ```powershell
149
+ foldermaker structure.txt -o D:\MY_AGENT --dry-run
150
+ ```
151
+
152
+ ## Python API
153
+
154
+ ### Create from a `.txt` file
155
+
156
+ ```python
157
+ import foldermaker
158
+
159
+ folderforge.build(
160
+ structure_file="structure.txt",
161
+ output_dir=r"D:\MY_AGENT"
162
+ )
163
+ ```
164
+
165
+ ### Create from tree text directly
166
+
167
+ ```python
168
+ import foldermaker
169
+
170
+ tree = """
171
+ D:\MY_AGENT\
172
+ │
173
+ ├── main.py
174
+ ├── config\
175
+ │ └── settings.py
176
+ ├── core\
177
+ │ ├── agent.py
178
+ │ └── planner.py
179
+ """
180
+
181
+ foldermaker.build_from_text(
182
+ tree_text=tree,
183
+ output_dir=r"D:\MY_AGENT"
184
+ )
185
+ ```
186
+
187
+ ### Preview without creating files
188
+
189
+ ```python
190
+ import foldermaker
191
+
192
+ folderforge.build(
193
+ structure_file="structure.txt",
194
+ output_dir=r"D:\MY_AGENT",
195
+ dry_run=True
196
+ )
197
+ ```
198
+
199
+ ## Folder and File Detection
200
+
201
+ FolderForge uses these rules:
202
+
203
+ | Example | Created as | Reason |
204
+ |---|---|---|
205
+ | `config\` | Folder | Ends with `\` |
206
+ | `tools/` | Folder | Ends with `/` |
207
+ | `main.py` | File | Has a file extension |
208
+ | `README.md` | File | Has a file extension |
209
+ | `Modelfile` | File | Has no children |
210
+ | `logs\` | Folder | Ends with `\` |
211
+ | `core` | Folder | Has child files or folders |
212
+
213
+ ## Supported Tree Formats
214
+
215
+ FolderForge supports common AI-generated tree formats, including:
216
+
217
+ ```text
218
+ project/
219
+ ├── main.py
220
+ ├── config/
221
+ │ └── settings.py
222
+ └── core/
223
+ ├── agent.py
224
+ └── planner.py
225
+ ```
226
+
227
+ And Windows-style trees:
228
+
229
+ ```text
230
+ D:\MY_AGENT\
231
+ │
232
+ ├── main.py
233
+ ├── config\
234
+ │ └── settings.py
235
+ └── core\
236
+ ├── agent.py
237
+ └── planner.py
238
+ ```
239
+
240
+ ## Project Structure
241
+
242
+ ```text
243
+ folderforge/
244
+ ├── folderforge/
245
+ │ ├── __init__.py
246
+ │ ├── parser.py
247
+ │ └── builder.py
248
+ ├── structure.txt
249
+ ├── generate_project.py
250
+ ├── README.md
251
+ ├── LICENSE
252
+ └── pyproject.toml
253
+ ```
254
+
255
+ ## Safety Notes
256
+
257
+ - FolderMaker creates empty files only; it does not generate file contents.
258
+ - Existing files are not overwritten.
259
+ - Existing folders are reused safely.
260
+ - Use `dry_run=True` first if you are unsure where the structure will be created.
261
+
262
+ ## Contributing
263
+
264
+ Contributions are welcome.
265
+
266
+ 1. Fork the repository
267
+ 2. Create a new branch
268
+ 3. Make your changes
269
+ 4. Add examples or tests if possible
270
+ 5. Submit a pull request
271
+
272
+ ## License
273
+
274
+ This project is released under the MIT License. See the [`LICENSE`](LICENSE) file for details.
@@ -0,0 +1,9 @@
1
+ foldermaker/__init__.py,sha256=syNXAC4fcuymYBWDw0u2G8xFsNc9wSm3V5RT7JAtOXc,303
2
+ foldermaker/builder.py,sha256=UGJXe_6kQlme1nIOdaM5WqXJL6zYI7gPeDkKGY2NG7M,3204
3
+ foldermaker/parser.py,sha256=L1vvGEJaePnK8saR9wNk2WYmHwiwlumLd21k9FXo-04,3015
4
+ foldermaker-1.0.0.dist-info/licenses/LICENSE,sha256=A9DZFW4q-K8qBi5jpny-1Gix_T-Of0pP_5Kt1UdB1Rk,1095
5
+ foldermaker-1.0.0.dist-info/METADATA,sha256=8logEbgdlTLflwzbJWOz_n08MepyhG8YKjMLFpIC5y4,6022
6
+ foldermaker-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
7
+ foldermaker-1.0.0.dist-info/entry_points.txt,sha256=VrkIjn29LLNIWVd33fDjYuhl9gLyflO7eMojISEdLp4,56
8
+ foldermaker-1.0.0.dist-info/top_level.txt,sha256=DFv3ug3WnWOBvJWzV6RUnbbFfs38_KSl5poSx5pQizw,12
9
+ foldermaker-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ folderforge = foldermaker.builder:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LetWeDo.freedev.app
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ foldermaker