makeless 0.1.0__tar.gz → 0.1.1__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 (36) hide show
  1. makeless-0.1.1/LICENSE +21 -0
  2. {makeless-0.1.0 → makeless-0.1.1}/PKG-INFO +22 -2
  3. {makeless-0.1.0 → makeless-0.1.1}/main.py +115 -50
  4. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/PKG-INFO +22 -2
  5. {makeless-0.1.0 → makeless-0.1.1}/pyproject.toml +1 -1
  6. {makeless-0.1.0 → makeless-0.1.1}/tools/filesystem.py +29 -25
  7. {makeless-0.1.0 → makeless-0.1.1}/tools/indexer.py +83 -19
  8. {makeless-0.1.0 → makeless-0.1.1}/tools/watcher.py +22 -22
  9. makeless-0.1.0/LICENSE +0 -1
  10. {makeless-0.1.0 → makeless-0.1.1}/README.md +0 -0
  11. {makeless-0.1.0 → makeless-0.1.1}/agent/planner.py +0 -0
  12. {makeless-0.1.0 → makeless-0.1.1}/agent/runtime.py +0 -0
  13. {makeless-0.1.0 → makeless-0.1.1}/agent/state.py +0 -0
  14. {makeless-0.1.0 → makeless-0.1.1}/app/main.py +0 -0
  15. {makeless-0.1.0 → makeless-0.1.1}/execution/executor.py +0 -0
  16. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/SOURCES.txt +0 -0
  17. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/dependency_links.txt +0 -0
  18. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/entry_points.txt +0 -0
  19. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/requires.txt +0 -0
  20. {makeless-0.1.0 → makeless-0.1.1}/makeless.egg-info/top_level.txt +0 -0
  21. {makeless-0.1.0 → makeless-0.1.1}/memory/store.py +0 -0
  22. {makeless-0.1.0 → makeless-0.1.1}/observability/logger.py +0 -0
  23. {makeless-0.1.0 → makeless-0.1.1}/requirements.txt +0 -0
  24. {makeless-0.1.0 → makeless-0.1.1}/security/permissions.py +0 -0
  25. {makeless-0.1.0 → makeless-0.1.1}/setup.cfg +0 -0
  26. {makeless-0.1.0 → makeless-0.1.1}/tests/test_state.py +0 -0
  27. {makeless-0.1.0 → makeless-0.1.1}/tools/app_finder.py +0 -0
  28. {makeless-0.1.0 → makeless-0.1.1}/tools/app_launcher.py +0 -0
  29. {makeless-0.1.0 → makeless-0.1.1}/tools/builtin.py +0 -0
  30. {makeless-0.1.0 → makeless-0.1.1}/tools/launcher.py +0 -0
  31. {makeless-0.1.0 → makeless-0.1.1}/tools/locations.py +0 -0
  32. {makeless-0.1.0 → makeless-0.1.1}/tools/open_router.py +0 -0
  33. {makeless-0.1.0 → makeless-0.1.1}/tools/opener.py +0 -0
  34. {makeless-0.1.0 → makeless-0.1.1}/tools/reader.py +0 -0
  35. {makeless-0.1.0 → makeless-0.1.1}/tools/registry.py +0 -0
  36. {makeless-0.1.0 → makeless-0.1.1}/tools/selector.py +0 -0
makeless-0.1.1/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.1
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
@@ -7,6 +7,7 @@ from tools.open_router import open_item
7
7
  from tools.app_finder import find_apps
8
8
  from tools.app_launcher import launch_app
9
9
  from tools.launcher import search_in_browser
10
+ from tools.indexer import ensure_index
10
11
 
11
12
 
12
13
  def choose_path(query):
@@ -60,15 +61,21 @@ def handle_instruction(instruction):
60
61
  query = instruction[5:].strip()
61
62
 
62
63
  if not query:
63
- print("AgentCore: Tell me what you want me to read.")
64
+ print(
65
+ "AgentCore: Tell me what you want me to read."
66
+ )
64
67
  return
65
68
 
66
- print(f"\nAgentCore: Looking for '{query}'...")
69
+ print(
70
+ f"\nAgentCore: Looking for '{query}'..."
71
+ )
67
72
 
68
73
  path = choose_path(query)
69
74
 
70
75
  if not path:
