makeless 0.1.0__tar.gz → 0.1.2__tar.gz

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.
Files changed (40) hide show
  1. makeless-0.1.2/LICENSE +21 -0
  2. {makeless-0.1.0 → makeless-0.1.2}/PKG-INFO +22 -2
  3. makeless-0.1.2/main.py +410 -0
  4. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/PKG-INFO +22 -2
  5. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/SOURCES.txt +1 -0
  6. {makeless-0.1.0 → makeless-0.1.2}/pyproject.toml +1 -1
  7. makeless-0.1.2/tools/app_finder.py +104 -0
  8. makeless-0.1.2/tools/database.py +62 -0
  9. makeless-0.1.2/tools/filesystem.py +131 -0
  10. {makeless-0.1.0 → makeless-0.1.2}/tools/indexer.py +77 -25
  11. {makeless-0.1.0 → makeless-0.1.2}/tools/watcher.py +42 -49
  12. makeless-0.1.0/LICENSE +0 -1
  13. makeless-0.1.0/main.py +0 -272
  14. makeless-0.1.0/tools/app_finder.py +0 -80
  15. makeless-0.1.0/tools/filesystem.py +0 -103
  16. {makeless-0.1.0 → makeless-0.1.2}/README.md +0 -0
  17. {makeless-0.1.0 → makeless-0.1.2}/agent/planner.py +0 -0
  18. {makeless-0.1.0 → makeless-0.1.2}/agent/runtime.py +0 -0
  19. {makeless-0.1.0 → makeless-0.1.2}/agent/state.py +0 -0
  20. {makeless-0.1.0 → makeless-0.1.2}/app/main.py +0 -0
  21. {makeless-0.1.0 → makeless-0.1.2}/execution/executor.py +0 -0
  22. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/dependency_links.txt +0 -0
  23. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/entry_points.txt +0 -0
  24. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/requires.txt +0 -0
  25. {makeless-0.1.0 → makeless-0.1.2}/makeless.egg-info/top_level.txt +0 -0
  26. {makeless-0.1.0 → makeless-0.1.2}/memory/store.py +0 -0
  27. {makeless-0.1.0 → makeless-0.1.2}/observability/logger.py +0 -0
  28. {makeless-0.1.0 → makeless-0.1.2}/requirements.txt +0 -0
  29. {makeless-0.1.0 → makeless-0.1.2}/security/permissions.py +0 -0
  30. {makeless-0.1.0 → makeless-0.1.2}/setup.cfg +0 -0
  31. {makeless-0.1.0 → makeless-0.1.2}/tests/test_state.py +0 -0
  32. {makeless-0.1.0 → makeless-0.1.2}/tools/app_launcher.py +0 -0
  33. {makeless-0.1.0 → makeless-0.1.2}/tools/builtin.py +0 -0
  34. {makeless-0.1.0 → makeless-0.1.2}/tools/launcher.py +0 -0
  35. {makeless-0.1.0 → makeless-0.1.2}/tools/locations.py +0 -0
  36. {makeless-0.1.0 → makeless-0.1.2}/tools/open_router.py +0 -0
  37. {makeless-0.1.0 → makeless-0.1.2}/tools/opener.py +0 -0
  38. {makeless-0.1.0 → makeless-0.1.2}/tools/reader.py +0 -0
  39. {makeless-0.1.0 → makeless-0.1.2}/tools/registry.py +0 -0
  40. {makeless-0.1.0 → makeless-0.1.2}/tools/selector.py +0 -0
makeless-0.1.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Avinash Manikonda
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.
@@ -1,9 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: makeless
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A local-first computer operator for Windows.
5
5
  Author: Avinash
6
- License: Copyright (c) 2026 Avinash
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Avinash Manikonda
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
7
27
  Project-URL: Homepage, https://github.com/kkj4u2t7/agentcore
8
28
  Project-URL: Repository, https://github.com/kkj4u2t7/agentcore
