lwazi 1.15.0 → 1.16.2
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/crawl.php +102 -34
- package/bin/uninstall.js +7 -0
- package/bin/update.js +12 -3
- package/install +16 -3
- package/package.json +1 -1
- package/uninstall +37 -33
package/bin/crawl.php
CHANGED
|
@@ -14,20 +14,106 @@ if (!is_dir($storageDir)) {
|
|
|
14
14
|
mkdir($storageDir, 0755, true);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
$maxDepth = (int)($argv[3] ?? 10);
|
|
17
|
+
echo "Lwazi Web Crawler\n";
|
|
18
|
+
echo "==================\n\n";
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
$options = [
|
|
21
|
+
'url' => 'http://localhost',
|
|
22
|
+
'max_pages' => 1000,
|
|
23
|
+
'max_depth' => 10,
|
|
24
|
+
'login_url' => '',
|
|
25
|
+
'login_user' => '',
|
|
26
|
+
'login_pass' => '',
|
|
27
|
+
];
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
echo "
|
|
29
|
+
// Parse command line arguments
|
|
30
|
+
for ($i = 1; $i < $argc; $i++) {
|
|
31
|
+
$arg = $argv[$i];
|
|
32
|
+
if ($arg === '-h' || $arg === '--help') {
|
|
33
|
+
echo "Usage: php lwazi/bin/crawl.php [options]\n\n";
|
|
34
|
+
echo "Options:\n";
|
|
35
|
+
echo " -u, --url <url> Root URL to crawl (default: http://localhost)\n";
|
|
36
|
+
echo " -m, --max-pages <n> Maximum pages to crawl (default: 1000)\n";
|
|
37
|
+
echo " -d, --max-depth <n> Maximum depth (default: 10)\n";
|
|
38
|
+
echo " -l, --login-url <url> Login page URL\n";
|
|
39
|
+
echo " -e, --login-email <email> Login email/username\n";
|
|
40
|
+
echo " -p, --login-pass <pass> Login password\n";
|
|
41
|
+
echo " --url <url> Root URL to crawl (default: http://localhost)\n";
|
|
42
|
+
echo "\nExamples:\n";
|
|
43
|
+
echo " php lwazi/bin/crawl.php\n";
|
|
44
|
+
echo " php lwazi/bin/crawl.php --url http://localhost:8000\n";
|
|
45
|
+
echo " php lwazi/bin/crawl.php -u http://localhost:8000 -m 500\n";
|
|
46
|
+
echo " php lwazi/bin/crawl.php -u http://localhost -l http://localhost/login -e admin@example.com -p secret\n";
|
|
47
|
+
exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (in_array($arg, ['-u', '--url']) && isset($argv[$i + 1])) {
|
|
51
|
+
$options['url'] = $argv[++$i];
|
|
52
|
+
} elseif (in_array($arg, ['-m', '--max-pages']) && isset($argv[$i + 1])) {
|
|
53
|
+
$options['max_pages'] = (int)$argv[++$i];
|
|
54
|
+
} elseif (in_array($arg, ['-d', '--max-depth']) && isset($argv[$i + 1])) {
|
|
55
|
+
$options['max_depth'] = (int)$argv[++$i];
|
|
56
|
+
} elseif (in_array($arg, ['-l', '--login-url']) && isset($argv[$i + 1])) {
|
|
57
|
+
$options['login_url'] = $argv[++$i];
|
|
58
|
+
} elseif (in_array($arg, ['-e', '--login-email', '--login-user']) && isset($argv[$i + 1])) {
|
|
59
|
+
$options['login_user'] = $argv[++$i];
|
|
60
|
+
} elseif (in_array($arg, ['-p', '--login-pass', '--login-password']) && isset($argv[$i + 1])) {
|
|
61
|
+
$options['login_pass'] = $argv[++$i];
|
|
62
|
+
} elseif (!str_starts_with($arg, '-')) {
|
|
63
|
+
// First non-option argument is URL
|
|
64
|
+
if ($options['url'] === 'http://localhost') {
|
|
65
|
+
$options['url'] = $arg;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Interactive mode if no URL provided
|
|
71
|
+
if ($options['url'] === 'http://localhost' && $argc === 1) {
|
|
72
|
+
echo "Interactive Mode - Press Enter for defaults\n\n";
|
|
73
|
+
|
|
74
|
+
$input = readline("Root URL to crawl [http://localhost:8000]: ");
|
|
75
|
+
if (!empty(trim($input))) {
|
|
76
|
+
$options['url'] = trim($input);
|
|
77
|
+
} else {
|
|
78
|
+
$options['url'] = 'http://localhost:8000';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
$input = readline("Max pages [1000]: ");
|
|
82
|
+
if (!empty(trim($input))) {
|
|
83
|
+
$options['max_pages'] = (int)trim($input);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
$input = readline("Max depth [10]: ");
|
|
87
|
+
if (!empty(trim($input))) {
|
|
88
|
+
$options['max_depth'] = (int)trim($input);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
$input = readline("Login URL (optional, press Enter to skip): ");
|
|
92
|
+
if (!empty(trim($input))) {
|
|
93
|
+
$options['login_url'] = trim($input);
|
|
94
|
+
|
|
95
|
+
if (!empty($options['login_url'])) {
|
|
96
|
+
$input = readline("Login email/username: ");
|
|
97
|
+
$options['login_user'] = trim($input);
|
|
98
|
+
|
|
99
|
+
$input = readline("Login password: ");
|
|
100
|
+
$options['login_pass'] = trim($input);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
echo "\n";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
echo "Root URL: {$options['url']}\n";
|
|
108
|
+
echo "Max pages: {$options['max_pages']}\n";
|
|
109
|
+
echo "Max depth: {$options['max_depth']}\n";
|
|
110
|
+
|
|
111
|
+
$rootUrl = $options['url'];
|
|
112
|
+
$maxPages = $options['max_pages'];
|
|
113
|
+
$maxDepth = $options['max_depth'];
|
|
114
|
+
$loginUrl = $options['login_url'];
|
|
115
|
+
$loginUser = $options['login_user'];
|
|
116
|
+
$loginPass = $options['login_pass'];
|
|
31
117
|
|
|
32
118
|
$cookies = tempnam(sys_get_temp_dir(), 'lwazi_cookies_');
|
|
33
119
|
|
|
@@ -112,7 +198,6 @@ function extractMeta(string $html, string $name): string {
|
|
|
112
198
|
}
|
|
113
199
|
|
|
114
200
|
function extractCsrfToken(string $html): ?string {
|
|
115
|
-
// Look for Laravel CSRF token
|
|
116
201
|
if (preg_match('/name="_token"\s+value="([^"]+)"/', $html, $m)) return $m[1];
|
|
117
202
|
if (preg_match('/name="_token"\s*value="([^"]+)"/', $html, $m)) return $m[1];
|
|
118
203
|
if (preg_match('/meta\s+name="csrf-token"\s+content="([^"]+)"/', $html, $m)) return $m[1];
|
|
@@ -122,7 +207,6 @@ function extractCsrfToken(string $html): ?string {
|
|
|
122
207
|
function loginAndGetCookies(string $loginUrl, string $username, string $password, string $cookies): bool {
|
|
123
208
|
echo "Attempting to login to $loginUrl...\n";
|
|
124
209
|
|
|
125
|
-
// First, get the login page to extract CSRF token
|
|
126
210
|
$ch = curl_init();
|
|
127
211
|
curl_setopt($ch, CURLOPT_URL, $loginUrl);
|
|
128
212
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
@@ -141,15 +225,11 @@ function loginAndGetCookies(string $loginUrl, string $username, string $password
|
|
|
141
225
|
return false;
|
|
142
226
|
}
|
|
143
227
|
|
|
144
|
-
// Extract CSRF token
|
|
145
228
|
$csrfToken = extractCsrfToken($loginPage);
|
|
146
229
|
|
|
147
|
-
// Determine login field names (common patterns)
|
|
148
230
|
$emailField = 'email';
|
|
149
231
|
$passwordField = 'password';
|
|
150
|
-
$usernameField = 'username';
|
|
151
232
|
|
|
152
|
-
// Try to detect field names from the form
|
|
153
233
|
if (preg_match('/name="(email|user|username|login)"[^>]*>/i', $loginPage, $m)) {
|
|
154
234
|
$emailField = $m[1];
|
|
155
235
|
}
|
|
@@ -157,7 +237,6 @@ function loginAndGetCookies(string $loginUrl, string $username, string $password
|
|
|
157
237
|
$passwordField = $m[1];
|
|
158
238
|
}
|
|
159
239
|
|
|
160
|
-
// Build login data
|
|
161
240
|
$loginData = [
|
|
162
241
|
$emailField => $username,
|
|
163
242
|
$passwordField => $password,
|
|
@@ -167,12 +246,8 @@ function loginAndGetCookies(string $loginUrl, string $username, string $password
|
|
|
167
246
|
$loginData['_token'] = $csrfToken;
|
|
168
247
|
}
|
|
169
248
|
|
|
170
|
-
// Try common login field combinations
|
|
171
|
-
$postUrl = $loginUrl;
|
|
172
|
-
|
|
173
|
-
// Submit login
|
|
174
249
|
$ch = curl_init();
|
|
175
|
-
curl_setopt($ch, CURLOPT_URL, $
|
|
250
|
+
curl_setopt($ch, CURLOPT_URL, $loginUrl);
|
|
176
251
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
177
252
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($loginData));
|
|
178
253
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
@@ -187,7 +262,6 @@ function loginAndGetCookies(string $loginUrl, string $username, string $password
|
|
|
187
262
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
188
263
|
curl_close($ch);
|
|
189
264
|
|
|
190
|
-
// Check if login was successful (usually redirects to dashboard or returns 200)
|
|
191
265
|
if ($httpCode >= 200 && $httpCode < 400) {
|
|
192
266
|
echo "Login successful!\n";
|
|
193
267
|
return true;
|
|
@@ -197,18 +271,16 @@ function loginAndGetCookies(string $loginUrl, string $username, string $password
|
|
|
197
271
|
return false;
|
|
198
272
|
}
|
|
199
273
|
|
|
200
|
-
// Login if credentials provided
|
|
201
274
|
if ($loginUrl && $loginUser && $loginPass) {
|
|
202
275
|
$loggedIn = loginAndGetCookies($loginUrl, $loginUser, $loginPass, $cookies);
|
|
203
276
|
if (!$loggedIn) {
|
|
204
277
|
echo "Warning: Login may have failed. Continuing anyway...\n";
|
|
205
278
|
}
|
|
206
|
-
}
|
|
207
|
-
echo "
|
|
208
|
-
echo " php lwazi/bin/crawl.php <url> [max_pages] [max_depth] <login_url> <username> <password>\n\n";
|
|
279
|
+
} elseif ($loginUrl && !$loginUser) {
|
|
280
|
+
echo "Login URL provided but no credentials. Skipping login.\n";
|
|
209
281
|
}
|
|
210
282
|
|
|
211
|
-
echo "
|
|
283
|
+
echo "\nStarting crawl...\n\n";
|
|
212
284
|
|
|
213
285
|
$visited = [];
|
|
214
286
|
$queue = [[$rootUrl, 0]];
|
|
@@ -250,7 +322,6 @@ while (!empty($queue) && $totalPages < $maxPages) {
|
|
|
250
322
|
continue;
|
|
251
323
|
}
|
|
252
324
|
|
|
253
|
-
// Check for login redirect
|
|
254
325
|
if (stripos($html, 'login') !== false && stripos($html, 'password') !== false) {
|
|
255
326
|
echo " -> Login required, skipping\n";
|
|
256
327
|
continue;
|
|
@@ -284,7 +355,6 @@ while (!empty($queue) && $totalPages < $maxPages) {
|
|
|
284
355
|
|
|
285
356
|
echo "\nCrawling complete! Found $totalPages pages.\n";
|
|
286
357
|
|
|
287
|
-
// Save manifest
|
|
288
358
|
$manifest = [
|
|
289
359
|
'root_url' => $rootUrl,
|
|
290
360
|
'crawled_at' => date('c'),
|
|
@@ -296,12 +366,10 @@ $manifest = [
|
|
|
296
366
|
file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT));
|
|
297
367
|
echo "Saved manifest to lwazi/manifest.json\n";
|
|
298
368
|
|
|
299
|
-
// Save page data for later indexing
|
|
300
369
|
$indexFile = $storageDir . '/crawl_data.json';
|
|
301
370
|
file_put_contents($indexFile, json_encode($pageData));
|
|
302
371
|
echo "Saved page data to storage/lwazi/crawl_data.json\n";
|
|
303
372
|
|
|
304
|
-
// Cleanup
|
|
305
373
|
@unlink($cookies);
|
|
306
374
|
|
|
307
375
|
echo "\nDone! You can now use lwazi with your knowledge base.\n";
|
package/bin/uninstall.js
CHANGED
|
@@ -100,6 +100,13 @@ function manualCleanup() {
|
|
|
100
100
|
console.log(colors.green('✓') + ' Removed lwazi directory');
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
// Remove storage/lwazi directory
|
|
104
|
+
const storageLwazi = path.join(projectRoot, 'storage', 'lwazi');
|
|
105
|
+
if (fs.existsSync(storageLwazi)) {
|
|
106
|
+
fs.rmSync(storageLwazi, { recursive: true, force: true });
|
|
107
|
+
console.log(colors.green('✓') + ' Removed storage/lwazi directory');
|
|
108
|
+
}
|
|
109
|
+
|
|
103
110
|
// Remove from composer.json
|
|
104
111
|
const composerJson = path.join(projectRoot, 'composer.json');
|
|
105
112
|
if (fs.existsSync(composerJson)) {
|
package/bin/update.js
CHANGED
|
@@ -125,6 +125,15 @@ try {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
console.log("\nLwazi updated successfully!");
|
|
128
|
-
console.log("\
|
|
129
|
-
console.log("
|
|
130
|
-
console.log("
|
|
128
|
+
console.log("\n========================================");
|
|
129
|
+
console.log(" Available Commands");
|
|
130
|
+
console.log("========================================");
|
|
131
|
+
console.log("\n1. Crawl your website (builds page map):");
|
|
132
|
+
console.log(" php lwazi/bin/crawl.php # Interactive mode");
|
|
133
|
+
console.log(" php lwazi/bin/crawl.php -u http://localhost:8000");
|
|
134
|
+
console.log(" php lwazi/bin/crawl.php --url http://localhost --help");
|
|
135
|
+
console.log("\n2. Re-analyze project (updates routes/models):");
|
|
136
|
+
console.log(" php lwazi/bin/analyze.php");
|
|
137
|
+
console.log("\n3. Crawl with login (for authenticated pages):");
|
|
138
|
+
console.log(" php lwazi/bin/crawl.php -u http://localhost -l /login -e user@email.com -p password");
|
|
139
|
+
console.log("\n========================================");
|
package/install
CHANGED
|
@@ -214,9 +214,22 @@ if [ "$COMPOSER_USED" = true ]; then
|
|
|
214
214
|
fi
|
|
215
215
|
|
|
216
216
|
echo ""
|
|
217
|
-
echo "
|
|
218
|
-
echo "
|
|
219
|
-
echo "
|
|
217
|
+
echo "========================================"
|
|
218
|
+
echo " Available Commands"
|
|
219
|
+
echo "========================================"
|
|
220
|
+
echo ""
|
|
221
|
+
echo "1. Crawl your website (builds page map):"
|
|
222
|
+
echo " php lwazi/bin/crawl.php # Interactive mode"
|
|
223
|
+
echo " php lwazi/bin/crawl.php -u http://localhost:8000"
|
|
224
|
+
echo " php lwazi/bin/crawl.php --url http://localhost --help"
|
|
225
|
+
echo ""
|
|
226
|
+
echo "2. Re-analyze project (updates routes/models):"
|
|
227
|
+
echo " php lwazi/bin/analyze.php"
|
|
228
|
+
echo ""
|
|
229
|
+
echo "3. Crawl with login (for authenticated pages):"
|
|
230
|
+
echo " php lwazi/bin/crawl.php -u http://localhost -l /login -e user@email.com -p password"
|
|
231
|
+
echo ""
|
|
232
|
+
echo "========================================"
|
|
220
233
|
echo ""
|
|
221
234
|
echo "Configuration:"
|
|
222
235
|
echo " - Model: $MODEL"
|
package/package.json
CHANGED
package/uninstall
CHANGED
|
@@ -98,44 +98,48 @@ if [ -f "$PROJECT_DIR/artisan" ]; then
|
|
|
98
98
|
echo "Cleared caches"
|
|
99
99
|
fi
|
|
100
100
|
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
# Always clean up composer.json (lwazi might have added it even if mode wasn't saved)
|
|
102
|
+
echo "Cleaning up composer.json..."
|
|
103
|
+
php -r '
|
|
104
|
+
$file = "composer.json";
|
|
105
|
+
if (file_exists($file)) {
|
|
106
|
+
$json = json_decode(file_get_contents($file), true);
|
|
107
|
+
$changed = false;
|
|
108
|
+
|
|
109
|
+
if (isset($json["require"]["lwazi/core"])) {
|
|
110
|
+
unset($json["require"]["lwazi/core"]);
|
|
111
|
+
$changed = true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (isset($json["repositories"]) && is_array($json["repositories"])) {
|
|
115
|
+
$originalCount = count($json["repositories"]);
|
|
116
|
+
$json["repositories"] = array_filter($json["repositories"], function($repo) {
|
|
117
|
+
return !isset($repo["url"]) || $repo["url"] !== "lwazi";
|
|
118
|
+
});
|
|
119
|
+
if (count($json["repositories"]) !== $originalCount) {
|
|
112
120
|
$changed = true;
|
|
113
121
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
$original = $json["repositories"];
|
|
117
|
-
$json["repositories"] = array_filter($json["repositories"], function($repo) {
|
|
118
|
-
return !isset($repo["url"]) || $repo["url"] !== "lwazi";
|
|
119
|
-
});
|
|
120
|
-
if (count($json["repositories"]) !== count($original)) {
|
|
121
|
-
$changed = true;
|
|
122
|
-
}
|
|
123
|
-
if (empty($json["repositories"])) {
|
|
124
|
-
unset($json["repositories"]);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if ($changed) {
|
|
129
|
-
file_put_contents($file, json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
130
|
-
echo "Removed lwazi from composer.json\n";
|
|
122
|
+
if (empty($json["repositories"])) {
|
|
123
|
+
unset($json["repositories"]);
|
|
131
124
|
}
|
|
132
125
|
}
|
|
133
|
-
'
|
|
134
126
|
|
|
135
|
-
|
|
136
|
-
if
|
|
137
|
-
|
|
138
|
-
|
|
127
|
+
// Remove minimum-stability if it was added for lwazi
|
|
128
|
+
if (isset($json["minimum-stability"]) && isset($json["prefer-stable"])) {
|
|
129
|
+
// Keep them if other packages need them
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ($changed) {
|
|
133
|
+
file_put_contents($file, json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
134
|
+
echo "Removed lwazi from composer.json\n";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
'
|
|
138
|
+
|
|
139
|
+
# Remove storage/lwazi directory
|
|
140
|
+
if [ -d "$PROJECT_DIR/storage/lwazi" ]; then
|
|
141
|
+
rm -rf "$PROJECT_DIR/storage/lwazi"
|
|
142
|
+
echo "Removed storage/lwazi directory"
|
|
139
143
|
fi
|
|
140
144
|
|
|
141
145
|
echo ""
|