Compare commits
No commits in common. "860a460a93fcce8b4e187d071793c1c367477f71" and "ece4a72e10b10b919fc1d6108cdd8b8522c9c981" have entirely different histories.
860a460a93
...
ece4a72e10
28 changed files with 482 additions and 1586 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
|
@ -30,17 +30,7 @@ botserver-installers/*
|
||||||
!botserver-installers/.gitkeep
|
!botserver-installers/.gitkeep
|
||||||
botserver-stack
|
botserver-stack
|
||||||
TODO*
|
TODO*
|
||||||
work
|
|
||||||
|
|
||||||
# Lock file (regenerated from Cargo.toml)
|
# Lock file (regenerated from Cargo.toml)
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.kiro
|
|
||||||
config
|
|
||||||
|
|
||||||
# Playwright
|
|
||||||
node_modules/
|
|
||||||
/test-results/
|
|
||||||
/playwright-report/
|
|
||||||
/blob-report/
|
|
||||||
/playwright/.cache/
|
|
||||||
/playwright/.auth/
|
|
||||||
|
|
|
||||||
9
.idea/gb.iml
generated
9
.idea/gb.iml
generated
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
10
.idea/libraries/botserver_installers.xml
generated
10
.idea/libraries/botserver_installers.xml
generated
|
|
@ -1,10 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="botserver-installers">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$PROJECT_DIR$/botserver/botserver-installers/llama-b7345-bin-ubuntu-x64.zip!/" />
|
|
||||||
<root url="jar://$PROJECT_DIR$/botserver/botserver-installers/vault_1.15.4_linux_amd64.zip!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager" version="2">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/gb.iml" filepath="$PROJECT_DIR$/.idea/gb.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
52
.idea/workspace.xml
generated
52
.idea/workspace.xml
generated
|
|
@ -1,52 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="32fd08b0-7933-467d-9a46-1a53fd2da15c" name="Changes" comment="">
|
|
||||||
<change beforePath="$PROJECT_DIR$/botserver" beforeDir="false" afterPath="$PROJECT_DIR$/botserver" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectColorInfo"><![CDATA[{
|
|
||||||
"associatedIndex": 1
|
|
||||||
}]]></component>
|
|
||||||
<component name="ProjectId" id="38qdWTFkX8Nem4LzgigXpAycSN7" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
|
||||||
"keyToString": {
|
|
||||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
|
||||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
||||||
"git-widget-placeholder": "main",
|
|
||||||
"last_opened_file_path": "/home/rodriguez/src/gb",
|
|
||||||
"vue.rearranger.settings.migration": "true"
|
|
||||||
}
|
|
||||||
}]]></component>
|
|
||||||
<component name="SharedIndexes">
|
|
||||||
<attachedChunks>
|
|
||||||
<set>
|
|
||||||
<option value="bundled-jdk-30f59d01ecdd-2fc7cc6b9a17-intellij.indexing.shared.core-IU-253.30387.90" />
|
|
||||||
</set>
|
|
||||||
</attachedChunks>
|
|
||||||
</component>
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="32fd08b0-7933-467d-9a46-1a53fd2da15c" name="Changes" comment="" />
|
|
||||||
<created>1769531070022</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1769531070022</updated>
|
|
||||||
<workItem from="1769531115917" duration="176000" />
|
|
||||||
</task>
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,198 +0,0 @@
|
||||||
{
|
|
||||||
"languages": {
|
|
||||||
"typescript": {
|
|
||||||
"name": "typescript-language-server",
|
|
||||||
"command": "typescript-language-server",
|
|
||||||
"args": [
|
|
||||||
"--stdio"
|
|
||||||
],
|
|
||||||
"file_extensions": [
|
|
||||||
"ts",
|
|
||||||
"js",
|
|
||||||
"tsx",
|
|
||||||
"jsx"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"package.json",
|
|
||||||
"tsconfig.json"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/node_modules/**",
|
|
||||||
"**/dist/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {
|
|
||||||
"preferences": {
|
|
||||||
"disableSuggestions": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"python": {
|
|
||||||
"name": "pyright",
|
|
||||||
"command": "pyright-langserver",
|
|
||||||
"args": [
|
|
||||||
"--stdio"
|
|
||||||
],
|
|
||||||
"file_extensions": [
|
|
||||||
"py"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"pyproject.toml",
|
|
||||||
"setup.py",
|
|
||||||
"requirements.txt",
|
|
||||||
"pyrightconfig.json"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/__pycache__/**",
|
|
||||||
"**/venv/**",
|
|
||||||
"**/.venv/**",
|
|
||||||
"**/.pytest_cache/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"rust": {
|
|
||||||
"name": "rust-analyzer",
|
|
||||||
"command": "rust-analyzer",
|
|
||||||
"args": [],
|
|
||||||
"file_extensions": [
|
|
||||||
"rs"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"Cargo.toml"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/target/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {
|
|
||||||
"cargo": {
|
|
||||||
"buildScripts": {
|
|
||||||
"enable": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"diagnostics": {
|
|
||||||
"enable": true,
|
|
||||||
"enableExperimental": true
|
|
||||||
},
|
|
||||||
"workspace": {
|
|
||||||
"symbol": {
|
|
||||||
"search": {
|
|
||||||
"scope": "workspace"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"java": {
|
|
||||||
"name": "jdtls",
|
|
||||||
"command": "jdtls",
|
|
||||||
"args": [],
|
|
||||||
"file_extensions": [
|
|
||||||
"java"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"pom.xml",
|
|
||||||
"build.gradle",
|
|
||||||
"build.gradle.kts",
|
|
||||||
".project"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/target/**",
|
|
||||||
"**/build/**",
|
|
||||||
"**/.gradle/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {
|
|
||||||
"settings": {
|
|
||||||
"java": {
|
|
||||||
"compile": {
|
|
||||||
"nullAnalysis": {
|
|
||||||
"mode": "automatic"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"configuration": {
|
|
||||||
"annotationProcessing": {
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"ruby": {
|
|
||||||
"name": "solargraph",
|
|
||||||
"command": "solargraph",
|
|
||||||
"args": [
|
|
||||||
"stdio"
|
|
||||||
],
|
|
||||||
"file_extensions": [
|
|
||||||
"rb"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"Gemfile",
|
|
||||||
"Rakefile"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/vendor/**",
|
|
||||||
"**/tmp/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"go": {
|
|
||||||
"name": "gopls",
|
|
||||||
"command": "gopls",
|
|
||||||
"args": [],
|
|
||||||
"file_extensions": [
|
|
||||||
"go"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"go.mod",
|
|
||||||
"go.sum"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/vendor/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {
|
|
||||||
"usePlaceholders": true,
|
|
||||||
"completeUnimported": true
|
|
||||||
},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
},
|
|
||||||
"cpp": {
|
|
||||||
"name": "clangd",
|
|
||||||
"command": "clangd",
|
|
||||||
"args": [
|
|
||||||
"--background-index"
|
|
||||||
],
|
|
||||||
"file_extensions": [
|
|
||||||
"cpp",
|
|
||||||
"cc",
|
|
||||||
"cxx",
|
|
||||||
"c",
|
|
||||||
"h",
|
|
||||||
"hpp",
|
|
||||||
"hxx"
|
|
||||||
],
|
|
||||||
"project_patterns": [
|
|
||||||
"CMakeLists.txt",
|
|
||||||
"compile_commands.json",
|
|
||||||
"Makefile"
|
|
||||||
],
|
|
||||||
"exclude_patterns": [
|
|
||||||
"**/build/**",
|
|
||||||
"**/cmake-build-**/**"
|
|
||||||
],
|
|
||||||
"multi_workspace": false,
|
|
||||||
"initialization_options": {},
|
|
||||||
"request_timeout_secs": 60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"languages": {
|
|
||||||
"Rust": {
|
|
||||||
"enable_language_server": false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
383
PROMPT.md
Normal file
383
PROMPT.md
Normal file
|
|
@ -0,0 +1,383 @@
|
||||||
|
# General Bots Workspace - Master Development Guide
|
||||||
|
|
||||||
|
**Version:** 6.2.0 - DO NOT CHANGE
|
||||||
|
**Project:** General Bots Workspace (Rust Monorepo)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 WORKSPACE STRUCTURE
|
||||||
|
|
||||||
|
| Crate | Purpose | Port | Tech Stack |
|
||||||
|
|-------|---------|------|------------|
|
||||||
|
| **botserver** | Main API server, business logic | 8088 | Axum, Diesel, Rhai BASIC |
|
||||||
|
| **botui** | Web UI server (dev) + proxy | 3000 | Axum, HTML/HTMX/CSS |
|
||||||
|
| **botapp** | Desktop app wrapper | - | Tauri 2 |
|
||||||
|
| **botlib** | Shared library | - | Core types, errors |
|
||||||
|
| **botbook** | Documentation | - | mdBook |
|
||||||
|
| **bottest** | Integration tests | - | tokio-test |
|
||||||
|
| **botdevice** | IoT/Device support | - | Rust |
|
||||||
|
| **botmodels** | Data models visualization | - | - |
|
||||||
|
| **botplugin** | Browser extension | - | JS |
|
||||||
|
|
||||||
|
### Key Paths
|
||||||
|
- **Binary:** `target/debug/botserver`
|
||||||
|
- **Run from:** `botserver/` directory
|
||||||
|
- **Env file:** `botserver/.env`
|
||||||
|
- **Stack:** `botserver/botserver-stack/`
|
||||||
|
- **UI Files:** `botui/ui/suite/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔥 ERROR FIXING WORKFLOW
|
||||||
|
|
||||||
|
### Mode 1: OFFLINE Batch Fix (PREFERRED)
|
||||||
|
|
||||||
|
When given error output:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Read ENTIRE error list first
|
||||||
|
2. Group errors by file
|
||||||
|
3. For EACH file with errors:
|
||||||
|
a. View file → understand context
|
||||||
|
b. Fix ALL errors in that file
|
||||||
|
c. Write once with all fixes
|
||||||
|
4. Move to next file
|
||||||
|
5. REPEAT until ALL errors addressed
|
||||||
|
6. ONLY THEN → verify with build/diagnostics
|
||||||
|
```
|
||||||
|
|
||||||
|
**NEVER run cargo build/check/clippy DURING fixing**
|
||||||
|
**Fix ALL errors OFFLINE first, verify ONCE at the end**
|
||||||
|
|
||||||
|
### Mode 2: Interactive Loop
|
||||||
|
|
||||||
|
```
|
||||||
|
LOOP UNTIL (0 warnings AND 0 errors):
|
||||||
|
1. Run diagnostics → pick file with issues
|
||||||
|
2. Read entire file
|
||||||
|
3. Fix ALL issues in that file
|
||||||
|
4. Write file once with all fixes
|
||||||
|
5. Verify with diagnostics
|
||||||
|
6. CONTINUE LOOP
|
||||||
|
END LOOP
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Error Patterns
|
||||||
|
|
||||||
|
| Error | Fix |
|
||||||
|
|-------|-----|
|
||||||
|
| `expected i64, found u64` | `value as i64` |
|
||||||
|
| `expected Option<T>, found T` | `Some(value)` |
|
||||||
|
| `expected T, found Option<T>` | `value.unwrap_or(default)` |
|
||||||
|
| `cannot multiply f32 by f64` | `f64::from(f32_val) * f64_val` |
|
||||||
|
| `no field X on type Y` | Check struct definition |
|
||||||
|
| `no variant X found` | Check enum definition |
|
||||||
|
| `function takes N arguments` | Match function signature |
|
||||||
|
| `cannot find function` | Add missing function or fix import |
|
||||||
|
| `unused variable` | Delete or use with `..` in patterns |
|
||||||
|
| `unused import` | Delete the import line |
|
||||||
|
| `cannot move out of X because borrowed` | Use scoping `{ }` to limit borrow |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 MEMORY MANAGEMENT
|
||||||
|
|
||||||
|
When compilation fails due to memory issues (process "Killed"):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pkill -9 cargo; pkill -9 rustc; pkill -9 botserver
|
||||||
|
CARGO_BUILD_JOBS=1 cargo check -p botserver 2>&1 | tail -200
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📏 FILE SIZE LIMITS - MANDATORY
|
||||||
|
|
||||||
|
### Maximum 1000 Lines Per File
|
||||||
|
|
||||||
|
When a file grows beyond this limit:
|
||||||
|
|
||||||
|
1. **Identify logical groups** - Find related functions
|
||||||
|
2. **Create subdirectory module** - e.g., `handlers/`
|
||||||
|
3. **Split by responsibility:**
|
||||||
|
- `crud.rs` - Create, Read, Update, Delete
|
||||||
|
- `ai.rs` - AI/ML handlers
|
||||||
|
- `export.rs` - Export/import
|
||||||
|
- `validation.rs` - Validation
|
||||||
|
- `mod.rs` - Re-exports
|
||||||
|
4. **Keep files focused** - Single responsibility
|
||||||
|
5. **Update mod.rs** - Re-export all public items
|
||||||
|
|
||||||
|
**NEVER let a single file exceed 1000 lines - split proactively at 800 lines**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 PERFORMANCE & SIZE STANDARDS
|
||||||
|
|
||||||
|
### Binary Size Optimization
|
||||||
|
- **Release Profile**: Always maintain `opt-level = "z"`, `lto = true`, `codegen-units = 1`, `strip = true`, `panic = "abort"`.
|
||||||
|
- **Dependencies**:
|
||||||
|
- Run `cargo tree --duplicates` weekly to find and resolve duplicate versions.
|
||||||
|
- Run `cargo machete` to remove unused dependencies.
|
||||||
|
- Use `default-features = false` and explicitly opt-in to needed features.
|
||||||
|
|
||||||
|
### Memory Optimization
|
||||||
|
- **Strings**: Prefer `&str` over `String` where possible. Use `Cow<str>` for conditional ownership.
|
||||||
|
- **Collections**: Use `Vec::with_capacity` when size is known. Consider `SmallVec` for hot paths.
|
||||||
|
- **Allocations**: Minimize heap allocations in hot paths.
|
||||||
|
|
||||||
|
### Linting & Code Quality
|
||||||
|
- **Clippy**: Code MUST pass `cargo clippy --all-targets --all-features` with **0 warnings**.
|
||||||
|
- **No Allow**: Do not use `#[allow(clippy::...)]` unless absolutely necessary and documented. Fix the underlying issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 SECURITY DIRECTIVES - MANDATORY
|
||||||
|
|
||||||
|
### Error Handling - NO PANICS IN PRODUCTION
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ❌ FORBIDDEN
|
||||||
|
value.unwrap()
|
||||||
|
value.expect("message")
|
||||||
|
panic!("error")
|
||||||
|
todo!()
|
||||||
|
unimplemented!()
|
||||||
|
|
||||||
|
// ✅ REQUIRED
|
||||||
|
value?
|
||||||
|
value.ok_or_else(|| Error::NotFound)?
|
||||||
|
value.unwrap_or_default()
|
||||||
|
value.unwrap_or_else(|e| { log::error!("{}", e); default })
|
||||||
|
if let Some(v) = value { ... }
|
||||||
|
match value { Ok(v) => v, Err(e) => return Err(e.into()) }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Execution - USE SafeCommand
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ❌ FORBIDDEN
|
||||||
|
Command::new("some_command").arg(user_input).output()
|
||||||
|
|
||||||
|
// ✅ REQUIRED
|
||||||
|
use crate::security::command_guard::SafeCommand;
|
||||||
|
SafeCommand::new("allowed_command")?
|
||||||
|
.arg("safe_arg")?
|
||||||
|
.execute()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Responses - USE ErrorSanitizer
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ❌ FORBIDDEN
|
||||||
|
Json(json!({ "error": e.to_string() }))
|
||||||
|
format!("Database error: {}", e)
|
||||||
|
|
||||||
|
// ✅ REQUIRED
|
||||||
|
use crate::security::error_sanitizer::log_and_sanitize;
|
||||||
|
let sanitized = log_and_sanitize(&e, "context", None);
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, sanitized)
|
||||||
|
```
|
||||||
|
|
||||||
|
### SQL - USE sql_guard
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ❌ FORBIDDEN
|
||||||
|
format!("SELECT * FROM {}", user_table)
|
||||||
|
|
||||||
|
// ✅ REQUIRED
|
||||||
|
use crate::security::sql_guard::{sanitize_identifier, validate_table_name};
|
||||||
|
let safe_table = sanitize_identifier(&user_table);
|
||||||
|
validate_table_name(&safe_table)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❌ ABSOLUTE PROHIBITIONS
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ NEVER use .unwrap() or .expect() in production code (tests OK)
|
||||||
|
❌ NEVER use panic!(), todo!(), unimplemented!()
|
||||||
|
❌ NEVER use Command::new() directly - use SafeCommand
|
||||||
|
❌ NEVER return raw error strings to HTTP clients
|
||||||
|
❌ NEVER use #[allow()] in source code - FIX the code instead
|
||||||
|
❌ NEVER add lint exceptions to Cargo.toml - FIX the code instead
|
||||||
|
❌ NEVER use _ prefix for unused variables - DELETE or USE them
|
||||||
|
❌ NEVER leave unused imports or dead code
|
||||||
|
❌ NEVER add comments - code must be self-documenting
|
||||||
|
❌ NEVER modify Cargo.toml lints section!
|
||||||
|
❌ NEVER use CDN links - all assets must be local
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ MANDATORY CODE PATTERNS
|
||||||
|
|
||||||
|
### Use Self in Impl Blocks
|
||||||
|
```rust
|
||||||
|
impl MyStruct {
|
||||||
|
fn new() -> Self { Self { } } // ✅ Not MyStruct
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Derive Eq with PartialEq
|
||||||
|
```rust
|
||||||
|
#[derive(PartialEq, Eq)] // ✅ Always both
|
||||||
|
struct MyStruct { }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inline Format Args
|
||||||
|
```rust
|
||||||
|
format!("Hello {name}") // ✅ Not format!("{}", name)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Combine Match Arms
|
||||||
|
```rust
|
||||||
|
match x {
|
||||||
|
A | B => do_thing(), // ✅ Combine identical arms
|
||||||
|
C => other(),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ UI Architecture (botui + botserver)
|
||||||
|
|
||||||
|
### Two Servers During Development
|
||||||
|
|
||||||
|
| Server | Port | Purpose |
|
||||||
|
|--------|------|---------|
|
||||||
|
| **botui** | 3000 | Serves UI files + proxies API to botserver |
|
||||||
|
| **botserver** | 8088 | Backend API + embedded UI fallback |
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser → localhost:3000 → botui (serves HTML/CSS/JS)
|
||||||
|
→ /api/* proxied to botserver:8088
|
||||||
|
→ /suite/* served from botui/ui/suite/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New Suite Apps
|
||||||
|
|
||||||
|
1. Create folder: `botui/ui/suite/<appname>/`
|
||||||
|
2. Add to `SUITE_DIRS` in `botui/src/ui_server/mod.rs`
|
||||||
|
3. Rebuild botui: `cargo build -p botui`
|
||||||
|
4. Add menu entry in `botui/ui/suite/index.html`
|
||||||
|
|
||||||
|
### Hot Reload
|
||||||
|
|
||||||
|
- **UI files (HTML/CSS/JS)**: Edit & refresh browser (no restart)
|
||||||
|
- **botui Rust code**: Rebuild + restart botui
|
||||||
|
- **botserver Rust code**: Rebuild + restart botserver
|
||||||
|
|
||||||
|
### Production (Single Binary)
|
||||||
|
|
||||||
|
When `botui/ui/suite/` folder not found, botserver uses **embedded UI** compiled into binary via `rust-embed`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 FRONTEND STANDARDS
|
||||||
|
|
||||||
|
### HTMX-First Approach
|
||||||
|
- Use HTMX to minimize JavaScript
|
||||||
|
- Server returns HTML fragments, not JSON
|
||||||
|
- Use `hx-get`, `hx-post`, `hx-target`, `hx-swap`
|
||||||
|
- WebSocket via htmx-ws extension
|
||||||
|
|
||||||
|
### Local Assets Only - NO CDN
|
||||||
|
```html
|
||||||
|
<!-- ✅ CORRECT -->
|
||||||
|
<script src="js/vendor/htmx.min.js"></script>
|
||||||
|
|
||||||
|
<!-- ❌ WRONG -->
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vendor Libraries Location
|
||||||
|
```
|
||||||
|
ui/suite/js/vendor/
|
||||||
|
├── htmx.min.js
|
||||||
|
├── htmx-ws.js
|
||||||
|
├── marked.min.js
|
||||||
|
└── gsap.min.js
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 PROJECT-SPECIFIC PROMPTS
|
||||||
|
|
||||||
|
Each crate has its own PROMPT.md with specific guidelines:
|
||||||
|
|
||||||
|
| Crate | PROMPT.md Location | Focus |
|
||||||
|
|-------|-------------------|-------|
|
||||||
|
| botserver | `botserver/PROMPT.md` | API, security, Rhai BASIC |
|
||||||
|
| botui | `botui/PROMPT.md` | UI, HTMX, CSS design system |
|
||||||
|
| botapp | `botapp/PROMPT.md` | Tauri, desktop features |
|
||||||
|
| botlib | `botlib/PROMPT.md` | Shared types, errors |
|
||||||
|
| botbook | `botbook/PROMPT.md` | Documentation, mdBook |
|
||||||
|
| bottest | `bottest/PROMPT.md` | Test infrastructure |
|
||||||
|
|
||||||
|
### Special Prompts
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `botserver/src/tasks/PROMPT.md` | AutoTask LLM executor |
|
||||||
|
| `botserver/src/auto_task/APP_GENERATOR_PROMPT.md` | App generation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 STARTING DEVELOPMENT
|
||||||
|
|
||||||
|
### Start Both Servers
|
||||||
|
```bash
|
||||||
|
# Terminal 1: botserver
|
||||||
|
cd botserver && cargo run -- --noconsole
|
||||||
|
|
||||||
|
# Terminal 2: botui
|
||||||
|
cd botui && BOTSERVER_URL="http://localhost:8088" cargo run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Commands
|
||||||
|
```bash
|
||||||
|
# Check single crate
|
||||||
|
cargo check -p botserver
|
||||||
|
|
||||||
|
# Build workspace
|
||||||
|
cargo build
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
cargo test -p bottest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 CONTINUATION PROMPT
|
||||||
|
|
||||||
|
When starting a new session or continuing work:
|
||||||
|
|
||||||
|
```
|
||||||
|
Continue on gb/ workspace. Follow PROMPT.md strictly:
|
||||||
|
|
||||||
|
1. Check current state with build/diagnostics
|
||||||
|
2. Fix ALL warnings and errors - NO #[allow()] attributes
|
||||||
|
3. Delete unused code, don't suppress warnings
|
||||||
|
4. Remove unused parameters, don't prefix with _
|
||||||
|
5. Verify after each fix batch
|
||||||
|
6. Loop until 0 warnings, 0 errors
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔑 REMEMBER
|
||||||
|
|
||||||
|
- **OFFLINE FIRST** - Fix all errors from list before compiling
|
||||||
|
- **ZERO WARNINGS, ZERO ERRORS** - The only acceptable state
|
||||||
|
- **FIX, DON'T SUPPRESS** - No #[allow()], no Cargo.toml lint exceptions
|
||||||
|
- **SECURITY FIRST** - No unwrap, no raw errors, no direct commands
|
||||||
|
- **READ BEFORE FIX** - Always understand context first
|
||||||
|
- **BATCH BY FILE** - Fix ALL errors in a file at once
|
||||||
|
- **WRITE ONCE** - Single edit per file with all fixes
|
||||||
|
- **VERIFY LAST** - Only compile/diagnostics after ALL fixes
|
||||||
|
- **DELETE DEAD CODE** - Don't keep unused code around
|
||||||
|
- **Version 6.2.0** - Do not change without approval
|
||||||
|
- **GIT WORKFLOW** - ALWAYS push to ALL repositories (github, pragmatismo)
|
||||||
2
botapp
2
botapp
|
|
@ -1 +1 @@
|
||||||
Subproject commit b5ee6e061acf1388aef777ddcd9a2bf84bd6ed57
|
Subproject commit 1a1e17fa1012e4db10a0f716c9b63a03b4863c9f
|
||||||
2
botbook
2
botbook
|
|
@ -1 +1 @@
|
||||||
Subproject commit 85696bb9070738f6bb865202f8c7de733f7c731a
|
Subproject commit c8d39c0e6232ca17118a6f106182c38b7159ccac
|
||||||
2
botlib
2
botlib
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2765fa2ebadc91435e8d90f068b4c96dbb77329b
|
Subproject commit bfaa68dc35e96ced2915d43ffe6fca8267a9a598
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 22a1954fac2f87a0a13b5e599771273172afc73a
|
Subproject commit 462a6dfa51b12f22e87712e613a559f66f9013cb
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 30345c66e2738ebe73d896841e54f655999e3630
|
Subproject commit 3c279f43e5a421bb5aab5a6e2c6d9924461d12f8
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit dd3d8c74dd58a1cc6d6b18d22108819519aaf9c3
|
Subproject commit 20e502e0cb8ff0fca5825ae5483a38d2fedb3ee5
|
||||||
2
bottest
2
bottest
|
|
@ -1 +1 @@
|
||||||
Subproject commit 74e761de0dd5105885acf00183223a702a8436df
|
Subproject commit 51458e391df2a47f5ccbcf10ec45edeeb9cf5902
|
||||||
2
botui
2
botui
|
|
@ -1 +1 @@
|
||||||
Subproject commit 414d277ae1757834d2ddbd6225063b451e919788
|
Subproject commit 497d0dd18c42a71cd3e2d9a329b98abe5ac5afb4
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"base_url": "http://localhost:8300",
|
|
||||||
"default_org": {
|
|
||||||
"id": "358572039839154190",
|
|
||||||
"name": "default",
|
|
||||||
"domain": "default.localhost"
|
|
||||||
},
|
|
||||||
"default_user": {
|
|
||||||
"id": "admin",
|
|
||||||
"username": "admin",
|
|
||||||
"email": "admin@localhost",
|
|
||||||
"password": "",
|
|
||||||
"first_name": "Admin",
|
|
||||||
"last_name": "User"
|
|
||||||
},
|
|
||||||
"admin_token": "eW0mGnOlKjpYHsrZZNAh1o3_8qeyF1iKKgEj-Y63GBdjQbQmxKxEjsNmVLZ_DWRDK6I3_yI",
|
|
||||||
"project_id": "",
|
|
||||||
"client_id": "358572040510308366",
|
|
||||||
"client_secret": "WyZRbj5iMkOkbvvtJWivXVaaydhWX1TodavhnAhsivl8IDZ44v2QoqT5upfgmOfz"
|
|
||||||
}
|
|
||||||
12
package.json
12
package.json
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"name": "gb",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"author": "Rodrigo Rodriguez (Pragmatismo) <me@rodrigorodriguez.com>",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"@playwright/test": "^1.58.1",
|
|
||||||
"@types/node": "^25.2.0"
|
|
||||||
},
|
|
||||||
"scripts": {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import { defineConfig, devices } from '@playwright/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read environment variables from file.
|
|
||||||
* https://github.com/motdotla/dotenv
|
|
||||||
*/
|
|
||||||
// import dotenv from 'dotenv';
|
|
||||||
// import path from 'path';
|
|
||||||
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
|
||||||
*/
|
|
||||||
export default defineConfig({
|
|
||||||
testDir: './tests',
|
|
||||||
/* Run tests in files in parallel */
|
|
||||||
fullyParallel: true,
|
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
||||||
forbidOnly: !!process.env.CI,
|
|
||||||
/* Retry on CI only */
|
|
||||||
retries: process.env.CI ? 2 : 0,
|
|
||||||
/* Opt out of parallel tests on CI. */
|
|
||||||
workers: process.env.CI ? 1 : undefined,
|
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
||||||
reporter: 'html',
|
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
||||||
use: {
|
|
||||||
/* Base URL to use in actions like `await page.goto('')`. */
|
|
||||||
// baseURL: 'http://localhost:3000',
|
|
||||||
|
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
||||||
trace: 'on-first-retry',
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chromium',
|
|
||||||
use: { ...devices['Desktop Chrome'] },
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'firefox',
|
|
||||||
use: { ...devices['Desktop Firefox'] },
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'webkit',
|
|
||||||
use: { ...devices['Desktop Safari'] },
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Test against mobile viewports. */
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Chrome',
|
|
||||||
// use: { ...devices['Pixel 5'] },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: { ...devices['iPhone 12'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against branded browsers. */
|
|
||||||
// {
|
|
||||||
// name: 'Microsoft Edge',
|
|
||||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Google Chrome',
|
|
||||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
|
||||||
// webServer: {
|
|
||||||
// command: 'npm run start',
|
|
||||||
// url: 'http://localhost:3000',
|
|
||||||
// reuseExistingServer: !process.env.CI,
|
|
||||||
// },
|
|
||||||
});
|
|
||||||
1
reset.sh
1
reset.sh
|
|
@ -1 +0,0 @@
|
||||||
rm -rf botserver-stack/ ./work/ .env
|
|
||||||
28
restart.sh
28
restart.sh
|
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "🛑 Stopping existing processes..."
|
|
||||||
pkill -f botserver || true
|
|
||||||
pkill -f botui || true
|
|
||||||
pkill -f rustc || true
|
|
||||||
|
|
||||||
echo "🧹 Cleaning logs..."
|
|
||||||
rm -f botserver.log botui.log
|
|
||||||
|
|
||||||
echo "🔨 Building botserver..."
|
|
||||||
cargo build -p botserver
|
|
||||||
|
|
||||||
echo "🔨 Building botui..."
|
|
||||||
cargo build -p botui
|
|
||||||
|
|
||||||
echo "🚀 Starting botserver..."
|
|
||||||
RUST_LOG=info ./target/debug/botserver --noconsole > botserver.log 2>&1 &
|
|
||||||
BOTSERVER_PID=$!
|
|
||||||
|
|
||||||
echo "🚀 Starting botui..."
|
|
||||||
BOTSERVER_URL="https://localhost:8088" ./target/debug/botui > botui.log 2>&1 &
|
|
||||||
BOTUI_PID=$!
|
|
||||||
|
|
||||||
echo "✅ Started botserver (PID: $BOTSERVER_PID) and botui (PID: $BOTUI_PID)"
|
|
||||||
echo "📊 Monitor with: tail -f botserver.log botui.log"
|
|
||||||
echo "🌐 Access at: http://localhost:3000"
|
|
||||||
28
start.bas
28
start.bas
|
|
@ -1,28 +0,0 @@
|
||||||
REM Knowledge Base Website Crawler Bot - Start Template
|
|
||||||
REM Sets up bot context and crawled websites, then exits
|
|
||||||
|
|
||||||
REM Load bot introduction
|
|
||||||
intro = GET BOT MEMORY "introduction"
|
|
||||||
IF intro = "" THEN
|
|
||||||
intro = "I'm your documentation assistant with access to crawled websites."
|
|
||||||
END IF
|
|
||||||
|
|
||||||
REM Register websites for crawling (preprocessing mode)
|
|
||||||
USE WEBSITE "https://docs.python.org"
|
|
||||||
USE WEBSITE "https://developer.mozilla.org"
|
|
||||||
USE WEBSITE "https://stackoverflow.com"
|
|
||||||
|
|
||||||
REM Set context for LLM
|
|
||||||
SET CONTEXT "role" AS intro
|
|
||||||
SET CONTEXT "capabilities" AS "I can search Python docs, MDN web docs, and Stack Overflow."
|
|
||||||
|
|
||||||
REM Configure suggestion buttons
|
|
||||||
CLEAR SUGGESTIONS
|
|
||||||
ADD SUGGESTION "python" AS "How do I use Python dictionaries?"
|
|
||||||
ADD SUGGESTION "javascript" AS "Explain JavaScript async/await"
|
|
||||||
ADD SUGGESTION "web" AS "What is the DOM in web development?"
|
|
||||||
|
|
||||||
REM Initial greeting
|
|
||||||
TALK intro
|
|
||||||
TALK "I have access to Python documentation, MDN web docs, and Stack Overflow."
|
|
||||||
TALK "Ask me any programming question!"
|
|
||||||
4
stop.sh
4
stop.sh
|
|
@ -1,4 +0,0 @@
|
||||||
pkill botui
|
|
||||||
pkill botserver -9
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
test('has title', async ({ page }) => {
|
|
||||||
await page.goto('https://playwright.dev/');
|
|
||||||
|
|
||||||
// Expect a title "to contain" a substring.
|
|
||||||
await expect(page).toHaveTitle(/Playwright/);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('get started link', async ({ page }) => {
|
|
||||||
await page.goto('https://playwright.dev/');
|
|
||||||
|
|
||||||
// Click the get started link.
|
|
||||||
await page.getByRole('link', { name: 'Get started' }).click();
|
|
||||||
|
|
||||||
// Expects page to have a heading with the name of Installation.
|
|
||||||
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
|
|
||||||
});
|
|
||||||
41
yarn.lock
41
yarn.lock
|
|
@ -1,41 +0,0 @@
|
||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@playwright/test@^1.58.1":
|
|
||||||
version "1.58.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.58.1.tgz#891dcd1da815cb1042490531f6d8778988509d22"
|
|
||||||
integrity sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==
|
|
||||||
dependencies:
|
|
||||||
playwright "1.58.1"
|
|
||||||
|
|
||||||
"@types/node@^25.2.0":
|
|
||||||
version "25.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-25.2.0.tgz#015b7d228470c1dcbfc17fe9c63039d216b4d782"
|
|
||||||
integrity sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==
|
|
||||||
dependencies:
|
|
||||||
undici-types "~7.16.0"
|
|
||||||
|
|
||||||
fsevents@2.3.2:
|
|
||||||
version "2.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
|
||||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
|
||||||
|
|
||||||
playwright-core@1.58.1:
|
|
||||||
version "1.58.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.58.1.tgz#d63be2c9b7dcbdb035beddd4b42437bd3ca89107"
|
|
||||||
integrity sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==
|
|
||||||
|
|
||||||
playwright@1.58.1:
|
|
||||||
version "1.58.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.58.1.tgz#63300e77a604c77264e1b499c0d94b54ed96d6ba"
|
|
||||||
integrity sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==
|
|
||||||
dependencies:
|
|
||||||
playwright-core "1.58.1"
|
|
||||||
optionalDependencies:
|
|
||||||
fsevents "2.3.2"
|
|
||||||
|
|
||||||
undici-types@~7.16.0:
|
|
||||||
version "7.16.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46"
|
|
||||||
integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==
|
|
||||||
Loading…
Add table
Reference in a new issue