9
29
  Requires-Python: >=3.9
makeless-0.1.2/main.py ADDED
@@ -0,0 +1,410 @@
1
+ from tools.filesystem import search_files
2
+ from tools.watcher import start_watcher
3
+ from tools.locations import get_system_location
4
+ from tools.reader import read_file
5
+ from tools.selector import select_result
6
+ from tools.open_router import open_item
7
+ from tools.app_finder import find_apps
8
+ from tools.app_launcher import launch_app
9
+ from tools.launcher import search_in_browser
10
+ from tools.indexer import ensure_index
11
+
12
+
13
+ def choose_path(query):
14
+ """
15
+ Search for an item and let the user choose if
16
+ multiple matches are found.
17
+ """
18
+
19
+ results = search_files(
20
+ query,
21
+ max_results=10
22
+ )
23
+
24
+ if not results:
25
+ return None
26
+
27
+ if len(results) == 1:
28
+ return results[0]
29
+
30
+ return select_result(results)
31
+
32
+
33
+ def choose_app(apps):
34
+ """
35
+ Choose the best application automatically.
36
+ """
37
+
38
+ if not apps:
39
+ return None
40
+
41
+ # app_finder removes duplicate application names
42
+ # and returns the best matches first.
43
+ return apps[0]
44
+
45
+ def handle_instruction(instruction):
46
+ instruction = instruction.strip()
47
+ lower_instruction = instruction.casefold()
48
+
49
+ # Read a file.
50
+ if lower_instruction.startswith("read "):
51
+ query = instruction[5:].strip()
52
+
53
+ if not query:
54
+ print(
55
+ "Makeless: Tell me what you want me to read."
56
+ )
57
+ return
58
+
59
+ print(
60
+ f"\nMakeless: Looking for '{query}'..."
61
+ )
62
+
63
+ path = choose_path(query)
64
+
65
+ if not path:
66
+ print(
67
+ "Makeless: I couldn't find that file."
68
+ )
69
+ return
70
+
71
+ success, content = read_file(path)
72
+
73
+ if not success:
74
+ print(
75
+ f"Makeless: {content}"
76
+ )
77
+ return
78
+
79
+ print("\n" + "=" * 50)
80
+ print(f"READING: {path}")
81
+ print("=" * 50 + "\n")
82
+ print(content)
83
+ print("\n" + "=" * 50)
84
+ print("End of file.")
85
+ print("=" * 50)
86
+
87
+ return
88
+
89
+ # Open a browser and search the web.
90
+ if lower_instruction.startswith("open "):
91
+
92
+ search_separators = [
93
+ " and search for ",
94
+ " and search "
95
+ ]
96
+
97
+ separator_found = None
98
+
99
+ for separator in search_separators:
100
+ if separator in lower_instruction:
101
+ separator_found = separator
102
+ break
103
+
104
+ if separator_found:
105
+ split_index = lower_instruction.index(
106
+ separator_found
107
+ )
108
+
109
+ browser_name = instruction[
110
+ 5:split_index
111
+ ].strip()
112
+
113
+ search_query = instruction[
114
+ split_index + len(separator_found):
115
+ ].strip()
116
+
117
+ if not browser_name:
118
+ print(
119
+ "Makeless: Tell me which browser to use."
120
+ )
121
+ return
122
+
123
+ if not search_query:
124
+ print(
125
+ "Makeless: Tell me what you want to search for."
126
+ )
127
+ return
128
+
129
+ print(
130
+ f"\nMakeless: Searching for "
131
+ f"'{search_query}' in "
132
+ f"{browser_name.title()}..."
133
+ )
134
+
135
+ success, message = search_in_browser(
136
+ search_query,
137
+ browser_name
138
+ )
139
+
140
+ print(f"Makeless: {message}")
141
+ return
142
+
143
+ # Find files and folders.
144
+ if lower_instruction.startswith("find "):
145
+ query = instruction[5:].strip()
146
+
147
+ if not query:
148
+ print(
149
+ "Makeless: Tell me what you want to find."
150
+ )
151
+ return
152
+
153
+ print(
154
+ f"\nMakeless: Searching for '{query}'...\n"
155
+ )
156
+
157
+ results = search_files(query)
158
+
159
+ if not results:
160
+ print(
161
+ "Makeless: Nothing found."
162
+ )
163
+ return
164
+
165
+ print(
166
+ f"Makeless: Found {len(results)} result(s)."
167
+ )
168
+
169
+ for index, result in enumerate(
170
+ results,
171
+ start=1
172
+ ):
173
+ print(
174
+ f"{index}. {result}"
175
+ )
176
+
177
+ return
178
+
179
+ # Open a browser and search the web.
180
+ separator = " and search for "
181
+
182
+ if (
183
+ lower_instruction.startswith("open ")
184
+ and separator in lower_instruction
185
+ ):
186
+ split_index = lower_instruction.index(
187
+ separator
188
+ )
189
+
190
+ browser_name = instruction[
191
+ 5:split_index
192
+ ].strip()
193
+
194
+ search_query = instruction[
195
+ split_index + len(separator):
196
+ ].strip()
197
+
198
+ if not browser_name:
199
+ print(
200
+ "Makeless: Tell me which browser to use."
201
+ )
202
+ return
203
+
204
+ if not search_query:
205
+ print(
206
+ "Makeless: Tell me what you want to search for."
207
+ )
208
+ return
209
+
210
+ print(
211
+ f"\nMakeless: Searching for "
212
+ f"'{search_query}' in "
213
+ f"{browser_name.title()}..."
214
+ )
215
+
216
+ success, message = search_in_browser(
217
+ search_query,
218
+ browser_name
219
+ )
220
+
221
+ print(f"Makeless: {message}")
222
+ return
223
+
224
+ # Open something in VS Code.
225
+ if (
226
+ lower_instruction.startswith("open ")
227
+ and (
228
+ lower_instruction.endswith(" in vs code")
229
+ or lower_instruction.endswith(" in vscode")
230
+ )
231
+ ):
232
+ if lower_instruction.endswith(
233
+ " in vs code"
234
+ ):
235
+ query = instruction[5:-11].strip()
236
+ else:
237
+ query = instruction[5:-10].strip()
238
+
239
+ if not query:
240
+ print(
241
+ "Makeless: Tell me what you want to open."
242
+ )
243
+ return
244
+
245
+ print(
246
+ f"\nMakeless: Looking for '{query}'..."
247
+ )
248
+
249
+ system_location = get_system_location(
250
+ query
251
+ )
252
+
253
+ if system_location:
254
+ path = str(system_location)
255
+ else:
256
+ path = choose_path(query)
257
+
258
+ if not path:
259
+ print(
260
+ "Makeless: I couldn't find that."
261
+ )
262
+ return
263
+
264
+ success, message = open_item(
265
+ path,
266
+ app="vscode"
267
+ )
268
+
269
+ print(f"Makeless: {message}")
270
+ return
271
+
272
+ # Open an app, file, or folder.
273
+ if lower_instruction.startswith("open "):
274
+ query = instruction[5:].strip()
275
+
276
+ if not query:
277
+ print(
278
+ "Makeless: Tell me what you want to open."
279
+ )
280
+ return
281
+
282
+ print(
283
+ f"\nMakeless: Looking for '{query}'..."
284
+ )
285
+
286
+ # 1. Check installed applications FIRST.
287
+ apps = find_apps(query)
288
+
289
+ if apps:
290
+ app = choose_app(apps)
291
+
292
+ if app:
293
+ success, message = launch_app(
294
+ app["path"]
295
+ )
296
+
297
+ if success:
298
+ print(
299
+ f"Makeless: Launched "
300
+ f"{app['name']}"
301
+ )
302
+ else:
303
+ print(
304
+ f"Makeless: {message}"
305
+ )
306
+
307
+ return
308
+
309
+ # 2. Check known system locations.
310
+ system_location = get_system_location(
311
+ query
312
+ )
313
+
314
+ if system_location:
315
+ path = str(system_location)
316
+
317
+ else:
318
+ # 3. Search indexed files and folders.
319
+ path = choose_path(query)
320
+
321
+ if not path:
322
+ print(
323
+ "Makeless: I couldn't find that."
324
+ )
325
+ return
326
+
327
+ success, message = open_item(path)
328
+
329
+ print(f"Makeless: {message}")
330
+ return
331
+
332
+ print(
333
+ "Makeless: I don't know how to perform "
334
+ "that task yet."
335
+ )
336
+
337
+
338
+ def main():
339
+ print("================================")
340
+ print(" Makeless")
341
+ print("================================")
342
+ print("Starting local computer operator...")
343
+
344
+ try:
345
+ ensure_index()
346
+
347
+ observer = start_watcher()
348
+
349
+ except Exception as error:
350
+ print(
351
+ f"\nMakeless: Startup error: {error}"
352
+ )
353
+ return
354
+
355
+ print("\nReady.")
356
+ print("Tell me what you want to do.")
357
+ print("Type 'exit' to close.\n")
358
+
359
+ try:
360
+ while True:
361
+ try:
362
+ instruction = input("You: ")
363
+
364
+ if (
365
+ instruction.strip().casefold()
366
+ == "exit"
367
+ ):
368
+ print(
369
+ "\nMakeless: Shutting down..."
370
+ )
371
+ break
372
+
373
+ if not instruction.strip():
374
+ continue
375
+
376
+ # Run one command safely.
377
+ # If it fails, Makeless stays alive.
378
+ try:
379
+ handle_instruction(instruction)
380
+
381
+ except Exception as error:
382
+ print(
383
+ "\nMakeless: Something went wrong "
384
+ f"while handling that command: {error}"
385
+ )
386
+ print(
387
+ "Makeless: Try another command."
388
+ )
389
+
390
+ except EOFError:
391
+ print(
392
+ "\nMakeless: Input closed."
393
+ )
394
+ break
395
+
396
+ except KeyboardInterrupt:
397
+ print(
398
+ "\n\nMakeless: Interrupted. "
399
+ "Shutting down..."
400
+ )
401
+
402
+ finally:
403
+ observer.stop()
404
+ observer.join()
405
+
406
+ print("Makeless: Goodbye!")
407
+
408
+
409
+ if __name__ == "__main__":
410
+ main()
@@ -1,9 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: makeless
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A local-first computer operator for Windows.
5
5
  Author: Avinash
6
- License: Copyright (c) 2026 Avinash
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Avinash Manikonda
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
7
27
  Project-URL: Homepage, https://github.com/kkj4u2t7/agentcore
8
28
  Project-URL: Repository, https://github.com/kkj4u2t7/agentcore
9
29
  Requires-Python: >=3.9
@@ -21,6 +21,7 @@ tests/test_state.py
21
21
  tools/app_finder.py
22
22
  tools/app_launcher.py
23
23
  tools/builtin.py
24
+ tools/database.py
24
25
  tools/filesystem.py
25
26
  tools/indexer.py
26
27
  tools/launcher.py
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "makeless"
8
- version = "0.1.0"
8
+ version = "0.1.2"
9
9
  description = "A local-first computer operator for Windows."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.9"
@@ -0,0 +1,104 @@
1
+ import os
2
+
3
+
4
+ APP_ALIASES = {
5
+ "vscode": "visual studio code",
6
+ "vs code": "visual studio code",
7
+ "code": "visual studio code",
8
+ "chrome": "google chrome",
9
+ "brave": "brave",
10
+ "edge": "microsoft edge"
11
+ }
12
+
13
+
14
+ def get_start_menu_locations():
15
+ locations = []
16
+
17
+ program_data = os.environ.get("PROGRAMDATA")
18
+
19
+ if program_data:
20
+ locations.append(
21
+ os.path.join(
22
+ program_data,
23
+ "Microsoft",
24
+ "Windows",
25
+ "Start Menu",
26
+ "Programs"
27
+ )
28
+ )
29
+
30
+ app_data = os.environ.get("APPDATA")
31
+
32
+ if app_data:
33
+ locations.append(
34
+ os.path.join(
35
+ app_data,
36
+ "Microsoft",
37
+ "Windows",
38
+ "Start Menu",
39
+ "Programs"
40
+ )
41
+ )
42
+
43
+ return locations
44
+
45
+
46
+ def find_apps(query, max_results=10):
47
+ """
48
+ Search Windows Start Menu shortcuts for applications.
49
+ """
50
+
51
+ query = query.casefold().strip()
52
+
53
+ if not query:
54
+ return []
55
+
56
+ search_query = APP_ALIASES.get(
57
+ query,
58
+ query
59
+ )
60
+
61
+ results = []
62
+ seen_names = set()
63
+
64
+ for location in get_start_menu_locations():
65
+
66
+ if not os.path.exists(location):
67
+ continue
68
+
69
+ for root, directories, files in os.walk(location):
70
+
71
+ for file_name in files:
72
+
73
+ if not file_name.casefold().endswith(".lnk"):
74
+ continue
75
+
76
+ app_name = os.path.splitext(
77
+ file_name
78
+ )[0]
79
+
80
+ normalized_name = app_name.casefold()
81
+
82
+ if search_query not in normalized_name:
83
+ continue
84
+
85
+ # Avoid duplicate shortcuts for the same app.
86
+ if normalized_name in seen_names:
87
+ continue
88
+
89
+ seen_names.add(normalized_name)
90
+
91
+ results.append(
92
+ {
93
+ "name": app_name,
94
+ "path": os.path.join(
95
+ root,
96
+ file_name
97
+ )
98
+ }
99
+ )
100
+
101
+ if len(results) >= max_results:
102
+ return results
103
+
104
+ return results
@@ -0,0 +1,62 @@
1
+ import os
2
+ import sqlite3
3
+ from pathlib import Path
4
+
5
+
6
+ def get_data_directory():
7
+ """
8
+ Return a writable location for Makeless user data.
9
+ """
10
+
11
+ local_app_data = os.environ.get("LOCALAPPDATA")
12
+
13
+ if local_app_data:
14
+ data_directory = Path(local_app_data) / "Makeless"
15
+ else:
16
+ data_directory = Path.home() / ".makeless"
17
+
18
+ data_directory.mkdir(parents=True, exist_ok=True)
19
+
20
+ return data_directory
21
+
22
+
23
+ DATABASE_PATH = get_data_directory() / "agentcore.db"
24
+
25
+
26
+ def get_database_connection():
27
+ """
28
+ Open the Makeless SQLite database.
29
+ """
30
+
31
+ DATABASE_PATH.parent.mkdir(parents=True, exist_ok=True)
32
+
33
+ return sqlite3.connect(DATABASE_PATH)
34
+
35
+
36
+ def create_database():
37
+ """
38
+ Create the database and required tables.
39
+ """
40
+
41
+ connection = get_database_connection()
42
+ cursor = connection.cursor()
43
+
44
+ cursor.execute(
45
+ """
46
+ CREATE TABLE IF NOT EXISTS file_index (
47
+ path TEXT PRIMARY KEY,
48
+ name TEXT NOT NULL,
49
+ item_type TEXT NOT NULL
50
+ )
51
+ """
52
+ )
53
+
54
+ cursor.execute(
55
+ """
56
+ CREATE INDEX IF NOT EXISTS idx_file_name
57
+ ON file_index(name)
58
+ """
59
+ )
60
+
61
+ connection.commit()
62
+ connection.close()