diff --git a/docker/postgresql/test/Dockerfile b/docker/postgresql/test/Dockerfile
deleted file mode 100644
index e69de29b..00000000
diff --git a/docker/postgresql/test/file.test b/docker/postgresql/test/file.test
deleted file mode 100644
index e69de29b..00000000
diff --git a/examples/develop/heroprompt/heroprompt_example.vsh b/examples/develop/heroprompt/heroprompt_example.vsh
index 1b1c2edc..de7e241f 100755
--- a/examples/develop/heroprompt/heroprompt_example.vsh
+++ b/examples/develop/heroprompt/heroprompt_example.vsh
@@ -2,25 +2,41 @@
import freeflowuniverse.herolib.develop.heroprompt
-mut session := heroprompt.new_session()
+import freeflowuniverse.herolib.core.playbook
+import os
-mut workspace1 := session.add_workspace()!
-// TODO: Check the name bug
-// mut workspace2 := session.add_workspace(name: 'withname')!
-mut dir1 := workspace1.add_dir(path: '/Users/mahmoud/code/github/freeflowuniverse/herolib/docker')!
+heroscript_config := '
+ !!heropromptworkspace.configure name:"test workspace" path:"${os.home_dir()}/code/github/freeflowuniverse/herolib"
+'
+mut plbook := playbook.new(
+ text: heroscript_config
+)!
+
+heroprompt.play(mut plbook)!
+
+mut workspace1 := heroprompt.new_workspace(
+ path: '${os.home_dir()}/code/github/freeflowuniverse/herolib'
+)!
+
+// mut workspace2 := heroprompt.get(
+// name: 'test workspace'
+// )!
+
+mut dir1 := workspace1.add_dir(path: '${os.home_dir()}/code/github/freeflowuniverse/herolib/docker')!
dir1.select_file(name: 'docker_ubuntu_install.sh')!
mut dir2 := workspace1.add_dir(
- path: '/Users/mahmoud/code/github/freeflowuniverse/herolib/docker/herolib'
+ path: '${os.home_dir()}/code/github/freeflowuniverse/herolib/docker/herolib'
)!
dir2.select_file(name: '.gitignore')!
dir2.select_file(name: 'build.sh')!
-dir2.select_file(name: 'debug.sh')!
+file := dir2.select_file(name: 'debug.sh')!
+// println(file.read()!)
mut dir3 := workspace1.add_dir(
- path: '/Users/mahmoud/code/github/freeflowuniverse/herolib/docker/postgresql'
+ path: '${os.home_dir()}/code/github/freeflowuniverse/herolib/docker/postgresql'
select_all: true
)!
diff --git a/examples/develop/heroprompt/heroprompt_heroscript_example.vsh b/examples/develop/heroprompt/heroprompt_heroscript_example.vsh
new file mode 100644
index 00000000..e11fdf52
--- /dev/null
+++ b/examples/develop/heroprompt/heroprompt_heroscript_example.vsh
@@ -0,0 +1,15 @@
+#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
+
+import freeflowuniverse.herolib.core.playbook
+import os
+
+
+heroscript_config := '
+ !!heropromptworkspace.configure name:"test workspace" path:"${os.home_dir()}/code/github/freeflowuniverse/herolib"
+'
+mut plbook := playbook.new(
+ text: heroscript_config
+)!
+
+
+heroprompt.play(mut plbook)!
diff --git a/lib/data/encoderhero/decoder.v b/lib/data/encoderhero/decoder.v
index 0b3ff0c8..64f87d9b 100644
--- a/lib/data/encoderhero/decoder.v
+++ b/lib/data/encoderhero/decoder.v
@@ -24,7 +24,7 @@ fn decode_struct[T](_ T, data string) !T {
if !data.contains(action_name) {
action_name = '${obj_name}.configure'
if !data.contains(action_name) {
- $if debug{
+ $if debug {
print_backtrace()
}
return error('Data does not contain action name: ${obj_name}.define or ${action_name}')
@@ -66,11 +66,13 @@ fn decode_struct[T](_ T, data string) !T {
}
}
} $else $if field.is_array {
- if is_struct_array(typ.$(field.name))! {
- mut data_fmt := data.replace(action_str, '')
- data_fmt = data.replace('define.${obj_name}', 'define')
- arr := decode_array(typ.$(field.name), data_fmt)!
- typ.$(field.name) = arr
+ $if field.is_array {
+ $if field.typ is $struct {
+ mut data_fmt := data.replace(action_str, '')
+ data_fmt = data.replace('define.${obj_name}', 'define')
+ typ.$(field.name) = decode_array[field.elem_type](typ.$(field.name),
+ data_fmt)!
+ }
}
}
}
diff --git a/lib/develop/heroprompt/heroprompt_dir.v b/lib/develop/heroprompt/heroprompt_dir.v
index 88245978..044a5301 100644
--- a/lib/develop/heroprompt/heroprompt_dir.v
+++ b/lib/develop/heroprompt/heroprompt_dir.v
@@ -3,6 +3,15 @@ module heroprompt
import os
import freeflowuniverse.herolib.core.pathlib
+@[heap]
+pub struct HeropromptDir {
+pub mut:
+ name string
+ path pathlib.Path
+ files []&HeropromptFile @[skip; str: skip]
+ dirs []&HeropromptDir
+}
+
// Parameters for adding a file to a directory
@[params]
pub struct AddFileParams {
diff --git a/lib/develop/heroprompt/heroprompt_file.v b/lib/develop/heroprompt/heroprompt_file.v
index d52f0348..9dedb7ba 100644
--- a/lib/develop/heroprompt/heroprompt_file.v
+++ b/lib/develop/heroprompt/heroprompt_file.v
@@ -1,5 +1,16 @@
module heroprompt
+// import freeflowuniverse.herolib.data.paramsparser
+import freeflowuniverse.herolib.core.pathlib
+import os
+
+pub struct HeropromptFile {
+pub mut:
+ content string
+ path pathlib.Path
+ name string
+}
+
// Utility function to get file extension with special handling for common files
pub fn get_file_extension(filename string) string {
// Handle special cases for common files without extensions
@@ -57,3 +68,9 @@ pub fn get_file_extension(filename string) string {
return parts[parts.len - 1]
}
+
+// Read the file content
+pub fn (fl HeropromptFile) read() !string {
+ content := os.read_file(fl.path.path)!
+ return content
+}
diff --git a/lib/develop/heroprompt/heroprompt_session.v b/lib/develop/heroprompt/heroprompt_session.v
deleted file mode 100644
index b3c03469..00000000
--- a/lib/develop/heroprompt/heroprompt_session.v
+++ /dev/null
@@ -1,26 +0,0 @@
-module heroprompt
-
-import rand
-
-// HeropromptSession manages multiple workspaces for organizing AI prompts
-pub struct HeropromptSession {
-pub mut:
- id string // Unique session identifier
- workspaces []&HeropromptWorkspace // List of workspaces in this session
-}
-
-// new_session creates a new heroprompt session with a unique ID
-pub fn new_session() HeropromptSession {
- return HeropromptSession{
- id: rand.uuid_v4()
- workspaces: []
- }
-}
-
-// add_workspace creates and adds a new workspace to the session
-pub fn (mut self HeropromptSession) add_workspace(args_ NewWorkspaceParams) !&HeropromptWorkspace {
- mut wsp := &HeropromptWorkspace{}
- wsp = wsp.new(args_)!
- self.workspaces << wsp
- return wsp
-}
diff --git a/lib/develop/heroprompt/heroprompt_workspace.v b/lib/develop/heroprompt/heroprompt_workspace.v
index 8ab92470..7e2d0040 100644
--- a/lib/develop/heroprompt/heroprompt_workspace.v
+++ b/lib/develop/heroprompt/heroprompt_workspace.v
@@ -5,19 +5,11 @@ import time
import os
import freeflowuniverse.herolib.core.pathlib
-// HeropromptWorkspace represents a workspace containing multiple directories
-// and their selected files for AI prompt generation
-@[heap]
-pub struct HeropromptWorkspace {
-pub mut:
- name string = 'default' // Workspace name
- dirs []&HeropromptDir // List of directories in this workspace
-}
-
@[params]
-pub struct NewWorkspaceParams {
-pub mut:
+struct NewWorkspaceParams {
+mut:
name string
+ path string
}
/// Create a new workspace
@@ -28,10 +20,200 @@ fn (wsp HeropromptWorkspace) new(args_ NewWorkspaceParams) !&HeropromptWorkspace
args.name = generate_random_workspace_name()
}
- workspace := get(name: args.name)!
+ // Validate and set base path
+ if args.path.len > 0 {
+ if !os.exists(args.path) {
+ return error('Workspace path does not exist: ${args.path}')
+ }
+ if !os.is_dir(args.path) {
+ return error('Workspace path is not a directory: ${args.path}')
+ }
+ }
+
+ mut workspace := &HeropromptWorkspace{
+ name: args.name
+ base_path: os.real_path(args.path)
+ }
return workspace
}
+// WorkspaceItem represents a file or directory in the workspace tree
+pub struct WorkspaceItem {
+pub mut:
+ name string // Item name (file or directory name)
+ path string // Full path to the item
+ is_directory bool // True if this is a directory
+ is_file bool // True if this is a file
+ size i64 // File size in bytes (0 for directories)
+ extension string // File extension (empty for directories)
+ children []WorkspaceItem // Child items (for directories)
+ is_expanded bool // Whether directory is expanded in UI
+ is_selected bool // Whether this item is selected for prompts
+ depth int // Depth level in the tree (0 = root)
+}
+
+// WorkspaceList represents the complete hierarchical listing of a workspace
+pub struct WorkspaceList {
+pub mut:
+ root_path string // Root path of the workspace
+ items []WorkspaceItem // Top-level items in the workspace
+ total_files int // Total number of files
+ total_dirs int // Total number of directories
+}
+
+// list returns the complete hierarchical structure of the workspace
+pub fn (wsp HeropromptWorkspace) list() WorkspaceList {
+ mut result := WorkspaceList{
+ root_path: wsp.base_path
+ }
+
+ if wsp.base_path.len == 0 || !os.exists(wsp.base_path) {
+ return result
+ }
+
+ // Build the complete tree structure (ALL files and directories)
+ result.items = wsp.build_workspace_tree(wsp.base_path, 0)
+ wsp.calculate_totals(result.items, mut result)
+
+ // Mark selected items
+ wsp.mark_selected_items(mut result.items)
+
+ return result
+}
+
+// build_workspace_tree recursively builds the workspace tree structure
+fn (wsp HeropromptWorkspace) build_workspace_tree(path string, depth int) []WorkspaceItem {
+ mut items := []WorkspaceItem{}
+
+ entries := os.ls(path) or { return items }
+
+ for entry in entries {
+ full_path := os.join_path(path, entry)
+
+ if os.is_dir(full_path) {
+ mut dir_item := WorkspaceItem{
+ name: entry
+ path: full_path
+ is_directory: true
+ is_file: false
+ size: 0
+ extension: ''
+ is_expanded: false
+ is_selected: false
+ depth: depth
+ }
+
+ // Recursively get children
+ dir_item.children = wsp.build_workspace_tree(full_path, depth + 1)
+ items << dir_item
+ } else if os.is_file(full_path) {
+ file_info := os.stat(full_path) or { continue }
+ extension := get_file_extension(entry)
+
+ file_item := WorkspaceItem{
+ name: entry
+ path: full_path
+ is_directory: false
+ is_file: true
+ size: file_info.size
+ extension: extension
+ children: []
+ is_expanded: false
+ is_selected: false
+ depth: depth
+ }
+ items << file_item
+ }
+ }
+
+ // Sort: directories first, then files, both alphabetically
+ items.sort_with_compare(fn (a &WorkspaceItem, b &WorkspaceItem) int {
+ if a.is_directory && !b.is_directory {
+ return -1
+ }
+ if !a.is_directory && b.is_directory {
+ return 1
+ }
+ if a.name < b.name {
+ return -1
+ }
+ if a.name > b.name {
+ return 1
+ }
+ return 0
+ })
+
+ return items
+}
+
+// calculate_totals counts total files and directories in the workspace
+fn (wsp HeropromptWorkspace) calculate_totals(items []WorkspaceItem, mut result WorkspaceList) {
+ for item in items {
+ if item.is_directory {
+ result.total_dirs++
+ wsp.calculate_totals(item.children, mut result)
+ } else {
+ result.total_files++
+ }
+ }
+}
+
+// mark_selected_items marks which items are currently selected for prompts
+fn (wsp HeropromptWorkspace) mark_selected_items(mut items []WorkspaceItem) {
+ for mut item in items {
+ // Check if this item is selected by comparing paths
+ item.is_selected = wsp.is_item_selected(item.path)
+
+ // Recursively mark children
+ if item.is_directory && item.children.len > 0 {
+ wsp.mark_selected_items(mut item.children)
+ }
+ }
+}
+
+// is_item_selected checks if a specific path is selected in the workspace
+fn (wsp HeropromptWorkspace) is_item_selected(path string) bool {
+ for dir in wsp.dirs {
+ // Check if this directory is selected
+ if dir.path.path == path {
+ return true
+ }
+
+ // Check if any file in this directory is selected
+ for file in dir.files {
+ if file.path.path == path {
+ return true
+ }
+ }
+
+ // Recursively check subdirectories
+ if wsp.is_path_in_selected_dirs(path, dir.dirs) {
+ return true
+ }
+ }
+ return false
+}
+
+// is_path_in_selected_dirs recursively checks subdirectories for selected items
+fn (wsp HeropromptWorkspace) is_path_in_selected_dirs(path string, dirs []&HeropromptDir) bool {
+ for dir in dirs {
+ if dir.path.path == path {
+ return true
+ }
+
+ for file in dir.files {
+ if file.path.path == path {
+ return true
+ }
+ }
+
+ if wsp.is_path_in_selected_dirs(path, dir.dirs) {
+ return true
+ }
+ }
+ return false
+}
+
@[params]
pub struct AddDirParams {
pub mut:
diff --git a/lib/develop/heroprompt/reprompt_actions.v b/lib/develop/heroprompt/reprompt_actions.v
deleted file mode 100644
index 3e82df0b..00000000
--- a/lib/develop/heroprompt/reprompt_actions.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module heroprompt
-
-// TODO: Implement template-based prompt generation
-fn (mut ws HeropromptWorkspace) heroprompt() !string {
- // TODO: fill in template based on selection
- return ''
-}
-
-// TODO: Implement tree visualization utilities
-pub fn get_tree() {}
-
-// TODO: Implement prompt formatting utilities
-pub fn format_prompt() {}
diff --git a/lib/develop/heroprompt/reprompt_factory_.v b/lib/develop/heroprompt/reprompt_factory_.v
index 2df23ef1..c8af0d03 100644
--- a/lib/develop/heroprompt/reprompt_factory_.v
+++ b/lib/develop/heroprompt/reprompt_factory_.v
@@ -2,7 +2,6 @@ module heroprompt
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.core.playbook { PlayBook }
-import freeflowuniverse.herolib.ui.console
__global (
heroprompt_global map[string]&HeropromptWorkspace
@@ -35,7 +34,7 @@ pub fn get(args_ ArgsGet) !&HeropromptWorkspace {
if !exists(args)! {
set(obj)!
} else {
- heroscript := context.hero_config_get('heroprompt', args.name)!
+ heroscript := context.hero_config_get('heropromptworkspace', args.name)!
mut obj_ := heroscript_loads(heroscript)!
set_in_mem(obj_)!
}
@@ -52,20 +51,20 @@ pub fn set(o HeropromptWorkspace) ! {
set_in_mem(o)!
mut context := base.context()!
heroscript := heroscript_dumps(o)!
- context.hero_config_set('heroprompt', o.name, heroscript)!
+ context.hero_config_set('heropromptworkspace', o.name, heroscript)!
}
// does the config exists?
pub fn exists(args_ ArgsGet) !bool {
mut context := base.context()!
mut args := args_get(args_)
- return context.hero_config_exists('heroprompt', args.name)
+ return context.hero_config_exists('heropromptworkspace', args.name)
}
pub fn delete(args_ ArgsGet) ! {
mut args := args_get(args_)
mut context := base.context()!
- context.hero_config_delete('heroprompt', args.name)!
+ context.hero_config_delete('heropromptworkspace', args.name)!
if args.name in heroprompt_global {
// del heroprompt_global[args.name]
}
@@ -79,7 +78,7 @@ fn set_in_mem(o HeropromptWorkspace) ! {
}
pub fn play(mut plbook PlayBook) ! {
- mut install_actions := plbook.find(filter: 'heroprompt.configure')!
+ mut install_actions := plbook.find(filter: 'heropromptworkspace.configure')!
if install_actions.len > 0 {
for install_action in install_actions {
heroscript := install_action.heroscript()
diff --git a/lib/develop/heroprompt/reprompt_model.v b/lib/develop/heroprompt/reprompt_model.v
index 474d33c1..7d010448 100644
--- a/lib/develop/heroprompt/reprompt_model.v
+++ b/lib/develop/heroprompt/reprompt_model.v
@@ -1,51 +1,43 @@
module heroprompt
-import freeflowuniverse.herolib.data.paramsparser
-// import freeflowuniverse.herolib.data.encoderhero // temporarily commented out
-import freeflowuniverse.herolib.core.pathlib
-import os
+import freeflowuniverse.herolib.data.encoderhero
pub const version = '0.0.0'
const singleton = false
const default = true
-// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
-
-pub struct HeropromptFile {
+// HeropromptWorkspace represents a workspace containing multiple directories
+// and their selected files for AI prompt generation
+@[heap]
+pub struct HeropromptWorkspace {
pub mut:
- content string
- path pathlib.Path
- name string
+ name string = 'default' // Workspace name
+ base_path string // Base path of the workspace
+ dirs []&HeropromptDir // List of directories in this workspace
}
-pub struct HeropromptDir {
+@[params]
+pub struct AddWorkspaceParams {
pub mut:
- name string
- path pathlib.Path
- files []&HeropromptFile
- dirs []&HeropromptDir
+ name string
+ path string
}
-// pub fn (wsp HeropromptWorkspace) to_tag() {
-// tag := HeropromptTags.file_map
-// // We need to pass it to the template
-// }
+// add_workspace creates and adds a new workspace
+pub fn new_workspace(args_ AddWorkspaceParams) !&HeropromptWorkspace {
+ mut wsp := &HeropromptWorkspace{}
+ wsp = wsp.new(name: args_.name, path: args_.path)!
+ return wsp
+}
-// // pub fn (dir HeropromptDir) to_tag() {
-// // tag := HeropromptTags.file_content
-// // // We need to pass it to the template
-// // }
+// get_workspace gets the saved workspace
+pub fn get_workspace(args_ AddWorkspaceParams) !&HeropromptWorkspace {
+ if args_.name.len == 0 {
+ return error('Workspace name is required')
+ }
-// pub fn (fil HeropromptFile) to_tag() {
-// tag := HeropromptTags.file_content
-// // We need to pass it to the template
-// }
-
-// pub enum HeropromptTags {
-// file_map
-// file_content
-// user_instructions
-// }
+ return get(name: args_.name)!
+}
// your checking & initialization code if needed
fn obj_init(mycfg_ HeropromptWorkspace) !HeropromptWorkspace {
@@ -55,16 +47,11 @@ fn obj_init(mycfg_ HeropromptWorkspace) !HeropromptWorkspace {
/////////////NORMALLY NO NEED TO TOUCH
-// TODO: Check the compiler issue with the encde/decode
pub fn heroscript_dumps(obj HeropromptWorkspace) !string {
- // return encoderhero.encode[HeropromptWorkspace](obj)! // temporarily commented out
- return 'name: "${obj.name}"'
+ return encoderhero.encode[HeropromptWorkspace](obj)!
}
pub fn heroscript_loads(heroscript string) !HeropromptWorkspace {
- // mut obj := encoderhero.decode[HeropromptWorkspace](heroscript)! // temporarily commented out
- obj := HeropromptWorkspace{
- name: 'default'
- }
+ mut obj := encoderhero.decode[HeropromptWorkspace](heroscript)!
return obj
}
diff --git a/lib/develop/heroprompt/templates/heroscript_template.hero b/lib/develop/heroprompt/templates/heroscript_template.hero
index 6707d82c..58fec6df 100644
--- a/lib/develop/heroprompt/templates/heroscript_template.hero
+++ b/lib/develop/heroprompt/templates/heroscript_template.hero
@@ -1,10 +1,10 @@
-!!heroprompt.configure name:"default"
+!!heropromptworkspace.configure name:"default"
-!!heroprompt.workspace_dir name:"default"
- path:"@HOME/code/github/freeflowuniverse/herolib/lib/builder"
- selection:"path1,path2" //paths are relative in the path of workspace
- filter_exclude:","
- filter_include:","
+// !!heropromptworkspace.workspace_dir name:"default"
+ // path:"@HOME/code/github/freeflowuniverse/herolib/lib/builder"
+ // selection:"path1,path2" //paths are relative in the path of workspace
+ // filter_exclude:","
+ // filter_include:","
diff --git a/lib/develop/heroprompt/templates/prompt_example.md b/lib/develop/heroprompt/templates/prompt_example.md
deleted file mode 100644
index a335cffd..00000000
--- a/lib/develop/heroprompt/templates/prompt_example.md
+++ /dev/null
@@ -1,171 +0,0 @@
-
-/Users/mahmoud/code/github/freeflowuniverse/herolib
-└── docker
- └── docker_ubuntu_install.sh *
- ├── herolib
- │ ├── .gitignore*
- │ ├── build.sh *
- │ └── debug.sh*
-
-
-
-File: /Users/mahmoud/code/github/freeflowuniverse/herolib/docker/docker_ubuntu_install.sh
-
-```sh
-#!/bin/bash
-
-# Exit immediately if a command exits with a non-zero status
-set -e
-
-# Function to display an error message and exit
-error_exit() {
- echo "Error: $1" >&2
- exit 1
-}
-
-# Update package index and upgrade system
-echo "Updating system packages..."
-sudo apt update && sudo apt upgrade -y || error_exit "Failed to update system packages."
-
-# Install required packages for repository setup
-echo "Installing prerequisites..."
-sudo apt install -y ca-certificates curl gnupg || error_exit "Failed to install prerequisites."
-
-# Create directory for Docker GPG key
-echo "Setting up GPG keyring..."
-sudo mkdir -p /etc/apt/keyrings || error_exit "Failed to create keyring directory."
-
-# Add Docker's official GPG key
-DOCKER_GPG_KEY=/etc/apt/keyrings/docker.gpg
-echo "Adding Docker GPG key..."
-curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o $DOCKER_GPG_KEY || error_exit "Failed to add Docker GPG key."
-sudo chmod a+r $DOCKER_GPG_KEY
-
-# Set up Docker repository
-echo "Adding Docker repository..."
-REPO_ENTRY="deb [arch=$(dpkg --print-architecture) signed-by=$DOCKER_GPG_KEY] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
-if ! grep -Fxq "$REPO_ENTRY" /etc/apt/sources.list.d/docker.list; then
- echo "$REPO_ENTRY" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null || error_exit "Failed to add Docker repository."
-fi
-
-# Update package index
-echo "Updating package index..."
-sudo apt update || error_exit "Failed to update package index."
-
-# Install Docker Engine, CLI, and dependencies
-echo "Installing Docker Engine and dependencies..."
-sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || error_exit "Failed to install Docker packages."
-
-# Verify Docker installation
-echo "Verifying Docker installation..."
-if ! docker --version; then
- error_exit "Docker installation verification failed."
-fi
-
-# Run a test container
-echo "Running Docker test container..."
-if ! sudo docker run --rm hello-world; then
- error_exit "Docker test container failed to run."
-fi
-
-# Add current user to Docker group (if not already added)
-echo "Configuring Docker group..."
-if ! groups $USER | grep -q '\bdocker\b'; then
- sudo usermod -aG docker $USER || error_exit "Failed to add user to Docker group."
- echo "User added to Docker group. Please log out and back in for this change to take effect."
-else
- echo "User is already in the Docker group."
-fi
-
-# Enable Docker service on boot
-echo "Enabling Docker service on boot..."
-sudo systemctl enable docker || error_exit "Failed to enable Docker service."
-
-# Success message
-echo "Docker installation completed successfully!"
-
-```
-
-File: /Users/mahmoud/code/github/freeflowuniverse/herolib/docker/herolib/build.sh
-
-```sh
-#!/bin/bash -e
-
-# Get the directory where the script is located
-SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-cd "$SCRIPT_DIR"
-
-# Copy installation files
-cp ../../install_v.sh ./scripts/install_v.sh
-cp ../../install_herolib.vsh ./scripts/install_herolib.vsh
-
-# Docker image and container names
-DOCKER_IMAGE_NAME="herolib"
-DEBUG_CONTAINER_NAME="herolib"
-
-function cleanup {
- if docker ps -aq -f name="$DEBUG_CONTAINER_NAME" &>/dev/null; then
- echo "Cleaning up leftover debug container..."
- docker rm -f "$DEBUG_CONTAINER_NAME" &>/dev/null || true
- fi
-}
-trap cleanup EXIT
-
-# Attempt to build the Docker image
-BUILD_LOG=$(mktemp)
-set +e
-docker build --name herolib --progress=plain -t "$DOCKER_IMAGE_NAME" .
-BUILD_EXIT_CODE=$?
-set -e
-
-# Handle build failure
-if [ $BUILD_EXIT_CODE -ne 0 ]; then
- echo -e "\\n[ERROR] Docker build failed.\n"
- echo -e "remove the part which didn't build in the Dockerfile, the run again and to debug do:"
- echo docker run --name herolib -it --entrypoint=/bin/bash "herolib"
- exit $BUILD_EXIT_CODE
-else
- echo -e "\\n[INFO] Docker build completed successfully."
-fi
-
-
-
-```
-
-File: /Users/mahmoud/code/github/freeflowuniverse/herolib/docker/herolib/.gitignore
-
-```
-.bash_history
-.openvscode-server/
-.cache/
-```
-
-File: /Users/mahmoud/code/github/freeflowuniverse/herolib/docker/herolib/debug.sh
-
-```sh
-#!/bin/bash -ex
-
-# Get the directory where the script is located
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-cd "$SCRIPT_DIR"
-
-# Remove any existing container named 'debug' (ignore errors)
-docker rm -f herolib > /dev/null 2>&1
-
-docker run --name herolib -it \
- --entrypoint="/usr/local/bin/ourinit.sh" \
- -v "${SCRIPT_DIR}/scripts:/scripts" \
- -v "$HOME/code:/root/code" \
- -p 4100:8100 \
- -p 4101:8101 \
- -p 4102:8102 \
- -p 4379:6379 \
- -p 4022:22 \
- -p 4000:3000 herolib
-
-```
-
-
-
-This is a small repo prompt example
-