71
- print("AgentCore: I couldn't find that file.")
76
+ print(
77
+ "AgentCore: I couldn't find that file."
78
+ )
72
79
  return
73
80
 
74
81
  success, content = read_file(path)
@@ -94,10 +101,14 @@ def handle_instruction(instruction):
94
101
  query = instruction[5:].strip()
95
102
 
96
103
  if not query:
97
- print("AgentCore: Tell me what you want to find.")
104
+ print(
105
+ "AgentCore: Tell me what you want to find."
106
+ )
98
107
  return
99
108
 
100
- print(f"\nAgentCore: Searching for '{query}'...\n")
109
+ print(
110
+ f"\nAgentCore: Searching for '{query}'...\n"
111
+ )
101
112
 
102
113
  results = search_files(query)
103
114
 
@@ -105,47 +116,72 @@ def handle_instruction(instruction):
105
116
  print("AgentCore: Nothing found.")
106
117
  return
107
118
 
108
- print(f"AgentCore: Found {len(results)} result(s).")
119
+ print(
120
+ f"AgentCore: Found {len(results)} result(s)."
121
+ )
109
122
 
110
- for index, result in enumerate(results, start=1):
123
+ for index, result in enumerate(
124
+ results,
125
+ start=1
126
+ ):
111
127
  print(f"{index}. {result}")
112
128
 
113
129
  return
114
130
 
115
131
  # Open a browser and search the web.
116
- separator = " and search for "
117
-
118
- if (
119
- lower_instruction.startswith("open ")
120
- and separator in lower_instruction
121
- ):
122
- split_index = lower_instruction.index(separator)
132
+ if lower_instruction.startswith("open "):
133
+ search_separators = [
134
+ " and search for ",
135
+ " and search "
136
+ ]
123
137
 
124
- browser_name = instruction[5:split_index].strip()
125
- search_query = instruction[split_index + len(separator):].strip()
138
+ separator_found = None
126
139
 
127
- if not browser_name:
128
- print("AgentCore: Tell me which browser to use.")
129
- return
140
+ for separator in search_separators:
141
+ if separator in lower_instruction:
142
+ separator_found = separator
143
+ break
130
144
 
131
- if not search_query:
132
- print("AgentCore: Tell me what you want to search for.")
145
+ if separator_found:
146
+ split_index = lower_instruction.index(
147
+ separator_found
148
+ )
149
+
150
+ browser_name = instruction[
151
+ 5:split_index
152
+ ].strip()
153
+
154
+ search_query = instruction[
155
+ split_index + len(separator_found):
156
+ ].strip()
157
+
158
+ if not browser_name:
159
+ print(
160
+ "AgentCore: Tell me which browser to use."
161
+ )
162
+ return
163
+
164
+ if not search_query:
165
+ print(
166
+ "AgentCore: Tell me what you want to search for."
167
+ )
168
+ return
169
+
170
+ print(
171
+ f"\nAgentCore: Searching for "
172
+ f"'{search_query}' in "
173
+ f"{browser_name.title()}..."
174
+ )
175
+
176
+ success, message = search_in_browser(
177
+ search_query,
178
+ browser_name
179
+ )
180
+
181
+ print(f"AgentCore: {message}")
133
182
  return
134
183
 
