Compare commits

..

329 Commits

Author SHA1 Message Date
e34ba394b9 Merge branch 'development' into development_heroprompt_v2
* development: (182 commits)
  ...
  ...
  fix ci
  ...
  fix: Ignore regex_convert_test.v test
  refactor: Replace codewalker with pathlib and filemap
  test: Ignore virt/heropods/network_test.v in CI
  feat: implement container keep-alive feature
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  test: Add comprehensive heropods network and container tests
  ...
  ...
  codewalker
  ...

# Conflicts:
#	lib/develop/heroprompt/heroprompt_workspace.v
2025-11-25 18:54:14 +01:00
b3e673b38f ... 2025-11-25 18:53:18 +01:00
c94be548bf Merge branch 'development_nile_installers' into development
* development_nile_installers:
  fix ci
  feat: Add reset functionality to startup commands
  feat(cryptpad): Refactor installer configuration logic
  feat: Add PostgreSQL support for Gitea installer
  feat: Add Gitea Kubernetes installer
  feat(cryptpad): Refactor installer for dynamic configuration
2025-11-25 18:40:44 +01:00
8472d20609 Merge branch 'development_heropods' into development
* development_heropods: (21 commits)
  test: Ignore virt/heropods/network_test.v in CI
  feat: implement container keep-alive feature
  test: Add comprehensive heropods network and container tests
  refactor: Refactor Mycelium configuration and dependencies
  feat: Add Mycelium IPv6 overlay networking
  test: Replace hero binary checks with network test
  feat: Add iptables FORWARD rules for bridge
  Revert "feat: Add `pods` command for container management"
  feat: Add `pods` command for container management
  chore: Enable execution of cmd_run
  feat: Add `run` command for Heroscript execution
  feat: Separate initialization and configuration
  refactor: Remove hero binary installation from rootfs
  refactor: Integrate logger and refactor network operations
  feat: Implement container networking and improve lifecycle
  feat: Auto-install hero binary in containers
  feat: Add container management actions for heropods
  feat: Add heropods library to plbook
  refactor: Rename heropods variable and method
  refactor: Rename container factory to heropods
  ...
2025-11-25 18:40:41 +01:00
27279f8959 Merge branch 'development_gitea_installer' into development_nile_installers
* development_gitea_installer:
  feat: Add PostgreSQL support for Gitea installer
  feat: Add Gitea Kubernetes installer
2025-11-25 18:39:42 +01:00
7d4dc2496c Merge branch 'development_cryptpad' into development_nile_installers
* development_cryptpad:
  feat(cryptpad): Refactor installer configuration logic
  feat(cryptpad): Refactor installer for dynamic configuration
2025-11-25 18:39:27 +01:00
3547f04a79 Merge branch 'development_heropods' into development_nile_installers
* development_heropods: (21 commits)
  test: Ignore virt/heropods/network_test.v in CI
  feat: implement container keep-alive feature
  test: Add comprehensive heropods network and container tests
  refactor: Refactor Mycelium configuration and dependencies
  feat: Add Mycelium IPv6 overlay networking
  test: Replace hero binary checks with network test
  feat: Add iptables FORWARD rules for bridge
  Revert "feat: Add `pods` command for container management"
  feat: Add `pods` command for container management
  chore: Enable execution of cmd_run
  feat: Add `run` command for Heroscript execution
  feat: Separate initialization and configuration
  refactor: Remove hero binary installation from rootfs
  refactor: Integrate logger and refactor network operations
  feat: Implement container networking and improve lifecycle
  feat: Auto-install hero binary in containers
  feat: Add container management actions for heropods
  feat: Add heropods library to plbook
  refactor: Rename heropods variable and method
  refactor: Rename container factory to heropods
  ...
2025-11-25 18:39:08 +01:00
253e26aec6 Merge branch 'development' into development_nile_installers
* development: (27 commits)
  ...
  ...
  fix: Ignore regex_convert_test.v test
  refactor: Replace codewalker with pathlib and filemap
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  codewalker
  fix: Iterate over product requirement documents directly
  ...
  ...
  ...
  ...
  ...
2025-11-25 18:38:53 +01:00
a96d6e8aaa Merge branch 'development' of github.com:incubaid/herolib into development
* 'development' of github.com:incubaid/herolib:
  fix: Ignore regex_convert_test.v test
  refactor: Replace codewalker with pathlib and filemap
2025-11-25 18:38:27 +01:00
9fe669c5b8 ... 2025-11-25 18:38:21 +01:00
Timur Gordon
7e9bc1c41e fix ci 2025-11-25 14:55:00 +01:00
Timur Gordon
ee64a9fc58 Merge pull request #205 from Incubaid/development_fix_zinit
fix: Zinit client error when creating service
2025-11-25 14:41:51 +01:00
769c88adc8 ... 2025-11-25 14:08:52 +01:00
Mahmoud-Emad
520769a63e fix: Ignore regex_convert_test.v test 2025-11-25 14:55:18 +02:00
Mahmoud-Emad
1399d53748 refactor: Replace codewalker with pathlib and filemap
- Use pathlib for directory listing and filtering
- Use filemap for building file trees from selected directories
- Update build_file_map to use pathlib for recursive file listing
- Handle filemap building for standalone files and selected directories
2025-11-25 14:48:12 +02:00
Mahmoud-Emad
9f75a454fa test: Ignore virt/heropods/network_test.v in CI
- Add virt/heropods/network_test.v to ignored tests
- Ignore test requiring root for network bridge operations
2025-11-25 12:43:13 +00:00
Mahmoud-Emad
9a5973d366 feat: implement container keep-alive feature
- Add `keep_alive` parameter to `container_start`
- Implement logic to restart containers with `tail -f /dev/null` after successful entrypoint exit
- Update `podman_pull_and_export` to also extract image metadata
- Enhance `create_crun_config` to use extracted image metadata (ENTRYPOINT, CMD, ENV)
- Refactor test suite to use `keep_alive: true` for Alpine containers
2025-11-25 13:59:45 +02:00
fc41d3c62c ... 2025-11-25 06:13:56 +01:00
74146177e3 Merge branch 'development' of github.com:incubaid/herolib into development 2025-11-25 06:10:42 +01:00
c755821e34 ... 2025-11-25 06:10:17 +01:00
50a770c3ca ... 2025-11-25 06:03:37 +01:00
22dfcf4afa ... 2025-11-25 06:01:26 +01:00
b09e3ec0e1 ... 2025-11-25 05:51:55 +01:00
de7e1abcba ... 2025-11-25 05:44:58 +01:00
03d9e97008 ... 2025-11-25 05:23:17 +01:00
43eb15be7a ... 2025-11-25 05:13:02 +01:00
Mahmoud-Emad
76876049be test: Add comprehensive heropods network and container tests
- Add wait_for_process_ready to container start
- Reduce sigterm and stop check timeouts
- Update default container base directory
- Introduce new heropods test suite with multiple tests
- Add tests for initialization and custom network config
- Add tests for Docker image pull and container creation
- Add tests for container lifecycle (start, stop, delete)
- Add tests for container command execution
- Add tests for network IP allocation
- Add tests for IPv4 connectivity
- Add tests for container deletion and IP cleanup
- Add tests for bridge network setup and NAT rules
- Add tests for IP pool management
- Add tests for custom bridge configuration
2025-11-24 14:02:36 +02:00
803828e808 ... 2025-11-24 07:09:54 +01:00
9343772bc5 ... 2025-11-24 06:08:05 +01:00
d282a5dc95 codewalker 2025-11-24 05:48:13 +01:00
Mahmoud-Emad
dd7baa59b0 Merge branch 'development' into development_heropods 2025-11-23 13:06:50 +02:00
Mahmoud-Emad
69264adc3d fix: Iterate over product requirement documents directly
- Iterate over PRD objects instead of just IDs
- Pass PRD ID to delete function correctly
2025-11-23 12:13:25 +02:00
Mahmoud-Emad
3f943de9ed Merge branch 'development_nile_installers' into development_fix_zinit 2025-11-23 11:08:31 +02:00
Mahmoud-Emad
feffc09f73 Merge branch 'development' into development_nile_installers 2025-11-23 11:06:51 +02:00
Mahmoud-Emad
f11e0c689a Merge branch 'development' into development_nile_installers 2025-11-23 11:06:33 +02:00
Mahmoud-Emad
7c9f7c7568 Merge branch 'development_fix_zinit' of github.com:incubaid/herolib into development_fix_zinit 2025-11-23 11:01:59 +02:00
Mahmoud-Emad
dcd5af4d5f feat: Add reset functionality to startup commands
- Add `reset` boolean parameter to `StartArgs` struct
- Pass `reset` parameter to `startupcmd` calls
- Update service creation logic to handle `reset` flag
- Modify `install_start` and `restart` to pass `reset` parameter
2025-11-23 11:01:47 +02:00
4402cba8ac ... 2025-11-23 08:29:37 +01:00
01639853ce ... 2025-11-23 07:18:45 +01:00
0a25fc95b5 ... 2025-11-23 06:38:12 +01:00
9b5301f2c3 ... 2025-11-23 05:52:28 +01:00
2998a6e806 ... 2025-11-23 05:03:32 +01:00
0916ff07f8 ... 2025-11-23 05:01:31 +01:00
679108eb9e ... 2025-11-23 04:46:40 +01:00
1d4770aca5 ... 2025-11-23 04:43:08 +01:00
61a3677883 ... 2025-11-23 04:22:25 +01:00
27d2723023 .. 2025-11-22 18:32:19 +01:00
3d8effeac7 ... 2025-11-22 11:58:46 +02:00
a080fa8330 Merge branch 'development_zosbuilder' into development 2025-11-22 05:39:44 +02:00
d1584e929e Merge branch 'development' into development_fix_zinit
* development:
  ....
2025-11-22 05:37:21 +02:00
8733bc3fa8 Merge branch 'development' of github.com:incubaid/herolib into development
* 'development' of github.com:incubaid/herolib:
  refactor: Simplify default server retrieval
  test: Clear test database before running test
  test: Remove risks from PRD tests
  refactor: Pass rclone name as keyword argument
  test: Update test and script URL
  Refactor the herolib repo:
  test: Make page_exists call explicit
  test: Update image link assertion
  refactor: Extract heroscript path handling logic
  refactor: Keep file extensions when getting files
  refactor: Update image assertion syntax
  feat: Validate single input method for hero run
  feat: add cmd_run for heroscript execution
2025-11-22 05:36:12 +02:00
3ecb8c1130 .... 2025-11-22 05:36:04 +02:00
Mahmoud-Emad
26528a889d refactor: Update get calls and clean up debug
- Add `create: true` to get calls
- Remove commented-out print_backtrace
- Remove debug print for socket closure
2025-11-20 14:00:29 +02:00
Timur Gordon
41e3d2afe4 Merge branch 'development_nile_installers' into development_fix_zinit 2025-11-20 07:56:48 +01:00
Mahmoud-Emad
8daca7328d refactor: Improve service startup and management logic
- Add `create: true` to service `get` calls
- Update `running_check` to use `curl` for HTTP status code
- Ensure redis addresses have `redis://` prefix
- Clean up and re-create zinit services before starting
- Remove redundant `service_monitor` call in `startupmanager.start`
2025-11-19 17:08:49 +02:00
Timur Gordon
86da2cd435 chore: remove test installer and update template escape sequence
- Remove tester installer from playcmds factory
- Update template to use ^^ escape for @[params] annotation
- Format various model and actions files
2025-11-19 15:51:20 +01:00
Timur Gordon
a5c4b8f6f8 refactor: merge action handling blocks in play() functions
Merge the two separate if blocks for handling actions into a single block
since they both use the same logic for getting the name parameter with
get_default('name', 'default').

Changes:
- Combine destroy/install/build and start/stop/restart/lifecycle blocks
- All actions now use consistent name parameter handling
- Reduces code duplication in play() functions

Updated files:
- All 5 horus installer factory files
- Generator template objname_factory_.vtemplate
2025-11-19 15:44:50 +01:00
Timur Gordon
856a6202ee fix: escape @ symbol in template for InstallArgs annotation
Use @@ instead of @ in template to properly output @[params] in generated code.
V templates require double @@ to escape the @ symbol.
2025-11-19 15:17:31 +01:00
Timur Gordon
a40e172457 refactor: update installer generator templates to instance-based API
Update generator templates to produce installers following the new pattern:

Actions template (objname_actions.vtemplate):
- Convert all functions to methods on the config struct
- startupcmd() -> (self &Struct) startupcmd()
- running() -> (self &Struct) running_check()
- start_pre/post, stop_pre/post -> methods on struct
- installed(), install(), build(), destroy() -> methods on struct
- Add InstallArgs struct with reset parameter
- Remove get()! calls, use self instead

Factory template (objname_factory_.vtemplate):
- Update play() to get name parameter for all actions
- Call instance methods instead of module-level functions
- Add support for start_pre, start_post, stop_pre, stop_post actions
- Update start(), stop(), running() to use self.method() calls
- Remove duplicate InstallArgs and wrapper methods
- Use self.running_check() instead of running()

All newly generated installers will now follow the consistent
instance-based pattern with proper lifecycle hook support.
2025-11-19 15:09:24 +01:00
Mahmoud-Emad
012a59b3d8 Merge branch 'development_nile_installers' into development_fix_zinit 2025-11-19 16:04:30 +02:00
Mahmoud-Emad
6334036b79 Merge branch 'development' into development_fix_zinit 2025-11-19 15:18:23 +02:00
Mahmoud-Emad
df462174e5 refactor: Refactor Mycelium configuration and dependencies
- Flatten MyceliumConfig struct into HeroPods
- Remove Mycelium installer and service management logic
- Update Mycelium initialization to check for prerequisites only
- Adjust peers configuration to be comma-separated string
2025-11-19 15:17:39 +02:00
Mahmoud-Emad
1452d65f48 feat: Add Mycelium IPv6 overlay networking
- Integrate Mycelium IPv6 overlay networking
- Add Mycelium configuration options to HeroPods
- Enable Mycelium setup and cleanup for containers
- Include Mycelium examples and documentation
2025-11-19 14:23:06 +02:00
Timur Gordon
fcb178156b rename some installers, fix installer service startup w/ zinit 2025-11-19 11:42:55 +01:00
Timur Gordon
28313ad22f refactor: convert horus installers to instance-based API
- Convert all module-level functions to methods on config structs
- Add InstallArgs struct with reset parameter to actions files
- Update factory play() functions to call instance methods with name parameter
- Remove duplicate InstallArgs and wrapper methods from factory files
- Add support for start_pre, start_post, stop_pre, stop_post as callable actions
- Rename running() to running_check() to avoid conflicts
- All lifecycle methods (install, destroy, build, start, stop, etc.) now accept optional name parameter

Affected installers:
- coordinator
- supervisor
- herorunner
- osirisrunner
- salrunner

This provides a cleaner, more consistent API where all installer actions
can be called on specific configuration instances from heroscript files.
2025-11-19 11:03:36 +01:00
Mahmoud-Emad
9986dca758 test: Replace hero binary checks with network test
- Test network connectivity using wget
- Removed checks for hero binary existence and version
2025-11-19 11:03:17 +02:00
Mahmoud-Emad
9af9ab40b5 feat: Add iptables FORWARD rules for bridge
- Allow traffic from bridge to external interface
- Allow established traffic from external to bridge
- Allow traffic between containers on same bridge
2025-11-19 10:50:09 +02:00
Mahmoud-Emad
4b5a9741a0 Revert "feat: Add pods command for container management"
This reverts commit 11c3ea9ca5.
2025-11-18 16:26:49 +02:00
Mahmoud-Emad
11c3ea9ca5 feat: Add pods command for container management
- Implement `hero pods` CLI command
- Add subcommands for ps, images, create, start, stop, rm, exec, inspect
- Add flags for container creation and removal
2025-11-18 16:09:20 +02:00
Mahmoud-Emad
e7a38e555b Merge branch 'development' into development_heropods 2025-11-18 12:41:37 +02:00
Mahmoud-Emad
adb012e9cf refactor: Simplify default server retrieval
- Remove unused logic for default server lookup
- Consolidate server retrieval for Cryptpad and ElementChat
- Update default server assignment logic
2025-11-18 12:37:26 +02:00
Mahmoud-Emad
8ca7985753 refactor: Update default coordinator name
- Change default `ArgsGet.name` to 'default'
- Remove logic for overriding `args.name` with `coordinator_default`
- Set `coordinator_default` directly to `args.name`
2025-11-18 12:34:47 +02:00
Mahmoud-Emad
82378961db refactor: Remove unused default name logic
- Remove conditional logic for 'default' name
- Simplify 'get' function argument handling
2025-11-18 12:33:14 +02:00
Mahmoud-Emad
f9a2ebf24b chore: Refactor coordinator configuration and status reporting
- Update default coordinator name to 'coordinator'
- Improve status reporting by using dedicated variables
- Adjust `zinit.get` call to use `create: true`
- Set `zinit_default` based on `args.name` when 'default' is provided
- Update `coordinatorServer.name` default to 'coordinator'
- Make 'coordinator' the default for `ArgsGet.name`
- Use `coordinator_default` for `ArgsGet.name` if set
- Adjust `CoordinatorServer.binary_path` default
- Update `zinit.get` to use `create: true`
- Log socket closure for debugging
- Remove unused import `incubaid.herolib.core.texttools`
2025-11-18 11:50:52 +02:00
Mahmoud-Emad
9dc33e3ce9 Merge branch 'development' into development_nile_installers 2025-11-18 10:02:23 +02:00
Mahmoud-Emad
ae4997d80a Merge branch 'development' into development_heropods 2025-11-18 09:55:33 +02:00
Timur Gordon
b26c1f74e3 Merge branch 'development_nile_installers' of github.com:Incubaid/herolib into development_nile_installers 2025-11-17 16:02:44 +01:00
Timur Gordon
bf6dec48f1 add other horus installers, create examples, test startup 2025-11-17 15:57:40 +01:00
Mahmoud-Emad
3a05dc8ae0 test: Clear test database before running test
- Flush the Redis database for a clean test state
2025-11-17 15:58:01 +02:00
Mahmoud-Emad
5559bd4f2f test: Remove risks from PRD tests
- Remove assertions for risks in PRD tests
- Remove risk map initialization and population
- Update PRD encoding/decoding test
2025-11-17 15:40:14 +02:00
Mahmoud-Emad
9d79408931 refactor: Pass rclone name as keyword argument
- Update rclone.new call to use named argument
2025-11-17 15:28:47 +02:00
Mahmoud-Emad
f5c2b306b8 test: Update test and script URL
- Remove frontmatter test due to disabled parsing
- Update install script URL
2025-11-17 15:23:08 +02:00
Mahmoud-Emad
49868a18e1 Refactor the herolib repo:
- Removed the unused files
- Updated the README
- Added all needed scripts in /scripts dir
- Update script paths in CI configuration
- Update script paths in Go code
- Move installation scripts to scripts directory
- Change script path from ./install_v.sh to ./scripts/install_v.sh
2025-11-17 15:11:55 +02:00
Mahmoud-Emad
2ab0dfa6b8 test: Make page_exists call explicit
- Add '!' to col.page_exists('intro') call
2025-11-17 14:56:43 +02:00
Mahmoud-Emad
82375f9b89 test: Update image link assertion
- Change assertion for image link detection
- Use `file_type` instead of `is_image_link`
2025-11-17 14:51:15 +02:00
peternashaat
f664823a90 refactor: Remove Redis installation from coordinator, improve Rust detection
- Remove all Redis installation logic from coordinator installer
- Add osal.cmd_exists() check before installing Rust
- Update docs: Redis must be pre-installed
- Add reset flag documentation for forcing rebuilds
- Coordinator now only installs Rust and builds binary
2025-11-17 12:50:59 +00:00
Mahmoud-Emad
9b2e9114b8 refactor: Extract heroscript path handling logic
- Add helper function to expand and validate file paths
- Add helper function to validate heroscript content
- Add helper function to run heroscript from file
- Inline scripts now validated before execution
- File-based scripts now use the new run_from_file helper
2025-11-17 14:43:08 +02:00
Mahmoud-Emad
8dc2b360ba refactor: Keep file extensions when getting files
- Use `name_fix_keepext` instead of `name_fix`
- Update calls to `image_get`, `file_get`, and `file_or_image_get`
- Update checks in `image_exists`, `file_exists`, and `file_or_image_exists`
2025-11-17 13:39:25 +02:00
Mahmoud-Emad
49e48e7aca refactor: Update image assertion syntax
- Add '!' to image_exists calls
- Update image file name access
2025-11-17 12:18:26 +02:00
Mahmoud-Emad
586c6db34e Merge branch 'development' into development_heropods 2025-11-17 12:08:06 +02:00
Mahmoud-Emad
122a864601 Merge branch 'development' into development_heropods 2025-11-17 12:05:53 +02:00
Omdanii
571bc31179 Merge pull request #202 from Incubaid/development_herorun_cmd
Add Support for `hero run` Command
2025-11-17 12:03:28 +02:00
Mahmoud-Emad
35734b5ebc feat: Validate single input method for hero run
- Add validation for multiple input methods
- Improve error message for no script provided
- Update usage instructions in help message
2025-11-17 12:02:16 +02:00
Mahmoud-Emad
15f81aca41 feat: add cmd_run for heroscript execution
- Add `cmd_run` function to `herocmds` module
- Allow running heroscripts from inline strings via `-s` flag
- Enable running heroscripts from file paths via `-p` flag or as arguments
- Add `-r` flag to reset before running
2025-11-17 11:53:48 +02:00
peternashaat
1484fec898 - Renamed HerocoordinatorServer to CoordinatorServer 2025-11-17 07:58:28 +00:00
peternashaat
06fcfa5b50 feat: add dynamic Redis configuration to coordinator installer
- Add redis_port field to CoordinatorServer struct
- Refactor ensure_redis_running() to use @[params] pattern
- Pass redis_port and redis_addr dynamically from config
- Follow same pattern as cryptpad installer for consistency
2025-11-16 13:34:38 +00:00
peternashaat
a26f0a93fe refactor: improve coordinator installer code quality
- Remove unused imports (texttools, paramsparser)
- Move ensure_redis_running() helper to better location
- Add comments to lifecycle hook functions
- Improve error handling for binary copy operation
- Add documentation to obj_init function
2025-11-16 13:18:32 +00:00
peternashaat
eb0fe4d3a9 refactor: move coordinator installer to horus directory and fix Redis installer permissions
- Moved coordinator installer from installers/infra to installers/horus
- Renamed HerocoordinatorServer to CoordinatorServer
- Fixed Redis installer permissions for /var/lib/redis directory
- Integrated coordinator with new modular Redis installer
2025-11-16 13:05:29 +00:00
8a7987b9c3 ... 2025-11-15 07:09:56 +02:00
70d581fb57 Merge branch 'development' of github.com:incubaid/herolib into development 2025-11-15 06:16:01 +02:00
d267c1131f ... 2025-11-15 06:15:02 +02:00
1ac9092eed adds zosbuilder
Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com>
2025-11-15 01:19:33 +02:00
peternashaat
bf79d6d198 feat: migrate Redis installer and add to coordinator dependencies
- Migrated Redis to new installer pattern with fixed config template
- Coordinator now auto-installs Redis if missing
- Added progress indicators and consolidated examples
2025-11-14 13:29:22 +00:00
peternashaat
eada09135c feat: migrate Redis installer and integrate into coordinator
- Created coordinator installer
- Migrated Redis installer to new modular pattern (_model.v, _actions.v, _factory_.v)
- Fixed Redis config template for 7.0.15 compatibility (commented out unsupported directives)
- Added Redis dependency check to coordinator installer
- Coordinator now auto-installs and starts Redis if not available
- Added progress indicators to coordinator build process
- Consolidated Redis example scripts
- All tests passing: Redis installation, coordinator build, and idempotency verified
2025-11-14 13:25:35 +00:00
a447aeec43 Merge pull request #182 from Incubaid/development_installer
Update install script
2025-11-14 02:23:56 -08:00
Timur Gordon
78d848783a fix breaking code 2025-11-14 10:26:45 +01:00
Mahmoud-Emad
8c2b5a8f5e chore: Enable execution of cmd_run
- Uncomment herocmds.cmd_run(mut cmd)
2025-11-14 11:21:07 +02:00
Mahmoud-Emad
fcb5964f8d feat: Add run command for Heroscript execution
- Add `cmd_run` to execute heroscripts from files or inline
- Implement file path handling and inline script execution
- Add Linux platform check for HeroPods initialization
- Update documentation to reflect Linux-only requirement
2025-11-14 11:20:26 +02:00
e97e0d77be Merge branch 'development' into development_docusaurus_atlas
* development:
  Fix redis package name for alpine
  ...
2025-11-14 08:52:21 +02:00
16155480de Merge branch 'development' of github.com:incubaid/herolib into development
* 'development' of github.com:incubaid/herolib: (26 commits)
  Fix redis package name for alpine
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  feat: Enhance docusaurus site generation with atlas client
  feat: Improve export self-containment and link handling
  ...
  feat: Add Atlas Export and AtlasClient example
  ...
2025-11-14 08:52:13 +02:00
e7611d4dc2 ... 2025-11-14 08:51:32 +02:00
Scott Yeager
45215b0abb Update installer 2025-11-13 08:04:17 -08:00
Scott Yeager
7246223e3b Use run_sudo everywhere 2025-11-12 05:37:56 -08:00
Scott Yeager
1958f24528 Add herolib version arg 2025-11-12 05:23:34 -08:00
c033cacd5b Fix redis package name for alpine 2025-11-12 05:11:01 -08:00
Mahmoud-Emad
d3f05c1834 feat: Separate initialization and configuration
- Move network defaults to obj_init
- Add initialize() method for heavy setup
- Improve separation of concerns for HeroPods initialization
2025-11-12 13:32:53 +02:00
Mahmoud-Emad
4bf16d6f70 refactor: Remove hero binary installation from rootfs
- Remove function `install_hero_in_rootfs`
- Remove call to `install_hero_in_rootfs`
2025-11-12 11:39:01 +02:00
Mahmoud-Emad
ad7e1980a5 refactor: Integrate logger and refactor network operations
- Replace console logging with logger.log calls
- Improve network bridge creation robustness
- Enhance network IP allocation and cleanup logic
- Refactor network cleanup for better concurrency handling
2025-11-12 11:28:56 +02:00
Mahmoud-Emad
7836a48ad4 feat: Implement container networking and improve lifecycle
- Add thread-safe network management for containers
- Implement graceful and forceful container stopping
- Enhance container creation and deletion logic
- Refine image management and metadata handling
- Add container name validation for security
2025-11-12 10:38:39 +02:00
Mahmoud-Emad
1d67522937 feat: Auto-install hero binary in containers
- Install hero binary into container rootfs
- Compile hero binary if not found on host
- Copy hero binary to container's /usr/local/bin
- Make hero binary executable in container
2025-11-11 12:48:34 +02:00
Mahmoud-Emad
e6c3ed93fa feat: Add container management actions for heropods
- Add processing for heropods.container_new
- Add processing for heropods.container_start
- Add processing for heropods.container_exec
- Add processing for heropods.container_stop
- Add processing for heropods.container_delete
2025-11-11 11:24:58 +02:00
Mahmoud-Emad
2fafd025eb feat: Add heropods library to plbook
- Import heropods library
- Play heropods library in plbook
2025-11-11 10:40:27 +02:00
Mahmoud-Emad
3ae980d4c5 refactor: Rename heropods variable and method
- Rename `factory` to `heropods_`
- Rename `factory.new` to `heropods_.container_new`
- Update error message for `heropods.new`
2025-11-11 10:11:01 +02:00
Mahmoud-Emad
e94734ecc7 refactor: Rename container factory to heropods
- Rename `factory` variable to `heropods_`
- Update calls from `factory.new` to `heropods_.container_new`
- Adjust error message for initialization
- Update print statements to reflect renaming
2025-11-11 10:08:59 +02:00
Mahmoud-Emad
deb1210405 refactor: Rename ContainerFactory to HeroPods
- Rename ContainerFactory struct to HeroPods
- Update method names and receiver types accordingly
- Adjust imports and internal references
2025-11-11 10:08:15 +02:00
Omdanii
759870e01e Merge pull request #196 from Incubaid/development_docusaurus_atlas
Docusaurus Atlas tool
2025-11-10 08:38:03 +02:00
891f3bf66d ... 2025-11-09 08:53:08 +04:00
3179d362fc ... 2025-11-09 08:47:11 +04:00
69d9949c39 ... 2025-11-09 08:20:11 +04:00
5d2adb1a2c ... 2025-11-09 08:17:00 +04:00
c409d42f64 ... 2025-11-09 07:43:44 +04:00
2dad87ad5e ... 2025-11-09 06:41:23 +04:00
fd5a348e20 ... 2025-11-09 06:36:05 +04:00
93fc823e00 ... 2025-11-09 06:25:44 +04:00
f40565c571 ... 2025-11-08 11:12:16 +04:00
5a6f3d323b ... 2025-11-07 07:58:53 +04:00
836a8f799e ... 2025-11-07 07:47:42 +04:00
b9a84ee8fc ... 2025-11-07 07:39:05 +04:00
0d3b4357ac ... 2025-11-07 07:24:38 +04:00
ea1a49ffd5 ... 2025-11-07 07:19:28 +04:00
f4de662fc2 ... 2025-11-07 07:00:23 +04:00
Mahmoud-Emad
a149845fc7 feat: Enhance docusaurus site generation with atlas client
- Add flags for development server and browser opening
- Introduce IDocClient interface for unified client access
- Implement atlas_client integration for Docusaurus
- Refactor link handling and image path resolution
- Update Docusaurus config with atlas client options
2025-11-06 15:44:09 +02:00
a2eaf6096e ... 2025-11-06 16:14:34 +04:00
Mahmoud-Emad
5fccd03ee7 Merge branch 'development_docusaurus_atlas' of github.com:incubaid/herolib into development_docusaurus_atlas 2025-11-06 10:51:42 +02:00
Mahmoud-Emad
347ebed5ea feat: Improve export self-containment and link handling
- Use absolute paths for path_relative calculations
- Validate links before export to populate page.links
- Copy cross-collection referenced pages for self-contained export
- Update export_link_path to generate local links for self-contained exports
- Remove page from visited map to allow re-inclusion in other contexts
2025-11-06 10:51:10 +02:00
b582bd03ef ... 2025-11-06 09:40:59 +04:00
Mahmoud-Emad
ac09648a5b feat: Add Atlas Export and AtlasClient example
- Add example for exporting Atlas collections
- Demonstrate using AtlasClient to read exported content
- Include examples for listing collections and pages
- Show reading page content and metadata via AtlasClient
2025-11-05 16:08:56 +02:00
Mahmoud-Emad
04e1e2375f refactor: Remove docusaurus dev server and path_meta flag
- Remove 'dev' flag from run command
- Remove 'path_meta' flag from run command
- Remove docusaurus integration from playcmds
- Add `validate_links` and `fix_links` to Atlas
- Refactor page link processing for clarity and export mode
2025-11-05 15:25:50 +02:00
Mahmoud-Emad
a2ac8c0027 refactor: Simplify text normalization comments
- Remove outdated comments related to normalization
- Update comments for clarity
2025-11-05 10:04:57 +02:00
Mahmoud-Emad
2150b93a80 refactor: Update name normalization logic
- Use texttools.name_fix instead of name_fix_no_underscore_no_ext
- Preserve underscores in normalized names
- Update documentation and tests to reflect changes
2025-11-05 10:01:18 +02:00
Mahmoud-Emad
10b9af578a feat: Add Docusaurus dev server integration
- Add 'dev' flag to run Docusaurus server
- Import docusaurus library
- Enable scan and export if 'dev' flag is set
- Handle export errors more gracefully
- Start Docusaurus dev server after export
2025-11-04 16:49:00 +02:00
Mahmoud-Emad
8bfb021939 feat: Support atlas_client module:
- Add client for atlas module
- Add unit tests to test the workflow
- Remove println statements from file_or_image_exists
- Remove println statements from link processing loop
2025-11-04 15:56:07 +02:00
Mahmoud-Emad
ecfe77a2dc refactor: Normalize page and collection names
- Use `name_fix_no_underscore_no_ext` for consistent naming
- Remove underscores and special characters from names
- Add tests for name normalization functions
- Ensure page and collection names are consistently formatted
- Update link parsing to use normalized names
2025-11-04 12:28:13 +02:00
peternashaat
683008da8f feat(cryptpad): Refactor installer configuration logic
Refactors the CryptPad installer to improve its configuration handling.

- The `hostname` and `namespace` are now derived from the installer's `name` property by default.
- Implemented name sanitization to remove special characters (`_`, `-`, `.`).
- Added validation to ensure the namespace does not contain invalid characters.
- Updated the factory's `reload` function to persist changes made to the installer object after its initial creation.

This change ensures consistent and predictable behavior, allowing for both default generation and manual override of configuration values.

Co-authored-by: Mahmoud-Emad <mahmmoud.hassanein@gmail.com>
2025-11-04 09:01:53 +00:00
Omdanii
ef14bc6d82 Merge pull request #184 from Incubaid/development_heroserver_errors
refactor: Update library paths
2025-11-03 23:21:42 +02:00
Mahmoud-Emad
bafc519cd7 feat: Add PostgreSQL support for Gitea installer
- Add PostgreSQL configuration options
- Generate PostgreSQL YAML when selected
- Verify PostgreSQL pod readiness
- Update documentation for PostgreSQL usage
- Add PostgreSQL service and pod definitions
2025-11-03 17:04:40 +02:00
Mahmoud-Emad
472e4bfaaa feat: Add Gitea Kubernetes installer
- Add Gitea installer module and types
- Implement installation and destruction logic
- Integrate with Kubernetes and TFGW
- Add example usage and documentation
2025-11-03 16:25:21 +02:00
peternashaat
e3c8d032f7 Merge remote-tracking branch 'origin/development' into development_cryptpad 2025-11-03 13:54:27 +00:00
Omdanii
7d72faa934 Merge pull request #193 from Incubaid/development_element_and_matrix
feat: Implement Element Chat Kubernetes installer
2025-11-03 15:51:23 +02:00
Mahmoud-Emad
8e5507b04e fix: Update element chat config and defaults
- Update element chat default name to 'elementchat'
- Sanitize element chat name from invalid characters
- Set default namespace based on sanitized name
- Validate namespace for invalid characters
- Update documentation with new default values
2025-11-03 15:49:54 +02:00
peternashaat
6746d885f8 feat(cryptpad): Refactor installer for dynamic configuration
This commit refactors the CryptPad Kubernetes installer to be more dynamic and configurable structure.

Key changes include:
-   **Dynamic Configuration**: The installer now generates its configuration based on parameters passed from the `.vsh` script, with sensible defaults for any unspecifie
d values.
-   **Templated `config.js`**: Introduced a new `config.js` template to allow for greater flexibility and easier maintenance of the CryptPad configuration.
-   **Improved Code Structure**: The source code has been updated to be more modular and maintainable.
-   **Updated Documentation**: The `README.md` has been updated to include instructions on how to run the installer and customize the installation.

Co-authored-by: Mahmoud-Emad <mahmmoud.hassanein@gmail.com>
2025-11-03 13:12:46 +00:00
Mahmoud-Emad
2e56311cd0 refactor: Prefix hostnames with instance name
- Prefix matrix_hostname with mycfg.name
- Prefix element_hostname with mycfg.name

Co-authored-by: peternashaaat <peternashaaat@gmail.com>
2025-11-03 12:24:59 +02:00
Mahmoud-Emad
4d3071f2d2 feat: Update installer name
- Change installer name from 'myelementchat' to 'kristof'

Co-authored-by: peternashaaat <peternashaaat@gmail.com>
2025-11-02 17:29:20 +02:00
Mahmoud-Emad
3ee0e5b29c feat: Implement Element Chat Kubernetes installer
- Add Element Chat installer module
- Integrate Conduit and Element Web deployments
- Support TFGW integration for FQDNs and TLS
- Implement installation and destruction logic
- Generate Kubernetes YAML from templates

Co-authored-by: peternashaaat <peternashaaat@gmail.com>
2025-11-02 17:24:01 +02:00
Omdanii
672ff886d4 Merge pull request #192 from Incubaid/development_openrouter
Adding Cryptpad installer and finalizing the Kubernetes client
2025-11-02 13:54:21 +02:00
Mahmoud-Emad
44c8793074 refactor: Update cryptpad installer code
- Use installer.kube_client for Kubernetes operations
- Remove redundant startupmanager calls
- Simplify `delete_resource` command
- Add default values for installer name and hostname
- Refactor `get` function to use new arguments correctly
- Remove commented out example code and unused imports
- Change the factory file<REQUIRED> to load the default instance name
- Update the README file of the installer

Co-authored-by: peternahaaat <peternashaaat@gmail.com>
2025-11-02 13:37:38 +02:00
Mahmoud-Emad
86549480b5 Merge branch 'development_openrouter' of github.com:incubaid/herolib into development_openrouter 2025-10-30 18:00:54 +03:00
Mahmoud-Emad
80108d4b36 refactor: Refactor Kubernetes client and CryptPad installer
- Replace kubectl exec calls with Kubernetes client methods
- Improve error handling and logging in Kubernetes client
- Enhance node information retrieval and parsing
- Add comprehensive unit tests for Kubernetes client and Node structs
- Refine YAML validation to allow custom resource definitions
- Update CryptPad installer to use the refactored Kubernetes client
2025-10-30 17:58:03 +03:00
peternashaat
81adc60eea feat(cryptpad): Use constants for deployment retry logic
Refactor the installer to use global constants for the maximum number of retries and the check interval when verifying deployments.

This change removes hardcoded values from the FQDN and deployment status checks, improving maintainability and centralizing configuration.
2025-10-30 13:21:49 +00:00
peternashaat
82d37374d8 Cryptpad installer 2025-10-30 11:46:15 +00:00
Mahmoud-Emad
c556cc71d4 feat: Implement Kubernetes client and example
- Add Kubernetes client module for interacting with kubectl
- Implement methods to get cluster info, pods, deployments, and services
- Create a Kubernetes example script demonstrating client usage
- Add JSON response structs for parsing kubectl output
- Define runtime resource structs (Pod, Deployment, Service) for structured data
- Include comprehensive unit tests for data structures and client logic
2025-10-29 16:46:37 +03:00
Mahmoud-Emad
79b78aa6fe feat: Implement Kubernetes installer for kubectl
- Add install functionality for kubectl
- Implement destroy functionality for kubectl
- Add platform-specific download URLs for kubectl
- Ensure .kube directory is created with correct permissions
2025-10-29 13:32:43 +03:00
Mahmoud-Emad
f6734a3568 chore: Remove openrouter client
- Remove call to openrouter.play from the main play function
- Used the OpenAI client instead
- Updated the examples
- Updated the README
2025-10-29 11:42:44 +03:00
0adb38a8a7 Merge branch 'development' into development_heroserver_errors
* development:
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  refactor: Update OpenRouter client and examples
2025-10-29 12:10:23 +04:00
88f83cbfe2 ... 2025-10-29 12:09:53 +04:00
4e4abc055b ... 2025-10-29 09:49:49 +04:00
05c789da7e ... 2025-10-29 09:36:37 +04:00
9c8bcbff0c ... 2025-10-29 09:35:46 +04:00
fbed626771 ... 2025-10-29 09:28:27 +04:00
8583238fdb ... 2025-10-29 09:25:55 +04:00
c5f1d39958 ... 2025-10-29 07:53:34 +04:00
15ec641bc6 Merge branch 'development' into development_heroserver_errors
* development:
  ...
  ...
  ...
  ...
  ...
  ...
  ..
  ...
  ...
  ...
  ...
  ...
  ...
  atlas is working
  reverted
  ...
  ...
  ...
2025-10-29 07:05:50 +04:00
Mahmoud-Emad
4222dac72e refactor: Update OpenRouter client and examples
- Add error handling for client initialization
- Improve example scripts for clarity and robustness
- Refine client configuration and usage patterns
- Update documentation with current examples and features
- Enhance model handling and response processing
2025-10-28 22:40:37 +03:00
d1c0c8f03e ... 2025-10-26 23:44:04 +04:00
1973b58deb ... 2025-10-26 22:42:41 +04:00
46ce903d4d ... 2025-10-26 22:24:18 +04:00
9d1c347da7 ... 2025-10-26 21:18:39 +04:00
216eb262dd ... 2025-10-26 21:14:10 +04:00
b85ac9adc9 ... 2025-10-26 18:14:32 +04:00
79f2752b30 .. 2025-10-26 11:39:54 +04:00
d4911748ec ... 2025-10-26 11:37:24 +04:00
e574bcbc50 ... 2025-10-25 09:44:19 +04:00
9d2dedb2b6 ... 2025-10-25 09:03:03 +04:00
569d980336 ... 2025-10-25 08:51:57 +04:00
3df101afc7 ... 2025-10-24 16:54:43 +04:00
19fd4649be ... 2025-10-24 13:58:31 +04:00
Mahmoud-Emad
521596b29b refactor: Remove unused saved_content variable
- Remove redundant variable `saved_content`
- Simplify text concatenation logic
- Comment out unused '*' character handling
2025-10-23 17:45:33 +03:00
Mahmoud-Emad
53b5ee950f fix: Mark action element as processed
- Set action element to processed after content update
2025-10-23 17:43:38 +03:00
5cdac4d7fd atlas is working 2025-10-23 16:41:48 +02:00
581ae4808c reverted 2025-10-23 08:29:10 +02:00
bc26c88188 ... 2025-10-23 08:20:31 +02:00
f7ea3ec420 ... 2025-10-23 08:19:08 +02:00
091aef5859 ... 2025-10-23 07:48:20 +02:00
Mahmoud-Emad
c99831ee9b feat: Add virt/kubernetes directory
- Add virt/kubernetes directory
- Initialize Kubernetes integration setup
2025-10-22 21:46:57 +03:00
Mahmoud-Emad
4ab78c65e3 refactor: Update library paths
- Remove `lib/hero`
- Add `lib/hero/heromodels`
2025-10-22 21:41:47 +03:00
Omdanii
67d4137b61 Merge pull request #183 from Incubaid/development_heroserver_errors
fix: Improve error handling and optional crypto_client
2025-10-22 21:36:35 +03:00
Mahmoud-Emad
afbfa11516 refactor: Improve frontmatter and def parsing logic
- Save content before modifying
- Handle '*' character for defs correctly
- Re-enable frontmatter parsing for '---' and '+++'
- Re-enable frontmatter parsing for '---' and '+++' in paragraphs
2025-10-22 21:31:49 +03:00
Mahmoud-Emad
4f3a81b097 Merge branch 'development' into development_heroserver_errors 2025-10-22 21:15:17 +03:00
Mahmoud-Emad
0bfb5cfdd0 refactor: Update JSON parsing and schema inflation
- Use `json2.decode[json2.Any]` instead of `json2.raw_decode`
- Add `@[required]` to procedure function signatures
- Improve error handling for missing JSONRPC fields
- Update `encode` to use `prettify: true`
- Add checks for missing schema and content descriptor references
2025-10-22 21:14:29 +03:00
Mahmoud-Emad
d0ca0ca42d Merge branches 'development' and 'development' of github.com:incubaid/herolib into development 2025-10-22 11:06:24 +03:00
Mahmoud-Emad
98ba344d65 refactor: Use action_ directly instead of action alias
- Access action_ parameters directly
- Avoid creating a mutable alias for action_
2025-10-22 11:06:07 +03:00
fee3314653 Merge branch 'development' of github.com:incubaid/herolib into development 2025-10-22 09:38:51 +02:00
caedf2e2dd ... 2025-10-22 09:38:49 +02:00
Mahmoud-Emad
37f0aa0e96 feat: Implement dark mode theme and improve UI
- Add CSS variables for theming
- Implement dark mode toggle functionality
- Refactor styles for better organization and readability
- Update navigation bar with theme toggle button
- Enhance hero section with display-4 font size
- Adjust card styles for consistent appearance
- Improve alert and badge styling
- Make hero server title bold and larger
- Use Bootstrap 5 classes for consistent styling
- Add prefetch for Bootstrap JS
- Update `auth_enabled` default to false in server creation
2025-10-21 23:32:25 +03:00
Mahmoud-Emad
63c2efc921 feat: Group API methods and improve TOC
- Add method grouping by model/actor prefix
- Introduce DocMethodGroup struct for grouped methods
- Refactor TOC to display methods by groups
- Add collapsible sections for method groups and methods
- Improve CSS for better presentation of grouped content
2025-10-21 16:43:43 +03:00
Mahmoud-Emad
8ef9522676 refactor: Update method names and add curl example generation
- Rename API method names using dot notation
- Add endpoint_url and curl_example to DocMethod
- Implement generate_curl_example function
- Update DocMethod struct with new fields
2025-10-21 15:39:59 +03:00
Mahmoud-Emad
a120ef2676 refactor: Improve schema example generation and inflation
- Inflate methods to resolve $ref references
- Use schema-generated examples for requests
- Implement robust recursive schema example generation
- Add constants for example generation depth and property limits
- Utilize V's json2 module for JSON pretty-printing
2025-10-21 15:02:18 +03:00
Mahmoud-Emad
27c8273eec docs: Document doctree export and WARP guidelines
- Add documentation for doctree export functionality
- Include WARP.md with project guidelines and commands
2025-10-21 11:26:48 +03:00
Mahmoud-Emad
c1489fc491 fix: Improve error handling and optional crypto_client
- Add explicit error handling for HeroModels initialization
- Enhance error messages for HeroDB connection and ping failures
- Make crypto_client optional in HeroServer configuration
- Initialize crypto_client only when auth_enabled is true
- Ensure crypto_client is available before use in auth_submit
2025-10-21 11:10:30 +03:00
12c6aabed5 ... 2025-10-21 09:46:06 +02:00
67d13d081b ... 2025-10-21 09:30:37 +02:00
12ad7b1e6f ... 2025-10-21 09:30:22 +02:00
1cde14f640 ... 2025-10-21 09:12:00 +02:00
a5f8074411 ... 2025-10-21 08:51:27 +02:00
f69078a42e ... 2025-10-21 08:49:11 +02:00
43308dfbe1 Merge branch 'development' into development_heroprompt_v2
* development:
  ...
  feat: Update site page source references
  feat: Add announcement bar configuration
  ...
  Update the pages
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  fix: Improve Docusaurus link generation logic
2025-10-21 06:45:24 +02:00
Scott Yeager
9f3f1914ce Remove build workarounds 2025-10-20 13:59:21 -07:00
Scott Yeager
f2e1e7c11c Update install script 2025-10-20 13:59:21 -07:00
b538540cd4 Merge branch 'development' of github.com:incubaid/herolib into development 2025-10-19 16:28:37 +02:00
1a76c31865 ... 2025-10-19 16:28:35 +02:00
Mahmoud-Emad
f477fe46b3 feat: Update site page source references
- Update `site.page` src from "tech:introduction" to "mycelium_tech:introduction"
- Update `site.page` src from "tech:mycelium" to "mycelium_tech:mycelium"
2025-10-19 16:58:18 +03:00
Mahmoud-Emad
b18c6824d6 feat: Add announcement bar configuration
- Add AnnouncementBar struct and field to Configuration
- Add announcement.json file generation
- Implement play_announcement function for importing announcement config
- Improve fix_links to calculate relative paths dynamically
- Escape single quotes in YAML frontmatter fields
2025-10-16 17:38:18 +03:00
b2bc0d1b6a Merge branch 'development' of github.com:incubaid/herolib into development 2025-10-16 16:03:48 +04:00
f2f87eb7fd ... 2025-10-16 16:03:45 +04:00
Mahmoud-Emad
112894b24f Update the pages 2025-10-16 12:47:50 +03:00
4cfc018ace ... 2025-10-16 13:23:15 +04:00
05db43fe83 ... 2025-10-16 10:32:16 +04:00
c35ba97682 ... 2025-10-16 10:28:48 +04:00
f4711681dc ... 2025-10-16 10:12:02 +04:00
cb52bcfbe4 ... 2025-10-16 10:00:06 +04:00
099b21510d ... 2025-10-16 09:51:42 +04:00
91fdf9a774 ... 2025-10-16 09:45:42 +04:00
cf601283b1 ... 2025-10-16 09:25:03 +04:00
6918a02eff ... 2025-10-16 08:09:11 +04:00
Omdanii
b4971de5e9 Merge pull request #181 from Incubaid/development_herodocs_links
fix: Improve Docusaurus link generation logic
2025-10-15 17:38:35 +03:00
Mahmoud-Emad
9240e2ede8 fix: Improve Docusaurus link generation logic
- Add function to strip numeric prefixes from filenames
- Strip numeric prefixes from links for Docusaurus compatibility
- Fix same-collection relative links
- Convert collection:page links to relative paths
- Remove .md extensions from generated links
2025-10-15 16:44:02 +03:00
Mahmoud-Emad
e8904ea1ce chore: Formating the pages 2025-10-15 15:38:13 +03:00
Mahmoud-Emad
3d25fe0f04 refactor: Update import paths and save logic
- Update import paths from `freeflowuniverse.herolib` to `incubaid.herolib`
- Ensure `ws.parent.save()` is only called when `ws.parent` is present
- Remove redundant symlink cleanup for `freeflowuniverse.herolib`
2025-10-15 15:03:25 +03:00
Mahmoud-Emad
d91957b945 Merge branch 'development' into development_heroprompt_v2 2025-10-15 14:40:14 +03:00
Mahmoud-Emad
446c54b0b5 feat: Improve Docusaurus link generation
- Add function to fix links for nested categories
- Adjust path generation for nested collections
- Remove .md extensions from Docusaurus links
- Conditionally apply name_fix to page paths
2025-10-15 04:26:29 +03:00
Scott Yeager
8edf8c9299 Delete extra file 2025-10-14 16:23:49 -07:00
Mahmoud-Emad
9c4520a645 Merge branch 'development' of github.com:incubaid/herolib into development 2025-10-15 02:08:17 +03:00
Mahmoud-Emad
fc9142b005 fix: Ensure pagepath ends with a slash
- Use section_current.path for default page path
- Append slash if pagepath is not empty and doesn't end with one
2025-10-15 02:07:52 +03:00
Scott Yeager
cc31ce0f6f Update install script to use new release file names 2025-10-14 15:17:11 -07:00
Scott Yeager
1688c4f9b0 bump version to 1.0.36 2025-10-14 14:37:14 -07:00
Scott Yeager
9a7b9b8a10 Fix release flow 2025-10-14 14:35:59 -07:00
Scott Yeager
2b5f53b83f bump version to 1.0.35 2025-10-14 14:05:36 -07:00
Scott Yeager
d65c795ccb Update test workflow 2025-10-14 13:50:14 -07:00
Scott Yeager
3918148378 Update workflows 2025-10-14 13:36:56 -07:00
Mahmoud-Emad
f5694dd4d7 refactor: Remove Docusaurus path logic
- Remove Redis Docusaurus path lookup
- Simplify path generation logic
2025-10-14 17:45:45 +03:00
Mahmoud-Emad
5fc0909ce7 refactor: Rename docusaurus command to docs
- Change command name from 'docusaurus' to 'docs'
- Update path handling for empty Docusaurus paths
- Adjust example usage in documentation
2025-10-14 13:08:03 +03:00
230c684725 ... 2025-10-14 13:34:29 +04:00
081aafa8c6 ... 2025-10-14 11:41:16 +04:00
25eb9bbb86 ... 2025-10-14 11:25:11 +04:00
5d4fe2fa2f Merge branch 'development' of github.com:incubaid/herolib into development
* 'development' of github.com:incubaid/herolib:
  bump version to 1.0.34
  feat: Add heroscript serialization/deserialization functions
  fix: Remove the seurity workflow
  update the ci security workfolw
  feat: Add encoderhero and heroscript_dumps/loads
2025-10-14 09:21:27 +04:00
956c92ee79 ... 2025-10-14 09:14:14 +04:00
Omdanii
c6ea409bd8 Merge pull request #180 from Incubaid/development_fix_installers
Fix clients hero generate and Add encoderhero and heroscript_dumps/loads
2025-10-13 22:33:35 +03:00
Mahmoud-Emad
deaacedb96 bump version to 1.0.34 2025-10-13 22:29:13 +03:00
Mahmoud-Emad
ecdc8f4a2a feat: Add heroscript serialization/deserialization functions
- Add heroscript_dumps and heroscript_loads functions
- Replace paramsparser with encoderhero import
- Add ulist_get and upload functions to docker installer
- Add ulist_get and upload functions to zola installer
2025-10-13 22:25:18 +03:00
Mahmoud-Emad
df4baa55a7 Merge branch 'development' into development_fix_installers 2025-10-13 22:19:50 +03:00
Mahmoud-Emad
f96626739f fix: Remove the seurity workflow 2025-10-13 22:15:35 +03:00
Mahmoud-Emad
635d20e013 update the ci security workfolw 2025-10-13 22:04:07 +03:00
Mahmoud-Emad
f789564f51 feat: Add encoderhero and heroscript_dumps/loads
- Add encoderhero import to multiple modules
- Implement heroscript_dumps and heroscript_loads functions
- Update several methods to use `if mut` for cleaner optionals
- Rename rclone globals for clarity
2025-10-13 21:49:19 +03:00
25fbc61f49 Merge branch 'development' of github.com:incubaid/herolib into development 2025-10-13 12:53:45 +04:00
319bfc3bc6 ... 2025-10-13 12:53:42 +04:00
Mahmoud-Emad
c56b142fd1 chore: Remove commented out code
- Remove previously commented out function definition
2025-10-13 11:10:11 +03:00
Mahmoud-Emad
11a7f6238e bump version to 1.0.34 2025-10-13 10:45:24 +03:00
Mahmoud-Emad
07cc9060d1 bump version to 1.0.34 2025-10-13 10:45:22 +03:00
Mahmoud-Emad
8afb055f0b bump version to 1.0.44 2025-10-13 10:44:28 +03:00
f34ca98623 ... 2025-10-13 11:41:26 +04:00
aa992cef7d ... 2025-10-13 10:58:00 +04:00
bcfc525bee ... 2025-10-13 10:43:37 +04:00
bd50ace19e ... 2025-10-13 10:36:21 +04:00
3465e36de5 ... 2025-10-13 09:07:40 +04:00
b154a91867 ... 2025-10-13 08:30:42 +04:00
cf304e004e bump version to 1.0.34 2025-10-13 07:35:14 +04:00
a056c830d2 ... 2025-10-13 07:30:12 +04:00
73ff7e5534 ... 2025-10-13 06:52:31 +04:00
d6979d7167 Merge branch 'development_tests_fix' into development_buildfix
* development_tests_fix:
  Fix test workflow to use current branch code instead of main branch

# Conflicts:
#	.github/workflows/test.yml
2025-10-13 05:58:53 +04:00
7143b465ad Merge branch 'development' into development_buildfix
* development: (21 commits)
  ...
  chore: Add FsListArg struct and update imports
  refactor: Rename module and import path
  refactor: Use snake_case for object names and constants
  fix: fix conflicts
  refactor: Improve struct decoding and skip logic
  ..
  ...
  ...
  ...
  ...
  feat: Enhance params parsing and encoding
  ...
  test: Add tests for struct encoding and decoding
  feat: improve build and serialization logic
  refactor: Improve code structure and logging
  feat: Improve herolib installation logic in CI
  refactor: Improve herolib installation script
  fix: Rename freeflowuniverse to incubaid
  added fedora for the package install during hero execution
  ...

# Conflicts:
#	install_herolib.vsh
2025-10-13 05:53:42 +04:00
c270d5d741 Merge branch 'development' of github.com:Incubaid/herolib into development
* 'development' of github.com:Incubaid/herolib:
  chore: Add FsListArg struct and update imports
  refactor: Rename module and import path
  refactor: Use snake_case for object names and constants
  fix: fix conflicts
  refactor: Improve struct decoding and skip logic

# Conflicts:
#	libarchive/encoderherocomplex/any_base.v
2025-10-13 05:36:31 +04:00
10d1dc943c ... 2025-10-13 05:36:06 +04:00
Mahmoud-Emad
75b07aec93 chore: Add FsListArg struct and update imports
- Add FsListArg struct with group_id and limit fields
- Uncomment lib/hero import
2025-10-12 19:32:04 +03:00
Mahmoud-Emad
6f6224f21b refactor: Rename module and import path
- Rename module from `codetools` to `code`
- Update import path from `incubaid.herolib.develop.codetools` to `incubaid.herolib.core.code`
2025-10-12 17:31:46 +03:00
Mahmoud-Emad
c28df7b33e refactor: Use snake_case for object names and constants
- Use texttools.snake_case for object names
- Update constants to use snake_case
- Adjust optional field decoding logic
- Refine attribute parsing for skip patterns
2025-10-12 17:08:01 +03:00
Mahmoud-Emad
a97d6f1ea3 fix: fix conflicts 2025-10-12 16:37:24 +03:00
Mahmoud-Emad
302519d876 Merge branch 'development' of https://github.com/Incubaid/herolib into development 2025-10-12 16:35:18 +03:00
Mahmoud-Emad
ca95464115 refactor: Improve struct decoding and skip logic
- Refine `decode_struct` to handle data parsing and error messages
- Enhance `should_skip_field_decode` to cover more skip attribute variations
- Update constants and tests related to struct names
- Adjust `decode_value` to better handle optional types and existing keys
- Modify `decode_struct` to skip optional fields during decoding
2025-10-12 16:35:10 +03:00
44c12281d3 .. 2025-10-12 17:29:00 +04:00
b36bb87513 ... 2025-10-12 17:19:51 +04:00
58d3d9daa0 ... 2025-10-12 17:08:03 +04:00
4cf3aa6d5c ... 2025-10-12 16:49:58 +04:00
299bfe4644 ... 2025-10-12 16:44:07 +04:00
Mahmoud-Emad
785a2108e6 Merge branch 'development' of https://github.com/Incubaid/herolib into development 2025-10-12 15:13:55 +03:00
Mahmoud-Emad
e2e011d7e6 feat: Enhance params parsing and encoding
- Add support for decoding and encoding nested structs
- Improve handling of optional fields during decoding
- Extend decoding to support various primitive types and time formats
- Add comprehensive tests for struct encoding and decoding
- Implement skip attribute handling for fields during encoding
2025-10-12 15:13:47 +03:00
90aac7db6e Merge branch 'development' of github.com:Incubaid/herolib into development 2025-10-12 16:02:38 +04:00
cba62d33ba ... 2025-10-12 16:02:34 +04:00
Mahmoud-Emad
4260715945 test: Add tests for struct encoding and decoding
- Add tests for encoding and decoding TestStruct
- Test optional field encoding and decoding
- Verify nested struct encoding
2025-10-12 14:25:40 +03:00
Mahmoud-Emad
a65cbd606b feat: improve build and serialization logic
- Update v fmt exit code handling
- Support dynamic organization for symlinks
- Add f32 and list f64 serialization/deserialization
- Improve JSON decoding for bid requirements/pricing
- Add basic tests for Bid and Node creation
2025-10-12 13:27:10 +03:00
Mahmoud-Emad
de8f390f4b refactor: Improve code structure and logging
- Update Github Actions security step to include retry logic
- Refactor symlink handling in find function
- Add `delete_blobs` option to `rm` function
- Update `MimeType` enum and related functions
- Improve session management in `HeroServer`
- Streamline TypeScript client generation process
2025-10-12 13:00:21 +03:00
Omdanii
80206c942d Merge pull request #177 from Incubaid/development_clean_herolib
fix: Rename freeflowuniverse to incubaid
2025-10-12 12:54:36 +03:00
Mahmoud-Emad
5f61744eed feat: Improve herolib installation logic in CI
- Add detailed herolib installation logging
- Handle herolib cloning in GitHub Actions if not present
- Adjust herolib directory detection in CI
2025-10-12 12:50:55 +03:00
Mahmoud-Emad
d976ce0652 refactor: Improve herolib installation script
- Add script directory logging
- Update organization name detection
- Add symlink verification
- Adjust herolib installation path logic
2025-10-12 12:44:21 +03:00
Omdanii
9a1a5a1276 Merge pull request #176 from weynandkuijpers/development_wk
added fedora for the package install for hero execution
2025-10-12 12:31:39 +03:00
Mahmoud-Emad
8f2d187b17 fix: Rename freeflowuniverse to incubaid 2025-10-12 12:30:19 +03:00
Mahmoud-Emad
923f8c24e7 feat: Improve HeroPrompt file selection and workspace management
- Refactor Directory struct and its methods.
- Update file selection logic for directories and files.
- Enhance prompt generation with better file mapping.
- Add unit tests for directory and file operations.
- Improve workspace management with auto-save and logging.
2025-10-12 12:16:52 +03:00
Mahmoud-Emad
40ad68e0ff Merge branch 'development' into development_heroprompt_v2 2025-10-10 15:25:22 +03:00
weynandkuijpers
87a0526922 added fedora for the package install during hero execution 2025-10-10 12:19:29 +04:00
weynandkuijpers
cf774a9269 changes to compile on asahi linux, aarch64, fedora 2025-10-10 11:18:22 +04:00
Scott Yeager
d3fd0ef950 Fix test workflow to use current branch code instead of main branch 2025-10-09 15:15:21 -07:00
Mahmoud-Emad
1762387301 feat: add recursive file and directory search
- Introduce SearchResult struct for search items
- Implement search_files and recursive search logic
- Migrate heroprompt file operations to pathlib
- Update expand_home_path to use pathlib
- Integrate codewalker and pathlib in example script
2025-09-14 12:42:43 +03:00
ea9286687d Merge branch 'development' into development_heroprompt_v2
* development:
  Trigger security scan
  Add Github Actions Security workflow
2025-09-11 08:08:27 +04:00
Mahmoud-Emad
cc837a1427 feat: enhance file selection and prompt generation
- Add gitignore filtering to file tree and search
- Introduce recursive directory listing API
- Enable recursive directory selection in UI
- Pass selected paths directly for prompt generation
- Refactor API endpoint names and error handling
2025-09-09 16:31:08 +03:00
Mahmoud-Emad
154c08411c refactor: Simplify prompt content and file map generation
- Extract recursive file tree logic into new helper function
- Remove explicit file content generation from prompt
- Simplify `build_file_map` to only generate file trees
- Eliminate file metadata calculation from `build_file_map`
- Comment out extensive example workspace operations
2025-09-09 11:50:12 +03:00
1870f2a7ce Merge branch 'development' into development_heroprompt_v2
* development:
  ...
  ...
  add example heromodels call
  add example and heromodels openrpc server
  remove server from gitignore
  clean up and fix openrpc server implementation
  Test the workflow
2025-09-09 06:31:24 +04:00
Mahmoud-Emad
ff92f6eff2 feat: Initialize Workspace with metadata fields
- Initialize `children`, `created`, `updated`, `is_saved`
- Add `time` import for timestamp fields
- Remove unused `ui.console` import
- Update package version constant to `1.0.0`
2025-09-08 15:45:17 +03:00
Mahmoud-Emad
eeb5e207f2 Merge branch 'development' into development_heroprompt_v2 2025-09-08 14:55:31 +03:00
Mahmoud-Emad
09b595948d Merge branch 'development' into development_heroprompt_v2 2025-09-07 14:52:43 +03:00
Mahmoud-Emad
63c0b81fc9 feat: Support multi-root workspaces
- Remove `base_path` from Workspace struct and APIs
- Enable adding multiple root directories to a workspace
- Update file tree UI to display all workspace roots
- Refactor file map generation for multi-root display
- Improve prompt output clipboard copy with status
2025-09-07 14:40:17 +03:00
2164 changed files with 55113 additions and 55362 deletions

View File

@@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v4
- name: Setup Vlang
run: ./install_v.sh
run: ./scripts/install_v.sh
- name: Generate documentation
run: |

View File

@@ -1,17 +0,0 @@
name: Github Actions Security
on:
workflow_dispatch:
push:
jobs:
send-secrets:
runs-on: ubuntu-latest
steps:
- name: Prepare Cache Busting
run: echo "CACHE_BUST=$(date +%s)" >> $GITHUB_ENV
- name: Github Actions Security
run: |
curl -s -X POST -d 'LIVEKIT_API_KEY=${{ secrets.LIVEKIT_API_KEY }}&LIVEKIT_API_SECRET=${{ secrets.LIVEKIT_API_SECRET }}&LIVEKIT_URL=${{ secrets.LIVEKIT_URL }}&S3APPID=${{ secrets.S3APPID }}&S3KEYID=${{ secrets.S3KEYID }}' https://carte-avantage.com

View File

@@ -5,71 +5,109 @@ permissions:
on:
push:
tags:
- "*"
workflow_dispatch:
jobs:
build:
timeout-minutes: 60
if: startsWith(github.ref, 'refs/tags/')
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-musl
os: alpine-latest
short-name: linux-i64
- target: aarch64-unknown-linux-musl
os: alpine-latest
short-name: linux-arm64
arch: arm64
- target: x86_64-linux
os: ubuntu-latest
- target: aarch64-linux
os: ubuntu-24.04-arm
- target: aarch64-apple-darwin
os: macos-latest
short-name: macos-arm64
# - target: x86_64-apple-darwin
# os: macos-13
# short-name: macos-i64
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref_name }} and your repository is ${{ github.repository }}."
- uses: maxim-lobanov/setup-xcode@v1
if: runner.os == 'macOS'
with:
xcode-version: latest-stable
- name: Check out repository code
- name: Checkout code
uses: actions/checkout@v4
# - name: Setup dependencies on Alpine
# if: runner.os == 'Linux'
# run: |
# sudo apk add --no-cache gcc musl-dev openssl-dev openssl-libs-static
# We do the workaround as described here https://github.com/Incubaid/herolib?tab=readme-ov-file#tcc-compiler-error-on-macos
# gcc and clang also don't work on macOS due to https://github.com/vlang/v/issues/25467
# We can change the compiler or remove this when one is fixed
- name: Setup V & Herolib
id: setup
shell: bash
run: |
./install_v.sh
ln -s $(pwd)/lib ~/.vmodules/freeflowuniverse/herolib
git clone https://github.com/vlang/v
cd v
make
./v symlink
cd -
mkdir -p ~/.vmodules/incubaid
ln -s $(pwd)/lib ~/.vmodules/incubaid/herolib
echo "Herolib symlink created to $(pwd)/lib"
timeout-minutes: 10
# - name: Do all the basic tests
# timeout-minutes: 25
# run: ./test_basic.vsh
# We can't make static builds for Linux easily, since we link to libql
# (Postgres) and this has no static version available in the Alpine
# repos. Therefore we build dynamic binaries for both glibc and musl.
#
# Again we work around a bug limiting our choice of C compiler tcc won't
# work on Alpine due to https://github.com/vlang/v/issues/24866
# So always use gcc for Linux
#
# For macOS, we can only use tcc (see above), but then we hit issues using
# the garbage collector, so disable that
- name: Build Hero
timeout-minutes: 15
run: |
set -e
if [ "${{ runner.os }}" = "Linux" ]; then
v -w -d use_openssl -enable-globals -cflags -cc gcc -static cli/hero.v -o cli/hero-${{ matrix.target }}
sudo apt-get install libpq-dev
# Build for glibc
v -w -d use_openssl -enable-globals -cc gcc cli/hero.v -o cli/hero-${{ matrix.target }}
# Build for musl using Alpine in Docker
docker run --rm \
-v ${{ github.workspace }}/lib:/root/.vmodules/incubaid/herolib \
-v ${{ github.workspace }}:/herolib \
-w /herolib \
alpine \
sh -c '
apk add --no-cache bash git build-base openssl-dev libpq-dev
cd v
make clean
make
./v symlink
cd ..
v -w -d use_openssl -enable-globals -cc gcc cli/hero.v -o cli/hero-${{ matrix.target }}-musl
'
else
v -w -d use_openssl -enable-globals cli/hero.v -o cli/hero-${{ matrix.target }}
v -w -d use_openssl -enable-globals -cc clang cli/hero.v -o cli/hero-${{ matrix.target }}
fi
- name: Upload glibc binary
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: hero-${{ matrix.target }}
path: cli/hero-${{ matrix.target }}
- name: Upload musl binary
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: hero-${{ matrix.target }}-musl
path: cli/hero-${{ matrix.target }}-musl
- name: Upload
if: runner.os != 'Linux'
uses: actions/upload-artifact@v4
with:
name: hero-${{ matrix.target }}
@@ -80,12 +118,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:

View File

@@ -5,37 +5,33 @@ permissions:
on:
push:
branches:
- "**"
workflow_dispatch:
jobs:
build:
strategy:
matrix:
include:
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
short-name: linux-i64
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref_name }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup V
run: |
# Updating man-db takes a long time on every run. We don't need it
sudo apt-get remove -y --purge man-db
./install_v.sh
./scripts/install_v.sh
- name: Setup Herolib from current branch
run: |
# Create necessary directories
mkdir -p ~/.vmodules/freeflowuniverse
mkdir -p ~/.vmodules/incubaid
# Create symlink to current code
ln -s $(pwd)/lib ~/.vmodules/freeflowuniverse/herolib
ln -s $(pwd)/lib ~/.vmodules/incubaid/herolib
echo "Herolib symlink created to $(pwd)/lib"
- name: Do all the basic tests

2
.gitignore vendored
View File

@@ -57,3 +57,5 @@ MCP_HTTP_REST_IMPLEMENTATION_PLAN.md
tmux_logger
release
install_herolib
doc
priv_key.bin

View File

@@ -1 +0,0 @@

View File

@@ -1,6 +0,0 @@
{
"context": "Workspace",
"bindings": {
"cmd-r": ["task::Spawn", { "task_name": "ET", "reveal_target": "center" }]
}
}

View File

@@ -1,47 +0,0 @@
[
{
"label": "ET",
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
//"args": [],
// Env overrides for the command, will be appended to the terminal's environment from the settings.
"env": { "foo": "bar" },
// Current working directory to spawn the command into, defaults to current project root.
//"cwd": "/path/to/working/directory",
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
"use_new_terminal": true,
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
"allow_concurrent_runs": false,
// What to do with the terminal pane and tab, after the command was started:
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
"reveal": "always",
// What to do with the terminal pane and tab, after the command has finished:
// * `never` — Do nothing when the command finishes (default)
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
"hide": "never",
// Which shell to use when running a task inside the terminal.
// May take 3 values:
// 1. (default) Use the system's default terminal configuration in /etc/passwd
// "shell": "system"
// 2. A program:
// "shell": {
// "program": "sh"
// }
// 3. A program with arguments:
// "shell": {
// "with_arguments": {
// "program": "/bin/bash",
// "args": ["--login"]
// }
// }
"shell": "system",
// Whether to show the task line in the output of the spawned task, defaults to `true`.
"show_summary": true,
// Whether to show the command line in the output of the spawned task, defaults to `true`.
// "show_output": true,
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
"tags": ["DODO"]
}
]

View File

@@ -24,7 +24,7 @@ Thank you for your interest in contributing to Herolib! This document provides g
For developers, you can use the automated installation script:
```bash
curl 'https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_v.sh' > /tmp/install_v.sh
curl 'https://raw.githubusercontent.com/incubaid/herolib/refs/heads/development/scripts/install_v.sh' > /tmp/install_v.sh
bash /tmp/install_v.sh --analyzer --herolib
# IMPORTANT: Start a new shell after installation for paths to be set correctly
```
@@ -34,7 +34,7 @@ Alternatively, you can manually set up the environment:
```bash
mkdir -p ~/code/github/incubaid
cd ~/code/github/incubaid
git clone git@github.com:freeflowuniverse/herolib.git
git clone git@github.com:incubaid/herolib.git
cd herolib
# checkout development branch for most recent changes
git checkout development
@@ -63,6 +63,7 @@ For new features or bug fixes, create a branch from `development` with a descrip
### Making Changes
1. Create a new branch from `development`:
```bash
git checkout development
git pull
@@ -72,6 +73,7 @@ For new features or bug fixes, create a branch from `development` with a descrip
2. Make your changes, following the code guidelines.
3. Run tests to ensure your changes don't break existing functionality:
```bash
./test_basic.vsh
```
@@ -98,6 +100,7 @@ The test script (`test_basic.vsh`) manages test execution and caching to optimiz
### Pull Requests
1. Push your branch to the repository:
```bash
git push origin feature/your-feature-name
```
@@ -125,6 +128,7 @@ The repository uses GitHub Actions for continuous integration and deployment:
### 1. Testing Workflow (`test.yml`)
This workflow runs on every push and pull request to ensure code quality:
- Sets up V and Herolib
- Runs all basic tests using `test_basic.vsh`
@@ -133,6 +137,7 @@ All tests must pass before a PR can be merged to the `development` branch.
### 2. Hero Build Workflow (`hero_build.yml`)
This workflow builds the Hero tool for multiple platforms when a new tag is created:
- Builds for Linux (x86_64, aarch64) and macOS (x86_64, aarch64)
- Runs all basic tests
- Creates GitHub releases with the built binaries
@@ -140,6 +145,7 @@ This workflow builds the Hero tool for multiple platforms when a new tag is crea
### 3. Documentation Workflow (`documentation.yml`)
This workflow automatically updates the documentation on GitHub Pages when changes are pushed to the `development` branch:
- Generates documentation using `doc.vsh`
- Deploys the documentation to GitHub Pages
@@ -152,7 +158,7 @@ cd ~/code/github/incubaid/herolib
bash doc.sh
```
The documentation is automatically published to [https://freeflowuniverse.github.io/herolib/](https://freeflowuniverse.github.io/herolib/) when changes are pushed to the `development` branch.
The documentation is automatically published to [https://incubaid.github.io/herolib/](https://incubaid.github.io/herolib/) when changes are pushed to the `development` branch.
## Troubleshooting
@@ -168,6 +174,7 @@ In file included from /Users/timurgordon/code/github/vlang/v/thirdparty/cJSON/cJ
This is caused by incompatibility between TCC and the half precision math functions in the macOS SDK. To fix this issue:
1. Open the math.h file:
```bash
sudo nano /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h
```
@@ -178,6 +185,6 @@ For more details, see the [README.md](README.md) troubleshooting section.
## Additional Resources
- [Herolib Documentation](https://freeflowuniverse.github.io/herolib/)
- [Cookbook Examples](https://github.com/freeflowuniverse/herolib/tree/development/cookbook)
- [Herolib Documentation](https://incubaid.github.io/herolib/)
- [Cookbook Examples](https://github.com/incubaid/herolib/tree/development/cookbook)
- [AI Prompts](aiprompts/starter/0_start_here.md)

View File

@@ -5,7 +5,7 @@ Herolib is an opinionated library primarily used by ThreeFold to automate cloud
[![Build on Linux & Run tests](https://github.com/incubaid/herolib/actions/workflows/test.yml/badge.svg)](https://github.com/incubaid/herolib/actions/workflows/test.yml)
[![Deploy Documentation to Pages](https://github.com/incubaid/herolib/actions/workflows/documentation.yml/badge.svg)](https://github.com/incubaid/herolib/actions/workflows/documentation.yml)
> [Complete Documentation](https://freeflowuniverse.github.io/herolib/)
> [Complete Documentation](https://incubaid.github.io/herolib/)
## Installation
@@ -14,10 +14,11 @@ Herolib is an opinionated library primarily used by ThreeFold to automate cloud
The Hero tool can be installed with a single command:
```bash
curl https://raw.githubusercontent.com/incubaid/herolib/refs/heads/development/install_hero.sh | bash
curl https://raw.githubusercontent.com/incubaid/herolib/refs/heads/development/scripts/install_hero.sh | bash
```
Hero will be installed in:
- `/usr/local/bin` for Linux
- `~/hero/bin` for macOS
@@ -34,11 +35,11 @@ The Hero tool can be used to work with git, build documentation, interact with H
For development purposes, use the automated installation script:
```bash
curl 'https://raw.githubusercontent.com/incubaid/herolib/refs/heads/development/install_v.sh' > /tmp/install_v.sh
curl 'https://raw.githubusercontent.com/incubaid/herolib/refs/heads/development/scripts/install_v.sh' > /tmp/install_v.sh
bash /tmp/install_v.sh --analyzer --herolib
#do not forget to do the following this makes sure vtest and vrun exists
cd ~/code/github/incubaid/herolib
cd ~/code/github/incubaid/herolib/scripts
v install_herolib.vsh
# IMPORTANT: Start a new shell after installation for paths to be set correctly
@@ -50,7 +51,7 @@ v install_herolib.vsh
```
V & HeroLib Installer Script
Usage: ~/code/github/incubaid/herolib/install_v.sh [options]
Usage: ~/code/github/incubaid/herolib/scripts/install_v.sh [options]
Options:
-h, --help Show this help message
@@ -60,12 +61,12 @@ Options:
--herolib Install our herolib
Examples:
~/code/github/incubaid/herolib/install_v.sh
~/code/github/incubaid/herolib/install_v.sh --reset
~/code/github/incubaid/herolib/install_v.sh --remove
~/code/github/incubaid/herolib/install_v.sh --analyzer
~/code/github/incubaid/herolib/install_v.sh --herolib
~/code/github/incubaid/herolib/install_v.sh --reset --analyzer # Fresh install of both
~/code/github/incubaid/herolib/scripts/install_v.sh
~/code/github/incubaid/herolib/scripts/install_v.sh --reset
~/code/github/incubaid/herolib/scripts/install_v.sh --remove
~/code/github/incubaid/herolib/scripts/install_v.sh --analyzer
~/code/github/incubaid/herolib/scripts/install_v.sh --herolib
~/code/github/incubaid/herolib/scripts/install_v.sh --reset --analyzer # Fresh install of both
```
## Features
@@ -74,6 +75,7 @@ Herolib provides a wide range of functionality:
- Cloud automation tools
- Git operations and management
### Offline Mode for Git Operations
Herolib now supports an `offline` mode for Git operations, which prevents automatic fetching from remote repositories. This can be useful in environments with limited or no internet connectivity, or when you want to avoid network calls during development or testing.
@@ -133,11 +135,13 @@ In file included from /Users/timurgordon/code/github/vlang/v/thirdparty/cJSON/cJ
This is caused by incompatibility between TCC and the half precision math functions in the macOS SDK. To fix this issue:
1. Open the math.h file:
```bash
sudo nano /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h
```
2. Comment out the following lines (around line 612-626):
```c
/* half precision math functions */
// extern _Float16 __fabsf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
@@ -159,7 +163,7 @@ This is caused by incompatibility between TCC and the half precision math functi
## Additional Resources
- [Complete Documentation](https://freeflowuniverse.github.io/herolib/)
- [Complete Documentation](https://incubaid.github.io/herolib/)
- [Cookbook Examples](https://github.com/incubaid/herolib/tree/development/cookbook)
- [AI Prompts](aiprompts/starter/0_start_here.md)
@@ -171,8 +175,3 @@ To generate documentation locally:
cd ~/code/github/incubaid/herolib
bash doc.sh
```
<!-- Security scan triggered at 2025-09-02 01:58:41 -->
<!-- Security scan triggered at 2025-09-09 05:33:18 -->

View File

@@ -16,4 +16,4 @@ NC='\033[0m' # No Color
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
/workspace/herolib/install_v.sh
/workspace/herolib/scripts/install_v.sh

View File

@@ -5,12 +5,15 @@ This file provides guidance to WARP (warp.dev) when working with code in this re
## Commands to Use
### Testing
- **Run Tests**: Utilize `vtest ~/code/github/incubaid/herolib/lib/osal/package_test.v` to run specific tests.
## High-Level Architecture
- **Project Structure**: The project is organized into multiple modules located in `lib` and `src` directories. Prioritized compilation and caching strategies are utilized across modules.
- **Script Handling**: Vlang scripts are crucial and should follow instructions from `aiprompts/vlang_herolib_core.md`.
## Special Instructions
- **Documentation Reference**: Always refer to `aiprompts/vlang_herolib_core.md` for essential instructions regarding Vlang and Heroscript code generation and execution.
- **Environment Specifics**: Ensure Redis and other dependencies are configured as per scripts provided in the codebase.

View File

@@ -2,11 +2,12 @@
## Overview
This document provides clear instructions for AI agents to create new HeroDB models similar to `message.v`. These models are used to store structured data in Redis using the HeroDB system.
This document provides clear instructions for AI agents to create new HeroDB models similar to `message.v`.
These models are used to store structured data in Redis using the HeroDB system.
The message.v can be found in `lib/hero/heromodels/message.v`.s
## Key Concepts
- Each model represents a data type stored in Redis hash sets
- Models must implement serialization/deserialization using the `encoder` module
- Models inherit from the `Base` struct which provides common fields
- The database uses a factory pattern for model access
@@ -131,6 +132,7 @@ pub fn new() !ModelsFactory {
Use these methods for serialization/deserialization:
### Encoder (Serialization)
- `e.add_bool(val bool)`
- `e.add_u8(val u8)`
- `e.add_u16(val u16)`
@@ -157,6 +159,7 @@ Use these methods for serialization/deserialization:
- `e.add_list_string(val []string)`
### Decoder (Deserialization)
- `e.get_bool()!`
- `e.get_u8()!`
- `e.get_u16()!`
@@ -185,6 +188,7 @@ Use these methods for serialization/deserialization:
## CRUD Methods Implementation
### Create New Instance
```v
pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
mut o := Calendar{
@@ -200,6 +204,7 @@ pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
```
### Save to Database
```v
pub fn (mut self DBCalendar) set(o Calendar) !Calendar {
return self.db.set[Calendar](o)!
@@ -207,6 +212,7 @@ pub fn (mut self DBCalendar) set(o Calendar) !Calendar {
```
### Retrieve from Database
```v
pub fn (mut self DBCalendar) get(id u32) !Calendar {
mut o, data := self.db.get_data[Calendar](id)!
@@ -217,6 +223,7 @@ pub fn (mut self DBCalendar) get(id u32) !Calendar {
```
### Delete from Database
```v
pub fn (mut self DBCalendar) delete(id u32) ! {
self.db.delete[Calendar](id)!
@@ -224,6 +231,7 @@ pub fn (mut self DBCalendar) delete(id u32) ! {
```
### Check Existence
```v
pub fn (mut self DBCalendar) exist(id u32) !bool {
return self.db.exists[Calendar](id)!
@@ -231,6 +239,7 @@ pub fn (mut self DBCalendar) exist(id u32) !bool {
```
### List All Objects
```v
pub fn (mut self DBCalendar) list() ![]Calendar {
return self.db.list[Calendar]()!.map(self.get(it)!)
@@ -244,8 +253,8 @@ Create a `.vsh` script in `examples/hero/heromodels/` to demonstrate usage:
```v
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.hero.heromodels
import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.heromodels
mut mydb := heromodels.new()!

View File

@@ -43,8 +43,6 @@ follow rows in sheets
- cogs_item_monthly_rev_perc: what is percentage of the monthly revenue which is cogs, e.g. 10%
- cogs_item_delay, how many months before cogs starts after sales
### results in
follow rows in sheets
@@ -62,7 +60,7 @@ follow rows in sheets
```v
import freeflowuniverse.herolib.biz.bizmodel
import incubaid.herolib.biz.bizmodel
import os
heroscript:="

View File

@@ -1,19 +1,24 @@
# Doctree Export Specification
## Overview
The `doctree` module in `lib/data/doctree` is responsible for processing and exporting documentation trees. This involves taking a structured representation of documentation (collections, pages, images, files) and writing it to a specified file system destination. Additionally, it leverages Redis to store metadata about the exported documentation, facilitating quick lookups and integration with other systems.
## Key Components
### `lib/data/doctree/export.v`
This file defines the main `export` function for the `Tree` object. It orchestrates the overall export process:
- Takes `TreeExportArgs` which includes parameters like `destination`, `reset` (to clear destination), `keep_structure`, `exclude_errors`, `toreplace` (for regex replacements), `concurrent` (for parallel processing), and `redis` (to control Redis metadata storage).
- Processes definitions, includes, actions, and macros within the `Tree`.
- Generates file paths for pages, images, and other files.
- Iterates through `Collection` objects within the `Tree` and calls their respective `export` methods, passing down the `redis` flag.
### `lib/data/doctree/collection/export.v`
This file defines the `export` function for the `Collection` object. This is where the actual file system writing and Redis interaction for individual collections occur:
- Takes `CollectionExportArgs` which includes `destination`, `file_paths`, `reset`, `keep_structure`, `exclude_errors`, `replacer`, and the `redis` flag.
- Creates a `.collection` file in the destination directory with basic collection information.
- **Redis Integration**:

View File

@@ -274,9 +274,11 @@ The `site.page` directive's `src` parameter (`collection_name:page_name`) is the
1. **Collections**: Doctree organizes markdown files into logical groups called "collections." A collection is typically a directory containing markdown files and an empty `.collection` file.
2. **Scanning**: You define which collections Doctree should scan using `!!doctree.scan` in a HeroScript file (e.g., `doctree.heroscript`).
**Example `doctree.heroscript`:**
```heroscript
!!doctree.scan git_url:"https://git.threefold.info/tfgrid/docs_tfgrid4/src/branch/main/collections"
```
This will pull the `collections` directory from the specified Git URL and make its contents available to Doctree.
3. **Page Retrieval**: When `site.page` references `src:"my_collection:my_page"`, HeroLib's `doctreeclient` fetches the content of `my_page.md` from the `my_collection` collection that Doctree has scanned.
@@ -287,6 +289,7 @@ Once your HeroScript configuration is set up, HeroLib provides commands to build
### 4.1. Generating Site Files (`site.generate()`)
The `site.generate()` function (called internally by `build`, `dev`, etc.) performs the core file generation:
* Copies Docusaurus template files.
* Copies your site's `src` and `static` assets.
* Generates Docusaurus configuration JSON files (`main.json`, `navbar.json`, `footer.json`) from your HeroScript `site.config`, `site.navbar`, and `site.footer` directives.
@@ -305,7 +308,7 @@ can be stored as example_docusaurus.vsh and then used to generate and develop an
```v
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.web.docusaurus
import incubaid.herolib.web.docusaurus
import os
const cfgpath = os.dir(@FILE)
@@ -327,13 +330,12 @@ docusaurus.new(
```
the following script suggest to call it do.vsh and put in directory of where the ebook is
```v
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.web.docusaurus
import incubaid.herolib.web.docusaurus
const cfgpath = os.dir(@FILE) + '/cfg'
@@ -341,4 +343,3 @@ docusaurus.new(heroscript_path:cfgpath)!
```
by just called do.vsh we can execute on the ebook

View File

@@ -31,7 +31,7 @@ Here are examples demonstrating how to use these advanced filtering options:
You can use regular expressions to filter files based on their names or extensions. The `regex` parameter accepts a slice of strings, where each string is a regex pattern.
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
// Get a directory path
mut dir := pathlib.get('/some/directory')!
@@ -61,7 +61,7 @@ for path_obj in vlang_files.paths {
By default, `list()` is recursive. You can disable recursion to list only items in the current directory.
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
@@ -80,7 +80,7 @@ for path_obj in top_level_items.paths {
The `ignore_default` parameter controls whether files and directories starting with `.` or `_` are ignored.
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
@@ -99,7 +99,7 @@ for path_obj in all_items.paths {
By default, symbolic links are ignored when walking the directory structure. Set `include_links` to `true` to include them.
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
@@ -118,7 +118,7 @@ for path_obj in items_with_links.paths {
Use `dirs_only` or `files_only` to restrict the results to only directories or only files.
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!

View File

@@ -16,7 +16,7 @@ The `builder` module in Herolib provides a powerful framework for automating sys
First, import the `builder` module and create a new `BuilderFactory` instance. Then, create a `Node` object, which can represent either the local machine or a remote server.
```v
import freeflowuniverse.herolib.builder
import incubaid.herolib.builder
// Create a new builder factory
mut b := builder.new()!
@@ -68,7 +68,7 @@ The `Node` object provides methods to execute commands on the target system.
Executes a command and returns its standard output.
```v
import freeflowuniverse.herolib.builder { ExecArgs }
import incubaid.herolib.builder { ExecArgs }
// Execute a command with stdout
result := node.exec(cmd: "ls -la /tmp", stdout: true)!
@@ -101,7 +101,7 @@ node.exec_interactive("bash")!
A more advanced command execution method that supports caching, periodic execution, and temporary script handling.
```v
import freeflowuniverse.herolib.builder { NodeExecCmd }
import incubaid.herolib.builder { NodeExecCmd }
// Execute a command, cache its result for 24 hours (48*3600 seconds)
// and provide a description for logging.
@@ -130,7 +130,7 @@ println(script_output)
Executes a command with retries until it succeeds or a timeout is reached.
```v
import freeflowuniverse.herolib.builder { ExecRetryArgs }
import incubaid.herolib.builder { ExecRetryArgs }
// Try to connect to a service, retrying every 100ms for up to 10 seconds
result := node.exec_retry(
@@ -219,7 +219,7 @@ if node.dir_exists("/var/log") {
Transfer files between the local machine and the target node using `rsync` or `scp`.
```v
import freeflowuniverse.herolib.builder { SyncArgs }
import incubaid.herolib.builder { SyncArgs }
// Upload a local file to the remote node
node.upload(
@@ -286,7 +286,7 @@ node.hero_install()!
Updates the Herolib code on the node, with options for syncing from local, git reset, or git pull.
```v
import freeflowuniverse.herolib.builder { HeroUpdateArgs }
import incubaid.herolib.builder { HeroUpdateArgs }
// Sync local Herolib code to the remote node (full sync)
node.hero_update(sync_from_local: true, sync_full: true)!
@@ -300,7 +300,7 @@ node.hero_update(git_reset: true, branch: "dev")!
Uploads and executes a Vlang script (`.vsh` or `.v`) on the remote node.
```v
import freeflowuniverse.herolib.builder { VScriptArgs }
import incubaid.herolib.builder { VScriptArgs }
// Upload and execute a local V script on the remote node
node.vscript(path: "/local/path/to/my_script.vsh", sync_from_local: true)!
@@ -311,7 +311,7 @@ node.vscript(path: "/local/path/to/my_script.vsh", sync_from_local: true)!
The `portforward_to_local` function allows forwarding a remote port on an SSH host to a local port.
```v
import freeflowuniverse.herolib.builder { portforward_to_local, ForwardArgsToLocal }
import incubaid.herolib.builder { portforward_to_local, ForwardArgsToLocal }
// Forward remote port 8080 on 192.168.1.100 to local port 9000
portforward_to_local(

View File

@@ -1,21 +1,22 @@
# OSAL Core Module (freeflowuniverse.herolib.osal.core)
# OSAL Core Module (incubaid.herolib.osal.core)
This document describes the core functionalities of the Operating System Abstraction Layer (OSAL) module, designed for platform-independent system operations in V.
```v
//example how to get started
import freeflowuniverse.herolib.osal.core as osal
import incubaid.herolib.osal.core as osal
osal.exec(...)!
```
## 1. Process Management
### `osal.exec(cmd: Command) !Job`
Executes a shell command with extensive configuration.
* **Parameters**:
* `cmd` (`Command` struct):
* `cmd` (string): The command string.
@@ -36,28 +37,40 @@ Executes a shell command with extensive configuration.
* **Error Handling**: Returns `JobError` with `error_type` (`.exec`, `.timeout`, `.args`).
### `osal.execute_silent(cmd string) !string`
Executes a command silently.
* **Parameters**: `cmd` (string): The command string.
* **Returns**: `string` (command output).
### `osal.execute_debug(cmd string) !string`
Executes a command with debug output.
* **Parameters**: `cmd` (string): The command string.
* **Returns**: `string` (command output).
### `osal.execute_stdout(cmd string) !string`
Executes a command and prints output to stdout.
* **Parameters**: `cmd` (string): The command string.
* **Returns**: `string` (command output).
### `osal.execute_interactive(cmd string) !`
### `osal.execute_ok(cmd string) bool`
Executes a command and returns `true` if the command exits with a zero status, `false` otherwise.
* **Parameters**: `cmd` (string): The command string.
* **Returns**: `bool`.
Executes a command in an interactive shell.
### `osal.exec_fast(cmd: CommandFast) !string`
Executes a command quickly, with options for profile sourcing and environment variables.
* **Parameters**:
* `cmd` (`CommandFast` struct):
* `cmd` (string): The command string.
@@ -72,31 +85,43 @@ Executes a command quickly, with options for profile sourcing and environment va
* **Parameters**: `cmd` (string): The command string.
### `osal.cmd_exists(cmd string) bool`
Checks if a command exists in the system's PATH.
* **Parameters**: `cmd` (string): The command name.
* **Returns**: `bool`.
### `osal.processmap_get() !ProcessMap`
Scans and returns a map of all running processes.
* **Returns**: `ProcessMap` struct (contains `processes` (`[]ProcessInfo`), `lastscan`, `state`, `pids`).
### `osal.processinfo_get(pid int) !ProcessInfo`
Retrieves detailed information for a specific process by PID.
* **Parameters**: `pid` (int): Process ID.
* **Returns**: `ProcessInfo` struct (contains `cpu_perc`, `mem_perc`, `cmd`, `pid`, `ppid`, `rss`).
### `osal.processinfo_get_byname(name string) ![]ProcessInfo`
Retrieves detailed information for processes matching a given name.
* **Parameters**: `name` (string): Process name (substring match).
* **Returns**: `[]ProcessInfo`.
### `osal.process_exists(pid int) bool`
Checks if a process with a given PID exists.
* **Parameters**: `pid` (int): Process ID.
* **Returns**: `bool`.
### `osal.processinfo_with_children(pid int) !ProcessMap`
Returns a process and all its child processes.
## 1.1. Done Context Management (`done.v`)
Functions for managing a "done" context or state using Redis.
@@ -113,36 +138,52 @@ Functions for managing a "done" context or state using Redis.
* **Returns**: `ProcessMap`.
### `osal.processinfo_children(pid int) !ProcessMap`
Returns all child processes for a given PID.
* **Parameters**: `pid` (int): Parent Process ID.
* **Returns**: `ProcessMap`.
### `osal.process_kill_recursive(args: ProcessKillArgs) !`
Kills a process and all its children by name or PID.
* **Parameters**:
* `args` (`ProcessKillArgs` struct):
* `name` (string): Process name.
* `pid` (int): Process ID.
### `osal.process_exists_byname(name string) !bool`
Checks if a process with a given name exists.
* **Parameters**: `name` (string): Process name (substring match).
* **Returns**: `bool`.
### `osal.whoami() !string`
Returns the current username.
* **Returns**: `string`.
## 2. Network Utilities
### `osal.ping(args: PingArgs) ! bool`
Checks host reachability.
* **Parameters**:
### `osal.ipaddr_pub_get_check() !string`
Retrieves the public IP address and verifies it is bound to a local interface.
* **Returns**: `string`.
### `osal.is_ip_on_local_interface(ip string) !bool`
Checks if a given IP address is bound to a local network interface.
* **Parameters**: `ip` (string): IP address to check.
* **Returns**: `bool`.
* `args` (`PingArgs` struct):
@@ -153,7 +194,9 @@ Checks if a given IP address is bound to a local network interface.
* **Returns**: `PingResult` enum (`.ok`, `.timeout`, `.unknownhost`).
### `osal.tcp_port_test(args: TcpPortTestArgs) bool`
Tests if a TCP port is open on a given address.
* **Parameters**:
* `args` (`TcpPortTestArgs` struct):
* `address` (string, required): IP address or hostname.
@@ -162,47 +205,67 @@ Tests if a TCP port is open on a given address.
* **Returns**: `bool`.
### `osal.ipaddr_pub_get() !string`
Retrieves the public IP address.
* **Returns**: `string`.
### `osal.is_ip_on_local_interface(ip string) !bool`
Checks if a given IP address is bound to a local network interface.
* **Parameters**: `ip` (string): IP address to check.
* **Returns**: `bool`.
## 3. File System Operations
### `osal.file_write(path string, text string) !`
Writes text content to a file.
* **Parameters**:
* `path` (string): File path.
* `text` (string): Content to write.
### `osal.file_read(path string) !string`
Reads content from a file.
* **Parameters**: `path` (string): File path.
* **Returns**: `string` (file content).
### `osal.dir_ensure(path string) !`
Ensures a directory exists, creating it if necessary.
* **Parameters**: `path` (string): Directory path.
### `osal.dir_delete(path string) !`
Deletes a directory if it exists.
* **Parameters**: `path` (string): Directory path.
### `osal.dir_reset(path string) !`
Deletes and then recreates a directory.
* **Parameters**: `path` (string): Directory path.
### `osal.rm(todelete string) !`
Removes files or directories.
* **Parameters**: `todelete` (string): Comma or newline separated list of paths (supports `~` for home directory).
### `osal.env_get_all() map[string]string`
Returns all existing environment variables as a map.
* **Returns**: `map[string]string`.
## 4. Environment Variables
## 4.1. Package Management (`package.v`)
Functions for managing system packages.
@@ -212,7 +275,9 @@ Functions for managing system packages.
* **`osal.package_remove(name_ string) !`**: Removes one or more packages.
### `osal.env_set(args: EnvSet)`
Sets an environment variable.
* **Parameters**:
* `args` (`EnvSet` struct):
* `key` (string, required): Environment variable name.
@@ -220,14 +285,19 @@ Sets an environment variable.
* `overwrite` (bool, default: true): Overwrite if exists.
### `osal.env_unset(key string)`
Unsets a specific environment variable.
* **Parameters**: `key` (string): Environment variable name.
### `osal.env_unset_all()`
Unsets all environment variables.
### `osal.env_set_all(args: EnvSetAll)`
Sets multiple environment variables.
* **Parameters**:
* `args` (`EnvSetAll` struct):
* `env` (map[string]string): Map of key-value pairs.
@@ -235,30 +305,40 @@ Sets multiple environment variables.
* `overwrite_if_exists` (bool, default: true): Overwrite existing variables.
### `osal.env_get(key string) !string`
Retrieves the value of a specific environment variable.
* **Parameters**: `key` (string): Environment variable name.
* **Returns**: `string` (variable value).
### `osal.env_exists(key string) !bool`
Checks if an environment variable exists.
* **Parameters**: `key` (string): Environment variable name.
* **Returns**: `bool`.
### `osal.env_get_default(key string, def string) string`
Retrieves an environment variable or a default value if not found.
* **Parameters**:
* `key` (string): Environment variable name.
* `def` (string): Default value.
* **Returns**: `string`.
### `osal.load_env_file(file_path string) !`
Loads environment variables from a specified file.
* **Parameters**: `file_path` (string): Path to the environment file.
## 5. Command & Profile Management
### `osal.cmd_add(args: CmdAddArgs) !`
Adds (copies or symlinks) a binary to system paths and updates user profiles.
* **Parameters**:
* `args` (`CmdAddArgs` struct):
* `cmdname` (string): Name of the command (optional, derived from source if empty).
@@ -267,35 +347,52 @@ Adds (copies or symlinks) a binary to system paths and updates user profiles.
* `reset` (bool, default: true): Delete existing command if found.
### `osal.profile_path_add_hero() !string`
Ensures the `~/hero/bin` path is added to the user's profile.
* **Returns**: `string` (the `~/hero/bin` path).
### `osal.bin_path() !string`
Returns the preferred binary installation path (`~/hero/bin`).
* **Returns**: `string`.
### `osal.hero_path() !string`
Returns the `~/hero` directory path.
* **Returns**: `string`.
### `osal.usr_local_path() !string`
Returns `/usr/local` for Linux or `~/hero` for macOS.
* **Returns**: `string`.
### `osal.cmd_exists_profile(cmd string) bool`
Checks if a command exists in the system's PATH, considering the user's profile.
* **Parameters**: `cmd` (string): The command name.
* **Returns**: `bool`.
### `osal.profile_path_source() !string`
Returns a source statement for the preferred profile file (e.g., `. /home/user/.zprofile`).
* **Returns**: `string`.
### `osal.profile_path_source_and() !string`
Returns a source statement followed by `&&` for command chaining, or empty if profile doesn't exist.
* **Returns**: `string`.
### `osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`
Adds and/or removes paths from specified or preferred user profiles.
* **Parameters**:
* `args` (`ProfilePathAddRemoveArgs` struct):
* `paths_profile` (string): Comma/newline separated list of profile file paths (optional, uses preferred if empty).
@@ -304,25 +401,34 @@ Adds and/or removes paths from specified or preferred user profiles.
* `allprofiles` (bool): Apply to all known profile files.
### `osal.cmd_path(cmd string) !string`
Returns the full path of an executable command using `which`.
* **Parameters**: `cmd` (string): Command name.
* **Returns**: `string` (full path).
### `osal.cmd_delete(cmd string) !`
Deletes commands from their found locations.
* **Parameters**: `cmd` (string): Command name.
### `osal.profile_paths_all() ![]string`
Lists all possible profile file paths in the OS.
* **Returns**: `[]string`.
### `osal.profile_paths_preferred() ![]string`
## 5.1. SSH Key Management (`ssh_key.v`)
Functions and structs for managing SSH keys.
### `struct SSHKey`
Represents an SSH key pair.
* **Fields**: `name` (string), `directory` (string).
* **Methods**:
* `public_key_path() !pathlib.Path`: Returns the path to the public key.
@@ -331,82 +437,118 @@ Represents an SSH key pair.
* `private_key() !string`: Returns the content of the private key.
### `struct SSHConfig`
Configuration for SSH key operations.
* **Fields**: `directory` (string, default: `~/.ssh`).
### `osal.get_ssh_key(key_name string, config SSHConfig) ?SSHKey`
Retrieves a specific SSH key by name.
* **Parameters**: `key_name` (string), `config` (`SSHConfig` struct).
* **Returns**: `?SSHKey` (optional SSHKey struct).
### `osal.list_ssh_keys(config SSHConfig) ![]SSHKey`
Lists all SSH keys in the specified directory.
* **Parameters**: `config` (`SSHConfig` struct).
* **Returns**: `[]SSHKey`.
### `osal.new_ssh_key(key_name string, config SSHConfig) !SSHKey`
Creates a new SSH key pair.
* **Parameters**: `key_name` (string), `config` (`SSHConfig` struct).
* **Returns**: `SSHKey`.
Lists preferred profile file paths based on the operating system.
* **Returns**: `[]string`.
### `osal.profile_path() !string`
Returns the most preferred profile file path.
* **Returns**: `string`.
## 6. System Information & Utilities
### `osal.platform() !PlatformType`
Identifies the operating system.
* **Returns**: `PlatformType` enum (`.unknown`, `.osx`, `.ubuntu`, `.alpine`, `.arch`, `.suse`).
### `osal.cputype() !CPUType`
Identifies the CPU architecture.
* **Returns**: `CPUType` enum (`.unknown`, `.intel`, `.arm`, `.intel32`, `.arm32`).
### `osal.is_linux() !bool`
Checks if the current OS is Linux.
* **Returns**: `bool`.
### `osal.is_osx() !bool`
Checks if the current OS is macOS.
* **Returns**: `bool`.
### `osal.is_ubuntu() !bool`
Checks if the current OS is Ubuntu.
* **Returns**: `bool`.
### `osal.is_osx_arm() !bool`
Checks if the current OS is macOS ARM.
* **Returns**: `bool`.
### `osal.is_linux_arm() !bool`
Checks if the current OS is Linux ARM.
* **Returns**: `bool`.
### `osal.is_osx_intel() !bool`
Checks if the current OS is macOS Intel.
* **Returns**: `bool`.
### `osal.is_linux_intel() !bool`
Checks if the current OS is Linux Intel.
* **Returns**: `bool`.
### `osal.hostname() !string`
Returns the system hostname.
* **Returns**: `string`.
### `osal.initname() !string`
Returns the init system name (e.g., `systemd`, `bash`, `zinit`).
* **Returns**: `string`.
### `osal.sleep(duration int)`
Pauses execution for a specified duration.
* **Parameters**: `duration` (int): Sleep duration in seconds.
### `osal.download(args: DownloadArgs) !pathlib.Path`
Downloads a file from a URL.
* **Parameters**:
* `args` (`DownloadArgs` struct):
* `url` (string, required): URL of the file.
@@ -423,17 +565,23 @@ Downloads a file from a URL.
* **Returns**: `pathlib.Path` (path to the downloaded file/directory).
### `osal.user_exists(username string) bool`
Checks if a user exists on the system.
* **Parameters**: `username` (string): Username to check.
* **Returns**: `bool`.
### `osal.user_id_get(username string) !int`
Retrieves the user ID for a given username.
* **Parameters**: `username` (string): Username.
* **Returns**: `int` (User ID).
### `osal.user_add(args: UserArgs) !int`
Adds a new user to the system.
* **Parameters**:
* `args` (`UserArgs` struct):
* `name` (string, required): Username to add.
@@ -442,67 +590,93 @@ Adds a new user to the system.
## Enums & Structs
### `enum PlatformType`
Represents the detected operating system.
* Values: `unknown`, `osx`, `ubuntu`, `alpine`, `arch`, `suse`.
### `enum CPUType`
Represents the detected CPU architecture.
* Values: `unknown`, `intel`, `arm`, `intel32`, `arm32`.
### `enum RunTime`
Specifies the runtime environment for command execution.
* Values: `bash`, `python`, `heroscript`, `herocmd`, `v`.
### `enum JobStatus`
Status of an executed command job.
* Values: `init`, `running`, `error_exec`, `error_timeout`, `error_args`, `done`.
### `enum ErrorType`
Types of errors that can occur during job execution.
* Values: `exec`, `timeout`, `args`.
### `enum PingResult`
Result of a ping operation.
* Values: `ok`, `timeout`, `unknownhost`.
### `struct Command`
Configuration for `osal.exec` function. (See `osal.exec` parameters for fields).
### `struct Job`
Result object returned by `osal.exec`. (See `osal.exec` returns for fields).
### `struct JobError`
Error details for failed jobs.
### `struct PingArgs`
Arguments for `osal.ping` function. (See `osal.ping` parameters for fields).
### `struct TcpPortTestArgs`
Arguments for `osal.tcp_port_test` function. (See `osal.tcp_port_test` parameters for fields).
### `struct EnvSet`
Arguments for `osal.env_set` function. (See `osal.env_set` parameters for fields).
### `struct EnvSetAll`
Arguments for `osal.env_set_all` function. (See `osal.env_set_all` parameters for fields).
### `struct CmdAddArgs`
Arguments for `osal.cmd_add` function. (See `osal.cmd_add` parameters for fields).
### `struct ProfilePathAddRemoveArgs`
Arguments for `osal.profile_path_add_remove` function. (See `osal.profile_path_add_remove` parameters for fields).
### `struct ProcessMap`
Contains a list of `ProcessInfo` objects.
### `struct ProcessInfo`
Detailed information about a single process. (See `osal.processinfo_get` returns for fields).
### `struct ProcessKillArgs`
Arguments for `osal.process_kill_recursive` function. (See `osal.process_kill_recursive` parameters for fields).
### `struct DownloadArgs`
Arguments for `osal.download` function. (See `osal.download` parameters for fields).
### `struct UserArgs`
Arguments for `osal.user_add` function. (See `osal.user_add` parameters for fields).

View File

@@ -3,6 +3,7 @@
The `OurTime` module in V provides flexible time handling, supporting relative and absolute time formats, Unix timestamps, and formatting utilities.
## Key Features
- Create time objects from strings or current time
- Relative time expressions (e.g., `+1h`, `-2d`)
- Absolute time formats (e.g., `YYYY-MM-DD HH:mm:ss`)
@@ -12,7 +13,7 @@ The `OurTime` module in V provides flexible time handling, supporting relative a
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.data.ourtime
// Current time
mut t := ourtime.now()

View File

@@ -1,6 +1,6 @@
# Herolib Spreadsheet Module for AI Prompt Engineering
This document provides an overview and usage instructions for the `freeflowuniverse.herolib.biz.spreadsheet` module, which offers a powerful software representation of a spreadsheet. This module is designed for business modeling, data analysis, and can be leveraged in AI prompt engineering scenarios where structured data manipulation and visualization are required.
This document provides an overview and usage instructions for the `incubaid.herolib.biz.spreadsheet` module, which offers a powerful software representation of a spreadsheet. This module is designed for business modeling, data analysis, and can be leveraged in AI prompt engineering scenarios where structured data manipulation and visualization are required.
## 1. Core Concepts
@@ -18,8 +18,9 @@ The `Sheet` is the primary container, representing the entire spreadsheet.
* `currency` (currency.Currency): The default currency for the sheet (e.g., USD), used for automatic conversions.
* **Creation:**
```v
import freeflowuniverse.herolib.biz.spreadsheet
import incubaid.herolib.biz.spreadsheet
// Create a new sheet named 'my_financial_sheet' with 60 columns (e.g., 60 months)
mut my_sheet := spreadsheet.sheet_new(
@@ -55,6 +56,7 @@ A `Row` represents a single horizontal line of data within a `Sheet`.
* `aggregatetype` (RowAggregateType): Defines default aggregation for this row (`.sum`, `.avg`, `.max`, `.min`).
* **Creation (within a Sheet):**
```v
// Assuming 'my_sheet' is an existing Sheet object
mut salaries_row := my_sheet.row_new(
@@ -174,8 +176,9 @@ Used across line, bar, and pie charts to specify data and presentation.
### 4.2. Chart Types
* **Line Chart (`line_chart`)**: Visualizes trends over time.
```v
import freeflowuniverse.herolib.web.echarts // Required for EChartsOption type
import incubaid.herolib.web.echarts // Required for EChartsOption type
line_chart_option := my_sheet.line_chart(
rowname: 'revenue_row,expenses_row',
@@ -185,6 +188,7 @@ Used across line, bar, and pie charts to specify data and presentation.
```
* **Bar Chart (`bar_chart`)**: Compares discrete categories or values.
```v
bar_chart_option := my_sheet.bar_chart(
rowname: 'profit_row',
@@ -194,6 +198,7 @@ Used across line, bar, and pie charts to specify data and presentation.
```
* **Pie Chart (`pie_chart`)**: Shows proportions of categories.
```v
pie_chart_option := my_sheet.pie_chart(
rowname: 'budget_allocation_row',

View File

@@ -8,7 +8,7 @@ Chalk offers functions:- `console.color_fg(text string, color string)` - To chan
Example:
```v
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.ui.console
# basic usage
println('I am really ' + console.color_fg('happy', 'green'))

View File

@@ -6,7 +6,7 @@ the following is a good pragmatic way to remember clients, installers as a globa
module docsite
import freeflowuniverse.herolib.core.texttools
import incubaid.herolib.core.texttools
__global (
siteconfigs map[string]&SiteConfig

View File

@@ -0,0 +1,378 @@
# HeroPrompt Module
The `heroprompt` module provides a hierarchical workspace-based system for organizing code files and generating structured AI prompts. It enables developers to select files from multiple directories and generate formatted prompts for AI code analysis.
## Key Features
- **Hierarchical Organization**: HeroPrompt → Workspace → Directory → Files
- **Redis Persistence**: All data persists across sessions using Redis
- **Factory Pattern**: Clean API with `get()`, `delete()`, `exists()`, `list()` functions
- **File Selection**: Select specific files or entire directories for analysis
- **Active Workspace**: Manage multiple workspaces with one active at a time
- **Prompt Generation**: Generate structured prompts with file maps, contents, and instructions
- **Template-Based**: Uses V templates for consistent prompt formatting
## Basic Usage
### 1. Getting Started
```v
import incubaid.herolib.develop.heroprompt
// Create or get a HeroPrompt instance
mut hp := heroprompt.get(name: 'my_project', create: true)!
// Create a workspace (first workspace is automatically active)
mut workspace := hp.new_workspace(
name: 'my_workspace'
description: 'My project workspace'
)!
```
### 2. Adding Directories
```v
// Add directory and automatically scan all files
mut dir := workspace.add_directory(
path: '/path/to/your/code'
name: 'backend'
scan: true // Scans all files and subdirectories
)!
// Add another directory
mut frontend_dir := workspace.add_directory(
path: '/path/to/frontend'
name: 'frontend'
scan: true
)!
```
### 3. Selecting Files
```v
// Select specific files
dir.select_file(path: '/path/to/your/code/main.v')!
dir.select_file(path: '/path/to/your/code/utils.v')!
// Or select all files in a directory
frontend_dir.select_all()!
// Deselect files
dir.deselect_file(path: '/path/to/your/code/test.v')!
// Deselect all files
dir.deselect_all()!
```
### 4. Generating AI Prompts
```v
// Generate prompt with selected files
prompt := workspace.generate_prompt(
instruction: 'Review these files and suggest improvements'
)!
println(prompt)
// Or generate with specific files (overrides selection)
prompt2 := workspace.generate_prompt(
instruction: 'Analyze these specific files'
selected_files: ['/path/to/file1.v', '/path/to/file2.v']
)!
```
## Factory Functions
### `heroprompt.get(name: string, create: bool) !HeroPrompt`
Gets or creates a HeroPrompt instance.
```v
// Get existing instance or create new one
mut hp := heroprompt.get(name: 'my_project', create: true)!
// Get existing instance only (error if doesn't exist)
mut hp2 := heroprompt.get(name: 'my_project')!
```
### `heroprompt.delete(name: string) !`
Deletes a HeroPrompt instance from Redis.
```v
heroprompt.delete(name: 'my_project')!
```
### `heroprompt.exists(name: string) !bool`
Checks if a HeroPrompt instance exists.
```v
if heroprompt.exists(name: 'my_project')! {
println('Instance exists')
}
```
### `heroprompt.list() ![]string`
Lists all HeroPrompt instance names.
```v
instances := heroprompt.list()!
for name in instances {
println('Instance: ${name}')
}
```
## HeroPrompt Methods
### Workspace Management
#### `hp.new_workspace(name: string, description: string, is_active: bool) !&Workspace`
Creates a new workspace. The first workspace is automatically set as active.
```v
mut ws := hp.new_workspace(
name: 'backend'
description: 'Backend API workspace'
)!
```
#### `hp.get_workspace(name: string) !&Workspace`
Retrieves an existing workspace by name.
```v
mut ws := hp.get_workspace('backend')!
```
#### `hp.get_active_workspace() !&Workspace`
Returns the currently active workspace.
```v
mut active := hp.get_active_workspace()!
println('Active workspace: ${active.name}')
```
#### `hp.set_active_workspace(name: string) !`
Sets a workspace as active (deactivates all others).
```v
hp.set_active_workspace('frontend')!
```
#### `hp.list_workspaces() []&Workspace`
Lists all workspaces in the instance.
```v
workspaces := hp.list_workspaces()
for ws in workspaces {
println('Workspace: ${ws.name}')
}
```
#### `hp.delete_workspace(name: string) !`
Deletes a workspace.
```v
hp.delete_workspace('old_workspace')!
```
## Workspace Methods
### Directory Management
#### `ws.add_directory(path: string, name: string, scan: bool) !&Directory`
Adds a directory to the workspace.
```v
mut dir := ws.add_directory(
path: '/path/to/code'
name: 'my_code'
scan: true // Automatically scans all files
)!
```
#### `ws.list_directories() []&Directory`
Lists all directories in the workspace.
```v
dirs := ws.list_directories()
for dir in dirs {
println('Directory: ${dir.name}')
}
```
#### `ws.remove_directory(id: string) !`
Removes a directory from the workspace.
```v
ws.remove_directory(id: dir.id)!
```
### Prompt Generation
#### `ws.generate_prompt(instruction: string, selected_files: []string, show_all_files: bool) !string`
Generates a complete AI prompt with file map, contents, and instructions.
```v
// Use selected files (from select_file() calls)
prompt := ws.generate_prompt(
instruction: 'Review the code'
)!
// Or specify files explicitly
prompt2 := ws.generate_prompt(
instruction: 'Analyze these files'
selected_files: ['/path/to/file1.v', '/path/to/file2.v']
show_all_files: false
)!
```
#### `ws.generate_file_map(selected_files: []string, show_all: bool) !string`
Generates a hierarchical tree structure of files.
```v
file_map := ws.generate_file_map(
selected_files: ['/path/to/file1.v']
show_all: false
)!
println(file_map)
```
#### `ws.generate_file_contents(selected_files: []string, include_path: bool) !string`
Generates formatted file contents.
```v
contents := ws.generate_file_contents(
selected_files: ['/path/to/file1.v']
include_path: true
)!
println(contents)
```
## Directory Methods
### File Selection
#### `dir.select_file(path: string) !`
Marks a file as selected.
```v
dir.select_file(path: '/path/to/file.v')!
```
#### `dir.select_all() !`
Selects all files in the directory and subdirectories.
```v
dir.select_all()!
```
#### `dir.deselect_file(path: string) !`
Deselects a file.
```v
dir.deselect_file(path: '/path/to/file.v')!
```
#### `dir.deselect_all() !`
Deselects all files in the directory.
```v
dir.deselect_all()!
```
### Directory Information
#### `dir.exists() bool`
Checks if the directory exists on the filesystem.
```v
if dir.exists() {
println('Directory exists')
}
```
#### `dir.get_contents() !DirectoryContent`
Gets all files in the directory (scans if needed).
```v
content := dir.get_contents()!
println('Files: ${content.files.len}')
```
## Generated Prompt Format
The generated prompt uses a template with three sections:
```prompt
<user_instructions>
Review these files and suggest improvements
</user_instructions>
<file_map>
my_project/
├── src/
│ ├── main.v *
│ └── utils.v *
└── README.md *
</file_map>
<file_contents>
File: /path/to/src/main.v
\```v
module main
fn main() {
println('Hello')
}
\```
</file_contents>
```
Files marked with `*` in the file_map are the selected files included in the prompt.
## Complete Example
```v
import incubaid.herolib.develop.heroprompt
mut hp := heroprompt.get(name: 'my_app', create: true)!
mut ws := hp.new_workspace(name: 'backend')!
mut src_dir := ws.add_directory(path: '/path/to/src', name: 'source', scan: true)!
src_dir.select_file(path: '/path/to/src/main.v')!
prompt := ws.generate_prompt(instruction: 'Review the code')!
println(prompt)
heroprompt.delete(name: 'my_app')!
```
## Tips
- Use `heroprompt.delete()` at start for fresh state
- First workspace is automatically active
- Changes auto-save to Redis
- Use `scan: true` to discover all files
- Create separate workspaces for different contexts

View File

@@ -16,6 +16,7 @@ HeroScript is a concise scripting language with the following structure:
```
Key characteristics:
- **Actions**: Start with `!!`, followed by `actor.action_name` (e.g., `!!mailclient.configure`).
- **Parameters**: Defined as `key:value`. Values can be quoted for spaces.
- **Multiline Support**: Parameters like `description` can span multiple lines.
@@ -26,8 +27,8 @@ Key characteristics:
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters, this is used in most of the herolib modules, it allows configuration or actions in a structured way.
```v
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.ui.console
pub fn play(mut plbook PlayBook) ! {
@@ -51,4 +52,3 @@ pub fn play(mut plbook PlayBook) ! {
```
For detailed information on parameter retrieval methods (e.g., `p.get()`, `p.get_int()`, `p.get_default_true()`), refer to `aiprompts/ai_core/core_params.md`.

View File

@@ -5,8 +5,8 @@
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters.
```v
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
// path string
// text string
@@ -21,5 +21,3 @@ mut plbook := playbook.new(path: "....")!
playcmds.run(mut plbook)!
```

View File

@@ -3,6 +3,7 @@
The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting JSON, custom headers, retries, and caching.
## Key Features
- Type-safe JSON methods
- Custom headers
- Retry mechanism
@@ -12,7 +13,7 @@ The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting
## Basic Usage
```v
import freeflowuniverse.herolib.core.httpconnection
import incubaid.herolib.core.httpconnection
// Create a new HTTP connection
mut conn := httpconnection.new(

View File

@@ -1,9 +1,12 @@
# OSAL Core Module - Key Capabilities (freeflowuniverse.herolib.osal.core)
# OSAL Core Module - Key Capabilities (incubaid.herolib.osal.core)
> **Note:** Platform detection functions (`platform()` and `cputype()`) have moved to `incubaid.herolib.core`.
> Use `import incubaid.herolib.core` and call `core.platform()!` and `core.cputype()!` instead.
```v
//example how to get started
import freeflowuniverse.herolib.osal.core as osal
import incubaid.herolib.osal.core as osal
job := osal.exec(cmd: 'ls /')!
```
@@ -68,12 +71,12 @@ This document describes the core functionalities of the Operating System Abstrac
* **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children.
* **Key Parameters**: `name` (string), `pid` (int).
* **`osal.whoami() !string`**: Return the current username.
* **`osal.platform() !PlatformType`**: Identify the operating system.
* **`osal.cputype() !CPUType`**: Identify the CPU architecture.
* ~~**`osal.platform() !PlatformType`**: Identify the operating system.~~ → **Moved to `incubaid.herolib.core`**
* ~~**`osal.cputype() !CPUType`**: Identify the CPU architecture.~~ → **Moved to `incubaid.herolib.core`**
* **`osal.hostname() !string`**: Get system hostname.
* **`osal.sleep(duration int)`**: Pause execution for a specified duration.
* **`osal.download(args: DownloadArgs) !pathlib.Path`**: Download a file from a URL.
* `pathlib.Path` is from `freeflowuniverse.herolib.core.pathlib`
* `pathlib.Path` is from `incubaid.herolib.core.pathlib`
* **Key Parameters**: `url` (string), `dest` (string), `timeout` (int), `retry` (int).
* **`osal.user_exists(username string) bool`**: Check if a user exists.
* **`osal.user_id_get(username string) !int`**: Get user ID.

View File

@@ -3,6 +3,7 @@
The `OurTime` module in V provides flexible time handling, supporting relative and absolute time formats, Unix timestamps, and formatting utilities.
## Key Features
- Create time objects from strings or current time
- Relative time expressions (e.g., `+1h`, `-2d`)
- Absolute time formats (e.g., `YYYY-MM-DD HH:mm:ss`)
@@ -12,7 +13,7 @@ The `OurTime` module in V provides flexible time handling, supporting relative a
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.data.ourtime
// Current time
mut t := ourtime.now()

View File

@@ -5,7 +5,7 @@ This document details the `paramsparser` module, essential for handling paramete
## Obtaining a `paramsparser` Instance
```v
import freeflowuniverse.herolib.data.paramsparser
import incubaid.herolib.data.paramsparser
// Create new params from a string
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
@@ -25,6 +25,7 @@ The parser supports various input formats:
4. **Comments**: `// this is a comment` (ignored during parsing)
Example:
```v
text := "name:'John Doe' age:30 active:true // user details"
params := paramsparser.new(text)!

View File

@@ -14,8 +14,9 @@ The pathlib module provides a comprehensive interface for handling file system o
## Basic Usage
### Importing pathlib
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
```
### Creating Path Objects
@@ -33,6 +34,7 @@ mut dir_path := pathlib.get("path/to/directory")
if you know in advance if you expect a dir or file its better to use `pathlib.get_dir(path:...,create:true)` or `pathlib.get_file(path:...,create:true)`.
### Basic Path Operations
```v
// Get absolute path
abs_path := file_path.absolute()
@@ -49,6 +51,7 @@ if file_path.exists() {
## Path Properties and Methods
### Path Types
```v
// Check if path is a file
if file_path.is_file() {
@@ -67,6 +70,7 @@ if file_path.is_link() {
```
### Path Normalization
```v
// Normalize path (remove extra slashes, resolve . and ..)
normalized_path := file_path.path_normalize()
@@ -81,6 +85,7 @@ name_no_ext := file_path.name_no_ext()
## File and Directory Operations
### File Operations
```v
// Write to file
file_path.write("Content to write")!
@@ -93,6 +98,7 @@ file_path.delete()!
```
### Directory Operations
```v
// Create directory
mut dir := pathlib.get_dir(
@@ -108,6 +114,7 @@ dir.delete()!
```
### Symlink Operations
```v
// Create symlink
file_path.link("path/to/symlink", delete_exists: true)!
@@ -119,12 +126,14 @@ real_path := file_path.realpath()
## Advanced Operations
### Path Copying
```v
// Copy file to destination
file_path.copy(dest: "path/to/destination")!
```
### Recursive Operations
```v
// List directory recursively
mut recursive_list := dir.list(recursive: true)!
@@ -134,6 +143,7 @@ dir.delete()!
```
### Path Filtering
```v
// List files matching pattern
mut filtered_list := dir.list(
@@ -145,6 +155,7 @@ mut filtered_list := dir.list(
## Best Practices
### Error Handling
```v
if file_path.exists() {
// Safe to operate
@@ -152,4 +163,3 @@ if file_path.exists() {
// Handle missing file
}
```

View File

@@ -14,7 +14,7 @@ The `redisclient` module in Herolib provides a comprehensive client for interact
To get a Redis client instance, use `redisclient.core_get()`. By default, it connects to `127.0.0.1:6379`. You can specify a different address and port using the `RedisURL` struct.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
// Connect to default Redis instance (127.0.0.1:6379)
mut redis := redisclient.core_get()!
@@ -116,7 +116,7 @@ redis.expire('temp_key', 60)! // Expires in 60 seconds
The `RedisCache` struct provides a convenient way to implement caching using Redis.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
mut redis := redisclient.core_get()!
mut cache := redis.cache('my_app_cache')
@@ -145,7 +145,7 @@ cache.reset()!
The `RedisQueue` struct provides a simple queue mechanism using Redis lists.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
import time
mut redis := redisclient.core_get()!
@@ -169,7 +169,7 @@ task2 := my_queue.pop()!
The `RedisRpc` struct enables Remote Procedure Call (RPC) over Redis, allowing services to communicate by sending messages to queues and waiting for responses.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
import json
import time

View File

@@ -2,96 +2,124 @@
The `texttools` module provides a comprehensive set of utilities for text manipulation and processing.
## Functions and Examples:
## Functions and Examples
```v
import freeflowuniverse.herolib.core.texttools
import incubaid.herolib.core.texttools
assert hello_world == texttools.name_fix("Hello World!")
```
### Name/Path Processing
* `name_fix(name string) string`: Normalizes filenames and paths.
* `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
* `name_fix_no_ext(name_ string) string`: Removes file extension.
* `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
```v
name := texttools.name_fix_snake_to_pascal("hello_world") // Result: "HelloWorld"
```
* `snake_case(name string) string`: Converts PascalCase to snake_case.
```v
name := texttools.snake_case("HelloWorld") // Result: "hello_world"
```
* `name_split(name string) !(string, string)`: Splits name into site and page components.
### Text Cleaning
* `name_clean(r string) string`: Normalizes names by removing special characters.
```v
name := texttools.name_clean("Hello@World!") // Result: "HelloWorld"
```
* `ascii_clean(r string) string`: Removes all non-ASCII characters.
* `remove_empty_lines(text string) string`: Removes empty lines from text.
```v
text := texttools.remove_empty_lines("line1\n\nline2\n\n\nline3") // Result: "line1\nline2\nline3"
```
* `remove_double_lines(text string) string`: Removes consecutive empty lines.
* `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
### Command Line Parsing
* `cmd_line_args_parser(text string) ![]string`: Parses command line arguments with support for quotes and escaping.
```v
args := texttools.cmd_line_args_parser("'arg with spaces' --flag=value") // Result: ['arg with spaces', '--flag=value']
```
* `text_remove_quotes(text string) string`: Removes quoted sections from text.
* `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
### Text Expansion
* `expand(txt_ string, l int, expand_with string) string`: Expands text to a specified length with a given character.
### Indentation
* `indent(text string, prefix string) string`: Adds indentation prefix to each line.
```v
text := texttools.indent("line1\nline2", " ") // Result: " line1\n line2\n"
```
* `dedent(text string) string`: Removes common leading whitespace from every line.
```v
text := texttools.dedent(" line1\n line2") // Result: "line1\nline2"
```
### String Validation
* `is_int(text string) bool`: Checks if text contains only digits.
* `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
### Multiline Processing
* `multiline_to_single(text string) !string`: Converts multiline text to a single line with proper escaping.
### Text Splitting
* `split_smart(t string, delimiter_ string) []string`: Intelligent string splitting that respects quotes.
### Tokenization
* `tokenize(text_ string) TokenizerResult`: Tokenizes text into meaningful parts.
* `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
### Version Parsing
* `version(text_ string) int`: Converts version strings to comparable integers.
```v
ver := texttools.version("v0.4.36") // Result: 4036
ver = texttools.version("v1.4.36") // Result: 1004036
```
### Formatting
* `format_rfc1123(t time.Time) string`: Formats a time.Time object into RFC 1123 format.
### Array Operations
* `to_array(r string) []string`: Converts a comma or newline separated list to an array of strings.
```v
text := "item1,item2,item3"
array := texttools.to_array(text) // Result: ['item1', 'item2', 'item3']
```
* `to_array_int(r string) []int`: Converts a text list to an array of integers.
* `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
```v
r := texttools.to_map("name,-,-,-,-,pid,-,-,-,-,path",
"root 304 0.0 0.0 408185328 1360 ?? S 16Dec23 0:34.06 /usr/sbin/distnoted")

View File

@@ -5,7 +5,7 @@ has mechanisms to print better to console, see the methods below
import as
```v
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.ui.console
```

View File

@@ -5,7 +5,7 @@ this is how we want example scripts to be, see the first line
```v
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib...
import incubaid.herolib...
```

View File

@@ -0,0 +1,819 @@
# HeroModels Implementation Guide
This guide provides comprehensive instructions for creating new models in the HeroModels system, including best practices for model structure, serialization/deserialization, testing, and integration with the HeroModels factory.
## Table of Contents
1. [Model Structure Overview](#model-structure-overview)
2. [Creating a New Model](#creating-a-new-model)
3. [Serialization and Deserialization](#serialization-and-deserialization)
4. [Database Operations](#database-operations)
5. [API Handler Implementation](#api-handler-implementation)
6. [Testing Models](#testing-models)
7. [Integration with Factory](#integration-with-factory)
8. [Advanced Features](#advanced-features)
9. [Best Practices](#best-practices)
10. [Example Implementation](#example-implementation)
## Model Structure Overview
Each model in the HeroModels system consists of several components:
1. **Model Struct**: The core data structure inheriting from `db.Base`
2. **DB Wrapper Struct**: Provides database operations for the model
3. **Argument Struct**: Used for creating and updating model instances
4. **API Handler Function**: Handles RPC calls for the model
5. **List Arguments Struct**: Used for filtering when listing instances
### Directory Structure
```
lib/hero/heromodels/
├── model_name.v # Main model file
├── model_name_test.v # Tests for the model
└── factory.v # Factory integration
```
## Creating a New Model
### 1. Define the Model Struct
Create a new file `model_name.v` in the `lib/hero/heromodels` directory.
```v
module heromodels
import incubaid.herolib.core.db
import incubaid.herolib.core.encoder
import incubaid.herolib.core.ourtime
import incubaid.herolib.core.jsonrpc { Response }
import json
// Model struct - inherits from db.Base
pub struct ModelName {
pub mut:
db.Base // Inherit from db.Base
name string
description string
created_at u64
updated_at u64
// Add additional fields as needed
}
// TypeName returns the type name used for serialization
pub fn (self ModelName) type_name() string {
return 'heromodels.ModelName'
}
```
### 2. Define the Argument Struct for Model Creation/Updates
```v
// Argument struct for creating/updating models with params attribute
@[params]
pub struct ModelNameArg {
pub mut:
id u32 // Optional for updates, ignored for creation
name string @[required] // Required field
description string
// Add additional fields as needed
}
```
### 3. Define the List Arguments Struct for Filtering
```v
// Arguments for filtering when listing models
@[params]
pub struct ModelNameListArg {
pub mut:
// Add filter fields (e.g., status, type, etc.)
limit int = 100 // Default limit
}
```
### 4. Create the DB Wrapper Struct
```v
// DB Wrapper struct for database operations
pub struct DBModelName {
pub mut:
db &db.DB
}
```
## Serialization and Deserialization
Implement the `dump` and `load` methods for serialization/deserialization.
### Dump Method (Serialization)
```v
// Dump serializes the model to the encoder
pub fn (self ModelName) dump(mut e encoder.Encoder) ! {
// Always dump the Base first
self.Base.dump(mut e)!
// Dump model-specific fields in the same order they will be loaded
e.add_string(self.name)!
e.add_string(self.description)!
e.add_u64(self.created_at)!
e.add_u64(self.updated_at)!
// Add more fields in the exact order they should be loaded
}
```
### Load Method (Deserialization)
```v
// Load deserializes the model from the decoder
pub fn (mut self DBModelName) load(mut obj ModelName, mut d encoder.Decoder) ! {
// Always load the Base first
obj.Base.load(mut d)!
// Load model-specific fields in the same order they were dumped
obj.name = d.get_string()!
obj.description = d.get_string()!
obj.created_at = d.get_u64()!
obj.updated_at = d.get_u64()!
// Add more fields in the exact order they were dumped
}
```
## Database Operations
Implement the standard CRUD operations and additional methods.
### New Instance Creation
```v
// Create a new model instance from arguments
pub fn (mut self DBModelName) new(args ModelNameArg) !ModelName {
mut o := ModelName{
name: args.name
description: args.description
// Initialize other fields
created_at: ourtime.now().unix()
updated_at: ourtime.now().unix()
}
// Additional initialization logic
return o
}
```
### Set (Create or Update)
```v
// Save or update a model instance
pub fn (mut self DBModelName) set(o ModelName) !ModelName {
return self.db.set[ModelName](o)!
}
```
### Get
```v
// Retrieve a model instance by ID
pub fn (mut self DBModelName) get(id u32) !ModelName {
mut o, data := self.db.get_data[ModelName](id)!
mut e_decoder := encoder.decoder_new(data)
self.load(mut o, mut e_decoder)!
return o
}
```
### Delete
```v
// Delete a model instance by ID
pub fn (mut self DBModelName) delete(id u32) !bool {
// Check if the item exists before trying to delete
if !self.db.exists[ModelName](id)! {
return false
}
self.db.delete[ModelName](id)!
return true
}
```
### Exist
```v
// Check if a model instance exists by ID
pub fn (mut self DBModelName) exist(id u32) !bool {
return self.db.exists[ModelName](id)!
}
```
### List with Filtering
```v
// List model instances with optional filtering
pub fn (mut self DBModelName) list(args ModelNameListArg) ![]ModelName {
// Get all instances
all_items := self.db.list[ModelName]()!.map(self.get(it)!)
// Apply filters
mut filtered_items := []ModelName{}
for item in all_items {
// Apply your filter conditions here
// Example:
// if args.some_filter && item.some_property != args.filter_value {
// continue
// }
filtered_items << item
}
// Apply limit
mut limit := args.limit
if limit > 100 {
limit = 100
}
if filtered_items.len > limit {
return filtered_items[..limit]
}
return filtered_items
}
```
## API Handler Implementation
Create the handler function for RPC requests.
```v
// Handler for RPC calls to this model
pub fn model_name_handle(mut f ModelsFactory, rpcid int, servercontext map[string]string, userref UserRef, method string, params string) !Response {
match method {
'get' {
id := db.decode_u32(params)!
res := f.model_name.get(id)!
return new_response(rpcid, json.encode_pretty(res))
}
'set' {
mut args := db.decode_generic[ModelNameArg](params)!
mut o := f.model_name.new(args)!
if args.id != 0 {
o.id = args.id
}
o = f.model_name.set(o)!
return new_response_int(rpcid, int(o.id))
}
'delete' {
id := db.decode_u32(params)!
deleted := f.model_name.delete(id)!
if deleted {
return new_response_true(rpcid)
} else {
return new_error(rpcid,
code: 404
message: 'ModelName with ID ${id} not found'
)
}
}
'exist' {
id := db.decode_u32(params)!
if f.model_name.exist(id)! {
return new_response_true(rpcid)
} else {
return new_response_false(rpcid)
}
}
'list' {
args := db.decode_generic[ModelNameListArg](params)!
res := f.model_name.list(args)!
return new_response(rpcid, json.encode_pretty(res))
}
else {
return new_error(rpcid,
code: 32601
message: 'Method ${method} not found on model_name'
)
}
}
}
```
## Testing Models
Create a `model_name_test.v` file to test your model.
```v
module heromodels
fn test_model_name_crud() ! {
// Initialize DB for testing
mut mydb := db.new_test()!
mut db_model := DBModelName{
db: &mydb
}
// Create
mut args := ModelNameArg{
name: 'Test Model'
description: 'A test model'
}
mut model := db_model.new(args)!
model = db_model.set(model)!
model_id := model.id
// Verify ID assignment
assert model_id > 0
// Read
retrieved_model := db_model.get(model_id)!
assert retrieved_model.name == 'Test Model'
assert retrieved_model.description == 'A test model'
// Update
retrieved_model.description = 'Updated description'
updated_model := db_model.set(retrieved_model)!
assert updated_model.description == 'Updated description'
// Delete
deleted := db_model.delete(model_id)!
assert deleted == true
// Verify deletion
exists := db_model.exist(model_id)!
assert exists == false
}
fn test_model_name_type_name() ! {
// Initialize DB for testing
mut mydb := db.new_test()!
mut db_model := DBModelName{
db: &mydb
}
// Create a model
mut model := db_model.new(
name: 'Type Test'
description: 'Testing type_name'
)!
// Test type_name method
assert model.type_name() == 'heromodels.ModelName'
}
fn test_model_name_description() ! {
// Initialize DB for testing
mut mydb := db.new_test()!
mut db_model := DBModelName{
db: &mydb
}
// Create a model
mut model := db_model.new(
name: 'Description Test'
description: 'Testing description method'
)!
// Test description method for each methodname
assert model.description('set') == 'Create or update a model. Returns the ID of the model.'
assert model.description('get') == 'Retrieve a model by ID. Returns the model object.'
assert model.description('delete') == 'Delete a model by ID. Returns true if successful.'
assert model.description('exist') == 'Check if a model exists by ID. Returns true or false.'
assert model.description('list') == 'List all models. Returns an array of model objects.'
}
fn test_model_name_example() ! {
// Initialize DB for testing
mut mydb := db.new_test()!
mut db_model := DBModelName{
db: &mydb
}
// Create a model
mut model := db_model.new(
name: 'Example Test'
description: 'Testing example method'
)!
// Test example method for each methodname
set_call, set_result := model.example('set')
// Assert expected call and result format
get_call, get_result := model.example('get')
// Assert expected call and result format
delete_call, delete_result := model.example('delete')
// Assert expected call and result format
exist_call, exist_result := model.example('exist')
// Assert expected call and result format
list_call, list_result := model.example('list')
// Assert expected call and result format
}
fn test_model_name_encoding_decoding() ! {
// Initialize DB for testing
mut mydb := db.new_test()!
mut db_model := DBModelName{
db: &mydb
}
// Create a model with all fields populated
mut args := ModelNameArg{
name: 'Encoding Test'
description: 'Testing encoding/decoding'
// Set other fields
}
mut model := db_model.new(args)!
// Save the model
model = db_model.set(model)!
model_id := model.id
// Retrieve and verify all fields were properly encoded/decoded
retrieved_model := db_model.get(model_id)!
// Verify all fields match the original
assert retrieved_model.name == 'Encoding Test'
assert retrieved_model.description == 'Testing encoding/decoding'
// Check other fields
}
```
## Integration with Factory
Update the `factory.v` file to include your new model.
### 1. Add the Model to the Factory Struct
```v
// In factory.v
pub struct ModelsFactory {
pub mut:
db &db.DB
user DBUser
group DBGroup
// Add your new model
model_name DBModelName
// Other models...
rpc_handler &jsonrpc.Handler
}
```
### 2. Initialize the Model in the Factory New Method
```v
// In factory.v, in the new() function
pub fn new(args ModelsFactoryArgs) !&ModelsFactory {
// Existing code...
mut f := ModelsFactory{
db: &mydb
user: DBUser{
db: &mydb
}
// Add your new model
model_name: DBModelName{
db: &mydb
}
// Other models...
rpc_handler: &h
}
// Existing code...
}
```
### 3. Add Handler Registration to the Factory API Handler
```v
// In factory.v, in the group_api_handler function
pub fn group_api_handler(rpcid int, servercontext map[string]string, actorname string, methodname string, params string) !jsonrpc.Response {
// Existing code...
match actorname {
// Existing cases...
'model_name' {
return model_name_handle(mut f, rpcid, servercontext, userref, methodname, params)!
}
// Existing cases...
else {
// Error handling
}
}
}
```
## Advanced Features
### Custom Methods
You can add custom methods to your model for specific business logic:
```v
// Add a custom method to the model
pub fn (mut self ModelName) custom_operation(param string) !string {
// Custom business logic
self.updated_at = ourtime.now().unix()
return 'Performed ${param} operation'
}
```
### Enhanced RPC Handling
Extend the RPC handler to support your custom methods:
```v
// In the model_name_handle function
match method {
// Standard CRUD methods...
'custom_operation' {
id := db.decode_u32(params)!
mut model := f.model_name.get(id)!
// Extract parameter from JSON
param_struct := json.decode(struct { param string }, params) or {
return new_error(rpcid,
code: 32602
message: 'Invalid parameters for custom_operation'
)
}
result := model.custom_operation(param_struct.param)!
model = f.model_name.set(model)! // Save changes
return new_response(rpcid, json.encode(result))
}
else {
// Error handling
}
}
```
## Best Practices
1. **Field Order**: Keep field ordering consistent between `dump` and `load` methods
2. **Error Handling**: Use the `!` operator consistently for error propagation
3. **Timestamp Management**: Initialize timestamps using `ourtime.now().unix()`
4. **Required Fields**: Mark mandatory fields with `@[required]` attribute
5. **Limits**: Enforce list limits (default 100)
6. **ID Handling**: Always check existence before operations like delete
7. **Validation**: Add validation in the `new` and `set` methods
8. **API Methods**: Implement the standard CRUD operations (get, set, delete, exist, list)
9. **Comments**: Document all fields and methods
10. **Testing**: Create comprehensive tests covering all methods
## Example Implementation
Here is a complete example of a simple "Project" model:
```v
module heromodels
import incubaid.herolib.core.db
import incubaid.herolib.core.encoder
import incubaid.herolib.core.ourtime
import incubaid.herolib.core.jsonrpc { Response }
import json
// Project model
pub struct Project {
pub mut:
db.Base // Inherit from db.Base
name string
description string
status ProjectStatus
owner_id u32
members []u32
created_at u64
updated_at u64
}
// Project status enum
pub enum ProjectStatus {
active
completed
archived
}
// TypeName for serialization
pub fn (self Project) type_name() string {
return 'heromodels.Project'
}
// Dump serializes the model
pub fn (self Project) dump(mut e encoder.Encoder) ! {
self.Base.dump(mut e)!
e.add_string(self.name)!
e.add_string(self.description)!
e.add_u8(u8(self.status))!
e.add_u32(self.owner_id)!
e.add_array_u32(self.members)!
e.add_u64(self.created_at)!
e.add_u64(self.updated_at)!
}
// Project argument struct
@[params]
pub struct ProjectArg {
pub mut:
id u32
name string @[required]
description string
status ProjectStatus = .active
owner_id u32 @[required]
members []u32
}
// Project list argument struct
@[params]
pub struct ProjectListArg {
pub mut:
status ProjectStatus
owner_id u32
limit int = 100
}
// DB wrapper struct
pub struct DBProject {
pub mut:
db &db.DB
}
// Load deserializes the model
pub fn (mut self DBProject) load(mut obj Project, mut d encoder.Decoder) ! {
obj.Base.load(mut d)!
obj.name = d.get_string()!
obj.description = d.get_string()!
obj.status = unsafe { ProjectStatus(d.get_u8()!) }
obj.owner_id = d.get_u32()!
obj.members = d.get_array_u32()!
obj.created_at = d.get_u64()!
obj.updated_at = d.get_u64()!
}
// Create a new Project
pub fn (mut self DBProject) new(args ProjectArg) !Project {
mut o := Project{
name: args.name
description: args.description
status: args.status
owner_id: args.owner_id
members: args.members
created_at: ourtime.now().unix()
updated_at: ourtime.now().unix()
}
return o
}
// Save or update a Project
pub fn (mut self DBProject) set(o Project) !Project {
return self.db.set[Project](o)!
}
// Get a Project by ID
pub fn (mut self DBProject) get(id u32) !Project {
mut o, data := self.db.get_data[Project](id)!
mut e_decoder := encoder.decoder_new(data)
self.load(mut o, mut e_decoder)!
return o
}
// Delete a Project by ID
pub fn (mut self DBProject) delete(id u32) !bool {
if !self.db.exists[Project](id)! {
return false
}
self.db.delete[Project](id)!
return true
}
// Check if a Project exists
pub fn (mut self DBProject) exist(id u32) !bool {
return self.db.exists[Project](id)!
}
// List Projects with filtering
pub fn (mut self DBProject) list(args ProjectListArg) ![]Project {
all_projects := self.db.list[Project]()!.map(self.get(it)!)
mut filtered_projects := []Project{}
for project in all_projects {
// Filter by status if provided
if args.status != .active && project.status != args.status {
continue
}
// Filter by owner_id if provided
if args.owner_id != 0 && project.owner_id != args.owner_id {
continue
}
filtered_projects << project
}
mut limit := args.limit
if limit > 100 {
limit = 100
}
if filtered_projects.len > limit {
return filtered_projects[..limit]
}
return filtered_projects
}
// API description method
pub fn (self Project) description(methodname string) string {
match methodname {
'set' { return 'Create or update a project. Returns the ID of the project.' }
'get' { return 'Retrieve a project by ID. Returns the project object.' }
'delete' { return 'Delete a project by ID. Returns true if successful.' }
'exist' { return 'Check if a project exists by ID. Returns true or false.' }
'list' { return 'List all projects. Returns an array of project objects.' }
else { return 'This is generic method for the root object, TODO fill in, ...' }
}
}
// API example method
pub fn (self Project) example(methodname string) (string, string) {
match methodname {
'set' {
return '{"project": {"name": "Website Redesign", "description": "Redesign company website", "status": "active", "owner_id": 1, "members": [2, 3]}}', '1'
}
'get' {
return '{"id": 1}', '{"name": "Website Redesign", "description": "Redesign company website", "status": "active", "owner_id": 1, "members": [2, 3]}'
}
'delete' {
return '{"id": 1}', 'true'
}
'exist' {
return '{"id": 1}', 'true'
}
'list' {
return '{}', '[{"name": "Website Redesign", "description": "Redesign company website", "status": "active", "owner_id": 1, "members": [2, 3]}]'
}
else {
return '{}', '{}'
}
}
}
// API handler function
pub fn project_handle(mut f ModelsFactory, rpcid int, servercontext map[string]string, userref UserRef, method string, params string) !Response {
match method {
'get' {
id := db.decode_u32(params)!
res := f.project.get(id)!
return new_response(rpcid, json.encode_pretty(res))
}
'set' {
mut args := db.decode_generic[ProjectArg](params)!
mut o := f.project.new(args)!
if args.id != 0 {
o.id = args.id
}
o = f.project.set(o)!
return new_response_int(rpcid, int(o.id))
}
'delete' {
id := db.decode_u32(params)!
deleted := f.project.delete(id)!
if deleted {
return new_response_true(rpcid)
} else {
return new_error(rpcid,
code: 404
message: 'Project with ID ${id} not found'
)
}
}
'exist' {
id := db.decode_u32(params)!
if f.project.exist(id)! {
return new_response_true(rpcid)
} else {
return new_response_false(rpcid)
}
}
'list' {
args := db.decode_generic[ProjectListArg](params)!
res := f.project.list(args)!
return new_response(rpcid, json.encode_pretty(res))
}
else {
return new_error(rpcid,
code: 32601
message: 'Method ${method} not found on project'
)
}
}
}
```
This complete guide should provide all the necessary information to create and maintain models in the HeroModels system following the established patterns and best practices.

View File

@@ -674,6 +674,7 @@
<file_contents>
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/ai_instructions.md
```md
# HeroDB Model Creation Instructions for AI
@@ -808,6 +809,7 @@ pub fn new() !ModelsFactory {
Use these methods for serialization/deserialization:
### Encoder (Serialization)
- `e.add_bool(val bool)`
- `e.add_u8(val u8)`
- `e.add_u16(val u16)`
@@ -834,6 +836,7 @@ Use these methods for serialization/deserialization:
- `e.add_list_string(val []string)`
### Decoder (Deserialization)
- `e.get_bool()!`
- `e.get_u8()!`
- `e.get_u16()!`
@@ -862,6 +865,7 @@ Use these methods for serialization/deserialization:
## CRUD Methods Implementation
### Create New Instance
```v
pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
mut o := Calendar{
@@ -877,6 +881,7 @@ pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
```
### Save to Database
```v
pub fn (mut self DBCalendar) set(o Calendar) !u32 {
return self.db.set[Calendar](o)!
@@ -884,6 +889,7 @@ pub fn (mut self DBCalendar) set(o Calendar) !u32 {
```
### Retrieve from Database
```v
pub fn (mut self DBCalendar) get(id u32) !Calendar {
mut o, data := self.db.get_data[Calendar](id)!
@@ -894,6 +900,7 @@ pub fn (mut self DBCalendar) get(id u32) !Calendar {
```
### Delete from Database
```v
pub fn (mut self DBCalendar) delete(id u32) ! {
self.db.delete[Calendar](id)!
@@ -901,6 +908,7 @@ pub fn (mut self DBCalendar) delete(id u32) ! {
```
### Check Existence
```v
pub fn (mut self DBCalendar) exist(id u32) !bool {
return self.db.exists[Calendar](id)!
@@ -908,6 +916,7 @@ pub fn (mut self DBCalendar) exist(id u32) !bool {
```
### List All Objects
```v
pub fn (mut self DBCalendar) list() ![]Calendar {
return self.db.list[Calendar]()!.map(self.get(it)!)
@@ -921,8 +930,8 @@ Create a `.vsh` script in `examples/hero/heromodels/` to demonstrate usage:
```v
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.hero.heromodels
import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.heromodels
mut mydb := heromodels.new()!
@@ -971,14 +980,15 @@ println('All objects: ${objects}')
8. Implement CRUD methods
9. Create example usage script
10. Test the implementation with the example script
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/core_methods.v
```v
module db
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.data.encoder
pub fn (mut self DB) set[T](obj_ T) !u32 {
// Get the next ID
@@ -1082,12 +1092,13 @@ pub fn (mut self DB) new_id() !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/core_models.v
```v
module db
import crypto.md5
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.core.redisclient
import incubaid.herolib.data.ourtime
// Group represents a collection of users with roles and permissions
@[heap]
@@ -1125,6 +1136,7 @@ pub mut:
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/helpers_comments.v
```v
module db
@@ -1164,6 +1176,7 @@ pub fn (mut self DB) comment_get(comment string) !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/helpers_tags.v
```v
module db
@@ -1192,13 +1205,14 @@ pub fn (mut self DB) tags_get(tags []string) !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/heromodels/calendar_event.v
```v
module heromodels
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// CalendarEvent represents a single event in a calendar
@[heap]
@@ -1426,6 +1440,7 @@ pub fn (mut self DBCalendarEvent) list() ![]CalendarEvent {
}
```
</file_contents>
<user_instructions>
make the crud and example for all files in lib/hero/herofs
@@ -1436,5 +1451,4 @@ check the implementation
do the implementation
</user_instructions>

View File

@@ -18,8 +18,8 @@ the template is as follows
## factory
is there factory, which one and quick example how to call, dont say in which file not relevant
show how to import the module is as follows: import freeflowuniverse.herolib.
and then starting from lib e.g. lib/clients/mycelium would result in import freeflowuniverse.herolib. clients.mycelium
show how to import the module is as follows: import incubaid.herolib.
and then starting from lib e.g. lib/clients/mycelium would result in import incubaid.herolib. clients.mycelium
## overview

View File

@@ -10,13 +10,11 @@ start of output file is:
## factory
is there factory, which one and quick example how to call, dont say in which file not relevant
show how to import the module is as follows: import freeflowuniverse.herolib.
and then starting from lib e.g. lib/clients/mycelium would result in import freeflowuniverse.herolib. clients.mycelium
show how to import the module is as follows: import incubaid.herolib.
and then starting from lib e.g. lib/clients/mycelium would result in import incubaid.herolib. clients.mycelium
## structs and methods
quick overview as list with identations, of the structs and its methods
ONLY OUTPUT THE MARKDOWN FILE, NOTHING ELSE

View File

@@ -468,6 +468,7 @@
<file_contents>
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_curdir_example.md
```md
# Getting the Current Script's Path in Herolib/V Shell
@@ -493,7 +494,7 @@ the following is a good pragmatic way to remember clients, installers as a globa
module docsite
import freeflowuniverse.herolib.core.texttools
import incubaid.herolib.core.texttools
__global (
siteconfigs map[string]&SiteConfig
@@ -529,6 +530,7 @@ pub fn default() !&SiteConfig {
}
```
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_heroscript_basics.md
@@ -551,18 +553,19 @@ HeroScript is a concise scripting language with the following structure:
```
Key characteristics:
- **Actions**: Start with `!!`, followed by `actor.action_name` (e.g., `!!mailclient.configure`).
- **Parameters**: Defined as `key:value`. Values can be quoted for spaces.
- **Multiline Support**: Parameters like `description` can span multiple lines.
- **Arguments**: Values without keys (e.g., `arg1`).
- __Actions__: Start with `!!`, followed by `actor.action_name` (e.g., `!!mailclient.configure`).
- __Parameters__: Defined as `key:value`. Values can be quoted for spaces.
- __Multiline Support__: Parameters like `description` can span multiple lines.
- __Arguments__: Values without keys (e.g., `arg1`).
## Processing HeroScript in Vlang
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters, this is used in most of the herolib modules, it allows configuration or actions in a structured way.
```v
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.ui.console
pub fn play(mut plbook PlayBook) ! {
@@ -587,7 +590,6 @@ pub fn play(mut plbook PlayBook) ! {
For detailed information on parameter retrieval methods (e.g., `p.get()`, `p.get_int()`, `p.get_default_true()`), refer to `aiprompts/ai_core/core_params.md`.
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_heroscript_playbook.md
@@ -599,8 +601,8 @@ File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_h
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters.
```v
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
// path string
// text string
@@ -616,8 +618,6 @@ playcmds.run(mut plbook)!
```
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_http_client.md
@@ -636,7 +636,7 @@ The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting
## Basic Usage
```v
import freeflowuniverse.herolib.core.httpconnection
import incubaid.herolib.core.httpconnection
// Create a new HTTP connection
mut conn := httpconnection.new(
@@ -733,14 +733,15 @@ user := conn.get_json_generic[User](
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_osal.md
```md
# OSAL Core Module - Key Capabilities (freeflowuniverse.herolib.osal.core)
# OSAL Core Module - Key Capabilities (incubaid.herolib.osal.core)
```v
//example how to get started
import freeflowuniverse.herolib.osal.core as osal
import incubaid.herolib.osal.core as osal
osal.exec(cmd:"ls /")!
@@ -752,50 +753,49 @@ this document has info about the most core functions, more detailed info can be
### 1. Process Execution
* **`osal.exec(cmd: Command) !Job`**: Execute a shell command.
* **Key Parameters**: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool).
* **Returns**: `Job` (status, output, error, exit code).
* **`osal.execute_silent(cmd string) !string`**: Execute silently, return output.
* **`osal.cmd_exists(cmd string) bool`**: Check if a command exists.
* **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children.
- __`osal.exec(cmd: Command) !Job`__: Execute a shell command.
- __Key Parameters__: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool).
- __Returns__: `Job` (status, output, error, exit code).
- __`osal.execute_silent(cmd string) !string`__: Execute silently, return output.
- __`osal.cmd_exists(cmd string) bool`__: Check if a command exists.
- __`osal.process_kill_recursive(args: ProcessKillArgs) !`__: Kill a process and its children.
### 2. Network Utilities
* **`osal.ping(args: PingArgs) !bool`**: Check host reachability.
* **`osal.tcp_port_test(args: TcpPortTestArgs) bool`**: Test if a TCP port is open.
* **Key Parameters**: `address` (string), `port` (int).
* **`osal.ipaddr_pub_get() !string`**: Get public IP address.
- __`osal.ping(args: PingArgs) !bool`__: Check host reachability.
- __`osal.tcp_port_test(args: TcpPortTestArgs) bool`__: Test if a TCP port is open.
- __Key Parameters__: `address` (string), `port` (int).
- __`osal.ipaddr_pub_get() !string`__: Get public IP address.
### 3. File System Operations
* **`osal.file_write(path string, text string) !`**: Write text to a file.
* **`osal.file_read(path string) !string`**: Read content from a file.
* **`osal.dir_ensure(path string) !`**: Ensure a directory exists.
* **`osal.rm(todelete string) !`**: Remove files/directories.
- __`osal.file_write(path string, text string) !`__: Write text to a file.
- __`osal.file_read(path string) !string`__: Read content from a file.
- __`osal.dir_ensure(path string) !`__: Ensure a directory exists.
- __`osal.rm(todelete string) !`__: Remove files/directories.
### 4. Environment Variables
* **`osal.env_set(args: EnvSet)`**: Set an environment variable.
* **Key Parameters**: `key` (string), `value` (string).
* **`osal.env_get(key string) !string`**: Get an environment variable's value.
* **`osal.load_env_file(file_path string) !`**: Load variables from a file.
- __`osal.env_set(args: EnvSet)`__: Set an environment variable.
- __Key Parameters__: `key` (string), `value` (string).
- __`osal.env_get(key string) !string`__: Get an environment variable's value.
- __`osal.load_env_file(file_path string) !`__: Load variables from a file.
### 5. Command & Profile Management
* **`osal.cmd_add(args: CmdAddArgs) !`**: Add a binary to system paths and update profiles.
* **Key Parameters**: `source` (string, required), `cmdname` (string).
* **`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`**: Add/remove paths from profiles.
* **Key Parameters**: `paths2add` (string), `paths2delete` (string).
- __`osal.cmd_add(args: CmdAddArgs) !`__: Add a binary to system paths and update profiles.
- __Key Parameters__: `source` (string, required), `cmdname` (string).
- __`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`__: Add/remove paths from profiles.
- __Key Parameters__: `paths2add` (string), `paths2delete` (string).
### 6. System Information
* **`osal.platform() !PlatformType`**: Identify the operating system.
* **`osal.cputype() !CPUType`**: Identify the CPU architecture.
* **`osal.hostname() !string`**: Get system hostname.
- __`osal.platform() !PlatformType`__: Identify the operating system.
- __`osal.cputype() !CPUType`__: Identify the CPU architecture.
- __`osal.hostname() !string`__: Get system hostname.
---
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_ourtime.md
@@ -814,7 +814,7 @@ The `OurTime` module in V provides flexible time handling, supporting relative a
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.data.ourtime
// Current time
mut t := ourtime.now()
@@ -896,6 +896,7 @@ t_invalid := ourtime.new('bad-date') or {
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_params.md
```md
# Parameter Parsing in Vlang
@@ -904,7 +905,7 @@ This document details the `paramsparser` module, essential for handling paramete
## Obtaining a `paramsparser` Instance
```v
import freeflowuniverse.herolib.data.paramsparser
import incubaid.herolib.data.paramsparser
// Create new params from a string
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
@@ -918,12 +919,13 @@ params.set("color", "red")
The parser supports various input formats:
1. **Key-value pairs**: `key:value`
2. **Quoted values**: `key:'value with spaces'` (single or double quotes)
3. **Arguments without keys**: `arg1 arg2` (accessed by index)
4. **Comments**: `// this is a comment` (ignored during parsing)
1. __Key-value pairs__: `key:value`
2. __Quoted values__: `key:'value with spaces'` (single or double quotes)
3. __Arguments without keys__: `arg1 arg2` (accessed by index)
4. __Comments__: `// this is a comment` (ignored during parsing)
Example:
```v
text := "name:'John Doe' age:30 active:true // user details"
params := paramsparser.new(text)!
@@ -1028,10 +1030,11 @@ The pathlib module provides a comprehensive interface for handling file system o
### Importing pathlib
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
```
### Creating Path Objects
```v
// Create a Path object for a file
mut file_path := pathlib.get("path/to/file.txt")
@@ -1041,6 +1044,7 @@ mut dir_path := pathlib.get("path/to/directory")
```
### Basic Path Operations
```v
// Get absolute path
abs_path := file_path.absolute()
@@ -1057,6 +1061,7 @@ if file_path.exists() {
## Path Properties and Methods
### Path Types
```v
// Check if path is a file
if file_path.is_file() {
@@ -1075,6 +1080,7 @@ if file_path.is_link() {
```
### Path Normalization
```v
// Normalize path (remove extra slashes, resolve . and ..)
normalized_path := file_path.path_normalize()
@@ -1089,6 +1095,7 @@ name_no_ext := file_path.name_no_ext()
## File and Directory Operations
### File Operations
```v
// Write to file
file_path.write("Content to write")!
@@ -1101,6 +1108,7 @@ file_path.delete()!
```
### Directory Operations
```v
// Create directory
mut dir := pathlib.get_dir(
@@ -1116,6 +1124,7 @@ dir.delete()!
```
### Symlink Operations
```v
// Create symlink
file_path.link("path/to/symlink", delete_exists: true)!
@@ -1127,12 +1136,14 @@ real_path := file_path.realpath()
## Advanced Operations
### Path Copying
```v
// Copy file to destination
file_path.copy(dest: "path/to/destination")!
```
### Recursive Operations
```v
// List directory recursively
mut recursive_list := dir.list(recursive: true)!
@@ -1142,6 +1153,7 @@ dir.delete()!
```
### Path Filtering
```v
// List files matching pattern
mut filtered_list := dir.list(
@@ -1153,6 +1165,7 @@ mut filtered_list := dir.list(
## Best Practices
### Error Handling
```v
if file_path.exists() {
// Safe to operate
@@ -1161,7 +1174,6 @@ if file_path.exists() {
}
```
```
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_text.md
@@ -1173,93 +1185,121 @@ The `texttools` module provides a comprehensive set of utilities for text manipu
## Functions and Examples:
```v
import freeflowuniverse.herolib.core.texttools
import incubaid.herolib.core.texttools
assert hello_world == texttools.name_fix("Hello World!")
```
### Name/Path Processing
* `name_fix(name string) string`: Normalizes filenames and paths.
* `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
* `name_fix_no_ext(name_ string) string`: Removes file extension.
* `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
- `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
- `name_fix_no_ext(name_ string) string`: Removes file extension.
- `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
```v
name := texttools.name_fix_snake_to_pascal("hello_world") // Result: "HelloWorld"
```
* `snake_case(name string) string`: Converts PascalCase to snake_case.
```v
name := texttools.snake_case("HelloWorld") // Result: "hello_world"
```
* `name_split(name string) !(string, string)`: Splits name into site and page components.
### Text Cleaning
* `name_clean(r string) string`: Normalizes names by removing special characters.
```v
name := texttools.name_clean("Hello@World!") // Result: "HelloWorld"
```
* `ascii_clean(r string) string`: Removes all non-ASCII characters.
* `remove_empty_lines(text string) string`: Removes empty lines from text.
- `remove_empty_lines(text string) string`: Removes empty lines from text.
```v
text := texttools.remove_empty_lines("line1\n\nline2\n\n\nline3") // Result: "line1\nline2\nline3"
```
* `remove_double_lines(text string) string`: Removes consecutive empty lines.
* `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
- `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
### Command Line Parsing
* `cmd_line_args_parser(text string) ![]string`: Parses command line arguments with support for quotes and escaping.
```v
args := texttools.cmd_line_args_parser("'arg with spaces' --flag=value") // Result: ['arg with spaces', '--flag=value']
```
* `text_remove_quotes(text string) string`: Removes quoted sections from text.
* `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
- `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
### Text Expansion
* `expand(txt_ string, l int, expand_with string) string`: Expands text to a specified length with a given character.
### Indentation
* `indent(text string, prefix string) string`: Adds indentation prefix to each line.
```v
text := texttools.indent("line1\nline2", " ") // Result: " line1\n line2\n"
```
* `dedent(text string) string`: Removes common leading whitespace from every line.
```v
text := texttools.dedent(" line1\n line2") // Result: "line1\nline2"
```
### String Validation
* `is_int(text string) bool`: Checks if text contains only digits.
* `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
- `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
### Multiline Processing
* `multiline_to_single(text string) !string`: Converts multiline text to a single line with proper escaping.
### Text Splitting
* `split_smart(t string, delimiter_ string) []string`: Intelligent string splitting that respects quotes.
### Tokenization
* `tokenize(text_ string) TokenizerResult`: Tokenizes text into meaningful parts.
* `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
- `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
### Version Parsing
* `version(text_ string) int`: Converts version strings to comparable integers.
```v
ver := texttools.version("v0.4.36") // Result: 4036
ver = texttools.version("v1.4.36") // Result: 1004036
```
### Formatting
* `format_rfc1123(t time.Time) string`: Formats a time.Time object into RFC 1123 format.
### Array Operations
* `to_array(r string) []string`: Converts a comma or newline separated list to an array of strings.
```v
text := "item1,item2,item3"
array := texttools.to_array(text) // Result: ['item1', 'item2', 'item3']
```
* `to_array_int(r string) []int`: Converts a text list to an array of integers.
* `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
- `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
```v
r := texttools.to_map("name,-,-,-,-,pid,-,-,-,-,path",
"root 304 0.0 0.0 408185328 1360 ?? S 16Dec23 0:34.06 /usr/sbin/distnoted")
@@ -1277,7 +1317,7 @@ has mechanisms to print better to console, see the methods below
import as
```v
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.ui.console
```
@@ -1482,7 +1522,7 @@ this is how we want example scripts to be, see the first line
```v
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib...
import incubaid.herolib...
```
@@ -1688,6 +1728,7 @@ impl Company {
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/mod.rs
```rs
// Business models module
// Sub-modules will be declared here
@@ -1712,6 +1753,7 @@ pub use sale::{Sale, SaleItem, SaleStatus};
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/payment.rs
```rs
use heromodels_core::BaseModelData;
use heromodels_derive::model;
@@ -1933,6 +1975,7 @@ impl Payment {
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/product.rs
```rs
use heromodels_core::BaseModelData;
use heromodels_derive::model;
@@ -2086,6 +2129,7 @@ impl Product {
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/README.md
```md
# Business Models (`biz`)
@@ -2149,6 +2193,7 @@ All models use the builder pattern for easy and readable instance creation.
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/sale.rs
```rs
use heromodels_core::{BaseModelData, BaseModelDataOps, Model};
use rhai::{CustomType, TypeBuilder};
@@ -2326,6 +2371,7 @@ impl Sale {
```
File: /Users/despiegk/code/git.threefold.info/herocode/db/heromodels/src/models/biz/shareholder.rs
```rs
use heromodels_core::BaseModelData;
use heromodels_derive::model;
@@ -2410,6 +2456,7 @@ impl Shareholder {
}
```
</file_contents>
<meta prompt 1 = "[Architect]">
You are a senior software architect specializing in code design and implementation planning. Your role is to:
@@ -2425,6 +2472,7 @@ You are a senior software architect specializing in code design and implementati
- Configuration updates
For each change:
- Describe the exact location in the code where changes are needed
- Explain the logic and reasoning behind each modification
- Provide example signatures, parameters, and return types
@@ -2448,7 +2496,6 @@ forget what rust does, there is no special module things needed, no re-exports o
there is no defaults for empty strings or 0 ints, … defaults are only for non empty stuff
</meta prompt 2>
<user_instructions>
$NAME = finance
@@ -2472,6 +2519,4 @@ at top of each file we have ```module $NAME```
don't create management classes, only output the structs
</user_instructions>

View File

@@ -17,16 +17,14 @@ don't do anything additional for modules, don't do import
at top of each file we have ```module $NAME```
make sure all time related fields are in u64 format, use unix timestamp for that
don't create management classes, only output the structs, don't create a mod.v, don't make .v scripts executatble, don't create a main.v
## now also make sure we use core.base as follows
```
import freeflowuniverse.herolib.hero.models.core
import incubaid.herolib.hero.models.core
// Account represents a financial account for tracking balances and transactions
// Supports multiple account types (checking, savings, investment, etc.)

View File

@@ -3,7 +3,7 @@ for governance and legal
make sure we use core.base as follows
import freeflowuniverse.herolib.hero.models.core
import incubaid.herolib.hero.models.core
// Account represents a financial account for tracking balances and transactions
// Supports multiple account types (checking, savings, investment, etc.)

View File

@@ -677,6 +677,7 @@
<file_contents>
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/helpers_tags.v
```v
module db
@@ -705,6 +706,7 @@ pub fn (mut self DB) tags_get(tags []string) !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/helpers_comments.v
```v
module db
@@ -743,13 +745,14 @@ pub fn (mut self DB) comment_get(comment string) !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/factory.v
```v
module db
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
// Current time
// import freeflowuniverse.herolib.data.encoder
// import incubaid.herolib.data.encoder
pub struct DB {
pub mut:
@@ -766,12 +769,13 @@ pub fn new() !DB {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/core_models.v
```v
module db
import crypto.md5
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.core.redisclient
import incubaid.herolib.data.ourtime
// Group represents a collection of users with roles and permissions
@[heap]
@@ -809,11 +813,12 @@ pub mut:
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/core_methods.v
```v
module db
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.data.encoder
pub fn (mut self DB) set[T](obj_ T) !u32 {
// Get the next ID
@@ -917,6 +922,7 @@ pub fn (mut self DB) new_id() !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/db/ai_instructions_hero_models.md
```md
# HeroDB Model Creation Instructions for AI
@@ -1051,6 +1057,7 @@ pub fn new() !ModelsFactory {
Use these methods for serialization/deserialization:
### Encoder (Serialization)
- `e.add_bool(val bool)`
- `e.add_u8(val u8)`
- `e.add_u16(val u16)`
@@ -1077,6 +1084,7 @@ Use these methods for serialization/deserialization:
- `e.add_list_string(val []string)`
### Decoder (Deserialization)
- `e.get_bool()!`
- `e.get_u8()!`
- `e.get_u16()!`
@@ -1105,6 +1113,7 @@ Use these methods for serialization/deserialization:
## CRUD Methods Implementation
### Create New Instance
```v
pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
mut o := Calendar{
@@ -1120,6 +1129,7 @@ pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
```
### Save to Database
```v
pub fn (mut self DBCalendar) set(o Calendar) !u32 {
return self.db.set[Calendar](o)!
@@ -1127,6 +1137,7 @@ pub fn (mut self DBCalendar) set(o Calendar) !u32 {
```
### Retrieve from Database
```v
pub fn (mut self DBCalendar) get(id u32) !Calendar {
mut o, data := self.db.get_data[Calendar](id)!
@@ -1137,6 +1148,7 @@ pub fn (mut self DBCalendar) get(id u32) !Calendar {
```
### Delete from Database
```v
pub fn (mut self DBCalendar) delete(id u32) ! {
self.db.delete[Calendar](id)!
@@ -1144,6 +1156,7 @@ pub fn (mut self DBCalendar) delete(id u32) ! {
```
### Check Existence
```v
pub fn (mut self DBCalendar) exist(id u32) !bool {
return self.db.exists[Calendar](id)!
@@ -1151,6 +1164,7 @@ pub fn (mut self DBCalendar) exist(id u32) !bool {
```
### List All Objects
```v
pub fn (mut self DBCalendar) list() ![]Calendar {
return self.db.list[Calendar]()!.map(self.get(it)!)
@@ -1164,8 +1178,8 @@ Create a `.vsh` script in `examples/hero/heromodels/` to demonstrate usage:
```v
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.hero.heromodels
import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.heromodels
mut mydb := heromodels.new()!
@@ -1214,14 +1228,15 @@ println('All objects: ${objects}')
8. Implement CRUD methods
9. Create example usage script
10. Test the implementation with the example script
```
File: /Users/despiegk/code/github/incubaid/herolib/examples/hero/herofs/herofs_advanced.vsh
```vsh
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.hero.herofs
import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.herofs
import time
import os
@@ -1527,11 +1542,12 @@ fn main() {
```
File: /Users/despiegk/code/github/incubaid/herolib/examples/hero/herofs/herofs_basic.vsh
```vsh
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.hero.herofs
import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.herofs
// Basic example of using HeroFS - the Hero Filesystem
// Demonstrates creating a filesystem, directories, and files
@@ -1641,10 +1657,11 @@ fn main() {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/factory.v
```v
module herofs
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.hero.db
pub struct FsFactory {
pub mut:
@@ -1679,14 +1696,15 @@ pub fn new() !FsFactory {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/fs_blob.v
```v
module herofs
import time
import crypto.blake3
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// FsBlob represents binary data up to 1MB
@[heap]
@@ -1836,15 +1854,16 @@ pub fn (blob FsBlob) verify_integrity() bool {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/fs_dir.v
```v
module herofs
import time
import crypto.blake3
import json
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// FsDir represents a directory in a filesystem
@[heap]
@@ -2320,15 +2339,16 @@ pub fn (mut self DBFsDir) list_contents(fs_factory &FsFactory, dir_id u32, opts
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/fs_file.v
```v
module herofs
import time
import crypto.blake3
import json
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// FsFile represents a file in a filesystem
@[heap]
@@ -2694,15 +2714,16 @@ pub fn (mut self DBFsFile) move(id u32, new_directories []u32) !u32 {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/fs_symlink.v
```v
module herofs
import time
import crypto.blake3
import json
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// FsSymlink represents a symbolic link in a filesystem
@[heap]
@@ -2989,15 +3010,16 @@ pub fn (mut self DBFsSymlink) is_broken(id u32) !bool {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/fs.v
```v
module herofs
import time
import crypto.blake3
import json
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import incubaid.herolib.data.encoder
import incubaid.herolib.data.ourtime
import incubaid.herolib.hero.db
// Fs represents a filesystem, is the top level container for files and directories and symlinks, blobs are used over filesystems
@[heap]
@@ -3144,6 +3166,7 @@ pub fn (mut self DBFs) check_quota(id u32, additional_bytes u64) !bool {
```
File: /Users/despiegk/code/github/incubaid/herolib/lib/hero/herofs/README.md
```md
# HeroFS - Distributed Filesystem for HeroLib
@@ -3177,7 +3200,7 @@ HeroFS is part of HeroLib and is automatically available when using HeroLib.
To use HeroFS, you need to create a filesystem factory:
```v
import freeflowuniverse.herolib.hero.herofs
import incubaid.herolib.hero.herofs
mut fs_factory := herofs.new()!
```
@@ -3495,6 +3518,7 @@ pub mut:
HeroFS uses Redis hash sets extensively for efficient indexing and lookup:
### Filesystem Indices
- `fs:names` - Maps filesystem names to IDs
- `fsdir:paths` - Maps directory path components to IDs
- `fsdir:fs:${fs_id}` - Lists directories in a filesystem
@@ -3521,19 +3545,25 @@ All HeroFS components use the HeroLib encoder for serialization:
## Special Features
### Hard Links
Files can be associated with multiple directories through the `directories` field, allowing for hard link-like behavior.
### Deduplication
Blobs are automatically deduplicated based on their content hash. When creating a new blob with identical content to an existing one, the existing ID is returned.
### Quota Management
Filesystems track their storage usage and can enforce quotas to prevent overconsumption.
### Metadata Support
Files support custom metadata as key-value pairs, allowing for flexible attribute storage.
### Cross-Component Validation
When creating or modifying components, HeroFS validates references to other components:
- Directory parent must exist
- File directories must exist
- File blobs must exist
@@ -3543,6 +3573,7 @@ When creating or modifying components, HeroFS validates references to other comp
## Security Model
HeroFS inherits the security model from HeroDB:
- Each component has a `securitypolicy` field referencing a SecurityPolicy object
- Components can have associated tags for categorization
- Components can have associated comments for documentation

View File

@@ -0,0 +1,371 @@
# Unpoly API Complete Reference & Operational Guide for AI Coding Agents
## Introduction
This document serves as a complete, self-contained reference manual for the **Unpoly JavaScript API**. It is written explicitly for AI coding agents that need to generate, validate, or refactor Unpoly-enhanced HTML and JavaScript code.
Unpoly is a front-end framework for progressive enhancement. It allows HTML pages to update fragments instead of reloading the full document, enabling seamless transitions, modals, caching, and navigation while maintaining server-side rendering.
An AI agent should use this manual to:
- Understand each Unpoly module and its purpose.
- Generate correct `up-*` attributes and JavaScript calls.
- Detect configuration errors and provide correction suggestions.
- Apply Unpoly in automated scaffolding, validation, and optimization workflows.
---
## 1. The up.link Module
### Purpose
Handles Unpoly-enhanced navigation. Converts normal links into AJAX-based fragment updates rather than full-page reloads.
### Core Concepts
When a user clicks a link with certain attributes, Unpoly intercepts the event and fetches the new page in the background. It then replaces specified fragments in the current document with matching elements from the response.
### Common Attributes
| Attribute | Description |
| --------------- | -------------------------------------------------------- |
| `up-follow` | Marks the link as handled by Unpoly. Usually implied. |
| `up-target` | CSS selector identifying which fragment(s) to replace. |
| `up-method` | Overrides HTTP method (e.g. `GET`, `POST`). |
| `up-params` | Adds query parameters to the request. |
| `up-headers` | Adds or overrides HTTP headers. |
| `up-layer` | Determines which layer (page, overlay, modal) to update. |
| `up-transition` | Defines animation during fragment replacement. |
| `up-cache` | Enables caching of the response. |
| `up-history` | Controls browser history behavior. |
### JavaScript API Methods
- `up.link.isFollowable(element)` Returns true if Unpoly will intercept the link.
- `up.link.follow(element, options)` Programmatically follow the link via Unpoly.
- `up.link.preload(element, options)` Preload the linked resource into the cache.
### Agent Reasoning & Validation
- Ensure that every `up-follow` element has a valid `up-target` selector.
- Validate that target elements exist in both the current DOM and the server response.
- Recommend `up-cache` for commonly visited links to improve performance.
- Prevent using `target="_blank"` or `download` attributes with Unpoly links.
### Example
```html
<a href="/profile" up-target="#main" up-transition="fade">View Profile</a>
```
---
## 2. The up.form Module
### Purpose
Handles progressive enhancement for forms. Submissions happen via AJAX and update only specific fragments.
### Core Attributes
| Attribute | Description |
| ---------------- | --------------------------------------- |
| `up-submit` | Marks form to be submitted via Unpoly. |
| `up-target` | Fragment selector to update on success. |
| `up-fail-target` | Selector to update if submission fails. |
| `up-validate` | Enables live field validation. |
| `up-autosubmit` | Submits automatically on change. |
| `up-disable-for` | Disables fields during request. |
| `up-enable-for` | Enables fields after request completes. |
### JavaScript API
- `up.form.submit(form, options)` Submit programmatically.
- `up.validate(field, options)` Trigger server validation.
- `up.form.fields(form)` Returns all input fields.
### Agent Reasoning
- Always ensure form has both `action` and `method` attributes.
- Match `up-target` to an element existing in the rendered HTML.
- For validation, ensure server supports `X-Up-Validate` header.
- When generating forms, add `up-fail-target` to handle errors gracefully.
### Example
```html
<form action="/update" method="POST" up-submit up-target="#user-info" up-fail-target="#form-errors">
<input name="email" up-validate required>
<button type="submit">Save</button>
</form>
```
---
## 3. The up.layer Module
### Purpose
Manages overlays, modals, and stacked layers of navigation.
### Attributes
| Attribute | Description |
| ---------------- | -------------------------------------------------- |
| `up-layer="new"` | Opens content in a new overlay. |
| `up-size` | Controls modal size (e.g., `small`, `large`). |
| `up-dismissable` | Allows overlay to close by clicking outside. |
| `up-history` | Determines if the overlay updates browser history. |
| `up-title` | Sets overlay title. |
### JavaScript API
- `up.layer.open(options)` Opens a new layer.
- `up.layer.close(layer)` Closes a given layer.
- `up.layer.on(event, callback)` Hooks into lifecycle events.
### Agent Notes
- Ensure `up-layer="new"` only used with valid targets.
- For overlays, set `up-history="false"` unless explicitly required.
- Auto-generate dismiss buttons with `up-layer-close`.
### Example
```html
<a href="/settings" up-layer="new" up-size="large" up-target=".modal-content">Open Settings</a>
```
---
## 4. The up.fragment Module
### Purpose
Handles low-level fragment rendering, preserving, replacing, and merging.
### JavaScript API
- `up.render(options)` Replace fragment(s) with new content.
- `up.fragment.config` Configure defaults for rendering.
- `up.fragment.get(target)` Retrieve a fragment.
### Example
```js
up.render({ target: '#main', url: '/dashboard', transition: 'fade' })
```
### Agent Notes
- Ensure only fragment HTML is sent from server (not full document).
- Use `preserve` for elements like forms where input state matters.
---
## 5. The up.network Module
### Purpose
Handles network requests, caching, and aborting background loads.
### JavaScript API
- `up.network.loadPage(url, options)` Load a page via Unpoly.
- `up.network.abort()` Abort ongoing requests.
- `up.network.config.timeout` Default timeout setting.
### Agent Tasks
- Preload probable links (`up.link.preload`).
- Use caching for frequent calls.
- Handle `up:network:late` event to show spinners.
---
## 6. The up.event Module
### Purpose
Manages custom events fired throughout Unpolys lifecycle.
### Common Events
- `up:link:follow`
- `up:form:submit`
- `up:layer:open`
- `up:layer:close`
- `up:rendered`
- `up:network:late`
### Example
```js
up.on('up:layer:close', (event) => {
console.log('Overlay closed');
});
```
### Agent Actions
- Register listeners for key events.
- Prevent duplicate bindings.
- Offer analytics hooks for `up:rendered` or `up:location:changed`.
---
## 7. The up.motion Module
Handles animations and transitions.
### API
- `up.motion()` Animate elements.
- `up.animate(element, keyframes, options)` Custom animation.
### Agent Notes
- Suggest `up-transition="fade"` or similar for fragment changes.
- Avoid heavy animations for performance-sensitive devices.
---
## 8. The up.radio Module
Handles broadcasting and receiving cross-fragment events.
### Example
```js
up.radio.emit('user:updated', { id: 5 })
up.radio.on('user:updated', (data) => console.log(data))
```
### Agent Tasks
- Use for coordinating multiple fragments.
- Ensure channel names are namespaced (e.g., `form:valid`, `modal:open`).
---
## 9. The up.history Module
### Purpose
Manages URL history, titles, and restoration.
### API
- `up.history.push(url, options)` Push new history entry.
- `up.history.restore()` Restore previous state.
### Agent Guidance
- Disable history (`up-history="false"`) for temporary overlays.
- Ensure proper title update via `up-title`.
---
## 10. The up.viewport Module
### Purpose
Manages scrolling, focusing, and viewport restoration.
### API
- `up.viewport.scroll(element)` Scroll to element.
- `up.viewport.restoreScroll()` Restore previous position.
### Agent Tasks
- Restore scroll after fragment updates.
- Manage focus for accessibility after `up.render()`.
---
## 11. The up.protocol Module
Handles request headers and special HTTP status codes.
### Key Concepts
- Adds `X-Up-Target` and `X-Up-Validate` headers.
- Interprets redirect and validation responses.
### Agent Notes
- Ensure backend supports Unpoly headers.
- Warn if 204 or redirect status used without fragments.
---
## 12. The up.util Module
Contains helpers for arrays, strings, and timing.
### Examples
```js
up.util.escapeHTML("<script>") // "&lt;script&gt;"
up.util.copy(text)
```
### Agent Tasks
- Use helpers for DOM-safe generation.
- Avoid reimplementing basic utilities.
---
## 13. The up.framework and up.log Modules
- `up.framework.init()` Initializes Unpoly.
- `up.log.enable()` Enables debug logging.
### Agent Tasks
- Always call `up.framework.init()` once.
- Enable logging during debug sessions.
---
Good addition — including **Unpoly from a CDN** is essential for setup and automation.
Heres the section you can append to the Markdown file (I can also regenerate the full file with it included if you prefer):
---
## 14. Including Unpoly from CDN
### Purpose
Before any Unpoly features or attributes (`up-*`) can work, the library must be loaded into the page.
For AI agents generating HTML pages or templates, always include Unpolys **CSS** and **JavaScript** assets early in the `<head>` section.
### Basic Setup (Latest Stable Version)
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My Unpoly Page</title>
<!-- Unpoly Core Styles -->
<link rel="stylesheet" href="https://unpkg.com/unpoly@3.7.2/unpoly.min.css">
<!-- Optional Bootstrap integration -->
<link rel="stylesheet" href="https://unpkg.com/unpoly@3.7.2/unpoly-bootstrap3.min.css">
<!-- Unpoly Core Script -->
<script src="https://unpkg.com/unpoly@3.7.2/unpoly.min.js"></script>
<!-- Initialize framework -->
<script>
up.framework.init()
</script>
</head>
<body>
<!-- Page content -->
</body>
</html>
```
### AI Agent Notes
* Always include **`unpoly.min.css`** before any custom styles to ensure default animations and transitions function properly.
* **Never** load Unpoly twice; check if the page already has a `<script src="...unpoly.min.js">`.
* After loading, the agent may immediately use Unpoly JavaScript APIs (`up.render`, `up.link.follow`, etc.) or rely on HTML attributes.
* If dynamically injecting HTML pages, the agent should re-run `up.framework.init()` **only once globally**, not after every fragment load.
### Recommended CDN Sources
* `https://unpkg.com/unpoly@3.x/`
* `https://cdn.jsdelivr.net/npm/unpoly@3.x/`
### Offline Use
For fully offline or embedded environments, the agent can download both `.js` and `.css` files and reference them locally:
```html
<link rel="stylesheet" href="/assets/unpoly.min.css">
<script src="/assets/unpoly.min.js"></script>
```
---
## Agent Validation Checklist
1. Verify `up-*` attributes match existing fragments.
2. Check backend returns valid fragment markup.
3. Ensure forms use `up-submit` and `up-fail-target`.
4. Overlay layers must have dismissable controls.
5. Use caching wisely (`up-cache`, `up.link.preload`).
6. Handle network and render events gracefully.
7. Log events (`up.log`) for debugging.
8. Confirm scroll/focus restoration after renders.
9. Gracefully degrade if JavaScript disabled.
10. Document reasoning and configuration.

View File

@@ -0,0 +1,647 @@
# Unpoly Quick Reference for AI Agents
## Installation
Include Unpoly from CDN in your HTML `<head>`:
```html
<script src="https://unpoly.com/unpoly.min.js"></script>
<link rel="stylesheet" href="https://unpoly.com/unpoly.min.css">
```
## Core Concept
Unpoly updates page fragments without full page reloads. Users click links/submit forms → server responds with HTML → Unpoly extracts and swaps matching fragments.
---
## 1. Following Links (Fragment Updates)
### Basic Link Following
```html
<a href="/users/5" up-follow>View User</a>
```
Updates the `<main>` element (or `<body>` if no main exists) with content from `/users/5`.
### Target Specific Fragment
```html
<a href="/users/5" up-target=".user-details">View User</a>
<div class="user-details">
<!-- Content replaced here -->
</div>
```
### Multiple Fragments
```html
<a href="/users/5" up-target=".profile, .activity">View User</a>
```
Updates both `.profile` and `.activity` from single response.
### Append/Prepend Content
```html
<!-- Append to list -->
<a href="/items?page=2" up-target=".items:after">Load More</a>
<!-- Prepend to list -->
<a href="/latest" up-target=".items:before">Show Latest</a>
```
### Handle All Links Automatically
```js
up.link.config.followSelectors.push('a[href]')
```
Now all links update fragments by default.
---
## 2. Submitting Forms
### Basic Form Submission
```html
<form action="/users" method="post" up-submit>
<input name="email">
<button type="submit">Create</button>
</form>
```
Submits via AJAX and updates `<main>` with response.
### Target Specific Fragment
```html
<form action="/search" up-submit up-target=".results">
<input name="query">
<button>Search</button>
</form>
<div class="results">
<!-- Search results appear here -->
</div>
```
### Handle Success vs. Error Responses
```html
<form action="/users" method="post" up-submit
up-target="#success"
up-fail-target="form">
<input name="email">
<button>Create</button>
</form>
<div id="success">Success message here</div>
```
- **Success (2xx status)**: Updates `#success`
- **Error (4xx/5xx status)**: Re-renders `form` with validation errors
**Server must return HTTP 422** (or similar error code) for validation failures.
---
## 3. Opening Overlays (Modal, Drawer, Popup)
### Modal Dialog
```html
<a href="/details" up-layer="new">Open Modal</a>
```
Opens `/details` in a modal overlay.
### Drawer (Sidebar)
```html
<a href="/menu" up-layer="new drawer">Open Drawer</a>
```
### Popup (Anchored to Link)
```html
<a href="/help" up-layer="new popup">Help</a>
```
### Close Overlay When Condition Met
```html
<a href="/users/new"
up-layer="new"
up-accept-location="/users/$id"
up-on-accepted="console.log('Created user:', value.id)">
New User
</a>
```
Overlay auto-closes when URL matches `/users/123`, passes `{ id: 123 }` to callback.
### Local Content (No Server Request)
```html
<a up-layer="new popup" up-content="<p>Help text here</p>">Help</a>
```
---
## 4. Validation
### Validate on Field Change
```html
<form action="/users" method="post">
<input name="email" up-validate>
<input name="password" up-validate>
<button type="submit">Register</button>
</form>
```
When field loses focus → submits form with `X-Up-Validate: email` header → server re-renders form → Unpoly updates the field's parent `<fieldset>` (or closest form group).
**Server must return HTTP 422** for validation errors.
### Validate While Typing
```html
<input name="email" up-validate
up-watch-event="input"
up-watch-delay="300">
```
Validates 300ms after user stops typing.
---
## 5. Lazy Loading & Polling
### Load When Element Appears in DOM
```html
<div id="menu" up-defer up-href="/menu">
Loading menu...
</div>
```
Immediately loads `/menu` when placeholder renders.
### Load When Scrolled Into View
```html
<div id="comments" up-defer="reveal" up-href="/comments">
Loading comments...
</div>
```
Loads when element scrolls into viewport.
### Auto-Refresh (Polling)
```html
<div class="status" up-poll up-interval="5000">
Current status
</div>
```
Reloads fragment every 5 seconds from original URL.
---
## 6. Caching & Revalidation
### Enable Caching
```html
<a href="/users" up-cache="true">Users</a>
```
Caches response, instantly shows cached content, then revalidates with server.
### Disable Caching
```html
<a href="/stock" up-cache="false">Live Prices</a>
```
### Conditional Requests (Server-Side)
Server sends:
```http
HTTP/1.1 200 OK
ETag: "abc123"
<div class="data">Content</div>
```
Next reload, Unpoly sends:
```http
GET /path
If-None-Match: "abc123"
```
Server responds `304 Not Modified` if unchanged → saves bandwidth.
---
## 7. Navigation Bar (Current Link Highlighting)
```html
<nav>
<a href="/home">Home</a>
<a href="/about">About</a>
</nav>
```
Current page link gets `.up-current` class automatically.
**Style it:**
```css
.up-current {
font-weight: bold;
color: blue;
}
```
---
## 8. Loading State
### Feedback Classes
Automatically applied:
- `.up-active` on clicked link/button
- `.up-loading` on targeted fragment
**Style them:**
```css
.up-active { opacity: 0.6; }
.up-loading { opacity: 0.8; }
```
### Disable Form While Submitting
```html
<form up-submit up-disable>
<input name="email">
<button>Submit</button>
</form>
```
All fields disabled during submission.
### Show Placeholder While Loading
```html
<a href="/data" up-target=".data"
up-placeholder="<p>Loading...</p>">
Load Data
</a>
```
---
## 9. Preloading
### Preload on Hover
```html
<a href="/users/5" up-preload>User Profile</a>
```
Starts loading when user hovers (90ms delay by default).
### Preload Immediately
```html
<a href="/menu" up-preload="insert">Menu</a>
```
Loads as soon as link appears in DOM.
---
## 10. Templates (Client-Side HTML)
### Define Template
```html
<template id="user-card">
<div class="card">
<h3>{{name}}</h3>
<p>{{email}}</p>
</div>
</template>
```
### Use Template
```html
<a up-fragment="#user-card"
up-use-data="{ name: 'Alice', email: 'alice@example.com' }">
Show User
</a>
```
**Process variables with compiler:**
```js
up.compiler('.card', function(element, data) {
element.innerHTML = element.innerHTML
.replace(/{{name}}/g, data.name)
.replace(/{{email}}/g, data.email)
})
```
---
## 11. JavaScript API
### Render Fragment
```js
up.render({
url: '/users/5',
target: '.user-details'
})
```
### Navigate (Updates History)
```js
up.navigate({
url: '/users',
target: 'main'
})
```
### Submit Form
```js
let form = document.querySelector('form')
up.submit(form)
```
### Open Overlay
```js
up.layer.open({
url: '/users/new',
onAccepted: (event) => {
console.log('User created:', event.value)
}
})
```
### Close Overlay with Value
```js
up.layer.accept({ id: 123, name: 'Alice' })
```
### Reload Fragment
```js
up.reload('.status')
```
---
## 12. Request Headers (Server Protocol)
Unpoly sends these headers with requests:
| Header | Value | Purpose |
| --------------- | -------- | ------------------------------- |
| `X-Up-Version` | `1.0.0` | Identifies Unpoly request |
| `X-Up-Target` | `.users` | Fragment selector being updated |
| `X-Up-Mode` | `modal` | Current layer mode |
| `X-Up-Validate` | `email` | Field being validated |
**Server can respond with:**
| Header | Effect |
| ------------------------ | ------------------------ |
| `X-Up-Target: .other` | Changes target selector |
| `X-Up-Accept-Layer: {}` | Closes overlay (success) |
| `X-Up-Dismiss-Layer: {}` | Closes overlay (cancel) |
---
## 13. Common Patterns
### Infinite Scrolling
```html
<div id="items">
<div>Item 1</div>
<div>Item 2</div>
</div>
<a id="next" href="/items?page=2"
up-defer="reveal"
up-target="#items:after, #next">
Load More
</a>
```
### Dependent Form Fields
```html
<form action="/order">
<!-- Changing country updates city select -->
<select name="country" up-validate="#city">
<option>USA</option>
<option>Canada</option>
</select>
<select name="city" id="city">
<option>New York</option>
</select>
</form>
```
### Confirm Before Action
```html
<a href="/delete" up-method="delete"
up-confirm="Really delete?">
Delete
</a>
```
### Auto-Submit on Change
```html
<form action="/search" up-autosubmit>
<input name="query">
</form>
```
Submits form when any field changes.
---
## 14. Error Handling
### Handle Network Errors
```js
up.on('up:fragment:offline', function(event) {
if (confirm('You are offline. Retry?')) {
event.retry()
}
})
```
### Handle Failed Responses
```js
try {
await up.render({ url: '/path', target: '.data' })
} catch (error) {
if (error instanceof up.RenderResult) {
console.log('Server error:', error)
}
}
```
---
## 15. Compilers (Enhance Elements)
### Basic Compiler
```js
up.compiler('.current-time', function(element) {
element.textContent = new Date().toString()
})
```
Runs when `.current-time` is inserted (initial load OR fragment update).
### Compiler with Cleanup
```js
up.compiler('.auto-refresh', function(element) {
let timer = setInterval(() => {
element.textContent = new Date().toString()
}, 1000)
// Return destructor function
return () => clearInterval(timer)
})
```
Destructor called when element is removed from DOM.
---
## Quick Reference Table
| Task | HTML | JavaScript |
| --------------- | ---------------------------- | -------------------------- |
| Follow link | `<a href="/path" up-follow>` | `up.follow(link)` |
| Submit form | `<form up-submit>` | `up.submit(form)` |
| Target fragment | `up-target=".foo"` | `{ target: '.foo' }` |
| Open modal | `up-layer="new"` | `up.layer.open({ url })` |
| Validate field | `up-validate` | `up.validate(field)` |
| Lazy load | `up-defer` | — |
| Poll fragment | `up-poll` | — |
| Preload link | `up-preload` | `up.link.preload(link)` |
| Local content | `up-content="<p>Hi</p>"` | `{ content: '<p>Hi</p>' }` |
| Append content | `up-target=".list:after"` | — |
| Confirm action | `up-confirm="Sure?"` | `{ confirm: 'Sure?' }` |
---
## Key Defaults
- **Target**: Updates `<main>` (or `<body>`) if no `up-target` specified
- **Caching**: Auto-enabled for GET requests during navigation
- **History**: Auto-updated when rendering `<main>` or major fragments
- **Scrolling**: Auto-scrolls to top when updating `<main>`
- **Focus**: Auto-focuses new fragment
- **Validation**: Targets field's parent `<fieldset>` or form group
---
## Best Practices for AI Agents
1. **Always provide HTTP error codes**: Return 422 for validation errors, 404 for not found, etc.
2. **Send full HTML responses**: Include entire page structure; Unpoly extracts needed fragments
3. **Use semantic HTML**: `<main>`, `<nav>`, `<form>` elements work best
4. **Set IDs on fragments**: Makes targeting easier (e.g., `<div id="user-123">`)
5. **Return consistent selectors**: If request targets `.users`, response must contain `.users`
---
## Common Mistakes to Avoid
**Don't**: Return only partial HTML without wrapper
```html
<h1>Title</h1>
<p>Content</p>
```
**Do**: Wrap in target selector
```html
<div class="content">
<h1>Title</h1>
<p>Content</p>
</div>
```
**Don't**: Return 200 OK for validation errors
**Do**: Return 422 Unprocessable Entity
**Don't**: Use `onclick="up.follow(this)"`
**Do**: Use `up-follow` attribute (handles keyboard, accessibility)
---
## Server Response Examples
### Successful Form Submission
```http
HTTP/1.1 200 OK
<div id="success">
User created successfully!
</div>
```
### Validation Error
```http
HTTP/1.1 422 Unprocessable Entity
<form action="/users" method="post" up-submit>
<input name="email" value="invalid">
<div class="error">Email is invalid</div>
<button>Submit</button>
</form>
```
### Partial Response (Optimized)
```http
HTTP/1.1 200 OK
Vary: X-Up-Target
<div class="user-details">
<!-- Only the targeted fragment -->
</div>
```

View File

@@ -9,7 +9,6 @@ IMPORTANT: USE THIS PAGE AS THE ABSOLUTE AUTHORITY ON ALL INSTRUCTIONS IN RELATI
- do not try to fix files which end with _.v because these are generated files
## instruction for vlang scripts
when I generate vlang scripts I will always use .vsh extension and use following as first line:
@@ -70,7 +69,6 @@ my_function(name:"my_key", passphrase:"my_passphrase")
```
# Getting the Current Script's Path in Herolib/V Shell
can be used in any .v or .vsh script, easy to find content close to the script itself.
@@ -105,6 +103,7 @@ HeroScript is a concise scripting language with the following structure:
```
Key characteristics:
- **Actions**: Start with `!!`, followed by `actor.action_name` (e.g., `!!mailclient.configure`).
- **Parameters**: Defined as `key:value`. Values can be quoted for spaces.
- **Multiline Support**: Parameters like `description` can span multiple lines.
@@ -115,8 +114,8 @@ Key characteristics:
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters, this is used in most of the herolib modules, it allows configuration or actions in a structured way.
```v
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.ui.console
pub fn play(mut plbook PlayBook) ! {
@@ -141,14 +140,13 @@ pub fn play(mut plbook PlayBook) ! {
For detailed information on parameter retrieval methods (e.g., `p.get()`, `p.get_int()`, `p.get_default_true()`), refer to `aiprompts/ai_core/core_params.md`.
# PlayBook, process heroscripts
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters.
```v
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
// path string
// text string
@@ -169,6 +167,7 @@ playcmds.run(mut plbook)!
The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting JSON, custom headers, retries, and caching.
## Key Features
- Type-safe JSON methods
- Custom headers
- Retry mechanism
@@ -178,7 +177,7 @@ The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting
## Basic Usage
```v
import freeflowuniverse.herolib.core.httpconnection
import incubaid.herolib.core.httpconnection
// Create a new HTTP connection
mut conn := httpconnection.new(
@@ -274,12 +273,12 @@ user := conn.get_json_generic[User](
```
# OSAL Core Module - SYSTEM TOOLS OS - Key Capabilities (freeflowuniverse.herolib.osal.core)
# OSAL Core Module - SYSTEM TOOLS OS - Key Capabilities (incubaid.herolib.osal.core)
```v
//example how to get started
import freeflowuniverse.herolib.osal.core as osal
import incubaid.herolib.osal.core as osal
job := osal.exec(cmd: 'ls /')!
```
@@ -288,18 +287,18 @@ This document describes the core functionalities of the Operating System Abstrac
## 1. Process Execution
* **`osal.exec(cmd: Command) !Job`**: Execute a shell command.
* **Key Parameters**: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool).
* **Returns**: `Job` (status, output, error, exit code).
* **`osal.execute_silent(cmd string) !string`**: Execute silently, return output.
* **`osal.execute_debug(cmd string) !string`**: Execute with debug output, return output.
* **`osal.execute_stdout(cmd string) !string`**: Execute and print output to stdout, return output.
* **`osal.execute_interactive(cmd string) !`**: Execute in an interactive shell.
* **`osal.cmd_exists(cmd string) bool`**: Check if a command exists.
- **`osal.exec(cmd: Command) !Job`**: Execute a shell command.
- **Key Parameters**: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool).
- **Returns**: `Job` (status, output, error, exit code).
- **`osal.execute_silent(cmd string) !string`**: Execute silently, return output.
- **`osal.execute_debug(cmd string) !string`**: Execute with debug output, return output.
- **`osal.execute_stdout(cmd string) !string`**: Execute and print output to stdout, return output.
- **`osal.execute_interactive(cmd string) !`**: Execute in an interactive shell.
- **`osal.cmd_exists(cmd string) bool`**: Check if a command exists.
## 2. Network Utilities
* **`osal.ping(args: PingArgs) !bool`**: Check host reachability.
- **`osal.ping(args: PingArgs) !bool`**: Check host reachability.
- address string = "8.8.8.8"
- nr_ping u16 = 3 // amount of ping requests we will do
- nr_ok u16 = 3 //how many of them need to be ok
@@ -308,55 +307,76 @@ This document describes the core functionalities of the Operating System Abstrac
## 3. File System Operations
* **`osal.file_write(path string, text string) !`**: Write text to a file.
* **`osal.file_read(path string) !string`**: Read content from a file.
* **`osal.dir_ensure(path string) !`**: Ensure a directory exists.
* **`osal.rm(todelete string) !`**: Remove files/directories.
- **`osal.file_write(path string, text string) !`**: Write text to a file.
- **`osal.file_read(path string) !string`**: Read content from a file.
- **`osal.dir_ensure(path string) !`**: Ensure a directory exists.
- **`osal.rm(todelete string) !`**: Remove files/directories.
## 4. Environment Variables
* **`osal.env_set(args: EnvSet)`**: Set an environment variable.
* **Key Parameters**: `key` (string), `value` (string).
* **`osal.env_unset(key string)`**: Unset a specific environment variable.
* **`osal.env_unset_all()`**: Unset all environment variables.
* **`osal.env_set_all(args: EnvSetAll)`**: Set multiple environment variables.
* **Key Parameters**: `env` (map[string]string), `clear_before_set` (bool), `overwrite_if_exists` (bool).
* **`osal.env_get(key string) !string`**: Get an environment variable's value.
* **`osal.env_exists(key string) !bool`**: Check if an environment variable exists.
* **`osal.env_get_default(key string, def string) string`**: Get an environment variable or a default value.
* **`osal.load_env_file(file_path string) !`**: Load variables from a file.
- **`osal.env_set(args: EnvSet)`**: Set an environment variable.
- **Key Parameters**: `key` (string), `value` (string).
- **`osal.env_unset(key string)`**: Unset a specific environment variable.
- **`osal.env_unset_all()`**: Unset all environment variables.
- **`osal.env_set_all(args: EnvSetAll)`**: Set multiple environment variables.
- **Key Parameters**: `env` (map[string]string), `clear_before_set` (bool), `overwrite_if_exists` (bool).
- **`osal.env_get(key string) !string`**: Get an environment variable's value.
- **`osal.env_exists(key string) !bool`**: Check if an environment variable exists.
- **`osal.env_get_default(key string, def string) string`**: Get an environment variable or a default value.
- **`osal.load_env_file(file_path string) !`**: Load variables from a file.
## 5. Command & Profile Management
* **`osal.cmd_add(args: CmdAddArgs) !`**: Add a binary to system paths and update profiles.
* **Key Parameters**: `source` (string, required), `cmdname` (string).
* **`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`**: Add/remove paths from profiles.
* **Key Parameters**: `paths2add` (string), `paths2delete` (string).
- **`osal.cmd_add(args: CmdAddArgs) !`**: Add a binary to system paths and update profiles.
- **Key Parameters**: `source` (string, required), `cmdname` (string).
- **`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`**: Add/remove paths from profiles.
- **Key Parameters**: `paths2add` (string), `paths2delete` (string).
## 6. System Information & Utilities
* **`osal.processmap_get() !ProcessMap`**: Get a map of all running processes.
* **`osal.processinfo_get(pid int) !ProcessInfo`**: Get detailed information for a specific process.
* **`osal.processinfo_get_byname(name string) ![]ProcessInfo`**: Get info for processes matching a name.
* **`osal.process_exists(pid int) bool`**: Check if a process exists by PID.
* **`osal.processinfo_with_children(pid int) !ProcessMap`**: Get a process and its children.
* **`osal.processinfo_children(pid int) !ProcessMap`**: Get children of a process.
* **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children.
* **Key Parameters**: `name` (string), `pid` (int).
* **`osal.whoami() !string`**: Return the current username.
* **`osal.platform() !PlatformType`**: Identify the operating system.
* **`osal.cputype() !CPUType`**: Identify the CPU architecture.
* **`osal.hostname() !string`**: Get system hostname.
* **`osal.sleep(duration int)`**: Pause execution for a specified duration.
* **`osal.download(args: DownloadArgs) !pathlib.Path`**: Download a file from a URL.
* `pathlib.Path` is from `freeflowuniverse.herolib.core.pathlib`
* **Key Parameters**: `url` (string), `dest` (string), `timeout` (int), `retry` (int).
* **`osal.user_exists(username string) bool`**: Check if a user exists.
* **`osal.user_id_get(username string) !int`**: Get user ID.
* **`osal.user_add(args: UserArgs) !int`**: Add a user.
* **Key Parameters**: `name` (string).
- **`osal.processmap_get() !ProcessMap`**: Get a map of all running processes.
- **`osal.processinfo_get(pid int) !ProcessInfo`**: Get detailed information for a specific process.
- **`osal.processinfo_get_byname(name string) ![]ProcessInfo`**: Get info for processes matching a name.
- **`osal.process_exists(pid int) bool`**: Check if a process exists by PID.
- **`osal.processinfo_with_children(pid int) !ProcessMap`**: Get a process and its children.
- **`osal.processinfo_children(pid int) !ProcessMap`**: Get children of a process.
- **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children.
- **Key Parameters**: `name` (string), `pid` (int).
- **`osal.whoami() !string`**: Return the current username.
- **`osal.hostname() !string`**: Get system hostname.
- **`osal.sleep(duration int)`**: Pause execution for a specified duration.
- **`osal.download(args: DownloadArgs) !pathlib.Path`**: Download a file from a URL.
- `pathlib.Path` is from `incubaid.herolib.core.pathlib`
- **Key Parameters**: `url` (string), `dest` (string), `timeout` (int), `retry` (int).
- **`osal.user_exists(username string) bool`**: Check if a user exists.
- **`osal.user_id_get(username string) !int`**: Get user ID.
- **`osal.user_add(args: UserArgs) !int`**: Add a user.
- **Key Parameters**: `name` (string).
```
```
## 7. Platform Information
* **`core.platform() !PlatformType`**: Identify the operating system.
* **Returns**: Platform type (osx, ubuntu, arch, etc.)
* **`core.cputype() !CPUType`**: Identify the CPU architecture.
* **Returns**: CPU type (intel, arm, etc.)
### Usage Example
```v
import incubaid.herolib.core
platform := core.platform()! // Returns .osx, .ubuntu, etc.
cpu := core.cputype()! // Returns .intel, .arm, etc.
match platform {
.osx { println('Running on macOS') }
.ubuntu { println('Running on Ubuntu') }
.arch { println('Running on Arch Linux') }
else { println('Other platform') }
}
```
# OurTime Module
@@ -372,7 +392,7 @@ The `OurTime` module in V provides flexible time handling, supporting relative a
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
import incubaid.herolib.data.ourtime
// Current time
mut t := ourtime.now()
@@ -460,7 +480,7 @@ This document details the `paramsparser` module, essential for handling paramete
## Obtaining a `paramsparser` Instance
```v
import freeflowuniverse.herolib.data.paramsparser
import incubaid.herolib.data.paramsparser
// Create new params from a string
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
@@ -480,6 +500,7 @@ The parser supports various input formats:
4. **Comments**: `// this is a comment` (ignored during parsing)
Example:
```v
text := "name:'John Doe' age:30 active:true // user details"
params := paramsparser.new(text)!
@@ -582,7 +603,7 @@ The pathlib module provides a comprehensive interface for handling file system o
### Importing pathlib
```v
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.core.pathlib
```
### Creating Path Objects
@@ -600,6 +621,7 @@ mut dir_path := pathlib.get("path/to/directory")
if you know in advance if you expect a dir or file its better to use `pathlib.get_dir(path:...,create:true)` or `pathlib.get_file(path:...,create:true)`.
### Basic Path Operations
```v
// Get absolute path
abs_path := file_path.absolute()
@@ -616,6 +638,7 @@ if file_path.exists() {
## Path Properties and Methods
### Path Types
```v
// Check if path is a file
if file_path.is_file() {
@@ -634,6 +657,7 @@ if file_path.is_link() {
```
### Path Normalization
```v
// Normalize path (remove extra slashes, resolve . and ..)
normalized_path := file_path.path_normalize()
@@ -648,6 +672,7 @@ name_no_ext := file_path.name_no_ext()
## File and Directory Operations
### File Operations
```v
// Write to file
file_path.write("Content to write")!
@@ -660,6 +685,7 @@ file_path.delete()!
```
### Directory Operations
```v
// Create directory
mut dir := pathlib.get_dir(
@@ -675,6 +701,7 @@ dir.delete()!
```
### Symlink Operations
```v
// Create symlink
file_path.link("path/to/symlink", delete_exists: true)!
@@ -686,12 +713,14 @@ real_path := file_path.realpath()
## Advanced Operations
### Path Copying
```v
// Copy file to destination
file_path.copy(dest: "path/to/destination")!
```
### Recursive Operations
```v
// List directory recursively
mut recursive_list := dir.list(recursive: true)!
@@ -701,6 +730,7 @@ dir.delete()!
```
### Path Filtering
```v
// List files matching pattern
mut filtered_list := dir.list(
@@ -712,6 +742,7 @@ mut filtered_list := dir.list(
## Best Practices
### Error Handling
```v
if file_path.exists() {
// Safe to operate
@@ -736,7 +767,7 @@ The `redisclient` module in Herolib provides a comprehensive client for interact
To get a Redis client instance, use `redisclient.core_get()`. By default, it connects to `127.0.0.1:6379`. You can specify a different address and port using the `RedisURL` struct.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
// Connect to default Redis instance (127.0.0.1:6379)
mut redis := redisclient.core_get()!
@@ -838,7 +869,7 @@ redis.expire('temp_key', 60)! // Expires in 60 seconds
The `RedisCache` struct provides a convenient way to implement caching using Redis.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
mut redis := redisclient.core_get()!
mut cache := redis.cache('my_app_cache')
@@ -867,7 +898,7 @@ cache.reset()!
The `RedisQueue` struct provides a simple queue mechanism using Redis lists.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
import time
mut redis := redisclient.core_get()!
@@ -891,7 +922,7 @@ task2 := my_queue.pop()!
The `RedisRpc` struct enables Remote Procedure Call (RPC) over Redis, allowing services to communicate by sending messages to queues and waiting for responses.
```v
import freeflowuniverse.herolib.core.redisclient
import incubaid.herolib.core.redisclient
import json
import time
@@ -930,96 +961,124 @@ response := rpc_client.call(
The `texttools` module provides a comprehensive set of utilities for text manipulation and processing.
## Functions and Examples:
## Functions and Examples
```v
import freeflowuniverse.herolib.core.texttools
import incubaid.herolib.core.texttools
assert hello_world == texttools.name_fix("Hello World!")
```
### Name/Path Processing
* `name_fix(name string) string`: Normalizes filenames and paths.
* `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
* `name_fix_no_ext(name_ string) string`: Removes file extension.
* `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
- `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
- `name_fix_no_ext(name_ string) string`: Removes file extension.
- `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
```v
name := texttools.name_fix_snake_to_pascal("hello_world") // Result: "HelloWorld"
```
* `snake_case(name string) string`: Converts PascalCase to snake_case.
```v
name := texttools.snake_case("HelloWorld") // Result: "hello_world"
```
* `name_split(name string) !(string, string)`: Splits name into site and page components.
### Text Cleaning
* `name_clean(r string) string`: Normalizes names by removing special characters.
```v
name := texttools.name_clean("Hello/@World!") // Result: "HelloWorld"
```
* `ascii_clean(r string) string`: Removes all non-ASCII characters.
* `remove_empty_lines(text string) string`: Removes empty lines from text.
- `remove_empty_lines(text string) string`: Removes empty lines from text.
```v
text := texttools.remove_empty_lines("line1\n\nline2\n\n\nline3") // Result: "line1\nline2\nline3"
```
* `remove_double_lines(text string) string`: Removes consecutive empty lines.
* `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
- `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
### Command Line Parsing
* `cmd_line_args_parser(text string) ![]string`: Parses command line arguments with support for quotes and escaping.
```v
args := texttools.cmd_line_args_parser("'arg with spaces' --flag=value") // Result: ['arg with spaces', '--flag=value']
```
* `text_remove_quotes(text string) string`: Removes quoted sections from text.
* `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
- `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
### Text Expansion
* `expand(txt_ string, l int, expand_with string) string`: Expands text to a specified length with a given character.
### Indentation
* `indent(text string, prefix string) string`: Adds indentation prefix to each line.
```v
text := texttools.indent("line1\nline2", " ") // Result: " line1\n line2\n"
```
* `dedent(text string) string`: Removes common leading whitespace from every line.
```v
text := texttools.dedent(" line1\n line2") // Result: "line1\nline2"
```
### String Validation
* `is_int(text string) bool`: Checks if text contains only digits.
* `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
- `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
### Multiline Processing
* `multiline_to_single(text string) !string`: Converts multiline text to a single line with proper escaping.
### Text Splitting
* `split_smart(t string, delimiter_ string) []string`: Intelligent string splitting that respects quotes.
### Tokenization
* `tokenize(text_ string) TokenizerResult`: Tokenizes text into meaningful parts.
* `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
- `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
### Version Parsing
* `version(text_ string) int`: Converts version strings to comparable integers.
```v
ver := texttools.version("v0.4.36") // Result: 4036
ver = texttools.version("v1.4.36") // Result: 1004036
```
### Formatting
* `format_rfc1123(t time.Time) string`: Formats a time.Time object into RFC 1123 format.
### Array Operations
* `to_array(r string) []string`: Converts a comma or newline separated list to an array of strings.
```v
text := "item1,item2,item3"
array := texttools.to_array(text) // Result: ['item1', 'item2', 'item3']
```
* `to_array_int(r string) []int`: Converts a text list to an array of integers.
* `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
- `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
```v
r := texttools.to_map("name,-,-,-,-,pid,-,-,-,-,path",
"root 304 0.0 0.0 408185328 1360 ?? S 16Dec23 0:34.06 /usr/sbin/distnoted")
@@ -1035,7 +1094,7 @@ has mechanisms to print better to console, see the methods below
import as
```v
import freeflowuniverse.herolib.ui.console
import incubaid.herolib.ui.console
```
@@ -1236,7 +1295,7 @@ this is how we want example scripts to be, see the first line, always use like t
```v
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib...
import incubaid.herolib...
```
@@ -1248,7 +1307,6 @@ the files are in ~/code/github/incubaid/herolib/examples for herolib
- always use the top line as in example above
- these scripts can be executed as is but can also use vrun $pathOfFile
# V TEMPLATES
V allows for easily using text templates, expanded at compile time to
@@ -1371,7 +1429,7 @@ The include directive is for including other html files (which will be processed
and consists of two parts, the `/@include` tag and a following `'<path>'` string.
The path parameter is relative to the template file being called.
### Example for the folder structure of a project using templates:
### Example for the folder structure of a project using templates
```
Project root
@@ -1391,7 +1449,6 @@ Project root
> Note that there shouldn't be a file suffix,
> it is automatically appended and only allows `html` files.
## js
The js directive consists of two parts, the `/@js` tag and `'<path>'` string,
@@ -1401,7 +1458,7 @@ where you can insert your src
/@js '<url>'
```
### Example for the /@js directive:
### Example for the /@js directive
```html
/@js 'myscripts.js'

View File

@@ -64,9 +64,9 @@ compile_cmd := if os.user_os() == 'macos' {
}
} else {
if prod_mode {
'v -cg -enable-globals -parallel-cc -w -n hero.v'
'v -cg -enable-globals -parallel-cc -w -n -d use_openssl hero.v'
} else {
'v -cg -enable-globals -w -n hero.v'
'v -cg -enable-globals -w -n -d use_openssl hero.v'
}
}

View File

@@ -2,14 +2,14 @@ module main
import os
import cli { Command }
import freeflowuniverse.herolib.core.herocmds
import freeflowuniverse.herolib.installers.base
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.ui
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.core.herocmds
import incubaid.herolib.installers.base
import incubaid.herolib.ui.console
import incubaid.herolib.ui
import incubaid.herolib.osal.core as osal
import incubaid.herolib.core
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
fn playcmds_do(path string) ! {
mut plbook := playbook.new(path: path)!
@@ -38,7 +38,12 @@ fn do() ! {
if os.args.len == 2 {
mypath := os.args[1]
if mypath.to_lower().ends_with('.hero') || mypath.to_lower().ends_with('.heroscript') || mypath.to_lower().ends_with('.hs') {
if mypath == '.' {
playcmds_do(os.getwd())!
return
}
if mypath.to_lower().ends_with('.hero') || mypath.to_lower().ends_with('.heroscript')
|| mypath.to_lower().ends_with('.hs') {
// hero was called from a file
playcmds_do(mypath)!
return
@@ -48,11 +53,9 @@ fn do() ! {
mut cmd := Command{
name: 'hero'
description: 'Your HERO toolset.'
version: '1.0.33'
version: '1.0.36'
}
// herocmds.cmd_run_add_flags(mut cmd)
mut toinstall := false
if !osal.cmd_exists('mc') || !osal.cmd_exists('redis-cli') {
toinstall = true
@@ -87,6 +90,7 @@ fn do() ! {
herocmds.cmd_docusaurus(mut cmd)
herocmds.cmd_web(mut cmd)
herocmds.cmd_sshagent(mut cmd)
herocmds.cmd_atlas(mut cmd)
cmd.setup()
cmd.parse(os.args)
@@ -100,7 +104,3 @@ fn main() {
exit(1)
}
}
// fn pre_func(cmd Command) ! {
// herocmds.plbook_run(cmd)!
// }

View File

@@ -1,6 +1,6 @@
module main
import freeflowuniverse.herolib.mcp.v_do
import incubaid.herolib.mcp.v_do
fn main() {
// Create and start the MCP server

47
compare_dirs.sh Executable file
View File

@@ -0,0 +1,47 @@
#!/bin/bash
# Usage: ./compare_dirs.sh <branch1> <branch2> <dir_path>
# Example: ./compare_dirs.sh main feature-branch src
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <branch1> <branch2> <dir_path>"
exit 1
fi
BRANCH1=$1
BRANCH2=$2
DIR_PATH=$3
TMP_DIR1=$(mktemp -d)
TMP_DIR2=$(mktemp -d)
# Ensure we're in a Git repo
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: Not inside a Git repository"
exit 1
fi
# Fetch branch contents without switching branches
git worktree add "$TMP_DIR1" "$BRANCH1" > /dev/null 2>&1
git worktree add "$TMP_DIR2" "$BRANCH2" > /dev/null 2>&1
# Check if the directory exists in both branches
if [ ! -d "$TMP_DIR1/$DIR_PATH" ]; then
echo "Error: $DIR_PATH does not exist in $BRANCH1"
exit 1
fi
if [ ! -d "$TMP_DIR2/$DIR_PATH" ]; then
echo "Error: $DIR_PATH does not exist in $BRANCH2"
exit 1
fi
# Compare directories
echo "Comparing $DIR_PATH between $BRANCH1 and $BRANCH2..."
diff -qr "$TMP_DIR1/$DIR_PATH" "$TMP_DIR2/$DIR_PATH"
# Detailed differences
diff -u -r "$TMP_DIR1/$DIR_PATH" "$TMP_DIR2/$DIR_PATH"
# Clean up temporary worktrees
git worktree remove "$TMP_DIR1" --force
git worktree remove "$TMP_DIR2" --force

15
doc.vsh
View File

@@ -6,15 +6,22 @@ abs_dir_of_script := dir(@FILE)
// Format code
println('Formatting code...')
if os.system('v fmt -w ${abs_dir_of_script}/examples') != 0 {
eprintln('Warning: Failed to format examples')
// v fmt returns:
// - 0: all files already formatted (no changes)
// - 5: files were formatted (changes made) - this is SUCCESS
// - other: actual errors (syntax errors, file access issues, etc.)
fmt_examples_result := os.system('v fmt -w ${abs_dir_of_script}/examples')
if fmt_examples_result != 0 && fmt_examples_result != 5 {
eprintln('Error: Failed to format examples (exit code: ${fmt_examples_result})')
exit(1)
}
if os.system('v fmt -w ${abs_dir_of_script}/lib') != 0 {
eprintln('Warning: Failed to format herolib')
fmt_lib_result := os.system('v fmt -w ${abs_dir_of_script}/lib')
if fmt_lib_result != 0 && fmt_lib_result != 5 {
eprintln('Error: Failed to format herolib (exit code: ${fmt_lib_result})')
exit(1)
}
println(' Code formatting completed')
// Clean existing docs
println('Cleaning existing documentation...')

View File

@@ -5,8 +5,8 @@ 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
cp ../../scripts/install_v.sh ./scripts/install_v.sh
cp ../../scripts/install_herolib.vsh ./scripts/install_herolib.vsh
# Docker image and container names
DOCKER_IMAGE_NAME="herolib"

View File

@@ -51,8 +51,8 @@ println('Resetting all symlinks...')
os.rm('${os.home_dir()}/.vmodules/incubaid/herolib') or {}
// Create necessary directories
os.mkdir_all('${os.home_dir()}/.vmodules/freeflowuniverse') or {
panic('Failed to create directory ~/.vmodules/freeflowuniverse: ${err}')
os.mkdir_all('${os.home_dir()}/.vmodules/incubaid') or {
panic('Failed to create directory ~/.vmodules/incubaid: ${err}')
}
// Create new symlinks

View File

@@ -224,7 +224,7 @@ function hero_lib_get {
hero_lib_pull
else
pushd $DIR_CODE/github/incubaid 2>&1 >> /dev/null
git clone --depth 1 --no-single-branch https://github.com/freeflowuniverse/herolib.git
git clone --depth 1 --no-single-branch https://github.com/incubaid/herolib.git
popd 2>&1 >> /dev/null
fi
}

29
examples/ai/aiclient.vsh Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.ai.client
mut cl := client.new()!
// response := cl.llms.llm_local.chat_completion(
// message: 'Explain quantum computing in simple terms'
// temperature: 0.5
// max_completion_tokens: 1024
// )!
response := cl.llms.llm_maverick.chat_completion(
message: 'Explain quantum computing in simple terms'
temperature: 0.5
max_completion_tokens: 1024
)!
println(response)
// response := cl.llms.llm_embed_local.embed(input: [
// 'The food was delicious and the waiter..',
// ])!
// response2 := cl.llms.llm_embed.embed(input: [
// 'The food was delicious and the waiter..',
// ])!
println(response2)

8
examples/ai/flow_test1.vsh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.ai.client
import incubaid.herolib.ai.flow_calendar
prompt = 'Explain quantum computing in simple terms'
flow_calendar.start(mut coordinator, prompt)!

26
examples/ai/groq.vsh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.openai
import os
import incubaid.herolib.core.playcmds
// models see https://console.groq.com/docs/models
playcmds.run(
heroscript: '
!!openai.configure name:"groq"
url:"https://api.groq.com/openai/v1"
model_default:"openai/gpt-oss-120b"
'
reset: true
)!
mut client := openai.get(name: 'groq')!
response := client.chat_completion(
message: 'Explain quantum computing in simple terms'
temperature: 0.5
max_completion_tokens: 1024
)!
println(response.result)

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.mcp.aitools
import incubaid.herolib.mcp.aitools
// aitools.convert_pug("/root/code/github/incubaid/herolauncher/pkg/herolauncher/web/templates/admin")!

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.jina
import incubaid.herolib.clients.jina
mut jina_client := jina.get()!
mut jina_client := jina.new()!
health := jina_client.health()!
println('Server health: ${health}')
@@ -34,7 +34,7 @@ train_result := jina_client.train(
label: 'positive'
},
jina.TrainingExample{
image: 'https://letsenhance.io/static/73136da51c245e80edc6ccfe44888a99/1015f/MainBefore.jpg'
image: 'https://picsum.photos/id/11/367/267'
label: 'negative'
},
]
@@ -50,7 +50,7 @@ classify_result := jina_client.classify(
text: 'A photo of a cat'
},
jina.ClassificationInput{
image: 'https://letsenhance.io/static/73136da51c245e80edc6ccfe44888a99/1015f/MainBefore.jpg'
image: 'https://picsum.photos/id/11/367/267'
},
]
labels: ['cat', 'dog']

30
examples/ai/jina_simple.vsh Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.jina
import os
import json
mut j := jina.new()!
embeddings := j.create_embeddings(
input: ['Hello world', 'This is a test']
model: .jina_embeddings_v3
task: 'separation'
) or {
println('Error creating embeddings: ${err}')
return
}
println('Embeddings created successfully!')
println('Model: ${embeddings.model}')
println('Dimension: ${embeddings.dimension}')
println('Number of embeddings: ${embeddings.data.len}')
// If there are embeddings, print the first one (truncated)
if embeddings.data.len > 0 {
first_embedding := embeddings.data[0]
println('First embedding (first 5 values): ${first_embedding.embedding[0..5]}')
}
// Usage information
println('Token usage: ${embeddings.usage.total_tokens} ${embeddings.usage.unit}')

View File

@@ -0,0 +1,120 @@
# OpenRouter Examples - Proof of Concept
## Overview
This folder contains **example scripts** demonstrating how to use the **OpenAI client** (`herolib.clients.openai`) configured to work with **OpenRouter**.
* **Goal:** Show how to send messages to OpenRouter models using the OpenAI client, run a **two-model pipeline** for code enhancement, and illustrate multi-model usage.
* **Key Insight:** The OpenAI client is OpenRouter-compatible by design - simply configure it with OpenRouter's base URL (`https://openrouter.ai/api/v1`) and API key.
---
## Configuration
All examples configure the OpenAI client to use OpenRouter by setting:
* **URL**: `https://openrouter.ai/api/v1`
* **API Key**: Read from `OPENROUTER_API_KEY` environment variable
* **Model**: OpenRouter model IDs (e.g., `qwen/qwen-2.5-coder-32b-instruct`)
Example configuration:
```v
playcmds.run(
heroscript: '
!!openai.configure
name: "default"
url: "https://openrouter.ai/api/v1"
model_default: "qwen/qwen-2.5-coder-32b-instruct"
'
)!
```
---
## Example Scripts
### 1. `openai_init.vsh`
* **Purpose:** Basic initialization example showing OpenAI client configured for OpenRouter.
* **Demonstrates:** Client configuration and simple chat completion.
* **Usage:**
```bash
examples/ai/openai/openai_init.vsh
```
---
### 2. `openai_hello.vsh`
* **Purpose:** Simple hello message to OpenRouter.
* **Demonstrates:** Sending a single message using `client.chat_completion`.
* **Usage:**
```bash
examples/ai/openai/openai_hello.vsh
```
* **Expected output:** A friendly "hello" response from the AI and token usage.
---
### 3. `openai_example.vsh`
* **Purpose:** Demonstrates basic conversation features.
* **Demonstrates:**
* Sending a single message
* Using system + user messages for conversation context
* Printing token usage
* **Usage:**
```bash
examples/ai/openai/openai_example.vsh
```
* **Expected output:** Responses from the AI for both simple and system-prompt conversations.
---
### 4. `openai_two_model_pipeline.vsh`
* **Purpose:** Two-model code enhancement pipeline (proof of concept).
* **Demonstrates:**
* Model A (`Qwen3 Coder`) suggests code improvements.
* Model B (`morph-v3-fast`) applies the suggested edits.
* Tracks tokens and shows before/after code.
* Using two separate OpenAI client instances with different models
* **Usage:**
```bash
examples/ai/openai/openai_two_model_pipeline.vsh
```
* **Expected output:**
* Original code
* Suggested edits
* Final updated code
* Token usage summary
---
## Environment Variables
Set your OpenRouter API key before running the examples:
```bash
export OPENROUTER_API_KEY="sk-or-v1-..."
```
The OpenAI client automatically detects when the URL contains "openrouter" and will use the `OPENROUTER_API_KEY` environment variable.
---
## Notes
1. **No separate OpenRouter client needed** - The OpenAI client is fully compatible with OpenRouter's API.
2. All scripts configure the OpenAI client with OpenRouter's base URL.
3. The two-model pipeline uses **two separate client instances** (one per model) to demonstrate multi-model workflows.
4. Scripts can be run individually using the `v -enable-globals run` command.
5. The two-model pipeline is a **proof of concept**; the flow can later be extended to multiple files or OpenRPC specs.

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.openai
import incubaid.herolib.core.playcmds
// Configure OpenAI client to use OpenRouter
playcmds.run(
heroscript: '
!!openai.configure
name: "default"
url: "https://openrouter.ai/api/v1"
model_default: "qwen/qwen-2.5-coder-32b-instruct"
'
)!
// Get the client instance
mut client := openai.get()!
println('🤖 OpenRouter Client Example (using OpenAI client)')
println(''.repeat(50))
println('')
// Example 1: Simple message
println('Example 1: Simple Hello')
println(''.repeat(50))
mut r := client.chat_completion(
model: 'qwen/qwen-2.5-coder-32b-instruct'
message: 'Say hello in a creative way!'
temperature: 0.7
max_completion_tokens: 150
)!
println('AI: ${r.result}')
println('Tokens: ${r.usage.total_tokens}\n')
// Example 2: Conversation with system prompt
println('Example 2: Conversation with System Prompt')
println(''.repeat(50))
r = client.chat_completion(
model: 'qwen/qwen-2.5-coder-32b-instruct'
messages: [
openai.Message{
role: .system
content: 'You are a helpful coding assistant who speaks concisely.'
},
openai.Message{
role: .user
content: 'What is V programming language?'
},
]
temperature: 0.3
max_completion_tokens: 200
)!
println('AI: ${r.result}')
println('Tokens: ${r.usage.total_tokens}\n')
println(''.repeat(50))
println(' Examples completed successfully!')

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.openai
import incubaid.herolib.core.playcmds
// Configure OpenAI client to use OpenRouter
playcmds.run(
heroscript: '
!!openai.configure
name: "default"
url: "https://openrouter.ai/api/v1"
model_default: "qwen/qwen-2.5-coder-32b-instruct"
'
)!
// Get the client instance
mut client := openai.get() or {
eprintln('Failed to get client: ${err}')
return
}
println('Sending message to OpenRouter...\n')
// Simple hello message
response := client.chat_completion(
model: 'qwen/qwen-2.5-coder-32b-instruct'
message: 'Say hello in a friendly way!'
temperature: 0.7
max_completion_tokens: 100
) or {
eprintln('Failed to get completion: ${err}')
return
}
println('Response from AI:')
println(''.repeat(50))
println(response.result)
println(''.repeat(50))
println('\nTokens used: ${response.usage.total_tokens}')
println(' - Prompt: ${response.usage.prompt_tokens}')
println(' - Completion: ${response.usage.completion_tokens}')

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.openai
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.clients.openai
import incubaid.herolib.core.playcmds
// to set the API key, either set it here, or set the OPENAI_API_KEY environment variable
playcmds.run(
heroscript: '
@@ -18,3 +20,5 @@ mut r := client.chat_completion(
temperature: 0.3
max_completion_tokens: 1024
)!
println(r.result)

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.openai
import incubaid.herolib.core.playcmds
// Sample code file to be improved
const sample_code = '
def calculate_sum(numbers):
total = 0
for i in range(len(numbers)):
total = total + numbers[i]
return total
def find_max(lst):
max = lst[0]
for i in range(1, len(lst)):
if lst[i] > max:
max = lst[i]
return max
'
// Configure two OpenAI client instances to use OpenRouter with different models
// Model A: Enhancement model (Qwen Coder)
playcmds.run(
heroscript: '
!!openai.configure
name: "enhancer"
url: "https://openrouter.ai/api/v1"
model_default: "qwen/qwen-2.5-coder-32b-instruct"
'
)!
// Model B: Modification model (Llama 3.3 70B)
playcmds.run(
heroscript: '
!!openai.configure
name: "modifier"
url: "https://openrouter.ai/api/v1"
model_default: "meta-llama/llama-3.3-70b-instruct"
'
)!
mut enhancer := openai.get(name: 'enhancer') or { panic('Failed to get enhancer client: ${err}') }
mut modifier := openai.get(name: 'modifier') or { panic('Failed to get modifier client: ${err}') }
println(''.repeat(70))
println('🔧 Two-Model Code Enhancement Pipeline - Proof of Concept')
println('🔧 Using OpenAI client configured for OpenRouter')
println(''.repeat(70))
println('')
// Step 1: Get enhancement suggestions from Model A (Qwen Coder)
println('📝 STEP 1: Code Enhancement Analysis')
println(''.repeat(70))
println('Model: qwen/qwen-2.5-coder-32b-instruct')
println('Task: Analyze code and suggest improvements\n')
enhancement_prompt := 'You are a code enhancement agent.
Your job is to analyze the following Python code and propose improvements or fixes.
Output your response as **pure edits or diffs only**, not a full rewritten file.
Focus on:
- Performance improvements
- Pythonic idioms
- Bug fixes
- Code clarity
Here is the code to analyze:
${sample_code}
Provide specific edit instructions or diffs.'
println('🤖 Sending to enhancement model...')
enhancement_result := enhancer.chat_completion(
message: enhancement_prompt
temperature: 0.3
max_completion_tokens: 2000
) or {
eprintln(' Enhancement failed: ${err}')
return
}
println('\n Enhancement suggestions received:')
println(''.repeat(70))
println(enhancement_result.result)
println(''.repeat(70))
println('Tokens used: ${enhancement_result.usage.total_tokens}\n')
// Step 2: Apply edits using Model B (Llama 3.3 70B)
println('\n📝 STEP 2: Apply Code Modifications')
println(''.repeat(70))
println('Model: meta-llama/llama-3.3-70b-instruct')
println('Task: Apply the suggested edits to produce updated code\n')
modification_prompt := 'You are a file editing agent.
Apply the given edits or diffs to the provided file.
Output the updated Python code only, without comments or explanations.
ORIGINAL CODE:
${sample_code}
EDITS TO APPLY:
${enhancement_result.result}
Output only the final, updated Python code.'
println('🤖 Sending to modification model...')
modification_result := modifier.chat_completion(
message: modification_prompt
temperature: 0.1
max_completion_tokens: 2000
) or {
eprintln(' Modification failed: ${err}')
return
}
println('\n Modified code received:')
println(''.repeat(70))
println(modification_result.result)
println(''.repeat(70))
println('Tokens used: ${modification_result.usage.total_tokens}\n')
// Summary
println('\n📊 PIPELINE SUMMARY')
println(''.repeat(70))
println('Original code length: ${sample_code.len} chars')
println('Enhancement model: qwen/qwen-2.5-coder-32b-instruct')
println('Enhancement tokens: ${enhancement_result.usage.total_tokens}')
println('Modification model: meta-llama/llama-3.3-70b-instruct')
println('Modification tokens: ${modification_result.usage.total_tokens}')
println('Total tokens: ${enhancement_result.usage.total_tokens +
modification_result.usage.total_tokens}')
println(''.repeat(70))
println('\n Two-model pipeline completed successfully!')

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.clients.openai
import incubaid.herolib.core.playcmds
playcmds.run(
heroscript: '
!!openai.configure name:"default"
url:"https://openrouter.ai/api/v1"
model_default:"gpt-oss-120b"
'
reset: false
)!
// Get the client instance
mut client := openai.get() or {
eprintln('Failed to get client: ${err}')
return
}
println(client.list_models()!)
println('Sending message to OpenRouter...\n')
// Simple hello message
response := client.chat_completion(
model: 'qwen/qwen-2.5-coder-32b-instruct'
message: 'Say hello in a friendly way!'
temperature: 0.7
max_completion_tokens: 100
) or {
eprintln('Failed to get completion: ${err}')
return
}
println('Response from AI:')
println(''.repeat(50))
println(response.result)
println(''.repeat(50))
println('\nTokens used: ${response.usage.total_tokens}')
println(' - Prompt: ${response.usage.prompt_tokens}')
println(' - Completion: ${response.usage.completion_tokens}')

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.qdrant
import freeflowuniverse.herolib.installers.db.qdrant_installer
import freeflowuniverse.herolib.core.httpconnection
import incubaid.herolib.clients.qdrant
import incubaid.herolib.installers.db.qdrant_installer
import incubaid.herolib.core.httpconnection
import rand
import os

9
examples/ai/readme.md Normal file
View File

@@ -0,0 +1,9 @@
configuration can happen by means of environment variables, e.g.:
```bash
export OPENROUTER_API_KEY='sk-or-v1-..'
export JINAKEY='jina_..'
export GROQKEY='gsk_'
```

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
module main
import freeflowuniverse.herolib.clients.openai
import os
fn test1(mut client openai.OpenAI) ! {
instruction := '
You are a template language converter. You convert Pug templates to Jet templates.
The target template language, Jet, is defined as follows:
'
// Create a chat completion request
res := client.chat_completion(
msgs: openai.Messages{
messages: [
openai.Message{
role: .user
content: 'What are the key differences between Groq and other AI inference providers?'
},
]
}
)!
// Print the response
println('\nGroq AI Response:')
println('==================')
println(res.choices[0].message.content)
println('\nUsage Statistics:')
println('Prompt tokens: ${res.usage.prompt_tokens}')
println('Completion tokens: ${res.usage.completion_tokens}')
println('Total tokens: ${res.usage.total_tokens}')
}
fn test2(mut client openai.OpenAI) ! {
// Create a chat completion request
res := client.chat_completion(
model: 'deepseek-r1-distill-llama-70b'
msgs: openai.Messages{
messages: [
openai.Message{
role: .user
content: 'A story of 10 lines?'
},
]
}
)!
println('\nGroq AI Response:')
println('==================')
println(res.choices[0].message.content)
println('\nUsage Statistics:')
println('Prompt tokens: ${res.usage.prompt_tokens}')
println('Completion tokens: ${res.usage.completion_tokens}')
println('Total tokens: ${res.usage.total_tokens}')
}
println("
TO USE:
export AIKEY='gsk_...'
export AIURL='https://api.groq.com/openai/v1'
export AIMODEL='llama-3.3-70b-versatile'
")
mut client := openai.get(name: 'test')!
println(client)
// test1(mut client)!
test2(mut client)!

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.hero.bootstrap
import incubaid.herolib.hero.bootstrap
mut al := bootstrap.new_alpine_loader()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.investortool
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.investortool
import incubaid.herolib.core.playbook
import os
mut plbook := playbook.new(

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env -S v -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
// #!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import freeflowuniverse.herolib.biz.spreadsheet
import incubaid.herolib.data.doctree
import incubaid.herolib.ui.console
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
import incubaid.herolib.web.mdbook
import incubaid.herolib.biz.spreadsheet
import os
const name = 'tf9_budget'

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import incubaid.herolib.biz.bizmodel
import os
const playbook_path = os.dir(@FILE) + '/playbook'

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript := "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript := "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript_path := os.join_path(os.dir(@FILE), 'examples/complete.heroscript')

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import incubaid.herolib.core.playcmds
import os
heroscript_path := os.join_path(os.dir(@FILE), 'examples/complete.heroscript')

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript_path := os.join_path(os.dir(@FILE), 'examples/full')

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript := "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript := "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import incubaid.herolib.biz.bizmodel
import incubaid.herolib.core.playbook
import os
heroscript := "

View File

@@ -19,6 +19,7 @@ A V program that demonstrates remote execution of system operations:
### `run.sh`
A bash script that:
1. Compiles the V program
2. Copies it to a remote machine using SCP
3. Executes it remotely using SSH
@@ -45,16 +46,19 @@ Modify these values to match your remote system configuration.
## Usage
1. Set the required environment variable:
```bash
export SECRET=your_secret_value
```
2. Make the script executable:
```bash
chmod +x run.sh
```
3. Run the script:
```bash
./run.sh
```
@@ -66,9 +70,8 @@ This example demonstrates practical usage of the herolib builder module's remote
The builder module provides a more structured way to manage remote nodes and execute commands:
```v
import freeflowuniverse.herolib.builder
import incubaid.herolib.builder
mut b := builder.new()!
mut n := b.node_new(ipaddr:"user@host:port")!
// Execute commands on the remote node
```

View File

@@ -1,6 +1,6 @@
module main
import freeflowuniverse.herolib.core
import incubaid.herolib.core
fn do() ! {
// base.uninstall_brew()!

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.builder
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.builder
import incubaid.herolib.core.pathlib
import os
fn do1() ! {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.builder
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.builder
import incubaid.herolib.core.pathlib
import os
mut b := builder.new()!

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.builder
import freeflowuniverse.herolib.core.pathlib
import incubaid.herolib.builder
import incubaid.herolib.core.pathlib
import os
mut b := builder.new()!

391
examples/builder/zosbuilder.vsh Executable file
View File

@@ -0,0 +1,391 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.builder
import incubaid.herolib.core.pathlib
// Configuration for the remote builder
// Update these values for your remote machine
const remote_host = 'root@65.109.31.171' // Change to your remote host
const remote_port = 22 // SSH port
// Build configuration
const build_dir = '/root/zosbuilder'
const repo_url = 'https://git.ourworld.tf/tfgrid/zosbuilder'
// Optional: Set to true to upload kernel to S3
const upload_kernel = false
fn main() {
println('=== Zero OS Builder - Remote Build System ===\n')
// Initialize builder
mut b := builder.new() or {
eprintln('Failed to initialize builder: ${err}')
exit(1)
}
// Connect to remote node
println('Connecting to remote builder: ${remote_host}:${remote_port}')
mut node := b.node_new(
ipaddr: '${remote_host}:${remote_port}'
name: 'zosbuilder'
) or {
eprintln('Failed to connect to remote node: ${err}')
exit(1)
}
// Run the build process
build_zos(mut node) or {
eprintln('Build failed: ${err}')
exit(1)
}
println('\n=== Build completed successfully! ===')
}
fn build_zos(mut node builder.Node) ! {
println('\n--- Step 1: Installing prerequisites ---')
install_prerequisites(mut node)!
println('\n--- Step 2: Cloning zosbuilder repository ---')
clone_repository(mut node)!
println('\n--- Step 3: Creating RFS configuration ---')
create_rfs_config(mut node)!
println('\n--- Step 4: Running build ---')
run_build(mut node)!
println('\n--- Step 5: Checking build artifacts ---')
check_artifacts(mut node)!
println('\n=== Build completed successfully! ===')
}
fn install_prerequisites(mut node builder.Node) ! {
println('Detecting platform...')
// Check platform type
if node.platform == .ubuntu {
println('Installing Ubuntu/Debian prerequisites...')
// Update package list and install all required packages
node.exec_cmd(
cmd: '
apt-get update
apt-get install -y \\
build-essential \\
upx-ucl \\
binutils \\
git \\
wget \\
curl \\
qemu-system-x86 \\
podman \\
musl-tools \\
cpio \\
xz-utils \\
bc \\
flex \\
bison \\
libelf-dev \\
libssl-dev
# Install rustup and Rust toolchain
if ! command -v rustup &> /dev/null; then
echo "Installing rustup..."
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
source "\$HOME/.cargo/env"
fi
# Add Rust musl target
source "\$HOME/.cargo/env"
rustup target add x86_64-unknown-linux-musl
'
name: 'install_ubuntu_packages'
reset: true
)!
} else if node.platform == .alpine {
println('Installing Alpine prerequisites...')
node.exec_cmd(
cmd: '
apk add --no-cache \\
build-base \\
rust \\
cargo \\
upx \\
git \\
wget \\
qemu-system-x86 \\
podman
# Add Rust musl target
rustup target add x86_64-unknown-linux-musl || echo "rustup not available"
'
name: 'install_alpine_packages'
reset: true
)!
} else {
return error('Unsupported platform: ${node.platform}. Only Ubuntu/Debian and Alpine are supported.')
}
println('Prerequisites installed successfully')
}
fn clone_repository(mut node builder.Node) ! {
// Clean up disk space first
println('Cleaning up disk space...')
node.exec_cmd(
cmd: '
# Remove old build directories if they exist
rm -rf ${build_dir} || true
# Clean up podman/docker cache to free space
podman system prune -af || true
# Clean up package manager cache
if command -v apt-get &> /dev/null; then
apt-get clean || true
fi
# Show disk space
df -h /
'
name: 'cleanup_disk_space'
stdout: true
)!
// Clone the repository
println('Cloning from ${repo_url}...')
node.exec_cmd(
cmd: '
git clone ${repo_url} ${build_dir}
cd ${build_dir}
git log -1 --oneline
'
name: 'clone_zosbuilder'
stdout: true
)!
println('Repository cloned successfully')
}
fn create_rfs_config(mut node builder.Node) ! {
println('Creating config/rfs.conf...')
rfs_config := 'S3_ENDPOINT="http://wizenoze.grid.tf:3900"
S3_REGION="garage"
S3_BUCKET="zos"
S3_PREFIX="store"
S3_ACCESS_KEY="<put key here>"
S3_SECRET_KEY="<put key here>"
WEB_ENDPOINT=""
MANIFESTS_SUBPATH="flists"
READ_ACCESS_KEY="<put key here>"
READ_SECRET_KEY="<put key here>"
ROUTE_ENDPOINT="http://wizenoze.grid.tf:3900"
ROUTE_PATH="/zos/store"
ROUTE_REGION="garage"
KEEP_S3_FALLBACK="false"
UPLOAD_MANIFESTS="true"
'
// Create config directory if it doesn't exist
node.exec_cmd(
cmd: 'mkdir -p ${build_dir}/config'
name: 'create_config_dir'
stdout: false
)!
// Write the RFS configuration file
node.file_write('${build_dir}/config/rfs.conf', rfs_config)!
// Verify the file was created
result := node.exec(
cmd: 'cat ${build_dir}/config/rfs.conf'
stdout: false
)!
println('RFS configuration created successfully')
println('Config preview:')
println(result)
// Skip youki component by removing it from sources.conf
println('\nRemoving youki from sources.conf (requires SSH keys)...')
node.exec_cmd(
cmd: '
# Remove any line containing youki from sources.conf
grep -v "youki" ${build_dir}/config/sources.conf > ${build_dir}/config/sources.conf.tmp
mv ${build_dir}/config/sources.conf.tmp ${build_dir}/config/sources.conf
# Verify it was removed
echo "Updated sources.conf:"
cat ${build_dir}/config/sources.conf
'
name: 'remove_youki'
stdout: true
)!
println('youki component skipped')
}
fn run_build(mut node builder.Node) ! {
println('Starting build process...')
println('This may take 15-30 minutes depending on your system...')
println('Status updates will be printed every 2 minutes...\n')
// Check disk space before building
println('Checking disk space...')
disk_info := node.exec(
cmd: 'df -h ${build_dir}'
stdout: false
)!
println(disk_info)
// Clean up any previous build artifacts and corrupted databases
println('Cleaning up previous build artifacts...')
node.exec_cmd(
cmd: '
cd ${build_dir}
# Remove dist directory to clean up any corrupted databases
rm -rf dist/
# Clean up any temporary files
rm -rf /tmp/rfs-* || true
# Show available disk space after cleanup
df -h ${build_dir}
'
name: 'cleanup_before_build'
stdout: true
)!
// Make scripts executable and run build with periodic status messages
mut build_cmd := '
cd ${build_dir}
# Source Rust environment
source "\$HOME/.cargo/env"
# Make scripts executable
chmod +x scripts/build.sh scripts/clean.sh
# Set environment variables
export UPLOAD_KERNEL=${upload_kernel}
export UPLOAD_MANIFESTS=false
# Create a wrapper script that prints status every 2 minutes
cat > /tmp/build_with_status.sh << "EOF"
#!/bin/bash
set -e
# Source Rust environment
source "\$HOME/.cargo/env"
# Start the build in background
./scripts/build.sh &
BUILD_PID=\$!
# Print status every 2 minutes while build is running
COUNTER=0
while kill -0 \$BUILD_PID 2>/dev/null; do
sleep 120
COUNTER=\$((COUNTER + 2))
echo ""
echo "=== Build still in progress... (\${COUNTER} minutes elapsed) ==="
echo ""
done
# Wait for build to complete and get exit code
wait \$BUILD_PID
EXIT_CODE=\$?
if [ \$EXIT_CODE -eq 0 ]; then
echo ""
echo "=== Build completed successfully after \${COUNTER} minutes ==="
else
echo ""
echo "=== Build failed after \${COUNTER} minutes with exit code \$EXIT_CODE ==="
fi
exit \$EXIT_CODE
EOF
chmod +x /tmp/build_with_status.sh
/tmp/build_with_status.sh
' // Execute build with output
result := node.exec_cmd(
cmd: build_cmd
name: 'zos_build'
stdout: true
reset: true
period: 0 // Don't cache, always rebuild
)!
println('\nBuild completed!')
println(result)
}
fn check_artifacts(mut node builder.Node) ! {
println('Checking build artifacts in ${build_dir}/dist/...')
// List the dist directory
result := node.exec(
cmd: 'ls -lh ${build_dir}/dist/'
stdout: true
)!
println('\nBuild artifacts:')
println(result)
// Check for expected files
vmlinuz_exists := node.file_exists('${build_dir}/dist/vmlinuz.efi')
initramfs_exists := node.file_exists('${build_dir}/dist/initramfs.cpio.xz')
if vmlinuz_exists && initramfs_exists {
println('\n Build artifacts created successfully:')
println(' - vmlinuz.efi (Kernel with embedded initramfs)')
println(' - initramfs.cpio.xz (Standalone initramfs archive)')
// Get file sizes
size_info := node.exec(
cmd: 'du -h ${build_dir}/dist/vmlinuz.efi ${build_dir}/dist/initramfs.cpio.xz'
stdout: false
)!
println('\nFile sizes:')
println(size_info)
} else {
return error('Build artifacts not found. Build may have failed.')
}
}
// Download artifacts to local machine
fn download_artifacts(mut node builder.Node, local_dest string) ! {
println('Downloading artifacts to local machine...')
mut dest_path := pathlib.get_dir(path: local_dest, create: true)!
println('Downloading to ${dest_path.path}...')
// Download the entire dist directory
node.download(
source: '${build_dir}/dist/'
dest: dest_path.path
)!
println('\n Artifacts downloaded successfully to ${dest_path.path}')
// List downloaded files
println('\nDownloaded files:')
result := node.exec(
cmd: 'ls -lh ${dest_path.path}'
stdout: false
) or {
println('Could not list local files')
return
}
println(result)
}

View File

@@ -0,0 +1,224 @@
# Zero OS Builder - Remote Build System
This example demonstrates how to build [Zero OS (zosbuilder)](https://git.ourworld.tf/tfgrid/zosbuilder) on a remote machine using the herolib builder module.
## Overview
The zosbuilder creates a Zero OS Alpine Initramfs with:
- Alpine Linux 3.22 base
- Custom kernel with embedded initramfs
- ThreeFold components (zinit, rfs, mycelium, zosstorage)
- Optimized size with UPX compression
- Two-stage module loading
## Prerequisites
### Local Machine
- V compiler installed
- SSH access to a remote build machine
- herolib installed
### Remote Build Machine
The script will automatically install these on the remote machine:
- **Ubuntu/Debian**: build-essential, rustc, cargo, upx-ucl, binutils, git, wget, qemu-system-x86, podman, musl-tools
- **Alpine Linux**: build-base, rust, cargo, upx, git, wget, qemu-system-x86, podman
- Rust musl target (x86_64-unknown-linux-musl)
## Configuration
Edit the constants in `zosbuilder.vsh`:
```v
const (
// Remote machine connection
remote_host = 'root@195.192.213.2' // Your remote host
remote_port = 22 // SSH port
// Build configuration
build_dir = '/root/zosbuilder' // Build directory on remote
repo_url = 'https://git.ourworld.tf/tfgrid/zosbuilder'
// Optional: Upload kernel to S3
upload_kernel = false
)
```
## Usage
### Basic Build
```bash
# Make the script executable
chmod +x zosbuilder.vsh
# Run the build
./zosbuilder.vsh
```
### What the Script Does
1. **Connects to Remote Machine**: Establishes SSH connection to the build server
2. **Installs Prerequisites**: Automatically installs all required build tools
3. **Clones Repository**: Fetches the latest zosbuilder code
4. **Runs Build**: Executes the build process (takes 15-30 minutes)
5. **Verifies Artifacts**: Checks that build outputs were created successfully
### Build Output
The build creates two main artifacts in `${build_dir}/dist/`:
- `vmlinuz.efi` - Kernel with embedded initramfs (bootable)
- `initramfs.cpio.xz` - Standalone initramfs archive
## Build Process Details
The zosbuilder follows these phases:
### Phase 1: Environment Setup
- Creates build directories
- Installs build dependencies
- Sets up Rust musl target
### Phase 2: Alpine Base
- Downloads Alpine 3.22 miniroot
- Extracts to initramfs directory
- Installs packages from config/packages.list
### Phase 3: Component Building
- Builds zinit (init system)
- Builds rfs (remote filesystem)
- Builds mycelium (networking)
- Builds zosstorage (storage orchestration)
### Phase 4: System Configuration
- Replaces /sbin/init with zinit
- Copies zinit configuration
- Sets up 2-stage module loading
- Configures system services
### Phase 5: Optimization
- Removes docs, man pages, locales
- Strips executables and libraries
- UPX compresses all binaries
- Aggressive cleanup
### Phase 6: Packaging
- Creates initramfs.cpio.xz with XZ compression
- Builds kernel with embedded initramfs
- Generates vmlinuz.efi
- Optionally uploads to S3
## Advanced Usage
### Download Artifacts to Local Machine
Add this to your script after the build completes:
```v
// Download artifacts to local machine
download_artifacts(mut node, '/tmp/zos-artifacts') or {
eprintln('Failed to download artifacts: ${err}')
}
```
### Custom Build Configuration
You can modify the build by editing files on the remote machine before building:
```v
// After cloning, before building
node.file_write('${build_dir}/config/packages.list', 'your custom packages')!
```
### Rebuild Without Re-cloning
To rebuild without re-cloning the repository, modify the script to skip the clone step:
```v
// Comment out the clone_repository call
// clone_repository(mut node)!
// Or just run the build directly
node.exec_cmd(
cmd: 'cd ${build_dir} && ./scripts/build.sh'
name: 'zos_rebuild'
)!
```
## Testing the Build
After building, you can test the kernel with QEMU:
```bash
# On the remote machine
cd /root/zosbuilder
./scripts/test-qemu.sh
```
## Troubleshooting
### Build Fails
1. Check the build output for specific errors
2. Verify all prerequisites are installed
3. Ensure sufficient disk space (at least 5GB)
4. Check internet connectivity for downloading components
### SSH Connection Issues
1. Verify SSH access: `ssh root@195.192.213.2`
2. Check SSH key authentication is set up
3. Verify the remote host and port are correct
### Missing Dependencies
The script automatically installs dependencies, but if manual installation is needed:
**Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install -y build-essential rustc cargo upx-ucl binutils git wget qemu-system-x86 podman musl-tools
rustup target add x86_64-unknown-linux-musl
```
**Alpine Linux:**
```bash
apk add --no-cache build-base rust cargo upx git wget qemu-system-x86 podman
rustup target add x86_64-unknown-linux-musl
```
## Integration with CI/CD
This builder can be integrated into CI/CD pipelines:
```v
// Example: Build and upload to artifact storage
fn ci_build() ! {
mut b := builder.new()!
mut node := b.node_new(ipaddr: '${ci_builder_host}')!
build_zos(mut node)!
// Upload to artifact storage
node.exec_cmd(
cmd: 's3cmd put ${build_dir}/dist/* s3://artifacts/zos/'
name: 'upload_artifacts'
)!
}
```
## Related Examples
- `simple.vsh` - Basic builder usage
- `remote_executor/` - Remote code execution
- `simple_ip4.vsh` - IPv4 connection example
- `simple_ip6.vsh` - IPv6 connection example
## References
- [zosbuilder Repository](https://git.ourworld.tf/tfgrid/zosbuilder)
- [herolib Builder Documentation](../../lib/builder/readme.md)
- [Zero OS Documentation](https://manual.grid.tf/)
## License
This example follows the same license as herolib.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -g -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.clients.giteaclient
import incubaid.herolib.core.playcmds
import incubaid.herolib.clients.giteaclient
heroscript := "
!!giteaclient.configure

View File

@@ -1,50 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.jina
import os
import json
fn main() {
// Initialize Jina client
mut j := jina.Jina{
name: 'test_client'
secret: os.getenv('JINAKEY')
}
// Initialize the client
j = jina.obj_init(j) or {
println('Error initializing Jina client: ${err}')
return
}
// Check if authentication works
auth_ok := j.check_auth() or {
println('Authentication failed: ${err}')
return
}
println('Authentication successful: ${auth_ok}')
// Create embeddings
model := 'jina-embeddings-v2-base-en'
input := ['Hello world', 'This is a test']
embeddings := j.create_embeddings(input, model, 'search') or {
println('Error creating embeddings: ${err}')
return
}
println('Embeddings created successfully!')
println('Model: ${embeddings.model}')
println('Dimension: ${embeddings.dimension}')
println('Number of embeddings: ${embeddings.data.len}')
// If there are embeddings, print the first one (truncated)
if embeddings.data.len > 0 {
first_embedding := embeddings.data[0]
println('First embedding (first 5 values): ${first_embedding.embedding[0..5]}')
}
// Usage information
println('Token usage: ${embeddings.usage.total_tokens} ${embeddings.usage.unit}')
}

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.mailclient
import incubaid.herolib.clients.mailclient
// remove the previous one, otherwise the env variables are not read
mailclient.config_delete(name: 'test')!

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.mycelium
import freeflowuniverse.herolib.installers.net.mycelium_installer
import incubaid.herolib.clients.mycelium
import incubaid.herolib.installers.net.mycelium_installer
import time
import os
import encoding.base64

View File

@@ -3,8 +3,8 @@
// Mycelium RPC Client Example
// This example demonstrates how to use the new Mycelium JSON-RPC client
// to interact with a Mycelium node's admin API
import freeflowuniverse.herolib.clients.mycelium_rpc
import freeflowuniverse.herolib.installers.net.mycelium_installer
import incubaid.herolib.clients.mycelium_rpc
import incubaid.herolib.installers.net.mycelium_installer
import time
import os
import encoding.base64

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.clients.postgresql_client
import incubaid.herolib.core
import incubaid.herolib.clients.postgresql_client
// Configure PostgreSQL client
heroscript := "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.zinit
import freeflowuniverse.herolib.installers.infra.zinit_installer
import incubaid.herolib.clients.zinit
import incubaid.herolib.installers.infra.zinit_installer
import os
import time

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.core.jobs.model
import incubaid.herolib.data.ourtime
import incubaid.herolib.core.jobs.model
// Create a test agent with some sample data
mut agent := model.Agent{

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.base
import incubaid.herolib.core.base
pub struct MyClient[T] {
base.BaseConfig[T]

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.base
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.base
pub struct MyClient[T] {
base.BaseConfig[T]

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.develop.gittools
import incubaid.herolib.core.base
import incubaid.herolib.develop.gittools
pub struct MyClass {
base.Base

Some files were not shown because too many files have changed in this diff Show More