135
- print(
136
- f"\nAgentCore: Searching for "
137
- f"'{search_query}' in {browser_name.title()}..."
138
- )
139
-
140
- success, message = search_in_browser(
141
- search_query,
142
- browser_name
143
- )
144
-
145
- print(f"AgentCore: {message}")
146
- return
147
-
148
- # Open something in a specific application.
184
+ # Open something in VS Code.
149
185
  if (
150
186
  lower_instruction.startswith("open ")
151
187
  and (
@@ -159,10 +195,14 @@ def handle_instruction(instruction):
159
195
  query = instruction[5:-10].strip()
160
196
 
161
197
  if not query:
162
- print("AgentCore: Tell me what you want to open.")
198
+ print(
199
+ "AgentCore: Tell me what you want to open."
200
+ )
163
201
  return
164
202
 
165
- print(f"\nAgentCore: Looking for '{query}'...")
203
+ print(
204
+ f"\nAgentCore: Looking for '{query}'..."
205
+ )
166
206
 
167
207
  system_location = get_system_location(query)
168
208
 
@@ -172,7 +212,9 @@ def handle_instruction(instruction):
172
212
  path = choose_path(query)
173
213
 
174
214
  if not path:
175
- print("AgentCore: I couldn't find that.")
215
+ print(
216
+ "AgentCore: I couldn't find that."
217
+ )
176
218
  return
177
219
 
178
220
  success, message = open_item(
@@ -188,18 +230,23 @@ def handle_instruction(instruction):
188
230
  query = instruction[5:].strip()
189
231
 
190
232
  if not query:
191
- print("AgentCore: Tell me what you want to open.")
233
+ print(
234
+ "AgentCore: Tell me what you want to open."
235
+ )
192
236
  return
193
237
 
194
- print(f"\nAgentCore: Looking for '{query}'...")
238
+ print(
239
+ f"\nAgentCore: Looking for '{query}'..."
240
+ )
195
241
 
196
- # 1. Check known locations first.
242
+ # 1. Check known Windows locations.
197
243
  system_location = get_system_location(query)
198
244
 
199
245
  if system_location:
200
246
  path = str(system_location)
247
+
201
248
  else:
202
- # 2. Check installed apps.
249
+ # 2. Check installed applications.
203
250
  apps = find_apps(query)
204
251
 
205
252
  if apps:
@@ -212,18 +259,23 @@ def handle_instruction(instruction):
212
259
 
213
260
  if success:
214
261
  print(
215
- f"AgentCore: Launched {app['name']}"
262
+ f"AgentCore: Launched "
263
+ f"{app['name']}"
216
264
  )
217
265
  else:
218
- print(f"AgentCore: {message}")
266
+ print(
267
+ f"AgentCore: {message}"
268
+ )
219
269
 
220
270
  return
221
271
 
222
- # 3. Otherwise search files.
272
+ # 3. Search indexed files.
223
273
  path = choose_path(query)
224
274
 
225
275
  if not path:
226
- print("AgentCore: I couldn't find that.")
276
+ print(
277
+ "AgentCore: I couldn't find that."
278
+ )
227
279
  return
228
280
 
229
281
  success, message = open_item(path)
@@ -231,15 +283,22 @@ def handle_instruction(instruction):
231
283
  print(f"AgentCore: {message}")
232
284
  return
233
285
 
234
- print("AgentCore: I don't know how to perform that task yet.")
286
+ print(
287
+ "AgentCore: I don't know how to perform "
288
+ "that task yet."
289
+ )
235
290
 
236
291
 
237
292
  def main():
238
293
  print("================================")
239
- print(" AgentCore Local")
294
+ print(" Makeless")
240
295
  print("================================")
241
296
  print("Starting local computer operator...")
242
297
 
298
+ # Automatically create and build the file index
299
+ # when Makeless runs for the first time.
300
+ ensure_index()
301
+
243
302
  observer = start_watcher()
244
303
 
245
304
  print("\nReady.")
@@ -251,7 +310,9 @@ def main():
251
310
  instruction = input("You: ")
252
311
 
253
312
  if instruction.strip().casefold() == "exit":
254
- print("\nAgentCore: Shutting down...")
313
+ print(
314
+ "\nAgentCore: Shutting down..."
315
+ )
255
316
  break
256
317
 
257
318
  if not instruction.strip():
@@ -260,11 +321,15 @@ def main():
260
321
  handle_instruction(instruction)
261
322
 
262
323
  except KeyboardInterrupt:
263
- print("\n\nAgentCore: Interrupted. Shutting down...")
324
+ print(
325
+ "\n\nAgentCore: Interrupted. "
326
+ "Shutting down..."
327
+ )
264
328
 
265
329
  finally:
266
330
  observer.stop()
267
331
  observer.join()
332
+
268
333
  print("AgentCore: Goodbye!")
269
334
 
270
335
 
@@ -1,9 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: makeless
3
- Version: 0.1.0
3
+ Version: 0.1.1
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
@@ -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.1"
9
9
  description = "A local-first computer operator for Windows."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.9"
@@ -3,28 +3,43 @@ import sqlite3
3
3
  from pathlib import Path
4
4
 
5
5
 
6
- PROJECT_ROOT = Path(__file__).resolve().parent.parent
7
- DATABASE_PATH = PROJECT_ROOT / "data" / "agentcore.db"
6
+ APP_DATA_DIR = Path(
7
+ os.environ.get("LOCALAPPDATA", Path.home())
8
+ ) / "Makeless"
9
+
10
+ DATABASE_PATH = APP_DATA_DIR / "makeless.db"
11
+
12
+
13
+ def get_database_connection():
14
+ APP_DATA_DIR.mkdir(parents=True, exist_ok=True)
15
+
16
+ return sqlite3.connect(DATABASE_PATH)
8
17
 
9
18
 
10
19
  def search_files(query, max_results=20):
11
20
  query = query.casefold()
12
21
 
13
- connection = sqlite3.connect(DATABASE_PATH)
22
+ connection = get_database_connection()
14
23
  cursor = connection.cursor()
15
24
 
16
- cursor.execute(
17
- """
18
- SELECT path, name, item_type
19
- FROM file_index
20
- WHERE LOWER(name) LIKE ?
21
- LIMIT ?
22
- """,
23
- (f"%{query}%", 200)
24
- )
25
+ try:
26
+ cursor.execute(
27
+ """
28
+ SELECT path, name, item_type
29
+ FROM file_index
30
+ WHERE LOWER(name) LIKE ?
31
+ LIMIT ?
32
+ """,
33
+ (f"%{query}%", 200)
34
+ )
35
+
36
+ rows = cursor.fetchall()
25
37
 
26
- rows = cursor.fetchall()
27
- connection.close()
38
+ except sqlite3.OperationalError:
39
+ rows = []
40
+
41
+ finally:
42
+ connection.close()
28
43
 
29
44
  results = []
30
45
 
@@ -37,14 +52,12 @@ def search_files(query, max_results=20):
37
52
  for path, name, item_type in rows:
38
53
  normalized_path = path.casefold()
39
54
 
40
- # Ignore locations that are almost never useful to a user.
41
55
  if any(
42
56
  ignored in normalized_path
43
57
  for ignored in ignored_paths
44
58
  ):
45
59
  continue
46
60
 
47
- # Ignore files that no longer exist.
48
61
  if not os.path.exists(path):
49
62
  continue
50
63
 
@@ -63,7 +76,6 @@ def find_best_match(query):
63
76
  return None
64
77
 
65
78
  query = query.casefold()
66
- project_root = str(PROJECT_ROOT).casefold()
67
79
 
68
80
  def score_result(path):
69
81
  normalized_path = path.casefold()
@@ -71,25 +83,17 @@ def find_best_match(query):
71
83
 
72
84
  score = 0
73
85
 
74
- # Exact filename match.
75
86
  if name == query:
76
87
  score += 1000
77
88
 
78
- # Filename starts with the query.
79
89
  elif name.startswith(query):
80
90
  score += 500
81
91
 
82
- # The AgentCore project gets a strong preference.
83
- if normalized_path.startswith(project_root):
84
- score += 2000
85
-
86
- # Prefer normal user files.
87
92
  user_home = str(Path.home()).casefold()
88
93
 
89
94
  if normalized_path.startswith(user_home):
90
95
  score += 200
91
96
 
92
- # Penalize shortcuts.
93
97
  if name.endswith(".lnk"):
94
98
  score -= 500
95
99
 
@@ -1,11 +1,11 @@
1
1
  import os
2
2
  import sqlite3
3
3
  import string
4
- from pathlib import Path
5
4
 
6
-
7
- PROJECT_ROOT = Path(__file__).resolve().parent.parent
8
- DATABASE_PATH = PROJECT_ROOT / "data" / "agentcore.db"
5
+ from tools.filesystem import (
6
+ DATABASE_PATH,
7
+ APP_DATA_DIR
8
+ )
9
9
 
10
10
 
11
11
  def get_available_drives():
@@ -21,28 +21,60 @@ def get_available_drives():
21
21
 
22
22
 
23
23
  def create_database():
24
- DATABASE_PATH.parent.mkdir(exist_ok=True)
24
+ APP_DATA_DIR.mkdir(
25
+ parents=True,
26
+ exist_ok=True
27
+ )
25
28
 
26
29
  connection = sqlite3.connect(DATABASE_PATH)
27
30
  cursor = connection.cursor()
28
31
 
29
- cursor.execute("""
32
+ cursor.execute(
33
+ """
30
34
  CREATE TABLE IF NOT EXISTS file_index (
31
35
  path TEXT PRIMARY KEY,
32
36
  name TEXT NOT NULL,
33
37
  item_type TEXT NOT NULL
34
38
  )
35
- """)
39
+ """
40
+ )
36
41
 
37
- cursor.execute("""
42
+ cursor.execute(
43
+ """
38
44
  CREATE INDEX IF NOT EXISTS idx_file_name
39
45
  ON file_index(name)
40
- """)
46
+ """
47
+ )
41
48
 
42
49
  connection.commit()
43
50
  connection.close()
44
51
 
45
52
 
53
+ def is_index_ready():
54
+ if not DATABASE_PATH.exists():
55
+ return False
56
+
57
+ try:
58
+ connection = sqlite3.connect(DATABASE_PATH)
59
+ cursor = connection.cursor()
60
+
61
+ cursor.execute(
62
+ """
63
+ SELECT COUNT(*)
64
+ FROM file_index
65
+ """
66
+ )
67
+
68
+ count = cursor.fetchone()[0]
69
+
70
+ connection.close()
71
+
72
+ return count > 0
73
+
74
+ except sqlite3.Error:
75
+ return False
76
+
77
+
46
78
  def index_drive(drive):
47
79
  connection = sqlite3.connect(DATABASE_PATH)
48
80
  cursor = connection.cursor()
@@ -57,7 +89,6 @@ def index_drive(drive):
57
89
  topdown=True,
58
90
  followlinks=False
59
91
  ):
60
- # Don't follow Windows links.
61
92
  directories[:] = [
62
93
  directory
63
94
  for directory in directories
@@ -67,7 +98,10 @@ def index_drive(drive):
67
98
  ]
68
99
 
69
100
  for directory in directories:
70
- full_path = os.path.join(root, directory)
101
+ full_path = os.path.join(
102
+ root,
103
+ directory
104
+ )
71
105
 
72
106
  try:
73
107
  cursor.execute(
@@ -76,7 +110,11 @@ def index_drive(drive):
76
110
  (path, name, item_type)
77
111
  VALUES (?, ?, ?)
78
112
  """,
79
- (full_path, directory, "folder")
113
+ (
114
+ full_path,
115
+ directory,
116
+ "folder"
117
+ )
80
118
  )
81
119
 
82
120
  indexed_count += 1
@@ -84,8 +122,11 @@ def index_drive(drive):
84
122
  except sqlite3.Error:
85
123
  continue
86
124
 
87
- for file in files:
88
- full_path = os.path.join(root, file)
125
+ for file_name in files:
126
+ full_path = os.path.join(
127
+ root,
128
+ file_name
129
+ )
89
130
 
90
131
  try:
91
132
  cursor.execute(
@@ -94,7 +135,11 @@ def index_drive(drive):
94
135
  (path, name, item_type)
95
136
  VALUES (?, ?, ?)
96
137
  """,
97
- (full_path, file, "file")
138
+ (
139
+ full_path,
140
+ file_name,
141
+ "file"
142
+ )
98
143
  )
99
144
 
100
145
  indexed_count += 1
@@ -102,8 +147,10 @@ def index_drive(drive):
102
147
  except sqlite3.Error:
103
148
  continue
104
149
 
105
- # Save progress periodically.
106
- if indexed_count % 1000 == 0 and indexed_count > 0:
150
+ if (
151
+ indexed_count > 0
152
+ and indexed_count % 1000 == 0
153
+ ):
107
154
  connection.commit()
108
155
 
109
156
  except PermissionError:
@@ -112,11 +159,14 @@ def index_drive(drive):
112
159
  connection.commit()
113
160
  connection.close()
114
161
 
115
- print(f"Finished {drive}: {indexed_count} items indexed.")
162
+ print(
163
+ f"Finished {drive}: "
164
+ f"{indexed_count} items indexed."
165
+ )
116
166
 
117
167
 
118
168
  def build_index():
119
- print("\nAgentCore File Indexer")
169
+ print("\nMakeless File Indexer")
120
170
  print("----------------------")
121
171
 
122
172
  create_database()
@@ -129,5 +179,19 @@ def build_index():
129
179
  print("\nIndexing complete.")
130
180
 
131
181
 
182
+ def ensure_index():
183
+ create_database()
184
+
185
+ if is_index_ready():
186
+ return
187
+
188
+ print(
189
+ "\nMakeless is setting up your "
190
+ "local file index for the first time..."
191
+ )
192
+
193
+ build_index()
194
+
195
+
132
196
  if __name__ == "__main__":
133
197
  build_index()
@@ -5,13 +5,7 @@ from pathlib import Path
5
5
  from watchdog.events import FileSystemEventHandler
6
6
  from watchdog.observers import Observer
7
7
 
8
-
9
- PROJECT_ROOT = Path(__file__).resolve().parent.parent
10
- DATABASE_PATH = PROJECT_ROOT / "data" / "agentcore.db"
11
-
12
-
13
- def get_database_connection():
14
- return sqlite3.connect(DATABASE_PATH)
8
+ from tools.filesystem import get_database_connection
15
9
 
16
10
 
17
11
  def add_to_index(path):
@@ -42,7 +36,10 @@ def add_to_index(path):
42
36
  print(f"[INDEX] Added: {path}")
43
37
 
44
38
  except sqlite3.Error as error:
45
- print(f"[WATCHER ERROR] Could not add {path}: {error}")
39
+ print(
40
+ f"[WATCHER ERROR] "
41
+ f"Could not add {path}: {error}"
42
+ )
46
43
 
47
44
 
48
45
  def remove_from_index(path):
@@ -63,10 +60,13 @@ def remove_from_index(path):
63
60
  print(f"[INDEX] Removed: {path}")
64
61
 
65
62
  except sqlite3.Error as error:
66
- print(f"[WATCHER ERROR] Could not remove {path}: {error}")
63
+ print(
64
+ f"[WATCHER ERROR] "
65
+ f"Could not remove {path}: {error}"
66
+ )
67
67
 
68
68
 
69
- class AgentCoreFileHandler(FileSystemEventHandler):
69
+ class MakelessFileHandler(FileSystemEventHandler):
70
70
 
71
71
  def on_created(self, event):
72
72
  add_to_index(event.src_path)
@@ -81,8 +81,9 @@ class AgentCoreFileHandler(FileSystemEventHandler):
81
81
 
82
82
  def get_windows_folder(folder_name):
83
83
  """
84
- Ask Windows for the actual location of a special user folder.
85
- This supports folders redirected to OneDrive.
84
+ Ask Windows for the actual location of a special
85
+ user folder. This supports folders redirected to
86
+ OneDrive.
86
87
  """
87
88
 
88
89
  try:
@@ -97,6 +98,7 @@ def get_windows_folder(folder_name):
97
98
  winreg.HKEY_CURRENT_USER,
98
99
  registry_key
99
100
  ) as key:
101
+
100
102
  value, _ = winreg.QueryValueEx(
101
103
  key,
102
104
  folder_name
@@ -113,12 +115,9 @@ def get_windows_folder(folder_name):
113
115
  def get_watch_paths():
114
116
  home = Path.home()
115
117
 
116
- # Ask Windows for these locations instead of guessing.
117
118
  desktop = get_windows_folder("Desktop")
118
119
  documents = get_windows_folder("Personal")
119
120
 
120
- # Downloads is usually stored under the user's home folder.
121
- # We'll make this dynamically discoverable in the next improvement.
122
121
  downloads = home / "Downloads"
123
122
 
124
123
  paths = [
@@ -142,11 +141,11 @@ def get_watch_paths():
142
141
 
143
142
  def start_watcher():
144
143
  observer = Observer()
145
- handler = AgentCoreFileHandler()
144
+ handler = MakelessFileHandler()
146
145
 
147
146
  watch_paths = get_watch_paths()
148
147
 
149
- print("\nAgentCore File Watcher")
148
+ print("\nMakeless File Watcher")
150
149
  print("----------------------")
151
150
 
152
151
  for path in watch_paths:
@@ -167,12 +166,13 @@ if __name__ == "__main__":
167
166
  observer = start_watcher()
168
167
 
169
168
  try:
170
- print("\nWatcher is running. Press Ctrl + C to stop.")
169
+ print(
170
+ "\nWatcher is running. "
171
+ "Press Ctrl + C to stop."
172
+ )
171
173
 
172
- while True:
173
- pass
174
+ observer.join()
174
175
 
175
176
  except KeyboardInterrupt:
176
177
  observer.stop()
177
-
178
- observer.join()
178
+ observer.join()
makeless-0.1.0/LICENSE DELETED
@@ -1 +0,0 @@
1
- Copyright (c) 2026 Avinash
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes