Compare commits

...

766 Commits
v1.0.6 ... main

Author SHA1 Message Date
55f0621983 ... 2025-08-13 09:35:58 +02:00
75363d7aeb ... 2025-08-13 08:55:38 +02:00
1f9bc11a2e ... 2025-08-13 08:49:44 +02:00
aab018925d ... 2025-08-13 07:23:14 +02:00
5fa361256a ... 2025-08-13 07:18:02 +02:00
42fe7b0a0d Merge branch 'development_fix_docusaurus' of github.com:freeflowuniverse/herolib into development_fix_docusaurus
* 'development_fix_docusaurus' of github.com:freeflowuniverse/herolib:
  refactor: Improve docusaurus import and site handling
2025-08-13 05:59:46 +02:00
011e5b039e ... 2025-08-13 05:59:40 +02:00
Mahmoud-Emad
e9bcf6ef69 refactor: Improve docusaurus import and site handling
- Simplify command logic to use a single defined site
- Enhance git import to resolve paths relative to project root
- Add `docusaurus.export` action to trigger `build_publish`
- Change asset import destination from `docs` to `static`
- Add `dsite_get_only` helper for simplified site access
2025-08-13 04:19:32 +03:00
f885563982 Co-authored-by: Omdanii <mahmmoud.hassanein@gmail.com> 2025-08-12 16:01:27 +02:00
ffff44f347 .. 2025-08-12 15:52:13 +02:00
Mahmoud-Emad
0e1450b5db chore: add debug prints and perform code cleanup
- Add extensive debug prints for troubleshooting
- Comment out docusaurus build/dev action logic
- Rename gittools parameters for clarity (reset/pull)
- Apply consistent formatting to function calls
- Remove unused imports in playbook include module
2025-08-12 13:37:01 +03:00
f8734a7e9f .. 2025-08-12 11:07:09 +02:00
c05ec6be7f ... 2025-08-12 11:03:49 +02:00
8677d177cb ... 2025-08-12 11:02:21 +02:00
dd37eeaa29 ... 2025-08-12 10:58:53 +02:00
d5753ee794 replace 2025-08-12 10:39:18 +02:00
6b46b3dbaa ... 2025-08-12 10:36:26 +02:00
4cd5b51085 ... 2025-08-12 10:33:29 +02:00
0a7851b920 ... 2025-08-12 09:41:50 +02:00
a0fdaf395e ... 2025-08-12 09:33:53 +02:00
2c5a2ace17 ... 2025-08-11 22:34:23 +02:00
965a2bebb7 ... 2025-08-11 22:12:44 +02:00
2c08ee8687 to compare 2025-08-11 21:41:38 +02:00
e105dd73b5 Merge branch 'development_fix_docusaurus_include' into development
* development_fix_docusaurus_include:
  refactor: Rework playbook include and site import logic
2025-08-11 21:26:49 +02:00
f5dfe8c0af Merge branch 'fix-issue-104' into development
* fix-issue-104:
  Fix issue #104: Fix all biztools examples to use playbook.new()
  Fix issue #104: Add fixed examples and solution documentation
  Fix issue #104: Add notworking.md documenting biztools examples test results

# Conflicts:
#	examples/biztools/notworking.md
2025-08-11 21:26:18 +02:00
ac97e9e7bc Merge branch 'copilot/fix-104' into development
* copilot/fix-104:
  Complete testing of all biztools examples - all 11 scripts are non-functional
  Initial plan
2025-08-11 21:25:57 +02:00
Mahmoud-Emad
beae2cef82 refactor: Rework playbook include and site import logic
- Replace manual script concatenation with playbook include handling
- Preserve site configuration (imports, menu) during generation
- Add support for copying static files from imported content
- Handle static assets from sibling `ebooksall` directories
- Fix import copy logic to not delete destination before copying
2025-08-11 21:53:24 +03:00
2b23771056 ... 2025-08-11 16:38:54 +02:00
19632b4b4b ... 2025-08-11 15:32:12 +02:00
31c033300a Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-08-11 11:51:54 +02:00
ca4127319d ... 2025-08-11 11:51:51 +02:00
openhands
d3d8f0d0f1 ... 2025-08-10 03:50:00 +00:00
openhands
2968e4dddc Fix issue #104: Fix all biztools examples to use playbook.new() 2025-08-09 20:08:51 +00:00
copilot-swe-agent[bot]
30c7951058 Complete testing of all biztools examples - all 11 scripts are non-functional
Co-authored-by: despiegk <6021844+despiegk@users.noreply.github.com>
2025-08-09 20:01:58 +00:00
openhands
af63e266d8 Fix issue #104: Add fixed examples and solution documentation 2025-08-09 20:01:37 +00:00
openhands
5d1e3d416e Fix issue #104: Add notworking.md documenting biztools examples test results 2025-08-09 19:57:37 +00:00
copilot-swe-agent[bot]
dd9dc59485 Initial plan 2025-08-09 19:51:51 +00:00
b473630ceb ... 2025-08-09 06:16:49 +02:00
a34b8b70ba ... 2025-08-08 21:36:46 +02:00
fd195f0824 ... 2025-08-08 17:51:57 +02:00
a727d19281 ... 2025-08-08 17:13:33 +02:00
52c88bccb5 bump version to 1.0.28 2025-08-08 17:02:05 +02:00
85cb868bff ... 2025-08-08 17:01:27 +02:00
4339220b42 bump version to 1.0.28 2025-08-08 17:01:11 +02:00
2eb62063f2 bump version to 1.0.27 2025-08-08 16:42:25 +02:00
eaccbe610f ... 2025-08-08 16:28:05 +02:00
53e685241a ... 2025-08-08 16:17:52 +02:00
9d87fc62f3 ... 2025-08-08 16:00:37 +02:00
682abdbda9 ... 2025-08-08 15:53:25 +02:00
6308d232aa ... 2025-08-08 15:46:01 +02:00
56d6a05ced ... 2025-08-08 13:19:30 +02:00
0c93a5abe8 ... 2025-08-08 13:15:31 +02:00
2726ecbe2e ... 2025-08-08 13:11:05 +02:00
aa26ae60e2 ... 2025-08-08 09:25:56 +02:00
Mahmoud-Emad
edefab866f docs: add hero command usage and update examples
- Add recommended `hero` command workflow section
- Update `!!docusaurus.add` example with `play` parameter
- Clarify comments for optional git parameters
2025-08-07 16:29:30 +03:00
Mahmoud-Emad
b01e6a5a4c refactor: Centralize Docusaurus site processing logic
- Add central `process_site_from_path` function
- Recursively process heroscript files in `cfg` directory
- Remove duplicated site processing from `run` and `add` commands
- Respect `play` parameter from heroscript `define` block
2025-08-07 16:22:35 +03:00
Mahmoud-Emad
843b20804b refactor: improve docusaurus site creation and handling
- Change site.new to always create/overwrite a site
- Add early exit to site.play if no config exists
- Use explicit sitename from docusaurus.config
- Enable openai.play action processing
- Remove debug code and improve struct initialization
2025-08-07 13:42:53 +03:00
daf6ce5126 Merge branch 'development_fix_hero_and_ci' of github.com:freeflowuniverse/herolib into development_fix_hero_and_ci
* 'development_fix_hero_and_ci' of github.com:freeflowuniverse/herolib:
  refactor: overhaul Docusaurus command and generation
2025-08-07 10:23:12 +02:00
52214f79d6 ... 2025-08-07 10:23:06 +02:00
Mahmoud-Emad
6ae6cc35ee Merge branch 'development_fix_hero_and_ci' of https://github.com/freeflowuniverse/herolib into development_fix_hero_and_ci 2025-08-07 10:54:42 +03:00
Mahmoud-Emad
82a46e8149 refactor: overhaul Docusaurus command and generation
- Rework `hero docusaurus` command to use local `cfg` files
- Scan and export doctree collections during site generation
- Fix `baseUrl` redirect path handling in `index.tsx`
- Add cycle detection for `play.include` in playbooks
- Improve site config processing to prevent duplicate items
2025-08-07 10:46:57 +03:00
93953ed570 ... 2025-08-07 08:15:04 +02:00
2667856633 ... 2025-08-06 13:00:51 +02:00
3bca5f661e ... 2025-08-06 12:50:30 +02:00
d4df226381 ... 2025-08-06 12:36:09 +02:00
d56a04e3ea Merge branch 'development' into development_fix_hero_and_ci
* development:
  ...

# Conflicts:
#	lib/core/herocmds/docusaurus.v
#	lib/data/encoderhero/decoder.v
#	lib/data/encoderhero/postgres_client_decoder_test.v
#	lib/web/site/play.v
2025-08-06 08:55:07 +02:00
e4c204376e Merge branch 'development' of github.com:freeflowuniverse/herolib into development
# Conflicts:
#	lib/core/herocmds/docusaurus.v
#	lib/web/docusaurus/factory.v
2025-08-06 08:51:38 +02:00
04403b62a4 ... 2025-08-06 08:50:32 +02:00
Mahmoud-Emad
3b0232ebe3 refactor: improve skip attribute detection logic
- Normalize attributes by removing all whitespace
- Simplify conditional logic for skip attribute check
- Add fallback skip check for fields named 'other'
- Remove debugging print statements
2025-08-05 20:14:47 +03:00
Mahmoud-Emad
29e0efa3d6 debug: Add some print statments to see the output in the CI 2025-08-05 20:05:30 +03:00
Mahmoud-Emad
c81af5e235 fix: make skip attribute detection more robust
- Replace simple `contains('skip')` with stricter checks
- Normalize attribute string before checking
- Avoid matching 'skip' as a substring of another word
- Handle space and semicolon-separated attribute lists
2025-08-05 19:52:01 +03:00
Mahmoud-Emad
b15c4cd15a refactor: Change hero action syntax to verb.noun
- Change action name format from `obj.verb` to `verb.obj`
- Update decoder to look for `define.obj` or `configure.obj`
- Modify encoder export to use the new `define.obj` prefix
- Update all test constants and scripts to the new syntax
- Make Remark struct public for test visibility
2025-08-05 19:02:26 +03:00
Mahmoud-Emad
65d75a8148 test: add link_def_test.v 2025-08-05 18:07:26 +03:00
Mahmoud-Emad
b04e1d7f99 fix: Return the test_basic.vsh file back 2025-08-05 17:58:45 +03:00
Mahmoud-Emad
a848eaa18b refactor: Improve playbook processing and add generation
- Trigger doc content generation after playbook processing
- Remove mutable variables for playbook actions
- Eliminate `action.done = true` assignments
- Derive site name from title if not explicitly provided
- Separate local path and git URL for docusaurus sites
2025-08-05 17:47:33 +03:00
Mahmoud-Emad
ccf2d4a3a5 fix: Fix docusaurus compilation issues in development branch
- Update docusaurus.v to use correct API (dsite_add instead of add)
- Fix factory.v compiler bug by rewriting problematic or block syntax
- Ensure compilation works with current docusaurus module structure
2025-08-05 15:34:46 +03:00
Mahmoud-Emad
59acea177d test: overhaul mycelium two-node communication test
- Start two local mycelium nodes without TUN interfaces
- Add pre-test cleanup for processes and configurations
- Implement readiness check to wait for servers to start
- Test bidirectional messaging between the two nodes
- Verify message payload and source public key
2025-08-05 15:11:46 +03:00
5cb52ba6b1 ... 2025-08-04 09:35:50 +02:00
6a2ea52e48 ... 2025-08-04 08:55:12 +02:00
c853f3b0ce ... 2025-08-04 08:01:26 +02:00
07bd258e54 ... 2025-08-04 07:05:04 +02:00
52f7a7a2b8 Merge branch 'development_ds' into development_fix_herobin
* development_ds:
  refactor: improve config path handling and clean up code
  refactor: dynamically load site config from heroscript
  feat: add multi-site support and playbook enhancements

# Conflicts:
#	lib/web/docusaurus/dsite_configuration.v
2025-08-04 05:41:59 +02:00
cf4d9e86c8 Merge branch 'development_ds' of github.com:freeflowuniverse/herolib into development_ds
* 'development_ds' of github.com:freeflowuniverse/herolib:
  refactor: improve config path handling and clean up code
  refactor: dynamically load site config from heroscript
  feat: add multi-site support and playbook enhancements
2025-08-04 05:41:11 +02:00
Mahmoud-Emad
44effe9a4b refactor: improve config path handling and clean up code
- Allow specifying project root or cfg dir for config
- Remove verbose debug print statements during load
- Remove unused site.page action find operation
- Improve validation for relative paths in remove list
2025-08-03 18:07:53 +03:00
Mahmoud-Emad
2502f0a655 refactor: dynamically load site config from heroscript
- Process heroscript files using a playbook
- Dynamically add config, menus, and page files
- Retrieve site config from the processed playbook
- Override site description from meta config
- Remove unused 'deploykey' flag and import
2025-08-03 17:33:23 +03:00
Mahmoud-Emad
d747977185 feat: add multi-site support and playbook enhancements
- Refactor `site` module to process multiple configurations
- Add environment variable templating for playbook actions
- Activate playbook actions for setting coderoot and params
- Improve docusaurus config with metadata fallbacks
- Fix docusaurus navbar generation when logo is not defined
2025-08-03 12:14:55 +03:00
4b900e383a Merge branch 'development_ds' into development_fix_herobin
* development_ds:
  ...
  refactor: improve session action handling in play_core
  refactor: adapt docusaurus to use generic site module
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...
  ...

# Conflicts:
#	lib/biz/bizmodel/play.v
#	lib/threefold/grid4/cloudslices/play.v
#	lib/threefold/grid4/farmingsimulator/play.v
#	lib/web/docusaurus/dsite.v
#	lib/web/docusaurus/dsite_add.v
#	lib/web/docusaurus/dsite_configuration.v
#	lib/web/docusaurus/dsite_generate.v
2025-08-03 04:47:53 +02:00
8ae0d6e401 ... 2025-08-03 04:44:55 +02:00
Mahmoud-Emad
198a394be8 refactor: improve session action handling in play_core
- Clean up `play_core` by removing dead code and unused imports
- Check `action.name` directly instead of param existence
- Allow 'value' as an alias for 'val' in session env actions
- Use `env_set` for `env_set_once` to avoid duplicate errors
2025-07-31 17:59:44 +03:00
Mahmoud-Emad
697c500e35 refactor: adapt docusaurus to use generic site module
- Introduce a new generic `site` module for web generation
- Update `herocmds` to use the new site creation flow
- Simplify docusaurus playbook logic with a `docusaurus.play` fn
- Refactor site generation to act on `Site` struct directly
- Fix playbook find filter to use wildcard `*`
2025-07-31 14:42:36 +03:00
Mahmoud-Emad
e6c1d84836 refactor: Generalize playbook find method and restructure site module
- Replace `actions_find` with a more generic `find(filter:)`
- Rename `siteconfig` module and related types to `site`
- Introduce a `Site` object to encapsulate configuration
- Update site generation to accept a playbook object directly
- Remove redundant blank lines and format code
2025-07-31 14:02:46 +03:00
e837912363 ... 2025-07-31 03:51:36 +02:00
50a76dd096 ... 2025-07-31 03:44:44 +02:00
a7f6548bea ... 2025-07-30 23:43:41 +02:00
34da4f06e1 ... 2025-07-30 23:00:49 +02:00
932b6508c9 ... 2025-07-30 22:23:24 +02:00
bfaa2446cd ... 2025-07-30 22:12:19 +02:00
bfe3110894 ... 2025-07-30 21:36:30 +02:00
59386bb1c2 ... 2025-07-30 20:06:27 +02:00
b99f5ae6e9 ... 2025-07-30 19:17:14 +02:00
4472dc7d04 ... 2025-07-30 19:14:31 +02:00
d3d7eccf3d ... 2025-07-30 19:08:15 +02:00
7e250d1224 ... 2025-07-30 18:58:11 +02:00
14d8d5af8d ... 2025-07-30 18:51:29 +02:00
1cb6c486df ... 2025-07-30 17:43:39 +02:00
bc163eb61d ... 2025-07-30 17:35:19 +02:00
802f6e074d ... 2025-07-30 15:58:04 +02:00
4bf4294c42 ... 2025-07-30 15:28:14 +02:00
cb13febd78 ... 2025-07-30 15:24:10 +02:00
685a58aa14 ... 2025-07-30 15:21:10 +02:00
2bc2c07114 ... 2025-07-30 15:08:23 +02:00
66757c52d7 ... 2025-07-30 15:00:20 +02:00
9fd551e0f7 ... 2025-07-30 14:37:02 +02:00
705f2d640e ... 2025-07-30 14:27:06 +02:00
0eb4dd38f8 ... 2025-07-30 14:19:16 +02:00
6233961371 ... 2025-07-30 14:01:29 +02:00
ddfb48f7ab Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-07-30 13:53:56 +02:00
800133ab89 .. 2025-07-30 13:53:54 +02:00
Mahmoud-Emad
2319912f8f refactor: Simplify site.config_meta action handling
- Replace `plbook.find` loop with direct `action_get`
- Standardize on single quotes for string arguments
- Adjust spacing around variable assignment operator
- Simplify PlayBook type hint
2025-07-30 14:53:31 +03:00
0363e5e661 .. 2025-07-30 13:49:57 +02:00
d2bf58f514 ... 2025-07-30 13:19:17 +02:00
bc92114918 ... 2025-07-30 13:15:09 +02:00
f143e3cf48 ... 2025-07-30 13:01:20 +02:00
f20f5efcb6 ... 2025-07-30 13:00:26 +02:00
1d383faa62 ... 2025-07-30 12:57:32 +02:00
46e425cbc5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-07-30 12:53:01 +02:00
44d3edca55 ... 2025-07-30 12:52:59 +02:00
Mahmoud-Emad
a44072bd4d fix: add error propagation to git operations
- Add error propagation `!` to git method calls
- Handle potential errors from `gittools.get` and `gs.load`
- Adjust playbook import statement
- Remove unnecessary blank line

Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development
2025-07-30 13:48:36 +03:00
Mahmoud-Emad
957d977147 fix: add error propagation to git operations
- Add error propagation `!` to git method calls
- Handle potential errors from `gittools.get` and `gs.load`
- Adjust playbook import statement
- Remove unnecessary blank line
2025-07-30 13:47:52 +03:00
c038334e67 ... 2025-07-30 12:47:49 +02:00
2f450f7b9b ... 2025-07-30 12:42:53 +02:00
Omdanii
a840d1211a Merge pull request #96 from freeflowuniverse/development_mcp_server
Development mcp server
2025-07-29 20:05:25 +03:00
Mahmoud-Emad
f8dc42499b Merge branch 'development' into development_mcp_server 2025-07-29 20:05:00 +03:00
Mahmoud-Emad
78c5a7a3c6 feat: add SSE endpoint for streaming updates
- Add `/sse` endpoint for Server-Sent Events
- Handle SSE connection in a separate thread
- Periodically stream capabilities and tools list
- Send keepalive pings to maintain connection
2025-07-29 20:03:50 +03:00
Omdanii
983908e531 Merge pull request #95 from freeflowuniverse/development_mcp_server
Add HTTP/REST Transport Support to MCP Framework
2025-07-28 16:13:16 +03:00
Mahmoud-Emad
a76dfc3a28 Merge branch 'development' into development_mcp_server 2025-07-28 15:14:24 +03:00
Mahmoud-Emad
914cba5388 feat: add HTTP/REST transport for MCP servers
- Refactor server to use a generic transport interface
- Add HttpTransport for JSON-RPC and REST over HTTP
- Move existing STDIO logic into a StdioTransport
- Enable dual-mode (STDIO/HTTP) via command-line flags
- Add new examples and docs for HTTP server usage
2025-07-28 13:32:01 +03:00
4c7654fb3c ... 2025-07-28 10:42:27 +02:00
5b48304fac ... 2025-07-28 10:20:13 +02:00
Mahmoud-Emad
6357ae43db feat: add complete V server example and improve runner
- Create new `server.vsh` example with custom tools
- Update `example.sh` to use the new V server script
- Improve README with new, clearer running instructions
- Fix server to not send responses for notifications
- Remove debug logging statements from server and handler
2025-07-27 16:01:28 +03:00
ab5430ddc7 ... 2025-07-25 14:08:44 +02:00
6877de4626 ... 2025-07-25 13:35:30 +02:00
181a81a84a .... 2025-07-25 13:25:48 +02:00
f2079c7c3d ... 2025-07-25 11:05:30 +02:00
9b86f76eaa ... 2025-07-25 10:47:17 +02:00
Mahmoud-Emad
5cee9a4d5a refactor: Extract git repository management into a dedicated module
- Moved git repository handling logic from `gittools` to a new
  `gitresolver` module for better code organization and reusability.
- Created a `GitUrlResolver` interface to abstract git URL resolution.
- Implemented a `GitToolsResolver` struct to adapt the existing
  `gittools` functionality to the new interface.  This allows for
  future extensibility with different git repository management
  strategies.
- Improved error handling and added more informative error messages.
- Improved the structure of the `heroscript` by breaking down the
  actions into smaller, more manageable units.
2025-07-23 19:00:43 +03:00
835556b223 ... 2025-07-23 12:56:13 +02:00
0ebc06589e Merge branch 'development' of github.com:freeflowuniverse/herolib into development
* 'development' of github.com:freeflowuniverse/herolib:
  test: Update EUR/USD exchange rate assumption in tests
  fix: prevent 'img' directory from being ignored
2025-07-23 12:53:29 +02:00
2a23458b57 ... 2025-07-23 11:58:17 +02:00
Mahmoud-Emad
c27862262f test: Update EUR/USD exchange rate assumption in tests
- Updated the assertion for the EUR/USD exchange rate from >= 0.9 to >= 0.8.
- This reflects the current market exchange rate and prevents test failures.
2025-07-22 10:46:24 +03:00
Mahmoud-Emad
5592d13d66 fix: prevent 'img' directory from being ignored
- Prevent the 'img' directory from being incorrectly ignored.
- This ensures that the 'img' directory is processed correctly,
  fixing an issue where it was excluded unintentionally.
2025-07-22 10:29:19 +03:00
63fd9d1660 ... 2025-07-22 09:20:10 +02:00
d59c9a06fd ... 2025-07-22 09:04:42 +02:00
21e43c69a8 ... 2025-07-22 07:39:08 +02:00
b560288962 ... 2025-07-22 07:19:16 +02:00
57dfa87a9e ... 2025-07-21 17:50:37 +02:00
4fb7996f99 ... 2025-07-21 17:29:47 +02:00
bd9cc74c60 ... 2025-07-21 14:29:42 +02:00
ff79c952f2 ... 2025-07-21 13:57:38 +02:00
6c3032e65f ... 2025-07-21 13:42:27 +02:00
740b243356 .. 2025-07-21 13:40:04 +02:00
bb3dd2dbf9 ... 2025-07-21 13:35:30 +02:00
02c4229116 ... 2025-07-21 13:20:24 +02:00
55794a208c ... 2025-07-21 12:53:31 +02:00
c81e342037 ... 2025-07-21 12:50:29 +02:00
1fe0f04226 ... 2025-07-21 12:46:31 +02:00
bf01a35686 ... 2025-07-21 11:57:31 +02:00
1ea0978776 ... 2025-07-21 11:45:23 +02:00
8d7c8e8933 ... 2025-07-21 11:42:19 +02:00
5cc32b3e9c ... 2025-07-21 11:39:22 +02:00
0b8cba068e ... 2025-07-21 11:18:35 +02:00
8282bdf6d5 ... 2025-07-21 11:16:51 +02:00
b8759d29fb ... 2025-07-21 09:56:01 +02:00
1944d58c9f ... 2025-07-21 07:27:17 +02:00
959c1319e7 ... 2025-07-21 06:51:13 +02:00
a538b2af90 ... 2025-07-21 06:47:31 +02:00
0ec8fd58d2 ... 2025-07-21 06:45:50 +02:00
bd120180ea ... 2025-07-21 06:42:00 +02:00
2127fb2ec0 ... 2025-07-21 06:30:42 +02:00
ddf5fcbbcc ... 2025-07-21 06:18:46 +02:00
62932976dd ... 2025-07-20 16:01:09 +02:00
63217506dd ... 2025-07-20 15:57:36 +02:00
fdd619df85 ... 2025-07-20 15:52:46 +02:00
90fc08a816 ... 2025-07-20 15:29:42 +02:00
874ad25fe1 ... 2025-07-20 14:58:06 +02:00
35c3dd7955 ... 2025-07-20 11:23:32 +02:00
b6935cf673 ... 2025-07-20 11:04:10 +02:00
cbde29a8b4 ... 2025-07-20 10:31:19 +02:00
8e47487a23 ... 2025-07-20 06:21:14 +02:00
32fcda82e7 ... 2025-07-19 21:52:05 +02:00
721352489d ... 2025-07-19 21:48:11 +02:00
6092143ed8 ... 2025-07-19 21:19:00 +02:00
d469869b14 ... 2025-07-19 21:09:30 +02:00
391283159d ... 2025-07-19 21:09:16 +02:00
802dcdb8ac ... 2025-07-19 21:02:28 +02:00
a5146e4a27 ... 2025-07-19 20:58:32 +02:00
2c8daf11d8 ... 2025-07-19 19:51:08 +02:00
e798187b89 ... 2025-07-19 19:02:18 +02:00
b9eb75d13e ... 2025-07-19 18:18:46 +02:00
d32f0f4245 ... 2025-07-19 17:27:25 +02:00
e8d4d0afe6 ... 2025-07-19 17:08:33 +02:00
555272eeb3 ... 2025-07-19 16:19:21 +02:00
f53a1c3349 ... 2025-07-19 15:58:50 +02:00
02ffc71aea ... 2025-07-19 15:54:23 +02:00
f092095e7b ... 2025-07-19 13:49:10 +02:00
45c64b8184 ... 2025-07-18 08:06:03 +02:00
1fdd30c147 ... 2025-07-18 07:35:18 +02:00
8354ba4c8c ... 2025-07-18 07:04:00 +02:00
d9f1c93a01 ... 2025-07-18 06:17:57 +02:00
0e7ea1a6f0 ... 2025-07-18 05:55:23 +02:00
9ca0728929 ... 2025-07-18 05:40:57 +02:00
7ea0a43b0c ... 2025-07-18 05:15:30 +02:00
c3b517c4f3 ... 2025-07-17 20:29:11 +04:00
09dedf9669 ... 2025-07-17 20:25:17 +04:00
1b03a9ef6d ... 2025-07-17 20:18:24 +04:00
6ba074b29c ... 2025-07-17 19:50:05 +04:00
731c4a801a ... 2025-07-17 19:15:00 +04:00
0662b37915 ... 2025-07-12 20:37:13 +04:00
545fd75d71 ... 2025-07-12 16:48:50 +04:00
ca6fc6f7a5 ... 2025-07-12 12:28:01 +03:00
49bd1b84ff ... 2025-07-11 20:41:50 +03:00
Omdanii
6a22412a72 Merge pull request #93 from freeflowuniverse/development_docusaurus
feat: Add logo to navbar and update dependencies
2025-06-22 19:22:22 +03:00
Omdanii
35ae33f32a Merge pull request #94 from freeflowuniverse/development_hero_docusaurus
feat: Allow specifying host and port for dev servers
2025-06-22 19:21:47 +03:00
Mahmoud-Emad
e2aa9e7c46 feat: Improve Docusaurus dev server experience
- Stream server logs to the terminal for better monitoring.
- Run the server in a background screen session for persistence.
- Provide clearer instructions for managing the server.
- Improve error handling and fallback mechanisms.
2025-06-22 19:20:43 +03:00
Mahmoud-Emad
dbf18c7a34 feat: Allow specifying host and port for dev servers
- Updated `dev()` methods in Docusaurus and Starlight to accept
  host and port arguments, defaulting to `localhost:3000`.
- This allows more flexibility in development server setup.
- Updated example scripts to use the new parameters.
2025-06-22 15:34:03 +03:00
Mahmoud-Emad
8902d92534 feat: Add logo to navbar and update dependencies
- Added logo to the navbar for improved branding.
- Added `echarts` dependency for enhanced charting capabilities.
- Updated `play.v` to support logo configuration in the menu.
2025-06-17 13:43:30 +03:00
Mahmoud-Emad
483b6e3de3 bump version to 1.0.26 2025-06-17 09:51:38 +03:00
f769c34466 Merge branch 'development_griddriver' into development
* development_griddriver:
  Update griddriver to use prebuilt binary
2025-06-17 08:02:22 +02:00
Mahmoud-Emad
c0242a0729 Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development 2025-06-16 14:04:21 +03:00
Mahmoud-Emad
df452ce258 feat: Add mermaid diagrams support to documentation
- Added support for rendering mermaid diagrams in documentation.
- Updated Docusaurus configuration to include mermaid theme and enable
  mermaid rendering in markdown files.
- Updated package.json dependencies to use compatible versions.
2025-06-16 14:04:10 +03:00
7de290ae55 Merge branch 'dify_installer' into development
* dify_installer:
  dify installer
  dify installer
  adding dify installer
  feat: Improve Dify installer
  adding dify installer
  dify installer
  adding dify installer
  feat: Improve Dify installer
  adding dify installer
2025-06-16 10:21:39 +02:00
fe161c5bea Merge branch 'development_fix_zinit' into development
* development_fix_zinit:
  feat: Fix type mismatch error in rpc.discover response handling
2025-06-16 10:21:26 +02:00
Mahmoud-Emad
fca7c7364a docs: Remove redundant line in README
- Removed a trailing empty line in the README file.
2025-06-16 11:09:16 +03:00
Omdanii
ef705d1be0 Merge pull request #91 from freeflowuniverse/development_mecelium_rpc_client
feat: Add Mycelium JSON-RPC client
2025-06-16 10:51:31 +03:00
Omdanii
3154733be1 Merge pull request #92 from freeflowuniverse/development_zinit_rpc_client
feat: Add Zinit JSON-RPC client
2025-06-16 10:51:13 +03:00
b285e85eb5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development
* 'development' of github.com:freeflowuniverse/herolib:
  feat: Improve ZinitClient and JSON-RPC client
2025-06-15 16:30:46 +02:00
89b7f0d465 ... 2025-06-15 16:30:40 +02:00
Mahmoud-Emad
256d4e9bca feat: Add Zinit RPC client
- Adds a new V client for interacting with the Zinit JSON-RPC API.
- Includes comprehensive example demonstrating all API methods.
- Provides type-safe structs and error handling.
- Implements all 18 methods of the Zinit JSON-RPC API.
2025-06-03 11:11:46 +03:00
Mahmoud-Emad
54f4e83627 Merge branch 'development' into development_mecelium_rpc_client 2025-06-02 17:05:15 +03:00
Mahmoud-Emad
f7a770989b feat: Improve ZinitClient and JSON-RPC client
- Enhanced error handling and response parsing in `ZinitClient`: The
  `discover` function now provides more robust error handling and
  response parsing, improving reliability.
- Improved code style and formatting: Minor formatting changes for
  better readability and maintainability.  The `ServiceConfig` and
  `ServiceConfigResponse` structs have been slightly restructured.
- Updated JSON-RPC client structure: The `Client` struct is now
  publicly mutable (`pub mut`), simplifying its use.  Removed
  unnecessary blank lines for improved code clarity.
2025-06-02 17:04:25 +03:00
Mahmoud-Emad
c5759ea30e feat: Add Mycelium JSON-RPC client
- Adds a new V language client for interacting with the Mycelium
  JSON-RPC admin API.
- Includes comprehensive example code demonstrating all API features.
- Implements all methods defined in the Mycelium JSON-RPC spec.
- Provides type-safe API with robust error handling.
- Uses HTTP transport for communication with the Mycelium node.
2025-06-02 16:48:59 +03:00
Mahmoud-Emad
aef9c84eb5 feat: Fix type mismatch error in rpc.discover response handling
- Correctly handle the complex JSON response of the `rpc.discover`
  method by using `map[string]string` instead of `string`.  This
  addresses a type mismatch error that prevented proper parsing of
  the API specification.
- Improve error handling and provide more informative output to the
  user during the API discovery process.
- Add detailed analysis and recommendations for handling complex JSON
  responses in similar scenarios.
2025-06-01 15:09:57 +03:00
d0baac83a9 ... 2025-05-31 16:02:52 +03:00
b6a2671665 ... 2025-05-31 12:45:05 +03:00
a96ae1252c ... 2025-05-31 11:17:56 +03:00
ac4db0f789 rpc example 2025-05-31 11:05:59 +03:00
37f9ab78ec format, implement unixsocket rpc 2025-05-31 08:26:03 +03:00
timurgordon
9b3ac150bd Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development 2025-05-29 23:10:17 +03:00
timurgordon
dd577d51b9 match template and models for docusaurus 2025-05-29 23:10:13 +03:00
92f9714229 ... 2025-05-29 20:22:52 +04:00
timurgordon
632a1c11c2 fix docusaurus to use siteconfig in heroscript 2025-05-29 17:31:51 +03:00
Peternashaat
63d41352bc adding dify installer 2025-05-29 13:23:41 +00:00
Peternashaat
da8eef3711 dify installer 2025-05-29 13:06:36 +00:00
Peternashaat
f0a4732206 dify installer 2025-05-29 13:09:46 +03:00
Peternashaat
1f053edefc adding dify installer 2025-05-29 13:09:46 +03:00
Mahmoud-Emad
f93db1d23c feat: Improve Dify installer
- Update installer configuration to be more robust and flexible.
- Remove unnecessary installation steps in the installer script.
- Improve the installer's ability to check if Dify is running.
- Refactor Dify installer actions for better code organization.
- Add build functionality to Dify installer.
2025-05-29 13:09:46 +03:00
Peternashaat
105611bbfb adding dify installer 2025-05-29 13:09:46 +03:00
Peternashaat
4977c6de30 dify installer 2025-05-28 07:07:53 +00:00
Peternashaat
eb956bca3d adding dify installer 2025-05-27 11:40:50 +00:00
Mahmoud-Emad
5e511367c3 feat: Improve Dify installer
- Update installer configuration to be more robust and flexible.
- Remove unnecessary installation steps in the installer script.
- Improve the installer's ability to check if Dify is running.
- Refactor Dify installer actions for better code organization.
- Add build functionality to Dify installer.
2025-05-27 12:33:25 +03:00
Peternashaat
484bfe393e adding dify installer 2025-05-27 09:05:08 +00:00
a1404584d6 ... 2025-05-25 06:47:17 +04:00
3ef1698c2c ... 2025-05-25 06:44:51 +04:00
a7fb704627 ... 2025-05-25 06:30:48 +04:00
91ba6001cb ... 2025-05-22 20:12:06 +04:00
345a79d8ff ... 2025-05-21 09:05:30 +04:00
15d886e5e9 ... 2025-05-21 09:00:30 +04:00
d6224d1e60 ... 2025-05-21 08:56:34 +04:00
83fb647ac3 ... 2025-05-21 08:37:02 +04:00
b410544ee1 ... 2025-05-21 08:30:30 +04:00
2d5d1befae ... 2025-05-20 09:48:56 +04:00
fd8b8c8f42 revert 2025-05-20 07:00:00 +04:00
8ffb8c8caf ... 2025-05-20 06:49:39 +04:00
b8b339b85c ... 2025-05-20 06:47:36 +04:00
0789a38ea9 Merge branch 'development' of github.com:freeflowuniverse/herolib into development
# Conflicts:
#	lib/web/docusaurus/dsite.v
2025-05-20 06:40:48 +04:00
995d3c3f6d ... 2025-05-20 06:39:40 +04:00
timurgordon
822b179ef4 docusaurus fixes 2025-05-19 11:19:19 +03:00
4691971bd0 ... 2025-05-19 09:07:38 +04:00
9226e8b490 ... 2025-05-19 08:56:15 +04:00
b7fc7734b6 ... 2025-05-19 08:52:09 +04:00
8749e3a8cb ... 2025-05-19 08:52:03 +04:00
61f9f2868a ... 2025-05-19 08:25:47 +04:00
97dfcbeb51 ... 2025-05-19 07:37:10 +04:00
238fabbcb2 ... 2025-05-19 07:09:27 +04:00
49542b4bff ... 2025-05-19 07:04:20 +04:00
46898112f5 ... 2025-05-19 06:39:52 +04:00
f9bdb22c67 ... 2025-05-19 05:44:23 +04:00
cb664b2115 ... 2025-05-18 10:58:49 +03:00
timurgordon
761b9e031e docusaurus fixes 2025-05-16 18:03:22 +03:00
timurgordon
0d8d11fe26 small heroscript docusaurus fixes 2025-05-15 13:29:29 +03:00
timurgordon
2d5fbd3337 docusaurus fixes and correct hero cli implementation 2025-05-13 01:54:47 +03:00
cd3c98280e ... 2025-05-09 12:53:08 +03:00
39c6c37dee bump version to 1.0.25 2025-05-04 20:23:12 +03:00
3438f74e60 ... 2025-05-04 19:31:46 +03:00
4f79712570 ... 2025-05-04 19:26:39 +03:00
8e85ce0678 ... 2025-05-04 15:46:59 +03:00
ff09e7bf1b ... 2025-05-04 08:23:34 +03:00
46e1c6706c ... 2025-05-04 08:19:47 +03:00
d8a59d0726 ... 2025-05-04 07:57:23 +03:00
108d2019cd ... 2025-05-04 07:14:18 +03:00
3682ef2420 ... 2025-05-04 06:53:12 +03:00
a066db6624 ... 2025-05-04 05:36:10 +03:00
7458d64c05 ... 2025-05-04 05:29:10 +03:00
2a1787f28f ... 2025-04-21 22:49:24 +04:00
de78c229ce ... 2025-04-21 05:37:45 +02:00
Timur Gordon
f386c67acf rhai generation wip 2025-04-20 01:50:48 +02:00
Timur Gordon
75f98bf349 rust and rhai mcp improvements 2025-04-17 21:19:18 +02:00
Timur Gordon
9870fcbc5d fix import paths 2025-04-13 13:40:35 +02:00
Timur Gordon
d2b8379505 move mcp to ai mod 2025-04-13 13:39:03 +02:00
Timur Gordon
2dcb97255c Merge branch 'development_kristof_ai' of github.com:freeflowuniverse/herolib into development_kristof_ai 2025-04-13 13:30:50 +02:00
Timur Gordon
f7dd227cd0 mcp refactor wip 2025-04-13 13:28:55 +02:00
e2c18c3a24 ... 2025-04-13 10:06:11 +02:00
1bc6c6eab8 ... 2025-04-13 10:03:16 +02:00
Timur Gordon
4b39b137de rhai wrapper ai gen wip 2025-04-13 00:35:29 +02:00
e5de293919 ... 2025-04-04 14:02:17 +02:00
8a10374570 Merge branch 'development_actions007_timur' into development
* development_actions007_timur:
  progress in mail code gen
  vcode and baobab mcps enhancements
  generator mcp integration progress
  fix encoding of non-generic jsonrpc response
  add baobab methods for easier mcp integration
  implement more code functionalities
  reorganize and sort mcps
  manual updates

# Conflicts:
#	lib/mcp/README.md
2025-04-01 09:53:51 +02:00
ad37a041ab ... 2025-04-01 09:52:52 +02:00
44daea4447 ... 2025-03-31 21:44:54 +02:00
6989a4da13 ... 2025-03-31 21:38:42 +02:00
de4583691c ... 2025-03-31 21:30:54 +02:00
d8c9b07a51 ... 2025-03-31 21:22:05 +02:00
54d31f40b2 ... 2025-03-31 09:53:49 +02:00
ec73b5ff34 Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development 2025-03-31 09:33:05 +02:00
9fcdcc3aff ... 2025-03-31 09:32:58 +02:00
05ab2b68f4 ... 2025-03-31 09:32:03 +02:00
79330ef8f5 ... 2025-03-29 13:48:24 +01:00
45ed369a78 ... 2025-03-29 11:13:16 +01:00
37c17fc7da ... 2025-03-29 08:23:33 +01:00
23640d2647 ... 2025-03-29 08:09:04 +01:00
be54ec8302 ... 2025-03-29 07:34:15 +01:00
638f81a781 ... 2025-03-29 07:21:50 +01:00
e00306b6f8 ... 2025-03-29 07:17:20 +01:00
3fec1c38a1 ,,, 2025-03-29 07:06:32 +01:00
edc9e3c150 Merge branch 'development_action007_mahmoud' into development
* development_action007_mahmoud:
  feat: Add Qdrant destroy action and improve installation robustness
  feat: Improve Qdrant installer and update health check port
  feat: Enhance Qdrant client example script
  feat: Add ignore rules for storage and initialization files
  feat: Add index management and scroll functionality to Qdrant client
2025-03-29 05:59:19 +01:00
a155122898 Merge branch 'development_actions007' into development
* development_actions007:
  add vfs method to local vfs
  add actor gen func
  mcp fixes
  code module fixes
  Fix sidebar paths to include top-level directory names in wiki configuration
2025-03-29 05:59:15 +01:00
f0552f38a0 ... 2025-03-29 05:58:09 +01:00
Timur Gordon
f99419371a progress in mail code gen 2025-03-28 20:52:19 +01:00
Timur Gordon
86d47c218b vcode and baobab mcps enhancements 2025-03-28 19:47:26 +01:00
Timur Gordon
bd5cafbad7 generator mcp integration progress 2025-03-28 12:38:57 +01:00
Timur Gordon
b71362eb9a fix encoding of non-generic jsonrpc response 2025-03-28 12:22:36 +01:00
Timur Gordon
673d982360 add baobab methods for easier mcp integration 2025-03-28 12:22:19 +01:00
Timur Gordon
712b46864a implement more code functionalities 2025-03-28 12:21:55 +01:00
Timur Gordon
186c3aae59 reorganize and sort mcps 2025-03-28 12:20:56 +01:00
Mahmoud Emad
0794fe948b feat: Add Qdrant destroy action and improve installation robustness
- Added a `destroy` action to completely remove Qdrant, including
  its data directory and zinit service. This improves the cleanup
  process and prevents leftover files.
- Improved the `installed` check to be more reliable by directly
  checking the Qdrant version without relying on sourcing the
  profile.  This avoids potential issues with profile setup.
- Added more informative logging messages throughout the process to
  improve user experience and debugging.
- Improved error handling and reporting.
- Use zinit to manage qdrant service to ensure proper stop and remove.
2025-03-27 16:40:25 +02:00
Mahmoud Emad
ba2d6e4310 feat: Improve Qdrant installer and update health check port
- Update Qdrant startup command to use screen for better management.
- Change health check URL to use the correct port (6336).
- Improve Qdrant installation check by directly checking the binary.
- Simplify Qdrant version check.
- Remove unnecessary imports and unused functions.
- Update Qdrant config file with correct HTTP and gRPC ports.
- Add symlink creation in /usr/local/bin for improved usability.
- Use ~/hero/bin for all platforms to avoid permission issues.
2025-03-27 13:18:41 +02:00
Timur Gordon
b9e5d14b48 Merge pull request #88 from freeflowuniverse/development_fix_mail_vfs
Get mail VFS component to work
2025-03-26 20:34:05 +01:00
Timur Gordon
bf26b0af1d manual updates 2025-03-26 19:31:07 +01:00
Timur Gordon
8e82b2865b add vfs method to local vfs 2025-03-26 19:30:28 +01:00
Timur Gordon
367340d69d Merge branch 'development_actions007' of github.com:freeflowuniverse/herolib into development_actions007 2025-03-26 19:27:57 +01:00
Timur Gordon
0b77c73809 add actor gen func 2025-03-26 19:26:45 +01:00
Timur Gordon
51b432d911 mcp fixes 2025-03-26 19:26:03 +01:00
Timur Gordon
f7a679b2a3 code module fixes 2025-03-26 19:25:32 +01:00
Mahmoud Emad
15c9d60760 Merge branch 'development' into development_action007_mahmoud 2025-03-26 14:32:46 +02:00
Mahmoud Emad
c69b53fd4e feat: Enhance Qdrant client example script
- Added comprehensive error handling to all Qdrant client calls,
  improving robustness and providing informative error messages.
- Included logging statements to track script execution and provide
  feedback on each step.
- Added checks for Qdrant server health and service information before
  proceeding with other operations.
- Expanded the script to demonstrate more Qdrant client functionalities,
  including listing collections, checking collection existence, and
  retrieving and upserting points.
- Improved clarity and readability of the script by adding comments and
  better structuring the code.
2025-03-26 14:30:22 +02:00
Timur Gordon
9cdab1f392 Fix sidebar paths to include top-level directory names in wiki configuration 2025-03-26 13:28:10 +01:00
Mahmoud Emad
34656cf1f9 feat: Add ignore rules for storage and initialization files
- Add `.gitignore` rules to exclude the `storage/` directory and
  `.qdrant-initialized` file.
2025-03-26 14:00:57 +02:00
Mahmoud Emad
cf98822749 feat: Add index management and scroll functionality to Qdrant client
- Add support for creating and deleting indexes in Qdrant collections.
- Implement scrolling functionality for retrieving points in batches.
- Enhance point retrieval with options for including payload and vector.
- Add comprehensive error handling for all new operations.
- Introduce new structures for parameters and responses.
2025-03-26 13:34:07 +02:00
Mahmoud Emad
2335d14623 refactor: Remove unnecessary import in local filesystem model
- Removed unused `os` import from `model_fsentry.v`. This
  improves code clarity and reduces unnecessary dependencies.

- Updated `vfs_implementation_test.v` to use the correct
  import paths for mail-related modules.
2025-03-26 12:15:38 +02:00
4a72698402 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-03-24 19:49:59 +01:00
fcb857f756 Merge pull request #86 from freeflowuniverse/development_fixci
Fix CI
2025-03-24 12:30:01 +01:00
Mahmoud Emad
ba07f85fd8 feat: Improve Redis startup handling in install script
- Handle Redis startup differently for GitHub Actions on macOS:
  Start redis directly instead of relying on `brew services`.
- Improved error handling for redis start failures.
- Enhanced logging for better troubleshooting.
2025-03-24 13:12:48 +02:00
Mahmoud Emad
7b621243d0 fix: Correct assertion in link_def_test.v
- Corrected the assertion in `test_empty()` to reflect the
  expected number of children in an empty document.
2025-03-24 12:56:17 +02:00
598b312140 ... 2025-03-24 06:44:39 +01:00
0df10f5cb3 Merge branch 'development_grid_deploy' into development
* development_grid_deploy:
  Update shebang
  Add simple filter example
2025-03-24 05:30:21 +01:00
2c748a9fc8 Merge branch 'development_actions007' into development
* development_actions007: (49 commits)
  ...
  bump version to 1.0.22
  add baobab mcp
  feat: Improve path normalization in `namefix`
  feat: Improve Qdrant client library
  test: Skip Jina client for now
  feat: Remove redundant Jina client code
  feat: Remove optional age field from Person struct
  feat: Improve DedupeStore and update tests
  test: Improve test coverage for fenced code block and list item parsers
  test: Improve test coverage for paragraph parsing
  test: Improve test coverage for markdown block parser
  test: Improve list parsing test cases
  feat: Improve Markdown parser list and table detection
  fix: Fix CI
  feat: Improve RadixTree debugging output
  refactor: Simplify ContactsDB methods
  feat: Add calendar VFS implementation
  feat: Add Contacts VFS module
  feat: Add contacts database and VFS implementation
  ...

# Conflicts:
#	.gitignore
#	lib/clients/qdrant/qdrant_client.v
#	lib/core/texttools/namefix.v
2025-03-24 05:30:15 +01:00
a2e1b4fb27 Merge branch 'development_action007_mahmoud' into development
* development_action007_mahmoud:
  feat: Add upsert points functionality to Qdrant client
  feat: Remove unnecessary delete_collection call in example
  feat: Add Qdrant client's retrieve_points functionality
  feat: Improve Qdrant client example
  ...
  feat: Add Jina server health check
  feat: Add multi-vector API support
  feat: Add classifier deletion functionality
  qdrant
  feat: Add classifier listing functionality
  feat: Enhance Jina client with improved classification API
  feat: Add train functionality to Jina client
  feat: Add Jina client training and classification features
  feat: Add reranking functionality to Jina client
  feat: Enhance Jina client with additional embedding parameters
  feat: Add create_embeddings function to Jina client
  fix: Ensure the code compiles and add a test example
  ...
  jina specs
2025-03-24 05:29:51 +01:00
9b0da9f245 Merge branch 'development_ourdb_new' into development
* development_ourdb_new: (115 commits)
  webdav completion wip
  Remove path from fsentry metadata, make vfs and webdav work again with fixes
  feat: Implement database synchronization using binary encoding
  Add documentation and tests for model_property.v
  feat: Add diagrams and README for OurDB syncer
  circle core objects work again
  ...
  ...
  radix tree has now prefix
  names
  models
  ...
  ....
  ...
  ...
  vfs_basics working
  vfs working
  ...
  ...
  ...
  ...

# Conflicts:
#	.gitignore
#	lib/code/generator/installer_client/ask.v
#	lib/code/generator/installer_client/factory.v
#	lib/code/generator/installer_client/generate.v
#	lib/code/generator/installer_client/model.v
#	lib/code/generator/installer_client/readme.md
#	lib/code/generator/installer_client/scanner.v
#	lib/code/generator/installer_client/templates/atemplate.yaml
#	lib/code/generator/installer_client/templates/heroscript_client
#	lib/code/generator/installer_client/templates/heroscript_installer
#	lib/code/generator/installer_client/templates/objname_actions.vtemplate
#	lib/code/generator/installer_client/templates/objname_factory_.vtemplate
#	lib/code/generator/installer_client/templates/objname_model.vtemplate
#	lib/code/generator/installer_client/templates/readme.md
#	lib/code/generator/installer_client_OLD/ask.v
#	lib/code/generator/installer_client_OLD/do.v
#	lib/code/generator/installer_client_OLD/generate.v
#	lib/code/generator/installer_client_OLD/model.v
#	lib/code/generator/installer_client_OLD/readme.md
#	lib/code/generator/installer_client_OLD/scanner.v
#	lib/code/generator/installer_client_OLD/templates/atemplate.yaml
#	lib/code/generator/installer_client_OLD/templates/heroscript_client
#	lib/code/generator/installer_client_OLD/templates/heroscript_installer
#	lib/code/generator/installer_client_OLD/templates/objname_actions.vtemplate
#	lib/code/generator/installer_client_OLD/templates/objname_factory_.vtemplate
#	lib/code/generator/installer_client_OLD/templates/objname_model.vtemplate
#	lib/code/generator/installer_client_OLD/templates/readme.md
#	lib/core/generator/installer_client_OLD/ask.v
#	lib/core/generator/installer_client_OLD/factory.v
#	lib/core/generator/installer_client_OLD/generate.v
#	lib/core/generator/installer_client_OLD/model.v
#	lib/core/generator/installer_client_OLD/readme.md
#	lib/core/generator/installer_client_OLD/scanner.v
#	lib/core/generator/installer_client_OLD/templates/atemplate.yaml
#	lib/core/generator/installer_client_OLD/templates/heroscript_client
#	lib/core/generator/installer_client_OLD/templates/heroscript_installer
#	lib/core/generator/installer_client_OLD/templates/objname_actions.vtemplate
#	lib/core/generator/installer_client_OLD/templates/objname_factory_.vtemplate
#	lib/core/generator/installer_client_OLD/templates/objname_model.vtemplate
#	lib/core/generator/installer_client_OLD/templates/readme.md
#	lib/core/texttools/namefix.v
2025-03-24 05:29:46 +01:00
5b9426ba11 ... 2025-03-23 12:27:31 +01:00
8b6ad4d076 bump version to 1.0.22 2025-03-23 12:14:26 +01:00
Timur Gordon
7d4565e56f Merge branch 'development_actions007' of github.com:freeflowuniverse/herolib into development_actions007 2025-03-21 03:28:18 +01:00
Timur Gordon
92cceeb64b add baobab mcp 2025-03-21 03:26:26 +01:00
Mahmoud Emad
3d90e39781 feat: Improve path normalization in namefix
- Enhance path normalization to handle various edge cases, including
  paths with special characters, multiple slashes, and mixed case.
- Improve the robustness and accuracy of path normalization.
- Add more comprehensive test cases for improved code coverage.
2025-03-19 16:40:42 +02:00
Mahmoud Emad
efbf00830a feat: Improve Qdrant client library
- Updated Qdrant client to use the correct response data field.
- Improved parameter names and formatting for clarity.
- Fixed inconsistencies in parameter naming and structure.

NOTE: Skipping both Jina and Qdrant client tests for now, as they are not fully prepared yet.
2025-03-19 15:58:35 +02:00
Mahmoud Emad
b9969c69fd test: Skip Jina client for now 2025-03-19 15:44:38 +02:00
Mahmoud Emad
15d998bf76 feat: Remove redundant Jina client code
- Removed the redundant `jina_client.v` file, as its functionality
  was duplicated in `rank_api.v`. This simplifies the codebase and
  eliminates potential inconsistencies.
2025-03-19 15:20:59 +02:00
Mahmoud Emad
8c966ae853 feat: Remove optional age field from Person struct
- Removed the optional nature of the `age` field in the `Person` struct.
2025-03-19 15:12:33 +02:00
Mahmoud Emad
3e10db326f feat: Improve DedupeStore and update tests
- Updated DedupeStore to use radixtree.get and radixtree.set
  for improved performance and clarity.
- Improved error handling and code readability in DedupeStore.
- Updated tests to reflect changes in DedupeStore.  Added more
  comprehensive test cases for edge conditions and error handling.
- Updated data structures in encoder_test.v for clarity and
  consistency.  Fixed a minor bug in the encoding of strings.
- Updated assertions in flist_test.v to reflect changes in the
  merged flist structure. Added more tests for edge conditions.
- Updated link_def_test.v to fix a bug in empty document handling.
- Added an empty file for ourdb_syncer/http/client.v to fix a
  missing file error.
- Commented out failing tests in ourdb_syncer/http/server_test.v
  to allow the build to pass until the server is implemented fully.
- Removed unused import in ourdb_syncer/streamer/db_sync.v and
  commented out existing code that might cause errors.
- Added more tests to streamer/sync_test.v to handle edge cases
  related to syncing.
- Updated model_aggregated.v to remove a possible error that
  may occur from null values in NodeInfo
- Updated play.v to prevent errors with null values in NodeInfo
2025-03-19 14:19:11 +02:00
Mahmoud Emad
dc6f1bdf52 test: Improve test coverage for fenced code block and list item parsers
- Added more comprehensive test cases for `parse_fenced_code_block`
  to handle various edge cases and improve reliability.
- Improved tests for `parse_list_item` to cover continuation
  lines, empty lines, and task list items more thoroughly.
- Updated existing tests to use more consistent formatting and
  assertions.  This improves readability and maintainability.
2025-03-18 10:46:39 +02:00
Mahmoud Emad
429f3b1fea test: Improve test coverage for paragraph parsing
- Add tests for paragraphs with newlines and multiple lines.
- Add tests for paragraphs ending at various block elements.
- Improve assertions in existing tests for clarity and accuracy.
2025-03-18 10:26:03 +02:00
Mahmoud Emad
70009f1846 test: Improve test coverage for markdown block parser
- Updated existing tests to improve clarity and accuracy.
- Added more comprehensive tests for various block types including
  headings, blockquotes, horizontal rules, code blocks, lists, and
  paragraphs.
2025-03-17 23:05:54 +02:00
Mahmoud Emad
5f9024c7bf test: Improve list parsing test cases
- Updated test cases to better cover edge cases in list parsing.
- Improved assertion checks for more precise validation of parsed lists.
- Added tests for lists with different markers and custom start numbers.
2025-03-17 22:57:56 +02:00
Mahmoud Emad
f2138f104f feat: Improve Markdown parser list and table detection
- Enhance the accuracy of list detection to correctly identify
  ordered, unordered, and task lists.
- Improve table detection by ensuring a valid separator line
  exists before confirming a table.
- Fix a bug in footnote definition detection to handle cases
  where the closing bracket is missing.
2025-03-17 22:46:26 +02:00
Mahmoud Emad
04ee73e8dd fix: Fix CI 2025-03-17 22:35:01 +02:00
Mahmoud Emad
bd83ad37bf feat: Improve RadixTree debugging output
- Enable printing of RadixTree debug information: The `debug_db` and
  `print_tree_from_node` functions now print detailed information
  about the RadixTree's internal structure, aiding in debugging.  This
  improves the developer experience by providing better tools for
  understanding and troubleshooting issues within the RadixTree.
- Remove unnecessary comments:  Unnecessary comments in the `debug_db`
  function have been removed to improve code clarity.
2025-03-17 22:23:14 +02:00
Mahmoud Emad
7b175c8804 refactor: Simplify ContactsDB methods
- Removed redundant and inefficient methods from ContactsDB.
- Streamlined contact retrieval and deletion processes.
- Improved search functionality for better performance.
2025-03-17 22:21:29 +02:00
Mahmoud Emad
22cbc806dc feat: Add calendar VFS implementation
- Adds a new virtual file system (VFS) implementation for calendar data.
- The calendar VFS provides a read-only view of calendar events,
  organized by calendar, date, title, and organizer.
- Includes new modules for factory, model, and implementation details.
- Adds unit tests to verify the functionality of the calendar VFS.
2025-03-17 22:12:57 +02:00
Mahmoud Emad
02e0a073aa feat: Add Contacts VFS module
- Adds a new VFS module for accessing contact data.
- Provides read-only access to contacts, organized by groups and
  browsable by name and email.
- Includes comprehensive documentation and unit tests.
2025-03-17 16:44:41 +02:00
Mahmoud Emad
b2e5a84ff9 Merge branch 'development_actions007' of https://github.com/freeflowuniverse/herolib into development_actions007 2025-03-17 15:58:29 +02:00
Mahmoud Emad
abd694015b feat: Add contacts database and VFS implementation
- Added a new contacts database (`ContactsDB`) to store contact
  information.  This improves data organization and allows for
  more efficient querying and manipulation of contact data.
- Implemented a virtual file system (VFS) for contacts
  (`vfs_contacts`). This provides a file-like interface to access
  and manage contact data, improving integration with existing
  file-system-based tools and workflows.  The VFS supports
  listing by group, by name, and by email.
- Added model structs for contacts, improving data organization and
  serialization.  This lays the foundation for more robust data
  handling and future expansion.
2025-03-17 15:58:20 +02:00
Timur Gordon
57d30eab2d fix example 2025-03-17 12:36:19 +01:00
b27f0a5017 ... 2025-03-17 11:13:39 +01:00
Timur Gordon
c47002430e implement mcc baobab generation example 2025-03-17 01:25:26 +01:00
Timur Gordon
bd3abade55 fix example compilation 2025-03-17 01:14:04 +01:00
Timur Gordon
ea0637423e Merge branch 'development' into development_actions007 2025-03-17 00:39:38 +01:00
Timur Gordon
a6756bfe5a Merge branch 'development' into development_actions007 2025-03-17 00:38:42 +01:00
Timur Gordon
4cdbc51343 Merge branch 'development_actions007' of github.com:freeflowuniverse/herolib into development_actions007 2025-03-17 00:37:25 +01:00
Timur Gordon
2e5210a0b7 Merge pull request #82 from freeflowuniverse/6-openrpc-code-generator
6 openrpc code generator
2025-03-17 00:35:37 +01:00
Timur Gordon
e8574383ee merge fixes from development 2025-03-17 00:30:20 +01:00
Timur Gordon
21da15da0a Merge branch 'development' into 6-openrpc-code-generator 2025-03-17 00:20:20 +01:00
Timur Gordon
dca1d877ac remove rclone tests 2025-03-17 00:16:30 +01:00
Timur Gordon
007f65c27e remove code folder from tests 2025-03-17 00:03:35 +01:00
Timur Gordon
ef572f402d lib tools 2025-03-16 23:34:18 +01:00
Timur Gordon
133e7c9809 Merge branch 'development' into 6-openrpc-code-generator 2025-03-16 19:15:04 +01:00
0d38c1b471 ... 2025-03-16 17:10:42 +01:00
cf7bfb7650 specs 2025-03-16 14:27:18 +01:00
Mahmoud Emad
228abe36a3 feat: Add upsert points functionality to Qdrant client
- Added `upsert_points` method to the Qdrant client to allow
  inserting and updating points in a collection. This enhances
  the client's ability to manage data efficiently.
- Improved error handling in Qdrant client methods to provide
  more informative error messages. This improves the user
  experience by providing better feedback on failed operations.
2025-03-16 14:58:23 +02:00
b48abc474c ... 2025-03-16 12:50:41 +01:00
Mahmoud Emad
c3fe788a5b feat: Remove unnecessary delete_collection call in example
- Removed the `delete_collection` call from the Qdrant example
  to avoid unnecessary collection deletion. This simplifies the
  example and prevents potential issues if the collection doesn't
  exist.
- Updated `RetrievePointsParams` struct to use optional parameters
  for `shard_key`, `with_payload`, and `with_vectors`. This
  improves flexibility and reduces the required parameters.  The
  change simplifies the request structure.
2025-03-16 11:56:55 +02:00
Mahmoud Emad
025e8fba69 feat: Add Qdrant client's retrieve_points functionality
- Added a new `retrieve_points` function to the Qdrant client
  to retrieve points by their IDs. This allows for efficient
  fetching of specific points from a collection.
- Renamed `is_exists` to `is_collection_exists` for clarity
  and consistency.
- Added  `RetrievePointsRequest`, `RetrievePointsParams`, and
  `RetrievePointsResponse` structs for better structured data.
2025-03-16 11:40:52 +02:00
672904d914 openapi 2025-03-16 10:34:57 +01:00
fac783c58d refactored and working 2025-03-16 09:32:03 +01:00
6e7843f368 ...... 2025-03-16 09:23:51 +01:00
6a555a5fe3 refactor 2025-03-16 08:41:45 +01:00
4796e4fe82 rrefactor 2025-03-16 08:02:29 +01:00
3b1068a3a8 ... 2025-03-15 19:55:48 +01:00
392f764acc Merge branch 'development_actions007' of github.com:freeflowuniverse/herolib into development_actions007 2025-03-15 19:32:52 +01:00
122cba9f6b ... 2025-03-15 19:32:38 +01:00
Timur Gordon
dc178f68c7 mcp fixes wip 2025-03-15 10:29:24 +01:00
Scott Yeager
59a0519b4e Update shebang 2025-03-14 19:19:14 -07:00
Scott Yeager
dfcaeec85f Add simple filter example 2025-03-14 19:19:02 -07:00
Timur Gordon
ef922d162e implement groq example using openai client 2025-03-14 23:07:13 +01:00
Timur Gordon
02e4ea180d merge v_do into overarching developer mcp project 2025-03-14 23:06:34 +01:00
Timur Gordon
8b9b0678b8 implement tools resources and prompts for mcp 2025-03-14 23:05:55 +01:00
Timur Gordon
475e812ba3 add mpc inspector example 2025-03-14 02:37:48 +01:00
Timur Gordon
0a953f2c09 add documentation 2025-03-14 02:37:26 +01:00
Timur Gordon
1e26162e00 fix jsonrpc serializations 2025-03-14 02:36:40 +01:00
Timur Gordon
dd68bf950c fix mpc and refactor to make generic server 2025-03-14 02:25:38 +01:00
Mahmoud Emad
e374520654 feat: Improve Qdrant client example
- Simplify Qdrant client example script, removing unnecessary
  boilerplate and improving readability.
- Add functions for creating, getting, deleting and listing
  collections.
- Add function to check collection existence.
- Improve error handling and logging.
2025-03-13 16:06:23 +02:00
Timur Gordon
47c95f76e9 Merge branch 'development' into development_actions007 2025-03-13 13:33:46 +01:00
Timur Gordon
918cfd83ec rename old installer client 2025-03-13 13:20:45 +01:00
Timur Gordon
83387c47ec add troubleshooting info for using tcc 2025-03-13 13:07:00 +01:00
Timur Gordon
f6c22c733b rename module imports 2025-03-13 12:59:21 +01:00
Timur Gordon
269d0474c5 add refactored schemas modules from 6-openrpc-code-generator branch 2025-03-13 12:41:35 +01:00
Timur Gordon
28359984ff add case fixing tools 2025-03-13 12:40:50 +01:00
Timur Gordon
c09e424890 refactor and reorganize code modules 2025-03-13 12:39:38 +01:00
a55af220bf ... 2025-03-13 10:56:55 +01:00
9c09af83a2 Merge branch 'development_action007_mahmoud' into development_actions007 2025-03-13 07:15:40 +01:00
e69d67d238 Merge branch 'development_grid_deploy' into development_actions007 2025-03-13 07:15:34 +01:00
01c6ea66ac Merge branch 'development_ourdb_new' into development_actions007 2025-03-13 07:15:27 +01:00
f9ea731a6e Merge branch 'development_actions007' into development_action007_mahmoud
# Conflicts:
#	lib/clients/jina/jina_client.v
#	lib/clients/jina/jina_factory_.v
#	lib/clients/jina/jina_model.v
#	lib/clients/jina/rank_api.v
2025-03-13 07:14:09 +01:00
timurgordon
a974091442 webdav completion wip 2025-03-13 04:34:10 +01:00
Scott Yeager
413b805823 Update caddy gateway example 2025-03-12 17:08:24 -07:00
Scott Yeager
46069ba924 Restore old json encoders 2025-03-12 17:08:00 -07:00
Scott Yeager
f3e7b979a5 QSFS not implemented 2025-03-12 15:53:57 -07:00
Scott Yeager
f6733a67af No const inside funcs 2025-03-12 15:51:59 -07:00
Scott Yeager
4988b241ef Json encoding doesn't mutate 2025-03-12 15:51:44 -07:00
Scott Yeager
7807a8e736 Target correct struct 2025-03-12 15:30:58 -07:00
5ba11aab46 ... 2025-03-12 16:36:17 +01:00
Mahmoud Emad
4abb46b4bf feat: Add Jina server health check
- Added a health check to the Jina client to verify server availability.
- Improved error handling and messaging for failed health checks.
- Enhanced client robustness by providing feedback on server status.
2025-03-12 16:38:38 +02:00
Mahmoud Emad
a7976c45f9 feat: Add multi-vector API support
- Added a new `create_multi_vector` function to the Jina client
  to support creating multi-vector embeddings.
- Added a new `multi_vector_api.v` file containing the
  implementation for the multi-vector API.
- Updated the `jina.vsh` example to demonstrate the usage of the
  new multi-vector API.
2025-03-12 16:16:37 +02:00
Mahmoud Emad
5194fabe62 feat: Add classifier deletion functionality
- Added `delete_classifier` function to delete a classifier by ID.
- Added corresponding unit tests for the new function.
- Updated the client example to demonstrate classifier deletion.
- Renamed `jina_client_test.v` to `api_test.v` for better organization.
- Renamed `model_embed.v` to `embeddings_api.v` for better organization.
- Refactored the embedding API to use enums for task and truncate types,
  and added error handling for invalid inputs.
2025-03-12 14:29:40 +02:00
timurgordon
ff430c2e4d Remove path from fsentry metadata, make vfs and webdav work again with fixes 2025-03-12 02:16:40 +01:00
1581628ea3 Merge branch 'development_action007_mahmoud' into development_actions007 2025-03-11 20:41:52 +01:00
237f9bd742 qdrant 2025-03-11 20:41:33 +01:00
Mahmoud Emad
cf27e7880e feat: Add classifier listing functionality
- Added a new function to list available classifiers.
- Extended the Jina client with `list_classifiers()` method.
- Added unit tests to verify the new functionality.
2025-03-11 21:38:06 +02:00
Mahmoud Emad
ad300c068f feat: Enhance Jina client with improved classification API
- Update `jina.vsh` example to showcase the new classification API
  with support for both text and image inputs. This improves
  the flexibility and usability of the client.
- Introduce new structs `TextDoc`, `ImageDoc`, `ClassificationInput`,
  `ClassificationOutput`, `ClassificationResult`, and `LabelScore`
  to represent data structures for classification requests and
  responses. This enhances code clarity and maintainability.
- Implement the `classify` function in `jina_client.v` to handle
  classification requests with support for text and image inputs,
  model selection, and label specification. This adds a crucial
  feature to the Jina client.
- Add comprehensive unit tests in `jina_client_test.v` to cover
  the new `classify` function's functionality. This ensures the
  correctness and robustness of the implemented feature.
- Remove redundant code related to old classification API and data
  structures from `model_embed.v`, `model_rank.v`, and
  `jina_client.v`. This streamlines the codebase and removes
  obsolete elements.
2025-03-11 21:11:04 +02:00
Mahmoud Emad
1a02dcaf0f feat: Add train functionality to Jina client
- Added a `train` method to the Jina client for training models.
- Added a test case to verify the `train` functionality.
2025-03-11 20:20:46 +02:00
Mahmoud Emad
9ecc2444aa feat: Add Jina client training and classification features
- Added `train` function to the Jina client for training
  classifiers.
- Added `ClassificationTrain` struct to define training
  parameters.
- Added `TrainingExample` struct to represent training data.
- Added `ClassificationTrainOutput` struct for the training
  response.
- Added a new `classification_api.v` module for classifier
  training functionalities.
- Added a new `classify` function to the Jina client for
  classification tasks (currently commented out).
2025-03-11 20:17:35 +02:00
Mahmoud Emad
0e1836c5d0 feat: Add reranking functionality to Jina client
- Added a new `rerank` function to the Jina client for reranking documents.
- Added a new `RerankParams` struct to define parameters for reranking.
- Added unit tests for the new `rerank` function.
- Updated the example script to demonstrate reranking.
- Improved error handling and added more comprehensive logging.
2025-03-11 19:27:01 +02:00
Mahmoud Emad
7965883744 feat: Enhance Jina client with additional embedding parameters
- Add `type_`, `truncate`, and `late_chunking` parameters to the
  `create_embeddings` function for finer control over embedding
  generation. This allows users to specify embedding type,
  truncation method, and whether to apply late chunking.
- Rename model parameter to `model` for clarity and consistency.
- Improve model enum naming for better readability and API consistency.
- Add unit tests for the `create_embeddings` function to ensure
  correct functionality and handle potential errors.
2025-03-11 17:45:55 +02:00
Mahmoud Emad
b006bb1e41 feat: Add create_embeddings function to Jina client
- Added a `create_embeddings` function to the Jina client to
  generate embeddings for given input texts.
- Improved the `create_embeddings` function input parameters
  for better flexibility and error handling.
- Updated `TextEmbeddingInput` struct to handle optional
  parameters for embedding type, truncation type, and late
  chunking.  This improves the flexibility of the embedding
  generation process.
2025-03-11 17:18:47 +02:00
Mahmoud Emad
27c9018c48 fix: Ensure the code compiles and add a test example
- Fixed compilation issues and ensured the code builds successfully
- Created an example to test the client functionality
- Started implementing additional endpoints
2025-03-11 16:49:39 +02:00
Mahmoud Emad
f1991d89b3 feat: Implement database synchronization using binary encoding
- Adds a new mechanism to synchronize the database efficiently
  by serializing updates using binary encoding.  This improves
  performance and reduces bandwidth usage compared to previous methods.

- Introduces `SyncRecord` struct to represent database updates
  for easier handling and serialization.

- Implements `push_updates` to serialize database changes since a
  given index, handling both initial and incremental syncs.

- Implements `sync_updates` to apply received serialized updates
  to the database, robustly handling errors and deletions.
2025-03-11 15:15:19 +02:00
9448ae85cf ... 2025-03-11 14:07:16 +01:00
timurgordon
a64e964d83 Add documentation and tests for model_property.v 2025-03-11 14:03:10 +01:00
Mahmoud Emad
5e321b6b0f feat: Add diagrams and README for OurDB syncer
- Added a diagram explaining the architecture of the OurDB
  syncer, clarifying the interaction between the HTTP server,
  master, and worker nodes.
- Added a README file providing a comprehensive overview of
  the OurDB syncer project, including its architecture,
  features, prerequisites, installation instructions, and usage
  examples.
- Removed outdated Mycelium_Streamer documentation as it's no
  longer relevant to the current project structure.
- Created example scripts for running the database, master,
  and worker components, simplifying the setup and execution of
  the system.
- Added HTTP client and server documentation, clarifying their
  functionalities and interaction with the OurDB system.
2025-03-11 14:49:43 +02:00
b1453e3580 jina specs 2025-03-11 11:23:58 +01:00
3da895083b circle core objects work again 2025-03-11 08:49:47 +01:00
ac583741a4 ... 2025-03-11 08:27:46 +01:00
4358ba6471 ... 2025-03-10 14:31:26 +01:00
46afb63f31 radix tree has now prefix 2025-03-10 09:05:57 +01:00
f773ce168e names 2025-03-10 01:29:15 +01:00
aa79df1fcd models 2025-03-10 01:07:23 +01:00
420c9cb9e5 ... 2025-03-10 00:50:08 +01:00
83d935930f .... 2025-03-10 00:31:31 +01:00
2e2c94e897 ... 2025-03-09 22:56:33 +01:00
a96903da0e ... 2025-03-09 21:17:32 +01:00
3dbcf00e9f vfs_basics working 2025-03-09 20:14:08 +01:00
708147435e vfs working 2025-03-09 20:01:00 +01:00
26289bb00f Merge branch 'development_actions007' into development_ourdb_new
# Conflicts:
#	lib/data/dedupestor/dedupestor.v
#	lib/data/dedupestor/dedupestor_test.v
2025-03-09 19:07:12 +01:00
1489b9f44f ... 2025-03-09 18:34:58 +01:00
e4045ef179 Merge branch 'development_grid_deploy' into development_actions007 2025-03-09 17:40:20 +01:00
13f482fa12 Merge branch 'development_bizmodel' into development_grid_deploy 2025-03-09 17:38:23 +01:00
3e2013576f ... 2025-03-09 17:37:37 +01:00
e5aa8bca09 Merge branch 'development_bizmodel' of github.com:freeflowuniverse/herolib into development_bizmodel 2025-03-09 17:25:22 +01:00
4dd3908ff7 ... 2025-03-09 17:24:44 +01:00
09f388e2ff ... 2025-03-09 15:59:57 +01:00
baecb9bbe4 Merge branch 'development_grid_deploy' into development_generator_docusaurus
* development_grid_deploy:
  Restore all needed for basic deployments, add vm example
  Update griddriver to use prebuilt binary
  Return Deployer and update references
  Update module paths
  Update grid proxy module path
  commetbft
  cleanup client for grid
2025-03-08 10:56:16 +01:00
2c5986295e Merge branch 'development_bizmodel' into development_generator_docusaurus
* development_bizmodel: (93 commits)
  s
  Revert "test: add cmdline parser tests"
  test: add cmdline parser tests
  markdown code
  ...
  revert
  ...
  ..deployments
  ...
  bump version to 1.0.21
  ...
  bump version to 1.0.20
  ...
  fix tests and example
  bump version to 1.0.19
  bump version to 1.0.18
  bump version to 1.0.17
  ...
  ...
  bump version to 1.0.16
  ...

# Conflicts:
#	lib/web/docusaurus/config.v
2025-03-08 10:55:58 +01:00
126f23dfa2 s 2025-03-08 08:56:14 +01:00
Scott Yeager
407f3f85bc Restore all needed for basic deployments, add vm example 2025-03-07 18:09:28 -08:00
timurgordon
94da4fff5e fix delete data decoding 2025-03-08 01:55:10 +01:00
Scott Yeager
0fa54f1354 Update griddriver to use prebuilt binary 2025-03-07 16:54:44 -08:00
timurgordon
80677f7177 lock support fixes 2025-03-08 01:53:39 +01:00
timurgordon
01cac0f741 fixes to chunked file data processing 2025-03-08 01:52:53 +01:00
Scott Yeager
30546a34f9 Return Deployer and update references 2025-03-07 16:39:52 -08:00
Scott Yeager
0ccf317564 Update module paths 2025-03-07 16:36:01 -08:00
Scott Yeager
0c49e83a68 Update grid proxy module path 2025-03-07 16:00:15 -08:00
51db8257f5 Revert "test: add cmdline parser tests"
This reverts commit ecc2977581.
2025-03-07 21:56:33 +01:00
ecc2977581 test: add cmdline parser tests 2025-03-07 21:54:04 +01:00
ffafef0c88 markdown code 2025-03-07 21:03:55 +01:00
ca3bac1d76 ... 2025-03-07 20:02:37 +01:00
43f7bc7943 revert 2025-03-07 18:36:45 +01:00
b3555aa54e ... 2025-03-07 10:09:39 +01:00
Scott Yeager
54dc3d3f1f Update griddriver to use prebuilt binary 2025-03-06 18:26:33 -08:00
timurgordon
afad769066 Merge branch 'development_ourdb_new' of https://github.com/freeflowuniverse/herolib into development_ourdb_new 2025-03-06 15:50:03 +01:00
timurgordon
2da37ee4a5 fix propfind request handling and parsing, and file sending 2025-03-06 15:50:00 +01:00
timurgordon
90c81a1234 add path to fsentry metadata 2025-03-06 15:48:37 +01:00
Mahmoud Emad
34ea12ca23 Merge branch 'development_ourdb_new' of https://github.com/freeflowuniverse/herolib into development_ourdb_new 2025-03-06 13:33:07 +02:00
Mahmoud Emad
d2c1be5396 feat: Add basic key-value store example
- Added a client and server for a simple key-value store.
- Improved documentation with client and server usage examples.
- Created client and server implementations using the V language.
2025-03-06 13:32:57 +02:00
timurgordon
fe934bba36 webdav fixes 2025-03-06 01:24:04 +01:00
timurgordon
b01e40da40 fix vfsimplemetation, add path metadata 2025-03-06 01:23:17 +01:00
Mahmoud Emad
ae7e7ecb84 feat: Add OurDB key-value store server
- Adds a new lightweight key-value store server implemented in V.
- Includes basic CRUD operations (`set`, `get`, `delete`).
- Provides configurable host and operation restrictions for security.
- Offers middleware for logging and request validation.
- Supports incremental mode for automatic ID generation.
- Includes comprehensive documentation and example usage.
- Adds unit tests to ensure functionality and stability.
2025-03-05 23:02:35 +02:00
Mahmoud Emad
fdf540cbd0 docs: Add documentation for Mycelium Streamer example
- Added a new documentation file explaining the Mycelium Streamer
  example, covering setup, prerequisites, and execution.
- This provides users with clear instructions on how to use the
  example project.
2025-03-04 21:34:02 +02:00
timurgordon
7cb26e5569 fix webdav lock handling and xlm parsing 2025-03-04 00:50:40 +01:00
timurgordon
913b0cb790 fix vfs_db and add metadata_db 2025-03-04 00:49:57 +01:00
Mahmoud Emad
485b47d145 feat: Improve MyceliumStreamer worker communication
- Add worker registration to MyceliumStreamer:  Allows for explicit
  addition of workers, improving management and control.
- Simplify worker message handling: Streamlines message processing
  for increased efficiency and readability.  Removes unnecessary
  logging and simplifies message routing.
- Remove redundant message handling: Eliminates duplicate code
  paths for cleaner and more maintainable code.
- Improve worker data retrieval: Facilitates direct data retrieval
  from workers, enhancing efficiency and reliability.
2025-03-04 00:40:05 +02:00
fb9c9b8070 commetbft 2025-03-03 17:32:28 -05:00
Mahmoud Emad
5b69f935a5 feat: Improve MyceliumStreamer to read from workers
- Allow reading data directly from specific workers by specifying
  their public key in `MyceliumStreamer.read()`. This improves
  data retrieval flexibility and allows for distributed data access.
- Add master data reading to ensure data consistency and allow
  comparison between master and worker data.  This helps debug and
  verify data replication.
- Implement JSON encoding/decoding for database transfer between
  master and worker nodes. This enables efficient and structured
  data exchange.
2025-03-03 22:44:53 +02:00
Mahmoud Emad
9dbc36d634 feat: Enhance Deduplicated Mycelium example with multiple workers
- Updated the master node to support multiple workers, allowing for
  increased scalability and redundancy.
- Modified the worker node to simplify initialization and connection
  to the master.
- Added logging statements for better monitoring and debugging.
2025-03-03 17:34:41 +02:00
Mahmoud Emad
42b0c4d48f refactor: Improve MyceliumStreamer's message handling
- Removed unnecessary test data from `deduped_mycelium_master.vsh`.
- Simplified `MyceliumStreamer.listen()` to efficiently handle
  incoming messages, removing redundant code and improving readability.
- Enhanced error handling in `MyceliumStreamer.listen()` for more robust
  operation.
2025-03-03 16:58:13 +02:00
Mahmoud Emad
5343d9bff6 feat: Add unique ID to MyceliumStreamer
- Added a unique ID to the MyceliumStreamer struct for better
  identification of individual streamer instances.
2025-03-03 14:21:25 +02:00
Mahmoud Emad
eb47c8490d feat: Enhance Mycelium streamer with worker support
- Added worker ID to master and worker configurations for improved
  identification and management.
- Implemented worker registration and data synchronization mechanisms
  to enable distributed data access.
- Added a read function to retrieve data from specific workers,
  enhancing data access flexibility.
- Improved logging for better monitoring and debugging of the system.
2025-03-03 14:18:55 +02:00
Mahmoud Emad
1de9be2a8a feat: Improve Mycelium Streamer functionality
- Added continuous data writing and verification to the master node
  to ensure data persistence and integrity.
- Simplified worker update handling in the `listen` function for
  better efficiency and error handling.  The previous implementation
  had unnecessary complexity and potential for hangs.
2025-03-03 13:48:55 +02:00
Mahmoud Emad
d852ecc5b1 feat: Improve Mycelium client and streamer
- Changed Mycelium worker port to avoid conflict with master.
- Added debug print statements to Mycelium client for better troubleshooting.
- Removed unnecessary `SyncData` struct, simplifying data handling.
- Updated data encoding/decoding to directly use base64 for efficiency.
- Clarified message topic names for better understanding.
2025-03-03 12:50:59 +02:00
Mahmoud Emad
368edcd93a feat: Implement distributed database using Mycelium
- Refactor database streamer to support multiple workers.
- Add master node to manage and distribute data updates.
- Implement worker nodes to receive and apply updates.
- Remove unnecessary slave node.
- Improve error handling and logging.
- Use base64 encoding for JSON compatibility in data transfer.
2025-03-03 12:19:03 +02:00
Mahmoud Emad
71906fd891 feat: Improve Mycelium slave and streamer communication
- Renamed the topic for database synchronization messages from
  'db_sync' to 'sync_db' for clarity.
- Updated the Mycelium slave to decode base64 payload before
  processing and to log received messages and their source.
- Added logging to the Mycelium streamer to track sent messages.
- Added a new feature to retrieve and log the last index from the
  worker after syncing updates.  This improves monitoring and
  debugging capabilities.
2025-03-02 22:01:44 +02:00
Mahmoud Emad
dbd187a017 feat: Streamline mycelium example and add server port config
- Remove unnecessary code from the example to improve clarity.
- Add a configurable server port to the `MyceliumStreamer`.
2025-03-02 21:47:12 +02:00
Mahmoud Emad
52a3546325 feat: Improve Mycelium-based data synchronization
- Refactor data synchronization logic to use Mycelium messages for
  efficient updates between master and worker nodes.  This removes
  the previous inefficient polling method and simplifies the code.
- Update the slave node to receive and apply updates from the
  master, improving synchronization efficiency and robustness.
- Change the default slave port to 9000.
- Rename `db` variable to `worker` for clarity.
2025-03-02 21:40:37 +02:00
Mahmoud Emad
a23eb0ff0b feat: Implement MyceliumStreamer for distributed data synchronization
- Introduces `MyceliumStreamer` for synchronizing data across a
  Mycelium network, enabling distributed data access.
- Allows adding multiple worker nodes to the streamer for data
  replication and redundancy.
- Provides `write` and `read` methods for seamless data
  management across nodes.
2025-03-02 20:25:29 +02:00
Mahmoud Emad
b40c366335 feat: Update slave communication in mycelium example
- Rename `get_last_id` to `get_last_index` for clarity.
- Correctly send sync message to the slave instead of master.
2025-03-02 15:17:00 +02:00
Mahmoud Emad
d2ad18e8ec feat: Implement two-way communication between master and slave nodes
- Added message reply functionality to both master and slave
  nodes to enable a two-way communication flow for database
  synchronization. This improves the robustness and reliability
  of the database synchronization process.
- Enhanced the database synchronization process by allowing the
  slave node to send the last inserted record ID to the master
  node.  This provides better tracking of data changes.
2025-03-02 15:14:51 +02:00
Mahmoud Emad
9b737c9280 feat: Improve Mycelium example with bidirectional communication
- Remove unnecessary public key printing in master node.
- Use variable for slave public key in master node.
- Add message receiving functionality to master node.
- Remove redundant sending logic from slave node.
2025-03-02 14:57:33 +02:00
834c413cfc Merge branch 'development' of github.com:freeflowuniverse/herolib into development
* 'development' of github.com:freeflowuniverse/herolib:
  better heroscript encoding and support for ourtime
2025-03-01 05:50:43 -07:00
da9965bdc6 ... 2025-03-01 05:50:36 -07:00
6bbaa0d1f7 cleanup client for grid 2025-02-28 07:50:13 -07:00
834f612bfe ..deployments 2025-02-28 07:40:10 -07:00
timurgordon
171e54a68c added vfs_db examples with ourdb & dedupstore 2025-02-28 03:16:46 +03:00
timurgordon
a690f98cc1 fine tuned vfs_db to work with dedupe db 2025-02-28 03:15:47 +03:00
timurgordon
400ea6e80e moved webdav to dav 2025-02-28 03:15:05 +03:00
timurgordon
84c19ca9a4 implemented updates for radix tree 2025-02-28 03:14:44 +03:00
timurgordon
3b7ec028f9 created vscode extension for ourdb decoded viewing 2025-02-28 03:14:08 +03:00
83f7bf41e3 Merge branch 'development' into development_bizmodel 2025-02-27 06:40:38 -07:00
634b8c5bad Merge branch 'development_kristof10' into development
# Conflicts:
#	lib/data/encoderhero/encoder.v
2025-02-27 06:39:17 -07:00
4aabc8d1b0 Merge branch 'development' into development_bizmodel
# Conflicts:
#	cli/hero.v
#	install_hero.sh
2025-02-27 06:36:16 -07:00
75255d8cd0 ... 2025-02-27 06:34:24 -07:00
Mahmoud Emad
a0b53126ca feat: Add example scripts for Mycelium inter-node communication
- Added `deduped_mycelium_master.vsh` to demonstrate a master node
  sending data.
- Added `deduped_mycelium_slave.vsh` to demonstrate a slave node
  receiving data.  These scripts showcase basic inter-node
  communication using the Mycelium library.
2025-02-27 14:46:57 +02:00
Mahmoud Emad
38cd933d41 feat: Update import path for mycelium installer
- Correct the import path for the mycelium installer module.
2025-02-27 12:22:47 +02:00
Mahmoud Emad
2da014c407 Merge branch 'development_ourdb_new' of https://github.com/freeflowuniverse/herolib into development_ourdb_new 2025-02-27 12:09:50 +02:00
Mahmoud Emad
9d1752f4ed feat: Improve database synchronization and add deleted record handling
- Add `find_last_entry` function to efficiently determine the
  highest used ID in the lookup table, improving performance
  for non-incremental databases.
- Implement deleted record handling using a special marker,
  allowing for efficient tracking and synchronization of
  deleted entries.
- Enhance `get_last_index` to handle both incremental and
  non-incremental modes correctly, providing a unified
  interface for retrieving the last index.
- Modify `push_updates` to correctly handle initial syncs and
  account for deleted records during synchronization.
- Update `sync_updates` to correctly handle empty update data,
  indicating a record deletion.
- Add comprehensive tests for database synchronization, including
  edge cases like empty updates, invalid data, and various
  scenarios with deleted records.
2025-02-27 12:09:33 +02:00
timurgordon
d06a806184 isolate vfs's and improve documentation 2025-02-27 11:42:46 +03:00
timurgordon
fe1becabaf fix and refactor vfs modules to merge ourdb implementations into generic vfs_db and separate vfs_local 2025-02-27 11:12:17 +03:00
2d0d196cd3 bump version to 1.0.21 2025-02-26 18:09:19 -07:00
37573b0b59 ... 2025-02-26 18:09:10 -07:00
35dace9155 bump version to 1.0.20 2025-02-26 18:08:29 -07:00
69e7c1cce9 Merge branch 'development_bizmodel' of github.com:freeflowuniverse/herolib into development_bizmodel 2025-02-26 18:07:25 -07:00
d21e71e615 ... 2025-02-26 18:07:24 -07:00
timurgordon
972bb9f755 implement better reference tracking for deduped files 2025-02-26 22:24:40 +03:00
timurgordon
a798b2347f start implementing ourdb sync 2025-02-26 12:29:27 +03:00
timurgordon
17979b4fde start implementing vfs with dedupe ourdb driver 2025-02-26 03:12:09 +03:00
timurgordon
68d25d3622 move in radixtree and dedupstore 2025-02-26 02:38:38 +03:00
timurgordon
f38d4249ef fix tests and example 2025-02-26 02:31:04 +03:00
ded4a0b102 bump version to 1.0.19 2025-02-25 14:17:31 -07:00
6184441706 Merge branch 'development' into development_bizmodel
* development:
  s
  bump version to 1.0.14
  ...

# Conflicts:
#	cli/hero.v
#	install_hero.sh
#	test_basic.vsh
2025-02-25 14:16:54 -07:00
293dc3f1ac bump version to 1.0.18 2025-02-25 13:18:39 -07:00
6492e42358 bump version to 1.0.17 2025-02-25 11:41:01 -07:00
4aaf1bd6db ... 2025-02-25 11:36:01 -07:00
a56a251d7f ... 2025-02-25 11:17:11 -07:00
f306ff728f bump version to 1.0.16 2025-02-25 11:13:07 -07:00
a10a6d6507 bump version to 1.0.15 2025-02-25 10:22:29 -07:00
Mahmoud Emad
59efa18bce feat: Uncomment lib/vfs path in test_basic.vsh
- Uncommented the path `lib/vfs` in `test_basic.vsh`.
- This path was commented out, and is needed after merging PR #68.
2025-02-25 13:25:08 +02:00
Mahmoud Emad
4ed80481aa test: Add more comprehensive tests for vfsourdb
- Added tests to verify directory listing functionality after
  creating and moving directories.
- Improved test coverage for file operations within directories.
- Ensured tests accurately reflect the updated behavior of
  `dir_list` function.
2025-02-25 13:13:41 +02:00
fff14183a4 .... 2025-02-24 06:34:38 -07:00
Mahmoud Emad
1f58676278 Merge branch 'development' into development_vfs 2025-02-24 15:32:30 +02:00
Mahmoud Emad
b67db23e07 feat: Improve VFS rename and copy operations
- Return FSEntry from `rename` and `copy` operations in VFS
  to provide more information about the result.  This allows
  access to metadata after a successful rename or copy.

- Update `LocalVFS` and `NestedVFS` implementations to return
  the appropriate FSEntry objects after successful rename and
  copy operations.
2025-02-24 14:03:41 +02:00
Mahmoud Emad
4fe1e70881 feat: Improve directory copy functionality and add error handling
- Refactor `Directory.copy()` to use a struct for arguments,
  improving readability and maintainability.
- Add comprehensive error handling to `Directory.copy()`,
  preventing unexpected failures and providing informative error
  messages.  This includes handling cases where the source is not
  a directory, or a source and destination path are the same.
- Implement recursive copying of directory contents, including files
  and symlinks.
- Add unit tests to cover the new `copy` functionality and error
  handling.
- Update `OurDBVFS.copy()` to utilize the improved `Directory.copy()`
  method and add input validation.
2025-02-24 13:55:16 +02:00
Mahmoud Emad
988602f90f feat: Enhance VFS with file and directory manipulation
- Add `move`, `copy`, and `rename` methods to `Directory` and `File`
  for improved file system management.
- Refactor `move` operation in `Directory` for better error handling and
  support for recursive directory moves.  Improves robustness and
  clarity of the move operation.
- Implement a `MoveDirArgs` struct to improve the clarity and
  maintainability of the `move` function arguments.
- Remove unnecessary `save()` calls for improved performance.
- Add comprehensive tests for the new and improved file system
  operations.  Ensures reliability and correctness of the added
  functionality.
2025-02-24 13:10:34 +02:00
6a2e143b98 ... 2025-02-24 02:47:59 -07:00
Mahmoud Emad
306de32de8 feat: Implement rename functionality for directories and files
- Added `rename` method to `Directory` struct to rename files and
  directories, updating metadata and timestamps.  This improves
  file management capabilities.
- Added `rename` method to `OurDBVFS` to provide a unified
  interface for renaming files and directories across the VFS. This
  allows for consistent file system operations.
- Added tests for the new rename functionality in `vfsourdb_test.v`
  to ensure correctness and robustness. This enhances confidence in
  the implementation.
2025-02-23 22:35:37 +02:00
Mahmoud Emad
c0b57e2a01 feat: Add file move operation
- Added `move` operation to `Directory` to rename files and
  directories within the same directory.  This improves
  file management capabilities.
- Updated `VFS` interface to include `move` function with
  FSEntry return type for consistency. This allows for
  retrieving metadata of the moved file/directory.
- Implemented `move` operation for `LocalVFS`, `OurDBVFS`, and
  `NestedVFS`.  This provides consistent file move
  functionality across different VFS implementations.
- Added tests for the new move functionality in
  `vfsourdb_test.v`. This ensures the correct behavior of the
  new feature.
2025-02-23 22:26:05 +02:00
Mahmoud Emad
aeeacc877b feat: Improve VFS handling and authentication middleware
- Remove unnecessary debug print statements in VFS and WebDAV
  middleware for cleaner code.
- Fix a bug in `OurDBVFS.exists` to correctly handle root and
  current directory paths.
- Enhance `OurDBVFS.get_entry` to handle '.' path correctly.
- Improve WebDAV authentication middleware to gracefully handle
  unauthenticated requests.
2025-02-23 14:33:18 +02:00
6820a7e9c8 ... 2025-02-23 10:34:18 +00:00
1c7621f20a docusaurus 2025-02-23 07:42:16 +03:00
5263798b11 s 2025-02-22 19:03:45 +03:00
timurgordon
0d96c5fc65 fix webdav server implementation and logic 2025-02-22 01:40:46 +03:00
timurgordon
6b0cf48292 implement webdav server in veb 2025-02-20 19:04:07 +03:00
timurgordon
9160e95e4a fix circular printing 2025-02-20 18:03:30 +03:00
Mahmoud Emad
296cb9adf5 feat: Add WebDAV support and tests
- Added basic WebDAV functionality for interacting with the
  underlying VFS.
- Created unit tests to verify WebDAV methods.
- Improved OurDBFS implementation by adding skip attribute to
  myvfs field.
2025-02-20 16:50:11 +02:00
timurgordon
88fe8f503f rename example output dir 2025-02-20 08:15:49 +03:00
timurgordon
a26bb56b15 create missing dir 2025-02-20 08:12:48 +03:00
timurgordon
2f54f05cfd fix bizmodel docs export 2025-02-20 08:10:49 +03:00
timurgordon
f61d6808e8 fix compilation 2025-02-20 06:59:08 +03:00
timurgordon
4719876feb get example to work with echarts 2025-02-20 06:43:26 +03:00
timurgordon
975cca77b1 decouple charts from wiki representation 2025-02-20 06:41:17 +03:00
timurgordon
eb80294b0a improve echart exporting 2025-02-20 06:40:19 +03:00
timurgordon
0704c9421d make getters immutable 2025-02-20 06:38:42 +03:00
Mahmoud Emad
f08af0e2c5 refactor: Improve WebDAV VFS implementation
- Removed unnecessary dependencies and improved code structure in `webdav` module.
- Updated VFS configuration to use global VFS instance for WebDAV app.
- Renamed example VFS file to reflect WebDAV functionality.
- Removed redundant code and simplified app initialization.
- Used the vfs interface to interact with files and dirs.
2025-02-19 22:57:15 +02:00
29c2fccbe5 bump version to 1.0.14 2025-02-19 16:14:20 +03:00
975c07fc2e ... 2025-02-19 16:09:11 +03:00
timurgordon
814b61f25e Merge branch 'development_installers' into development_bizmodel 2025-02-19 13:30:34 +03:00
timurgordon
1c264815c3 update example 2025-02-19 13:28:38 +03:00
Mahmoud Emad
33150846cc feat: Add move operation and file type checks
- Add `move` operation to the VFS interface and implementations.
  This allows for moving files and directories within the VFS.
- Add `is_dir`, `is_file`, and `is_symlink` methods to the
  `FSEntry` interface and implementations.  This allows for
  robust file type checking before performing operations.
2025-02-19 12:10:52 +02:00
ff45beac09 ... 2025-02-19 09:46:41 +03:00
24eb709293 fixes docusaurus 2025-02-19 09:44:03 +03:00
49e2146152 Merge branch 'development_bizmodel' into development_installers 2025-02-19 07:15:28 +03:00
cdaf64b3cf git print better 2025-02-19 07:15:14 +03:00
49af31776e gitools 2025-02-19 05:53:29 +03:00
0880823576 Merge branch 'development_installers' of github.com:freeflowuniverse/herolib into development_installers 2025-02-19 05:10:45 +03:00
1fa1ecb8ec Merge branch 'development_fix' into development_installers 2025-02-19 05:09:56 +03:00
d6108c9836 Merge branch 'development' into development_installers 2025-02-19 05:08:41 +03:00
Mahmoud Emad
2e7efdf229 ci: Remove the vfs test from the CI to check what is wrong 2025-02-19 01:54:39 +02:00
Mahmoud Emad
f47703f599 feat: Simplify OurDB.set function
- Remove unnecessary nested `if` statement in `OurDB.set`.
- Improve code readability and maintainability.
2025-02-19 01:18:23 +02:00
Mahmoud Emad
383fc9fade feat: Improve OurDBFS ID generation and data persistence
- Use a counter for consistent ID generation in OurDBFS: This
  eliminates reliance on timestamps, preventing ID collisions and
  improving data integrity.
- Refactor save methods to directly use the VFS's save_entry
  function: This simplifies the code and reduces redundancy across
  different file system entity types (Directory, File, Symlink).
- Update `save_entry` in OurDBFS to use IDs for database updates:
  This ensures data is correctly updated in the database based on the
  unique ID of each entry.  This also fixes potential issues with
  overwriting data.
2025-02-19 01:12:19 +02:00
timurgordon
cc344fa60e bizmodel example report export wip 2025-02-18 23:23:26 +03:00
Mahmoud Emad
4691046d5f refactor: Remove unnecessary debug print statements
- Removed numerous println statements throughout the codebase.
2025-02-18 17:45:29 +02:00
Mahmoud Emad
7b453962ca feat: Enhance WebDAV server and add VFS encoder/decoder tests
- Add user authentication to the WebDAV server using a user
  database.
- Implement encoding and decoding functionality for directories,
  files, and symlinks in the OurDBFS VFS.
- Add comprehensive unit tests for the encoder and decoder
  functions.
- Improve the OurDBFS factory method to handle directory creation
  more robustly using pathlib.
- Add `delete` and `link_delete` methods to the `NestedVFS` and
  `OurDBVFS` implementations (though currently unimplemented).
- Improve WebDAV file handling to correctly determine and set the
  content type.  The previous implementation was incomplete and
  returned a dummy response.
- Update VFS test to actually test functionality.
- Remove unnecessary `root_dir` parameter from the WebDAV app.
2025-02-18 17:40:37 +02:00
Mahmoud Emad
528d594056 feat: Improve OurDBFS file system persistence and ID generation
- Fixed ID generation for files and directories in OurDBFS,
  preventing collisions and improving data integrity.  This
  ensures that IDs are consistently and uniquely assigned.
- Updated save methods to correctly update the `metadata.id`
  field across all FSEntry types (File, Directory, Symlink).
  This change solves a previous issue where IDs weren't being
  properly persisted.
- Added incremental mode to OurDB, improving performance for
  large datasets.  This allows for more efficient updates
  instead of full overwrites.
2025-02-18 13:27:22 +00:00
timurgordon
6305cf159e small fixes on example 2025-02-18 05:22:38 +03:00
timurgordon
5e468359a1 start implementing docusaurus bizmodel exporting 2025-02-18 05:09:56 +03:00
timurgordon
2317dd2d4c tidy up action processing & playing 2025-02-18 05:09:06 +03:00
timurgordon
b92647c52e fix sheet processing issues 2025-02-18 05:07:56 +03:00
Mahmoud Emad
906f13b562 feat: Refactor WebDAV server to use VFS core
- Replace custom VFS implementations with the core VFS module
- Simplify VFS setup and configuration in example code
- Improve code maintainability and consistency
2025-02-17 17:01:35 +00:00
timurgordon
84142b60a7 create webdav -> parent_vfs -> ourdb_vfs example 2025-02-17 19:14:00 +03:00
timurgordon
54024ee222 bizmodel example wip 2025-02-17 18:40:11 +03:00
Mahmoud Emad
66f29fcb02 feat: Improve OurDBFS and OurDBVFS functionalities
- Handle updates correctly in OurDB `set` function, preventing errors
  when incremental mode is enabled.
- Ensure directories are correctly created with metadata in OurDBFS.
- Add debug print statements to OurDBVFS for improved debugging.
- Simplify OurDBVFS `get_entry` function for better readability and
  correctness.  Fixes potential issues with returning references.
- Update tests to reflect changes and use a temporary directory
  to avoid conflicts.
2025-02-17 15:37:58 +00:00
Mahmoud Emad
73c3c3bdb5 feat: Add CLI for webdav server
- Replaced the old webdav server example with a CLI application.
- Added command-line flags for port, directory, username, and password.
- Improved usability and configurability of the webdav server.
2025-02-17 10:00:26 +00:00
Mahmoud Emad
fa677c01b2 feat: Improve safety of get_entry function
- Wrap child access in unsafe block to prevent potential data races.
2025-02-17 09:44:25 +00:00
60d6474a42 ... 2025-02-17 08:29:57 +03:00
8c52326550 ... 2025-02-17 06:41:19 +03:00
52aba347a8 ... 2025-02-17 06:40:06 +03:00
Mahmoud Emad
acd1a4a61d WIP: Fixing the tests 2025-02-16 14:04:17 +00:00
Mahmoud Emad
ee1ac54dde refactor: Rename crystallib to herolib
- Updated import paths to reflect the renaming of the
  `crystallib` module to `herolib`. This change improves
  consistency and clarity in the project structure.
2025-02-16 13:01:50 +00:00
Mahmoud Emad
2599fa6859 feat: Move the vfs dirs to the herolib 2025-02-16 14:56:29 +02:00
Mahmoud Emad
61a0fd2aa6 chore: Change the factories 2025-02-16 11:12:59 +00:00
Mahmoud Emad
d604d739e3 feat: Support garage_s3 installer
- Added a new config template file to be loaded when starting the server
- Run the server in zinit as a service
- Fix the install, destroy, installed, and running functions
2025-02-16 11:10:27 +00:00
Mahmoud Emad
a57f53fdb4 feat: Improved rclone installer 2025-02-16 08:56:28 +00:00
Mahmoud Emad
f276cdf697 feat: Improved tailwind installer 2025-02-16 08:15:43 +00:00
Mahmoud Emad
7fb46a4c0b feat: Improved b2 installer 2025-02-16 07:48:11 +00:00
Mahmoud Emad
fc993a95d7 feat: simplify actrunner installer
- Remove unnecessary dependencies and simplify the actrunner installation process.
2025-02-16 07:19:03 +00:00
c6ff7e7ba5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-02-16 10:05:41 +03:00
3f9a3fb1cd caldav... 2025-02-16 10:05:35 +03:00
7ae4f7dbd0 mail/contacts... 2025-02-16 09:30:51 +03:00
dbb44ec30a mail 2025-02-16 08:25:25 +03:00
7f4fc42a7a mail 2025-02-16 07:49:06 +03:00
01db4540b1 imap 2025-02-16 06:44:43 +03:00
5c0c096a79 Merge pull request #64 from freeflowuniverse/development_coredns
Development coredns
2025-02-13 19:19:09 +02:00
c1719a057a Merge pull request #62 from freeflowuniverse/development_coredns
coredns
2025-02-13 19:10:13 +02:00
e969eacd06 fix(golang): add go path to env 2025-02-13 16:56:45 +00:00
8ed3439cdc fix(coredns): comment getting machine public ip 2025-02-13 16:13:15 +00:00
Mahmoud Emad
5241dfddd4 refactor: rename mycelium to mycelium_installer
- Renamed the `mycelium` module to `mycelium_installer` to improve clarity and avoid naming conflicts.
- Updated all related files and references to reflect the name change.
2025-02-13 13:29:16 +00:00
Mahmoud Emad
6e0572b48a chore: restructure the installers for organize the installers 2025-02-13 13:11:49 +00:00
Mahmoud Emad
9a4a39b19a feat: add screen installer
- Add a new screen installer to the project.
2025-02-13 13:01:48 +00:00
Mahmoud Emad
8abf113715 feat: improve LiveKit installer
- Implement key generation for LiveKit.
- Improve health check for LiveKit server.
- Add support for different startup managers.
- Simplify installation process.
- Remove unnecessary code.
- Update dependencies.
2025-02-13 12:52:03 +00:00
timurgordon
0fb8901ab5 add more specifications necessary for example 2025-02-13 03:29:36 +03:00
timurgordon
6753b87873 clean generator module and archive unused 2025-02-13 02:34:33 +03:00
timurgordon
715f481364 fix generated code compilation for example 2025-02-13 02:33:24 +03:00
timurgordon
776942cd8b generic code generation improvements 2025-02-13 02:31:59 +03:00
timurgordon
f0c23eb4ae change actor module and folder naming 2025-02-13 02:30:53 +03:00
25c997fec5 fix(coredns): fixes in coredns installer and client 2025-02-12 17:55:36 +02:00
Mahmoud Emad
1546bf7f87 chore: Format the installers 2025-02-12 14:29:07 +00:00
Mahmoud Emad
02d4adcff0 refactor: improve gitea installer
- Simplify gitea installer logic.
- Remove unnecessary variables and functions.
- Improve code readability and maintainability.
- Update gitea version to 1.23.3.
- Add default values for GiteaServer fields.
- Remove redundant installer.v and server.v files.
2025-02-12 14:27:18 +00:00
Mahmoud Emad
147c889b53 feat: Add ZeroDB installer
- Add a new ZeroDB installer to the installers.
2025-02-12 13:44:52 +00:00
Mahmoud Emad
f6e7644284 refactor: Improve dagu, meilisearch, and postgres installers
- Remove redundant code and improve the overall structure of the installer actions.
- Add more robust error handling and logging.
- Update the postgres and dagu `destroy` function to properly remove all related services.
- Improve the `install` function to ensure all necessary components are installed.
2025-02-12 12:07:38 +00:00
Mahmoud Emad
582da6d7f0 feat: add wireguard installer
- Add a new wireguard installer to the installers.
2025-02-12 11:24:16 +00:00
Mahmoud Emad
3a337b7b0a refactor: fix meilisearch installler and rename meilisearchinstaller to meilisearch_installer
- Renamed the `meilisearchinstaller` module and related files to  `meilisearch_installer` for consistency.
- Updated import statements and references accordingly.
- Added functionality to install, start, and destroy the  Meilisearch service.
- Improved code readability and organization.
2025-02-12 11:06:08 +00:00
Mahmoud Emad
2953dd0172 fix: simplify meilisearch destroy action
- Remove unnecessary code from the `destroy` function in the `meilisearchinstaller_actions.v` file.
- NOTE: Couldn't test it due to the new hero update, don't know how even send the configs, WIP.
2025-02-12 09:31:39 +00:00
Mahmoud Emad
08f0620305 feat: add rust installer
- Add a new Rust installer.
- Fix some issues with the rust installer.
- better organize the language-specific installers.
2025-02-12 09:28:10 +00:00
Mahmoud Emad
ec22a8e0ec refactor: improve installer code
- Refactor installer code for better readability and maintainability.
- Move `dagu_server.vsh` to `examples/virt/daguserver/dagu_server.vsh`.
- Remove unnecessary `println` statements.
- Improve error handling in `zinit_installer_actions.v`.
- Update `zinit_installer_actions.v` startup type to systemd.
- Refactor several factory functions.
2025-02-12 09:02:33 +00:00
timurgordon
6644d3b11c imrprove code generation to support example 2025-02-12 03:37:22 +03:00
timurgordon
13471d4ca5 fix & improve example 2025-02-12 03:36:26 +03:00
timurgordon
80254739b0 better openapi schema support 2025-02-11 17:10:00 +03:00
Mahmoud Emad
be4d2547e4 refactor: Improved the hero generator, removed unneeded lines 2025-02-11 11:18:04 +00:00
Mahmoud Emad
a7f8893399 feat: Improved the zinit installer, 2025-02-11 11:11:21 +00:00
Mahmoud-Emad
d0b52f40b7 feat: Improved the pacman installer, added an example 2025-02-11 10:32:15 +00:00
30cb80efcd no message 2025-02-11 09:37:03 +03:00
3117d288b1 WIP(osal.coredns): add example for coredns usage
- added openssl and iproute2 installation to install_v.sh since they're
  needed in coredns installation and usage.
- fixed bug in coredns build process.
- fixed bug in getting own public ip.
- fixed bugs in json encoding dns records before pushing to redis
2025-02-10 17:07:49 +00:00
Mahmoud-Emad
6ecd190de8 feat: Improved the docker installer, added an example 2025-02-10 13:53:53 +00:00
Mahmoud-Emad
dacd6d5afb feat: Improved the nodejs installer, added an example 2025-02-10 13:49:27 +00:00
299f6dea06 bump version to 1.0.13 2025-02-10 15:53:30 +03:00
ed025f9acb ... 2025-02-10 15:53:06 +03:00
Mahmoud-Emad
de0e66a94a feat: Improved the python installer, added an example 2025-02-10 12:08:49 +00:00
Mahmoud-Emad
e86504ecd5 feat: Improved the griddriver installer, added an example 2025-02-10 11:51:39 +00:00
Mahmoud-Emad
1b192328b2 feat: Add an example for golang usage 2025-02-10 11:39:53 +00:00
Mahmoud-Emad
77a77ff87e fix: Rename zinit files to zinit_installer 2025-02-10 11:35:21 +00:00
Mahmoud-Emad
439dff4a64 fix: Updated the golang installer 2025-02-10 11:34:45 +00:00
Mahmoud-Emad
f8cb6f25f7 fix: Rename zinit files to zinit_installer 2025-02-10 11:23:38 +00:00
5a8daa3feb ... 2025-02-10 14:15:27 +03:00
timurgordon
c408934efd correct path to openapi.json 2025-02-10 13:23:54 +03:00
abe81190e6 fixes 2025-02-10 13:21:57 +03:00
c4ea066927 bump version to 1.0.12 2025-02-10 12:43:27 +03:00
e997946c56 bump version to 1.0.11 2025-02-10 12:42:44 +03:00
5f9c6ff2bb ... 2025-02-10 12:41:14 +03:00
timurgordon
dd4bb73a78 fix & improve actor code generation 2025-02-10 12:39:19 +03:00
8965f7ae89 bump version to 1.0.10 2025-02-10 12:08:03 +03:00
Mahmoud-Emad
c157c86600 refactor: move zinit installer to infra
- Move the zinit installer from `sysadmintools` to `infra`.
- This change improves the organization of the codebase and
- makes it easier to find and manage installers.  The old
- `zinit` module was a factory only and is removed.  The
- `zinit_installer` is now a normal installer.  The code is
- significantly refactored.
2025-02-10 09:00:49 +00:00
9a931b65e2 bump version to 1.0.9 2025-02-10 09:42:52 +03:00
2c149507f6 fixes 2025-02-10 09:42:09 +03:00
timurgordon
34dea39c52 ... 2025-02-09 20:13:18 +00:00
timurgordon
f1a4547961 Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development 2025-02-09 17:55:25 +00:00
timurgordon
8ae56a8df6 new 2025-02-09 17:53:16 +00:00
cb0110ed20 ... 2025-02-09 17:53:16 +01:00
2bbf814003 ... 2025-02-09 17:44:40 +01:00
86e3fdb910 WIP(osal.coredns): add example for coredns usage
- create an example to use coredns module for adding dns records
- fix module errors
2025-02-09 18:06:16 +02:00
b731c4c388 bump version to 1.0.8 2025-02-09 17:45:34 +03:00
e929ce029d Merge branch 'development_fix' of github.com:freeflowuniverse/herolib into development_fix 2025-02-09 13:51:43 +01:00
5160096a1a ... 2025-02-09 13:51:40 +01:00
f219a4041a ... 2025-02-09 15:50:56 +03:00
674eae1c11 ... 2025-02-09 13:33:21 +01:00
f62369bd01 ... 2025-02-09 13:32:44 +01:00
7a6660ebd8 ... 2025-02-09 13:32:34 +01:00
e20d1bdcc5 traeffik first version, coredns 2025-02-09 13:32:11 +01:00
3e309b6379 ... 2025-02-09 12:24:12 +01:00
ae4e92e090 ... 2025-02-09 08:55:41 +01:00
7b69719f0e ... 2025-02-09 08:55:01 +01:00
1d631fec21 ... 2025-02-09 08:52:42 +01:00
timurgordon
1005576814 Merge branch 'development' into 6-openrpc-code-generator 2025-02-08 17:45:43 +03:00
690b1b68c3 bump version to 1.0.7 2025-02-08 15:17:47 +01:00
6e619622d2 ... 2025-02-08 14:11:51 +01:00
timurgordon
963b31b087 Merge branch 'development_kristof10' of https://github.com/freeflowuniverse/herolib into development_kristof10 2025-02-07 16:38:40 +03:00
timurgordon
2aafab50ad better heroscript encoding and support for ourtime 2025-02-07 16:38:34 +03:00
timurgordon
10c15f6f8e add documentation gen script to actor 2025-02-03 14:59:31 +01:00
timurgordon
af2f33d4f6 improve actor run script 2025-02-03 14:59:19 +01:00
timurgordon
1db2c3ee54 baobab fixes to better support openapi codegen 2025-02-01 11:57:11 +03:00
timurgordon
7e8a4c5c45 fix schemas to better support code generation 2025-02-01 11:56:36 +03:00
timurgordon
f6fe3d4fda clean / improve code generation module 2025-02-01 11:55:45 +03:00
timurgordon
eeb2602bcf add casing text tools 2025-02-01 11:55:14 +03:00
timurgordon
565eec0292 redis fixes 2025-02-01 11:54:22 +03:00
timurgordon
a98fad32d3 generator fixes & improvements for end to end openapi generation 2025-02-01 11:53:56 +03:00
timurgordon
10f0c0bd31 create openapi end to end example 2025-02-01 11:53:13 +03:00
timurgordon
01552145a8 openapi typescript client generation example 2025-01-30 04:54:21 +03:00
timurgordon
09ed341b97 openapi typescript client generation implementation 2025-01-30 04:53:55 +03:00
timurgordon
5cb30e6783 openapi json model, processing & parsing fixes 2025-01-30 04:53:08 +03:00
timurgordon
ee8fbbca09 typescript client generation wip 2025-01-24 04:31:49 +01:00
timurgordon
b9b21ac44b add typescript generation support to code module 2025-01-24 04:30:51 +01:00
timurgordon
d403f84b6c fix osis compilation 2025-01-21 02:37:05 +00:00
timurgordon
dfeeb8cd4c add example actor generation from example specification 2025-01-21 02:36:31 +00:00
timurgordon
135866e5b0 add actor openapi interface swagger ui support 2025-01-21 02:32:33 +00:00
timurgordon
eef88b5375 better support for parsing generating numeric types 2025-01-21 02:30:38 +00:00
timurgordon
8b9717bb74 implement openrpc & openapi examples support 2025-01-21 02:29:23 +00:00
timurgordon
9a7a66192b implement ourdb in osis aside indexer 2025-01-08 02:24:20 -05:00
timurgordon
df950143b4 actor code generation minor fixes 2025-01-08 02:22:40 -05:00
timurgordon
038c563843 openrpc to actor spec base object fixes 2025-01-08 02:20:52 -05:00
timurgordon
4733e05c58 fix object type parsing from jsonschema, and type code generation 2025-01-08 02:17:58 -05:00
timurgordon
c9496f0973 generate base object CRUD methods (wip) 2025-01-07 00:43:12 -05:00
timurgordon
31dffa14ce add script generation for actors 2025-01-07 00:41:56 -05:00
timurgordon
7459501c8f minor warning and compilation bug fixes 2025-01-07 00:41:30 -05:00
timurgordon
bc9fd08f7e add openapi interface and interface tests generation 2025-01-07 00:40:09 -05:00
timurgordon
be1cee5d6a fix generated interface handlers and client 2025-01-04 01:01:43 -05:00
timurgordon
c91f9ba43c organize rpc logic in single module and fix rpc handling / client errs 2025-01-04 01:00:46 -05:00
timurgordon
357000ef13 implement openrpc and http interface generation for actor 2025-01-03 01:48:04 -05:00
timurgordon
6ba89a8b9c fix actor specification tests 2025-01-03 01:47:33 -05:00
timurgordon
d5af1d19b8 fix actor generation and tests 2025-01-03 01:47:16 -05:00
timurgordon
ce1ce722d5 fix actor redis rpc client and handler logic 2025-01-03 01:46:12 -05:00
timurgordon
fa192e10b8 rename actions module and fix tests 2025-01-03 01:45:15 -05:00
timurgordon
7ae3296ef5 improve code generation and add test & compilation checking 2025-01-03 01:44:24 -05:00
timurgordon
a6ba22b0b1 improve & fix openrpc handler and http interface 2025-01-03 01:42:21 -05:00
timurgordon
d49e94e412 make schema models and methods more defensive 2025-01-03 01:41:42 -05:00
timurgordon
ff8ee3693c add baobab code generation examples 2025-01-02 01:48:53 -05:00
timurgordon
d43d4d8a9f remove old jsonschema 2025-01-02 01:48:30 -05:00
timurgordon
6f814b5d09 add snake_case name fixer 2025-01-02 01:47:56 -05:00
timurgordon
5d3df608e1 lighten modules and remove unnecessary imports 2025-01-02 01:47:15 -05:00
timurgordon
86af42bf4a add performance analysis tool to view import trees 2025-01-02 01:44:49 -05:00
timurgordon
5869998f6e move codemodel to core as code and fix 2025-01-02 01:43:28 -05:00
timurgordon
cbdc0fd313 move and fix baobab for generation 2025-01-02 01:42:39 -05:00
timurgordon
bada9508ef create actor specification translation examples 2025-01-02 01:41:10 -05:00
timurgordon
7bc4da97ab port schema modules from crystallib 2025-01-02 01:40:01 -05:00
1844 changed files with 137526 additions and 27493 deletions

View File

@@ -24,9 +24,9 @@ jobs:
- target: aarch64-apple-darwin
os: macos-latest
short-name: macos-arm64
- target: x86_64-apple-darwin
os: macos-13
short-name: macos-i64
# - target: x86_64-apple-darwin
# os: macos-13
# short-name: macos-i64
runs-on: ${{ matrix.os }}
steps:
@@ -42,10 +42,9 @@ jobs:
run: ./install_v.sh --herolib
timeout-minutes: 10
- name: Do all the basic tests
timeout-minutes: 25
run: ./test_basic.vsh
# - name: Do all the basic tests
# timeout-minutes: 25
# run: ./test_basic.vsh
- name: Build Hero
timeout-minutes: 15

29
.gitignore vendored
View File

@@ -1,4 +1,13 @@
# Additional ignore files and directories
Thumbs.db
# Logs
logs/
*.log
*.out
# Compiled Python files
*.pyc
*.pyo
__pycache__/
*dSYM/
.vmodules/
.vscode
@@ -28,4 +37,20 @@ output/
.stellar
data.ms/
test_basic
cli/hero
cli/hero
.aider*
storage/
.qdrant-initialized
.compile_cache
compile_results.log
tmp
compile_summary.log
.summary_lock
.aider*
*.dylib
server
HTTP_REST_MCP_DEMO.md
MCP_HTTP_REST_IMPLEMENTATION_PLAN.md
.roo
.kilocode
.continue

183
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,183 @@
# Contributing to Herolib
Thank you for your interest in contributing to Herolib! This document provides guidelines and instructions for contributing to the project.
## Table of Contents
- [Getting Started](#getting-started)
- [Setting Up Development Environment](#setting-up-development-environment)
- [Repository Structure](#repository-structure)
- [Development Workflow](#development-workflow)
- [Branching Strategy](#branching-strategy)
- [Making Changes](#making-changes)
- [Testing](#testing)
- [Pull Requests](#pull-requests)
- [Code Guidelines](#code-guidelines)
- [CI/CD Process](#cicd-process)
- [Documentation](#documentation)
- [Troubleshooting](#troubleshooting)
## Getting Started
### Setting Up Development Environment
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
bash /tmp/install_v.sh --analyzer --herolib
# IMPORTANT: Start a new shell after installation for paths to be set correctly
```
Alternatively, you can manually set up the environment:
```bash
mkdir -p ~/code/github/freeflowuniverse
cd ~/code/github/freeflowuniverse
git clone git@github.com:freeflowuniverse/herolib.git
cd herolib
# checkout development branch for most recent changes
git checkout development
bash install.sh
```
### Repository Structure
Herolib is an opinionated library primarily used by ThreeFold to automate cloud environments. The repository is organized into several key directories:
- `/lib`: Core library code
- `/cli`: Command-line interface tools, including the Hero tool
- `/cookbook`: Examples and guides for using Herolib
- `/scripts`: Installation and utility scripts
- `/docs`: Generated documentation
## Development Workflow
### Branching Strategy
- `development`: Main development branch where all features and fixes are merged
- `main`: Stable release branch
For new features or bug fixes, create a branch from `development` with a descriptive name.
### Making Changes
1. Create a new branch from `development`:
```bash
git checkout development
git pull
git checkout -b feature/your-feature-name
```
2. Make your changes, following the code guidelines.
3. Run tests to ensure your changes don't break existing functionality:
```bash
./test_basic.vsh
```
4. Commit your changes with clear, descriptive commit messages.
### Testing
Before submitting a pull request, ensure all tests pass:
```bash
# Run all basic tests
./test_basic.vsh
# Run tests for a specific module
vtest ~/code/github/freeflowuniverse/herolib/lib/osal/package_test.v
# Run tests for an entire directory
vtest ~/code/github/freeflowuniverse/herolib/lib/osal
```
The test script (`test_basic.vsh`) manages test execution and caching to optimize performance. It automatically skips tests listed in the ignore or error sections of the script.
### Pull Requests
1. Push your branch to the repository:
```bash
git push origin feature/your-feature-name
```
2. Create a pull request against the `development` branch.
3. Ensure your PR includes:
- A clear description of the changes
- Any related issue numbers
- Documentation updates if applicable
4. Wait for CI checks to pass and address any feedback from reviewers.
## Code Guidelines
- Follow the existing code style and patterns in the repository
- Write clear, concise code with appropriate comments
- Keep modules separate and focused on specific functionality
- Maintain separation between the jsonschema and jsonrpc modules rather than merging them
## CI/CD Process
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`
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
### 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
## Documentation
To generate documentation locally:
```bash
cd ~/code/github/freeflowuniverse/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.
## Troubleshooting
### TCC Compiler Error on macOS
If you encounter the following error when using TCC compiler on macOS:
```
In file included from /Users/timurgordon/code/github/vlang/v/thirdparty/cJSON/cJSON.c:42:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h:614: error: ';' expected (got "__fabsf16")
```
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 half precision math functions (around line 612-626).
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)
- [AI Prompts](aiprompts/starter/0_start_here.md)

152
README.md
View File

@@ -1,32 +1,53 @@
# herolib
# Herolib
Herolib is an opinionated library primarily used by ThreeFold to automate cloud environments. It provides a comprehensive set of tools and utilities for cloud automation, git operations, documentation building, and more.
> [documentation of the library](https://freeflowuniverse.github.io/herolib/)
[![Build on Linux & Run tests](https://github.com/freeflowuniverse/herolib/actions/workflows/test.yml/badge.svg)](https://github.com/freeflowuniverse/herolib/actions/workflows/test.yml)
[![Deploy Documentation to Pages](https://github.com/freeflowuniverse/herolib/actions/workflows/documentation.yml/badge.svg)](https://github.com/freeflowuniverse/herolib/actions/workflows/documentation.yml)
## hero install for users
> [Complete Documentation](https://freeflowuniverse.github.io/herolib/)
## Installation
### For Users
The Hero tool can be installed with a single command:
```bash
curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_hero.sh > /tmp/install_hero.sh
bash /tmp/install_hero.sh
curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_hero.sh | bash
```
this tool can be used to work with git, build books, play with hero AI, ...
Hero will be installed in:
- `/usr/local/bin` for Linux
- `~/hero/bin` for macOS
## automated install for developers
After installation on macOS, you may need to do source see below or restart your terminal to ensure the `hero` command is available:
```bash
source ~/.zprofile
```
The Hero tool can be used to work with git, build documentation, interact with Hero AI, and more.
### For Developers
For development purposes, use the automated installation script:
```bash
curl 'https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_v.sh' > /tmp/install_v.sh
bash /tmp/install_v.sh --analyzer --herolib
#DONT FORGET TO START A NEW SHELL (otherwise the paths will not be set)
#do not forget to do the following this makes sure vtest and vrun exists
cd ~/code/github/freeflowuniverse/herolib
bash install_herolib.vsh
# IMPORTANT: Start a new shell after installation for paths to be set correctly
```
### details
```bash
~/code/github/freeflowuniverse/herolib/install_v.sh --help
#### Installation Options
```
V & HeroLib Installer Script
Usage: ~/code/github/freeflowuniverse/herolib/install_v.sh [options]
@@ -45,29 +66,108 @@ Examples:
~/code/github/freeflowuniverse/herolib/install_v.sh --analyzer
~/code/github/freeflowuniverse/herolib/install_v.sh --herolib
~/code/github/freeflowuniverse/herolib/install_v.sh --reset --analyzer # Fresh install of both
```
### to test
## Features
to run the basic tests, important !!!
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.
To enable offline mode:
- **Via `GitStructureConfig`**: Set the `offline` field to `true` in the `GitStructureConfig` struct.
- **Via `GitStructureArgsNew`**: When creating a new `GitStructure` instance using `gittools.new()`, set the `offline` parameter to `true`.
- **Via Environment Variable**: Set the `OFFLINE` environment variable to any value (e.g., `export OFFLINE=true`).
When offline mode is active, `git fetch --all` operations will be skipped, and a debug message "fetch skipped (offline)" will be printed.
- Documentation building
- Hero AI integration
- System management utilities
- And much more
Check the [cookbook](https://github.com/freeflowuniverse/herolib/tree/development/cookbook) for examples and use cases.
## Testing
Running tests is an essential part of development. To run the basic tests:
```bash
# Run all basic tests
~/code/github/freeflowuniverse/herolib/test_basic.vsh
```
```bash
# Run tests for a specific module
vtest ~/code/github/freeflowuniverse/herolib/lib/osal/package_test.v
#for a full dir
vtest ~/code/github/freeflowuniverse/herolib/lib/osal
#to do al basic tests
~/code/github/freeflowuniverse/herolib/test_basic.vsh
# Run tests for an entire directory
vtest ~/code/github/freeflowuniverse/herolib/lib/osal
```
The `vtest` command is an alias for testing functionality.
## Contributing
We welcome contributions to Herolib! Please see our [CONTRIBUTING.md](CONTRIBUTING.md) file for detailed information on:
- Setting up your development environment
- Understanding the repository structure
- Following our development workflow
- Making pull requests
- CI/CD processes
## Troubleshooting
### TCC Compiler Error on macOS
If you encounter the following error when using TCC compiler on macOS:
```
vtest is an alias to test functionality
In file included from /Users/timurgordon/code/github/vlang/v/thirdparty/cJSON/cJSON.c:42:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h:614: error: ';' expected (got "__fabsf16")
```
This is caused by incompatibility between TCC and the half precision math functions in the macOS SDK. To fix this issue:
## important to read
1. Open the math.h file:
```bash
sudo nano /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h
```
- [aiprompts/starter/0_start_here.md](aiprompts/starter/0_start_here.md)
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));
// extern _Float16 __hypotf16(_Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __sqrtf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __ceilf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __floorf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __rintf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __roundf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __truncf16(_Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __copysignf16(_Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __nextafterf16(_Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __fmaxf16(_Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __fminf16(_Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
// extern _Float16 __fmaf16(_Float16, _Float16, _Float16) __API_AVAILABLE(macos(15.0), ios(18.0), watchos(11.0), tvos(18.0));
```
3. Save the file and try compiling again.
## Additional Resources
- [Complete Documentation](https://freeflowuniverse.github.io/herolib/)
- [Cookbook Examples](https://github.com/freeflowuniverse/herolib/tree/development/cookbook)
- [AI Prompts](aiprompts/starter/0_start_here.md)
## Generating Documentation
To generate documentation locally:
```bash
cd ~/code/github/freeflowuniverse/herolib
bash doc.sh
```

View File

@@ -0,0 +1,19 @@
#!/bin/bash
# Herolib Web Server Installation Script
# This script sets up the necessary environment for the Flask web server.
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
/workspace/herolib/install_v.sh

View File

@@ -1,204 +0,0 @@
# instructions how to work with heroscript in vlang
## heroscript
Heroscript is our small scripting language which has following structure
an example of a heroscript is
```heroscript
!!mailclient.configure
name: 'myname'
host: 'localhost'
port: 25
secure: 1
reset: 1
description: '
a description can be multiline
like this
'
```
Notice how:
- every action starts with !!
- the first part is the actor, mailclient in this case
- the 2e part is the action name, configure in this case
- multilines are supported see the description field
## how to process heroscript in Vlang
- heroscript can be converted to a struct,
- the methods available to get the params are in 'params' section further in this doc
```vlang
//the object which will be configured
pub struct mailclient {
pub mut:
name string
host string
port int
secure bool
description string
}
mut plbook := playbook.new(text: $the_heroscript_from_above)!
play_mailclient(mut plbook)! //see below in vlang block there it all happens
pub fn play_mailclient(mut plbook playbook.PlayBook) ! {
//find all actions are !!$actor.$actionname. in this case above the actor is !!mailclient, we check with the fitler if it exists, if not we return
mailclient_actions := plbook.find(filter: 'mailclient.')!
for action in mailclient_actions {
if action.name == "configure"{
mut p := action.params
mut obj := mailclientScript{
//INFO: all details about the get methods can be found in 'params get methods' section
name : p.get('name')! //will give error if not exist
homedir : p.get('homedir')!
title : p.get_default('title', 'My Hero DAG')! //uses a default if not set
reset : p.get_default_false('reset')
start : p.get_default_true('start')
colors : p.get_list('colors')
description : p.get_default('description','')!
}
}
}
}
}
## params get methods (param getters)
above in the p.get...
below you can find the methods which can be used on the params
```vlang
exists(key_ string) bool
//check if arg exist (arg is just a value in the string e.g. red, not value:something)
exists_arg(key_ string) bool
//see if the kwarg with the key exists if yes return as string trimmed
get(key_ string) !string
//return the arg with nr, 0 is the first
get_arg(nr int) !string
//return arg, if the nr is larger than amount of args, will return the defval
get_arg_default(nr int, defval string) !string
get_default(key string, defval string) !string
get_default_false(key string) bool
get_default_true(key string) bool
get_float(key string) !f64
get_float_default(key string, defval f64) !f64
get_from_hashmap(key_ string, defval string, hashmap map[string]string) !string
get_int(key string) !int
get_int_default(key string, defval int) !int
//Looks for a list of strings in the parameters. ',' are used as deliminator to list
get_list(key string) ![]string
get_list_default(key string, def []string) ![]string
get_list_f32(key string) ![]f32
get_list_f32_default(key string, def []f32) []f32
get_list_f64(key string) ![]f64
get_list_f64_default(key string, def []f64) []f64
get_list_i16(key string) ![]i16
get_list_i16_default(key string, def []i16) []i16
get_list_i64(key string) ![]i64
get_list_i64_default(key string, def []i64) []i64
get_list_i8(key string) ![]i8
get_list_i8_default(key string, def []i8) []i8
get_list_int(key string) ![]int
get_list_int_default(key string, def []int) []int
get_list_namefix(key string) ![]string
get_list_namefix_default(key string, def []string) ![]string
get_list_u16(key string) ![]u16
get_list_u16_default(key string, def []u16) []u16
get_list_u32(key string) ![]u32
get_list_u32_default(key string, def []u32) []u32
get_list_u64(key string) ![]u64
get_list_u64_default(key string, def []u64) []u64
get_list_u8(key string) ![]u8
get_list_u8_default(key string, def []u8) []u8
get_map() map[string]string
get_path(key string) !string
get_path_create(key string) !string
get_percentage(key string) !f64
get_percentage_default(key string, defval string) !f64
//convert GB, MB, KB to bytes e.g. 10 GB becomes bytes in u64
get_storagecapacity_in_bytes(key string) !u64
get_storagecapacity_in_bytes_default(key string, defval u64) !u64
get_storagecapacity_in_gigabytes(key string) !u64
//Get Expiration object from time string input input can be either relative or absolute## Relative time
get_time(key string) !ourtime.OurTime
get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime
get_time_interval(key string) !Duration
get_timestamp(key string) !Duration
get_timestamp_default(key string, defval Duration) !Duration
get_u32(key string) !u32
get_u32_default(key string, defval u32) !u32
get_u64(key string) !u64
get_u64_default(key string, defval u64) !u64
get_u8(key string) !u8
get_u8_default(key string, defval u8) !u8
```

View File

@@ -1,142 +0,0 @@
# how to use params
works very well in combination with heroscript
## How to get the paramsparser
```v
import freeflowuniverse.herolib.data.paramsparser
// Create new params from text
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
// Or create empty params and add later
mut params := paramsparser.new_params()
params.set("color", "red")
```
## Parameter Format
The parser supports several formats:
1. Key-value pairs: `key:value`
2. Quoted values: `key:'value with spaces'`
3. Arguments without keys: `arg1 arg2`
4. Comments: `// this is a comment`
Example:
```v
text := "name:'John Doe' age:30 active:true // user details"
params := paramsparser.new(text)!
```
## Getting Values
The module provides various methods to retrieve values:
```v
// Get string value
name := params.get("name")! // returns "John Doe"
// Get with default value
color := params.get_default("color", "blue")! // returns "blue" if color not set
// Get as integer
age := params.get_int("age")! // returns 30
// Get as boolean (true if value is "1", "true", "y", "yes")
is_active := params.get_default_true("active")
// Get as float
score := params.get_float("score")!
// Get as percentage (converts "80%" to 0.8)
progress := params.get_percentage("progress")!
```
## Type Conversion Methods
The module supports various type conversions:
### Basic Types
- `get_int()`: Convert to int32
- `get_u32()`: Convert to unsigned 32-bit integer
- `get_u64()`: Convert to unsigned 64-bit integer
- `get_u8()`: Convert to unsigned 8-bit integer
- `get_float()`: Convert to 64-bit float
- `get_percentage()`: Convert percentage string to float (e.g., "80%" → 0.8)
### Boolean Values
- `get_default_true()`: Returns true if value is empty, "1", "true", "y", or "yes"
- `get_default_false()`: Returns false if value is empty, "0", "false", "n", or "no"
### Lists
The module provides robust support for parsing and converting lists:
```v
// Basic list parsing
names := params.get_list("users")! // parses ["user1", "user2", "user3"]
// With default value
tags := params.get_list_default("tags", ["default"])!
// Lists with type conversion
numbers := params.get_list_int("ids")! // converts each item to int
amounts := params.get_list_f64("prices")! // converts each item to f64
// Name-fixed lists (normalizes each item)
clean_names := params.get_list_namefix("categories")!
```
Supported list types:
- `get_list()`: String list
- `get_list_u8()`, `get_list_u16()`, `get_list_u32()`, `get_list_u64()`: Unsigned integers
- `get_list_i8()`, `get_list_i16()`, `get_list_int()`, `get_list_i64()`: Signed integers
- `get_list_f32()`, `get_list_f64()`: Floating point numbers
Each list method has a corresponding `_default` version that accepts a default value.
Valid list formats:
```v
users: "john, jane,bob"
ids: "1,2,3,4,5"
```
### Advanced
```v
get_map() map[string]string
get_path(key string) !string
get_path_create(key string) !string //will create path if it doesnt exist yet
get_percentage(key string) !f64
get_percentage_default(key string, defval string) !f64
//convert GB, MB, KB to bytes e.g. 10 GB becomes bytes in u64
get_storagecapacity_in_bytes(key string) !u64
get_storagecapacity_in_bytes_default(key string, defval u64) !u64
get_storagecapacity_in_gigabytes(key string) !u64
//Get Expiration object from time string input input can be either relative or absolute## Relative time
get_time(key string) !ourtime.OurTime
get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime
get_time_interval(key string) !Duration
get_timestamp(key string) !Duration
get_timestamp_default(key string, defval Duration) !Duration
```

View File

@@ -1,309 +0,0 @@
# how to work with heroscript in vlang
## heroscript
Heroscript is our small scripting language which has following structure
an example of a heroscript is
```heroscript
!!dagu.script_define
name: 'test_dag'
homedir:''
title:'a title'
reset:1
start:true //trie or 1 is same
colors: 'green,red,purple' //lists are comma separated
description: '
a description can be multiline
like this
'
!!dagu.add_step
dag: 'test_dag'
name: 'hello_world'
command: 'echo hello world'
!!dagu.add_step
dag: 'test_dag'
name: 'last_step'
command: 'echo last step'
```
Notice how:
- every action starts with !!
- the first part is the actor e.g. dagu in this case
- the 2e part is the action name
- multilines are supported see the description field
## how to process heroscript in Vlang
- heroscript can be converted to a struct,
- the methods available to get the params are in 'params' section further in this doc
```vlang
fn test_play_dagu() ! {
mut plbook := playbook.new(text: thetext_from_above)!
play_dagu(mut plbook)! //see below in vlang block there it all happens
}
pub fn play_dagu(mut plbook playbook.PlayBook) ! {
//find all actions are !!$actor.$actionname. in this case above the actor is !!dagu, we check with the fitler if it exists, if not we return
dagu_actions := plbook.find(filter: 'dagu.')!
if dagu_actions.len == 0 {
return
}
play_dagu_basic(mut plbook)!
}
pub struct DaguScript {
pub mut:
name string
homedir string
title string
reset bool
start bool
colors []string
}
// play_dagu plays the dagu play commands
pub fn play_dagu_basic(mut plbook playbook.PlayBook) ! {
//now find the specific ones for dagu.script_define
mut actions := plbook.find(filter: 'dagu.script_define')!
if actions.len > 0 {
for myaction in actions {
mut p := myaction.params //get the params object from the action object, this can then be processed using the param getters
mut obj := DaguScript{
//INFO: all details about the get methods can be found in 'params get methods' section
name : p.get('name')! //will give error if not exist
homedir : p.get('homedir')!
title : p.get_default('title', 'My Hero DAG')! //uses a default if not set
reset : p.get_default_false('reset')
start : p.get_default_true('start')
colors : p.get_list('colors')
description : p.get_default('description','')!
}
...
}
}
//there can be more actions which will have other filter
}
```
## params get methods (param getters)
```vlang
fn (params &Params) exists(key_ string) bool
//check if arg exist (arg is just a value in the string e.g. red, not value:something)
fn (params &Params) exists_arg(key_ string) bool
//see if the kwarg with the key exists if yes return as string trimmed
fn (params &Params) get(key_ string) !string
//return the arg with nr, 0 is the first
fn (params &Params) get_arg(nr int) !string
//return arg, if the nr is larger than amount of args, will return the defval
fn (params &Params) get_arg_default(nr int, defval string) !string
fn (params &Params) get_default(key string, defval string) !string
fn (params &Params) get_default_false(key string) bool
fn (params &Params) get_default_true(key string) bool
fn (params &Params) get_float(key string) !f64
fn (params &Params) get_float_default(key string, defval f64) !f64
fn (params &Params) get_from_hashmap(key_ string, defval string, hashmap map[string]string) !string
fn (params &Params) get_int(key string) !int
fn (params &Params) get_int_default(key string, defval int) !int
//Looks for a list of strings in the parameters. ',' are used as deliminator to list
fn (params &Params) get_list(key string) ![]string
fn (params &Params) get_list_default(key string, def []string) ![]string
fn (params &Params) get_list_f32(key string) ![]f32
fn (params &Params) get_list_f32_default(key string, def []f32) []f32
fn (params &Params) get_list_f64(key string) ![]f64
fn (params &Params) get_list_f64_default(key string, def []f64) []f64
fn (params &Params) get_list_i16(key string) ![]i16
fn (params &Params) get_list_i16_default(key string, def []i16) []i16
fn (params &Params) get_list_i64(key string) ![]i64
fn (params &Params) get_list_i64_default(key string, def []i64) []i64
fn (params &Params) get_list_i8(key string) ![]i8
fn (params &Params) get_list_i8_default(key string, def []i8) []i8
fn (params &Params) get_list_int(key string) ![]int
fn (params &Params) get_list_int_default(key string, def []int) []int
fn (params &Params) get_list_namefix(key string) ![]string
fn (params &Params) get_list_namefix_default(key string, def []string) ![]string
fn (params &Params) get_list_u16(key string) ![]u16
fn (params &Params) get_list_u16_default(key string, def []u16) []u16
fn (params &Params) get_list_u32(key string) ![]u32
fn (params &Params) get_list_u32_default(key string, def []u32) []u32
fn (params &Params) get_list_u64(key string) ![]u64
fn (params &Params) get_list_u64_default(key string, def []u64) []u64
fn (params &Params) get_list_u8(key string) ![]u8
fn (params &Params) get_list_u8_default(key string, def []u8) []u8
fn (params &Params) get_map() map[string]string
fn (params &Params) get_path(key string) !string
fn (params &Params) get_path_create(key string) !string
fn (params &Params) get_percentage(key string) !f64
fn (params &Params) get_percentage_default(key string, defval string) !f64
//convert GB, MB, KB to bytes e.g. 10 GB becomes bytes in u64
fn (params &Params) get_storagecapacity_in_bytes(key string) !u64
fn (params &Params) get_storagecapacity_in_bytes_default(key string, defval u64) !u64
fn (params &Params) get_storagecapacity_in_gigabytes(key string) !u64
//Get Expiration object from time string input input can be either relative or absolute## Relative time
fn (params &Params) get_time(key string) !ourtime.OurTime
fn (params &Params) get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime
fn (params &Params) get_time_interval(key string) !Duration
fn (params &Params) get_timestamp(key string) !Duration
fn (params &Params) get_timestamp_default(key string, defval Duration) !Duration
fn (params &Params) get_u32(key string) !u32
fn (params &Params) get_u32_default(key string, defval u32) !u32
fn (params &Params) get_u64(key string) !u64
fn (params &Params) get_u64_default(key string, defval u64) !u64
fn (params &Params) get_u8(key string) !u8
fn (params &Params) get_u8_default(key string, defval u8) !u8
```
## how internally a heroscript gets parsed for params
- example to show how a heroscript gets parsed in action with params
- params are part of action object
```heroscript
example text to parse (heroscript)
id:a1 name6:aaaaa
name:'need to do something 1'
description:
'
## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
name2: test
name3: hi
name10:'this is with space' name11:aaa11
name4: 'aaa'
//somecomment
name5: 'aab'
```
the params are part of the action and are represented as follow for the above:
```vlang
Params{
params: [Param{
key: 'id'
value: 'a1'
}, Param{
key: 'name6'
value: 'aaaaa'
}, Param{
key: 'name'
value: 'need to do something 1'
}, Param{
key: 'description'
value: '## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
}, Param{
key: 'name2'
value: 'test'
}, Param{
key: 'name3'
value: 'hi'
}, Param{
key: 'name10'
value: 'this is with space'
}, Param{
key: 'name11'
value: 'aaa11'
}, Param{
key: 'name4'
value: 'aaa'
}, Param{
key: 'name5'
value: 'aab'
}]
}
```

View File

@@ -1,441 +0,0 @@
# module osal
import as
```vlang
import freeflowuniverse.herolib.osal
osal.ping...
```
## ping
```go
assert ping(address:"338.8.8.8")==.unknownhost
assert ping(address:"8.8.8.8")==.ok
assert ping(address:"18.8.8.8")==.timeout
```
will do a panic if its not one of them, an unknown error
## platform
```go
if platform()==.osx{
//do something
}
pub enum PlatformType {
unknown
osx
ubuntu
alpine
}
pub enum CPUType {
unknown
intel
arm
intel32
arm32
}
```
## process
### execute jobs
```v
mut job2:=osal.exec(cmd:"ls /")?
println(job2)
//wont die, the result can be found in /tmp/execscripts
mut job:=osal.exec(cmd:"ls dsds",ignore_error:true)?
//this one has an error
println(job)
```
All scripts are executed from a file from /tmp/execscripts
If the script executes well then its removed, so no leftovers, if it fails the script stays in the dir
### check process logs
```
mut pm:=process.processmap_get()?
```
info returns like:
```json
}, freeflowuniverse.herolib.process.ProcessInfo{
cpu_perc: 0
mem_perc: 0
cmd: 'mc'
pid: 84455
ppid: 84467
rss: 3168
}, freeflowuniverse.herolib.process.ProcessInfo{
cpu_perc: 0
mem_perc: 0
cmd: 'zsh -Z -g'
pid: 84467
ppid: 84469
rss: 1360
}]
```
## other commands
fn bin*path() !string
fn cmd_add(args* CmdAddArgs) !
copy a binary to the right location on the local computer . e.g. is /usr/local/bin on linux . e.g. is ~/hero/bin on osx . will also add the bin location to the path of .zprofile and .zshrc (different per platform)
fn cmd*exists(cmd string) bool
fn cmd_exists_profile(cmd string) bool
fn cmd_path(cmd string) !string
is same as executing which in OS returns path or error
fn cmd_to_script_path(cmd Command) !string
will return temporary path which then can be executed, is a helper function for making script out of command
fn cputype() CPUType
fn cputype_enum_from_string(cpytype string) CPUType
Returns the enum value that matches the provided string for CPUType
fn dir_delete(path string) !
remove all if it exists
fn dir_ensure(path string) !
remove all if it exists
fn dir_reset(path string) !
remove all if it exists and then (re-)create
fn done_delete(key string) !
fn done_exists(key string) bool
fn done_get(key string) ?string
fn done_get_int(key string) int
fn done_get_str(key string) string
fn done_print() !
fn done_reset() !
fn done_set(key string, val string) !
fn download(args* DownloadArgs) !pathlib.Path
if name is not specified, then will be the filename part if the last ends in an extension like .md .txt .log .text ... the file will be downloaded
fn env_get(key string) !string
Returns the requested environment variable if it exists or throws an error if it does not
fn env_get_all() map[string]string
Returns all existing environment variables
fn env_get_default(key string, def string) string
Returns the requested environment variable if it exists or returns the provided default value if it does not
fn env_set(args EnvSet)
Sets an environment if it was not set before, it overwrites the enviroment variable if it exists and if overwrite was set to true (default)
fn env_set_all(args EnvSetAll)
Allows to set multiple enviroment variables in one go, if clear_before_set is true all existing environment variables will be unset before the operation, if overwrite_if_exists is set to true it will overwrite all existing enviromnent variables
fn env_unset(key string)
Unsets an environment variable
fn env_unset_all()
Unsets all environment variables
fn exec(cmd Command) !Job
cmd is the cmd to execute can use ' ' and spaces . if \n in cmd it will write it to ext and then execute with bash . if die==false then will just return returncode,out but not return error . if stdout will show stderr and stdout . . if cmd starts with find or ls, will give to bash -c so it can execute . if cmd has no path, path will be found . . Command argument: .
````
name string // to give a name to your command, good to see logs...
cmd string
description string
timeout int = 3600 // timeout in sec
stdout bool = true
stdout_log bool = true
raise_error bool = true // if false, will not raise an error but still error report
ignore_error bool // means if error will just exit and not raise, there will be no error reporting
work_folder string // location where cmd will be executed
environment map[string]string // env variables
ignore_error_codes []int
scriptpath string // is the path where the script will be put which is executed
scriptkeep bool // means we don't remove the script
debug bool // if debug will put +ex in the script which is being executed and will make sure script stays
shell bool // means we will execute it in a shell interactive
retry int
interactive bool = true // make sure we run on non interactive way
async bool
runtime RunTime (.bash, .python)
returns Job:
start time.Time
end time.Time
cmd Command
output []string
error []string
exit_code int
status JobStatus
process os.Process
```
return Job .
fn exec_string(cmd Command) !string
cmd is the cmd to execute can use ' ' and spaces if \n in cmd it will write it to ext and then execute with bash if die==false then will just return returncode,out but not return error if stdout will show stderr and stdout
if cmd starts with find or ls, will give to bash -c so it can execute if cmd has no path, path will be found $... are remplaced by environment arguments TODO:implement
Command argument: cmd string timeout int = 600 stdout bool = true die bool = true debug bool
return what needs to be executed can give it to bash -c ...
fn execute*debug(cmd string) !string
fn execute_interactive(cmd string) !
shortcut to execute a job interactive means in shell
fn execute_ok(cmd string) bool
executes a cmd, if not error return true
fn execute_silent(cmd string) !string
shortcut to execute a job silent
fn execute_stdout(cmd string) !string
shortcut to execute a job to stdout
fn file_read(path string) !string
fn file_write(path string, text string) !
fn get_logger() log.Logger
Returns a logger object and allows you to specify via environment argument OSAL_LOG_LEVEL the debug level
fn hero_path() !string
fn hostname() !string
fn initname() !string
e.g. systemd, bash, zinit
fn ipaddr_pub_get() !string
Returns the ipaddress as known on the public side is using resolver4.opendns.com
fn is_linux() bool
fn is_linux_arm()! bool
fn is_linux_intel() bool
fn is_osx() bool
fn is_osx_arm() bool
fn is_osx_intel() bool
fn is_ubuntu() bool
fn load_env_file(file_path string) !
fn memdb_exists(key string) bool
fn memdb_get(key string) string
fn memdb_set(key string, val string)
fn package_install(name* string) !
install a package will use right commands per platform
fn package_refresh() !
update the package list
fn ping(args PingArgs) PingResult
if reached in timout result will be True address is e.g. 8.8.8.8 ping means we check if the destination responds
fn platform() PlatformType
fn platform_enum_from_string(platform string) PlatformType
fn process_exists(pid int) bool
fn process_exists_byname(name string) !bool
fn process_kill_recursive(args ProcessKillArgs) !
kill process and all the ones underneith
fn processinfo_children(pid int) !ProcessMap
get all children of 1 process
fn processinfo_get(pid int) !ProcessInfo
get process info from 1 specific process returns
` pub struct ProcessInfo {
pub mut:
cpu_perc f32
mem_perc f32
cmd string
pid int
ppid int
//resident memory
rss int
}
`
fn processinfo_get_byname(name string) ![]ProcessInfo
fn processinfo_with_children(pid int) !ProcessMap
return the process and its children
fn processmap_get() !ProcessMap
make sure to use new first, so that the connection has been initted then you can get it everywhere
fn profile_path() string
fn profile_path_add(args ProfilePathAddArgs) !
add the following path to a profile
fn profile_path_add_hero() !string
fn profile_path_source() string
return the source statement if the profile exists
fn profile_path_source_and() string
return source $path && . or empty if it doesn't exist
fn sleep(duration int)
sleep in seconds
fn tcp_port_test(args TcpPortTestArgs) bool
test if a tcp port answers
` address string //192.168.8.8
port int = 22
timeout u16 = 2000 // total time in milliseconds to keep on trying
`
fn user_add(args UserArgs) !int
add's a user if the user does not exist yet
fn user_exists(username string) bool
fn user_id_get(username string) !int
fn usr_local_path() !string
/usr/local on linux, ${os.home_dir()}/hero on osx
fn whoami() !string
fn write_flags[T](options T) string
enum CPUType {
unknown
intel
arm
intel32
arm32
}
enum ErrorType {
exec
timeout
args
}
enum JobStatus {
init
running
error_exec
error_timeout
error_args
done
}
enum PMState {
init
ok
old
}
enum PingResult {
ok
timeout // timeout from ping
unknownhost // means we don't know the hostname its a dns issue
}
enum PlatformType {
unknown
osx
ubuntu
alpine
arch
suse
}
enum RunTime {
bash
python
heroscript
herocmd
v
}
struct CmdAddArgs {
pub mut:
cmdname string
source string @[required] // path where the binary is
symlink bool // if rather than copy do a symlink
reset bool // if existing cmd will delete
// bin_repo_url string = 'https://github.com/freeflowuniverse/freeflow_binary' // binary where we put the results
}
struct Command {
pub mut:
name string // to give a name to your command, good to see logs...
cmd string
description string
timeout int = 3600 // timeout in sec
stdout bool = true
stdout_log bool = true
raise_error bool = true // if false, will not raise an error but still error report
ignore_error bool // means if error will just exit and not raise, there will be no error reporting
work_folder string // location where cmd will be executed
environment map[string]string // env variables
ignore_error_codes []int
scriptpath string // is the path where the script will be put which is executed
scriptkeep bool // means we don't remove the script
debug bool // if debug will put +ex in the script which is being executed and will make sure script stays
shell bool // means we will execute it in a shell interactive
retry int
interactive bool = true
async bool
runtime RunTime
}
struct DownloadArgs {
pub mut:
name string // optional (otherwise derived out of filename)
url string
reset bool // will remove
hash string // if hash is known, will verify what hash is
dest string // if specified will copy to that destination
timeout int = 180
retry int = 3
minsize_kb u32 = 10 // is always in kb
maxsize_kb u32
expand_dir string
expand_file string
}
struct EnvSet {
pub mut:
key string @[required]
value string @[required]
overwrite bool = true
}
struct EnvSetAll {
pub mut:
env map[string]string
clear_before_set bool
overwrite_if_exists bool = true
}
struct Job {
pub mut:
start time.Time
end time.Time
cmd Command
output string
error string
exit_code int
status JobStatus
process ?&os.Process @[skip; str: skip]
runnr int // nr of time it runs, is for retry
}
fn (mut job Job) execute_retry() !
execute the job and wait on result will retry as specified
fn (mut job Job) execute() !
execute the job, start process, process will not be closed . important you need to close the process later by job.close()! otherwise we get zombie processes
fn (mut job Job) wait() !
wait till the job finishes or goes in error
fn (mut job Job) process() !
process (read std.err and std.out of process)
fn (mut job Job) close() !
will wait & close
struct JobError {
Error
pub mut:
job Job
error_type ErrorType
}
struct PingArgs {
pub mut:
address string @[required]
count u8 = 1 // the ping is successful if it got count amount of replies from the other side
timeout u16 = 1 // the time in which the other side should respond in seconds
retry u8
}
struct ProcessInfo {
pub mut:
cpu_perc f32
mem_perc f32
cmd string
pid int
ppid int // parentpid
// resident memory
rss int
}
fn (mut p ProcessInfo) str() string
struct ProcessKillArgs {
pub mut:
name string
pid int
}
struct ProcessMap {
pub mut:
processes []ProcessInfo
lastscan time.Time
state PMState
pids []int
}
struct ProfilePathAddArgs {
pub mut:
path string @[required]
todelete string // see which one to remove
}
struct TcpPortTestArgs {
pub mut:
address string @[required] // 192.168.8.8
port int = 22
timeout u16 = 2000 // total time in milliseconds to keep on trying
}
struct UserArgs {
pub mut:
name string @[required]
}
-
````

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
params:
- filepath: /Users/despiegk/code/github/freeflowuniverse/herolib/lib/clients/openai
make a dense overview of the code above, easy to understand for AI
the result is 1 markdown file called codeoverview.md and is stored in $filepath
try to figure out which functions are more important and which are less important, so that the most important functions are at the top of section you are working on
the template is as follows
```md
# the name of the module
2-5 liner description
## 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
## overview
quick overview as list with identations, of the structs and its methods
## structs
### structname
now list the methods & arguments, for arguments use table
for each method show the arguments needed to call the method, and what it returns
### methods
- if any methods which are on module
- only show public methods, don't show the get/set/exists methods on module level as part of factory.
```
don't mention what we don't show because of rules above.
the only output we want is markdown file as follows
===WRITE===
$filepath
===CONTENT===
$the content of the generated markdown file
===END===

View File

@@ -0,0 +1,22 @@
remove all navigation elements, and index
for each method, move the args as used in the methods to the method section so its easier to read
start of output file is:
# the name of the module
2-5 liner description
## 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
## structs and methods
quick overview as list with identations, of the structs and its methods
ONLY OUTPUT THE MARKDOWN FILE, NOTHING ELSE

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
in hero.db
make a generic function which takes any of the root objects (which inherits from Base)
and gets a json from it and add a save() function to it to store it in postgresql (see postgresql client)
and also a get and deserializes
the json is put in table as follows
tablename: $dirname_$rootobjectname all lowercase
each table has
- id
- ... the fields which represents indexes (see @[index])
- data which is the json
information how to use generics see aiprompts/v_advanced/generics.md and aiprompts/v_advanced/reflection.md

View File

@@ -0,0 +1,45 @@
$NAME = calendar
walk over all models from biz: db/heromodels/src/models/$NAME in the rust repo
create nice structured public models in Vlang (V) see instructions in herlolib
put the results in /Users/despiegk/code/github/freeflowuniverse/herolib/lib/hero/models/$NAME
put decorator on fields which need to be indexed: use @[index] for that at end of line of the property of the struct
copy the documentation as well and put on the vstruct and on its fields
make instructions so a coding agent can execute it, put the models in files, ...
keep it all simple
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
// Account represents a financial account for tracking balances and transactions
// Supports multiple account types (checking, savings, investment, etc.)
pub struct Account {
core.Base
```
remove Local BaseModel
make sure module ... is always at first line of file
- remove id from the model we update because it is in the Base
- created_at u64 // Creation timestamp
- updated_at u64 // Last modification timestamp
- basically each property in the Base should be removed from the model

View File

@@ -0,0 +1 @@
Kimi k2 on groq is doing well

View File

@@ -0,0 +1,20 @@
in lib/hero/models
for governance and legal
make sure we use core.base as follows
import freeflowuniverse.herolib.hero.models.core
// Account represents a financial account for tracking balances and transactions
// Supports multiple account types (checking, savings, investment, etc.)
pub struct Account {
core.Base
remove Local BaseModel
make sure module ... is always at first line of file
- remove id from the model we update because it is in the Base
- created_at u64 // Creation timestamp
- updated_at u64 // Last modification timestamp
- basically each property in the Base should be removed from the model

View File

@@ -1 +0,0 @@
../lib/data/encoder/readme.md

View File

@@ -0,0 +1,51 @@
# Cost Module Documentation
This module provides functionalities related to managing various costs within the business model.
## Actions
### `!!bizmodel.cost_define`
Defines a cost item and its associated properties.
**Parameters:**
* `bizname` (string, required): The name of the business model instance to which this cost belongs.
* `descr` (string, required): Description of the cost item. If `name` is not provided, it will be derived from this.
* `name` (string, optional): Unique name for the cost item. If not provided, it will be generated from `descr`.
* `cost` (string, required): The cost value. Can be a fixed value (e.g., '1000USD') or a growth rate (e.g., '0:1000,59:2000'). If `indexation` is used, this should not contain a colon. This value is extrapolated.
* `indexation` (percentage, optional, default: '0%'): Annual indexation rate for the cost. Applied over 6 years if specified.
* `costcenter` (string, optional): The costcenter associated with this cost.
* `cost_percent_revenue` (percentage, optional, default: '0%'): Ensures the cost is at least this percentage of the total revenue.
* `extrapolate`: If you want to extrapolate revenue or cogs do extrapolate:1, default is 0.
### `!!bizmodel.costcenter_define`
Defines a cost center.
**Parameters:**
* `bizname` (string, required): The name of the business model instance to which this cost belongs.
* `descr` (string, required): Description of the cost center. If `name` is not provided, it will be derived from this.
* `name` (string, optional): Unique name for the cost center. If not provided, it will be generated from `descr`.
* `department` (string, optional): The department associated with this cost center.
## **Example:**
```js
!!bizmodel.costcenter_define bizname:'test'
descr:'Marketing Cost Center'
name:'marketing_cc'
department:'marketing'
!!bizmodel.cost_define bizname:'test'
descr:'Office Rent'
cost:'5000USD'
indexation:'3%'
costcenter:'marketing_cc'
cost_percent_revenue:'1%'
```

View File

@@ -0,0 +1,35 @@
# Funding Module Documentation
This module provides functionalities related to managing various funding sources within the business model.
## Actions
### `!!bizmodel.funding_define`
Defines a funding entity and its associated properties.
**Parameters:**
* `bizname` (string, required): The name of the business model instance to which this funding belongs.
* `name` (string, required): Identifier for the funding entity.
* `descr` (string, optional): Human-readable description. If not provided, it will be derived from `description`.
* `investment` (string, required): Format `month:amount`, e.g., '0:10000,12:5000'. This value is extrapolated.
* `type` (string, optional, default: 'capital'): The type of funding. Allowed values: 'loan' or 'capital'.
* `extrapolate`: If you want to extrapolate revenue or cogs do extrapolate:1, default is 0.
### `funding_total`
Calculates the total funding.
## **Example:**
```js
!!bizmodel.funding_define bizname:'test' name:'seed_capital'
descr:'Initial Seed Capital Investment'
investment:'0:500000,12:200000'
type:'capital'
!!bizmodel.funding_define bizname:'test' name:'bank_loan'
descr:'Bank Loan for Expansion'
investment:'6:100000,18:50000'
type:'loan'

View File

@@ -0,0 +1,24 @@
create a bizmodel for a startup called threefold
it has 4 departments
- engineering
- operations
- sales
- admin
I need modest engineering 10, 5 people, team nr of people grows 10% per year, with max of 20 people
I need operational team of 2 people and 4% of revenue
I am selling services on a cloud, it starts at 10k USD a month after 10 months, then growing to 1 million a month after 3 years, then 5% up per year
we have 3 offices
we have 5m funding day 1
travelcost is 3% of revenue
create me the full heroscript which gives me this biz model
create bizmodel.heroscript in ~/code/github/freeflowuniverse/herolib/examples/biztools/generated_ai
as well as a do.vsh file which executes the heroscript and does a pprint, in do.vsh , call play with heroscript_path arg

View File

@@ -0,0 +1,69 @@
# HR Module Documentation
This module provides functionalities related to Human Resources within the business model.
## Actions
All actions in the `bizmodel` module accept a `bizname` parameter (string, required) which specifies the business model instance to which the action applies.
### `bizmodel.employee_define`
Defines an employee and their associated costs within the business model.
**Parameters:**
* `bizname` (string, required): The name of the business model instance to which this cost belongs.
* `descr` (string, required): Description of the employee (e.g., 'Junior Engineer'). If `name` is not provided, it will be derived from this.
* `name` (string, optional): Unique name for the employee. If not provided, it will be generated from `descr`.
* `cost` (string, required): The cost associated with the employee. Can be a fixed value (e.g., '4000USD') or a growth rate (e.g., '1:5,60:30'). If `indexation` is used, this should not contain a colon.
* `nrpeople` (string, optional, default: '1'): The number of people for this employee definition. Can be a fixed number or a growth rate (e.g., '1:5,60:30').
* `indexation` (percentage, optional, default: '0%'): Annual indexation rate for the cost. Applied over 6 years if specified.
* `department` (string, optional): The department the employee belongs to.
* `cost_percent_revenue` (percentage, optional, default: '0%'): Ensures the employee cost is at least this percentage of the total revenue.
* `costcenter` (string, optional, default: 'default_costcenter'): The cost center for the employee.
* `page` (string, optional): A reference to a page or document related to this employee.
* `fulltime` (percentage, optional, default: '100%'): The full-time percentage of the employee.
### `bizmodel.department_define`
Defines a department within the business model.
**Parameters:**
* `bizname` (string, required): The name of the business model instance to which this cost belongs.
* `name` (string, required): Unique name for the department.
* `descr` (string, optional): Description of the department. If not provided, `description` will be used.
* `description` (string, optional): Description of the department. Used if `descr` is not provided.
* `title` (string, optional): A title for the department.
* `page` (string, optional): A reference to a page or document related to this department.
## **Example:**
```js
!!bizmodel.department_define bizname:'test'
name:'engineering'
descr:'Software Development Department'
title:'Engineering Division'
//optional, if set overrules the hr_params
//avg_monthly_cost:'6000USD' avg_indexation:'5%'
!!bizmodel.employee_define bizname:'test'
name:'ourclo'
descr:'CLO'
cost:'10000EUR'
indexation:'5%'
!!bizmodel.employee_define bizname:'test'
name:'junior_engineer'
descr:'Junior Engineer'
nrpeople:'1:5,60:30'
cost:'4000USD'
indexation:'5%'
department:'engineering'
cost_percent_revenue:'4%'
```

View File

@@ -0,0 +1,92 @@
# Revenue
```
!!bizmodel.revenue_define bizname:'test' name:'oem1' ...
```
## Params
- bizname, is the name of the biz model we are populating
- name, name of product, project
- descr, description of the revenue line item
- nr_months_recurring: e.g. 60 is 5 years
## discrete revenue/cogs (not per item)
cogs stands for cost of goods
- revenue: one of revenue, can be extrapolated if specified
- cogs: cost of goods, this is the cost of the revenue, can be extrapolated if specified
- cogs_percent: percent of revenue
- cogs_delay: delay in months between cogs and revenue
- extrapolate: if you want to extrapolate revenue or cogs do extrapolate:1, default is 0
### results in
follow rows in sheets
- {name}_ + all the arg names as mentioned above...
- {name}_revenue_total
- {name}_cogs_total
## grouped per items sold
- nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200, default is 1)
- revenue_item_setup, revenue for 1 item '1000usd'
- revenue_item_setup_delay, delay between sell and recognition of sale in months e.g. 1
- revenue_item_monthly, revenue per month for 1 item
- revenue_item_monthly_delay, how many months before monthly revenue starts
- revenue_item_monthly_perc, how much percent of revenue_item_setup will come back over months e.g. 20%
- cogs_item_setup, cost of good for 1 item at setup
- cogs_item_setup_rev_perc: what is percentage of the revenue which is cogs, e.g. 2%
- cogs_item_monthly, cost of goods for the monthly per 1 item
- 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
- {name}_ + all the arg names as mentioned above...
- {name}_revenue_item_setup_total
- {name}_revenue_item_monthly_total
- {name}_revenue_item_total
- {name}_cogs_item_total
## to use
### basic example
```v
import freeflowuniverse.herolib.biz.bizmodel
import os
heroscript:="
Next will define an OEM product in month 10, 1 Million EUR, ... cogs is a percent which is 20% at start but goes to 10% after 20 months.
!!bizmodel.revenue_define bizname:'test' name:'oem1'
descr:'OEM Deals'
revenue:'10:1000000EUR,15:3333,20:1200000'
cogs_percent: '1:20%,20:10%'
This time we have the cogs defined in fixed manner, the default currency is USD doesn't have to be mentioned.
!!bizmodel.revenue_define bizname:'test' name:'oem2'
descr:'OEM Deals'
revenue:'10:1000000EUR,15:3333,20:1200000'
cogs: '10:100000,15:1000,20:120000'
"
bizmodel.play(heroscript:heroscript)!
mut bm:=bizmodel.get("test")!
bm.sheet.pprint()!
```

View File

@@ -0,0 +1,38 @@
//need to define some revenue because otherwise can't see how HR relates to it
!!bizmodel.revenue_define bizname:'test' name:'oem1' extrapolate:1
descr:'OEM Deals' revenue:'0:1000000,60:10000000'
cogs_percent: '0:20%'
!!bizmodel.department_define bizname:'test' name:'marketing'
descr:'Marketing Department'
!!bizmodel.department_define bizname:'test' name:'engineering'
descr:'Engineering Department'
!!bizmodel.costcenter_define bizname:'test' name:'marketing_cc'
descr:'Marketing Cost Center'
department:'marketing'
!!bizmodel.cost_define bizname:'test' name:'office_rent'
descr:'Office Rent'
cost:'8000USD'
indexation:'3%'
costcenter:'marketing_cc'
cost_percent_revenue:'0.5%'
!!bizmodel.cost_define bizname:'test' name:'travel'
descr:'Office Rent'
cost:'2:5000USD' //start month 3
costcenter:'marketing_cc'
!!bizmodel.cost_define bizname:'test' name:'triptomoon'
descr:'Office Rent'
cost:'10:500000USD' extrapolate:0 //this means we do a one off cost in this case month 11
costcenter:'marketing_cc'
// !!bizmodel.cost_define bizname:'test' name:'software_licenses'
// descr:'Annual Software Licenses'
// cost:'0:10000 10:EUR:20kCHF,12:5000USD'
// department:'engineering'

View File

@@ -1 +0,0 @@
../lib/data/currency/readme.md

View File

@@ -1,340 +0,0 @@
module datatypes
# datatypes
This module provides implementations of less frequently used, but still common data types.
V's `builtin` module is imported implicitly, and has implementations for arrays, maps and strings. These are good for many applications, but there are a plethora of other useful data structures/containers, like linked lists, priority queues, trees, etc, that allow for algorithms with different time complexities, which may be more suitable for your specific application.
It is implemented using generics, that you have to specialise for the type of your actual elements. For example:
```v
import datatypes
mut stack := datatypes.Stack[int]{}
stack.push(1)
println(stack)
```
## Currently Implemented Datatypes:
- [x] Linked list
- [x] Doubly linked list
- [x] Stack (LIFO)
- [x] Queue (FIFO)
- [x] Min heap (priority queue)
- [x] Set
- [x] Quadtree
- [x] Bloom filter
- [ ] ...
fn new_bloom_filter[T](hash_func fn (T) u32, table_size int, num_functions int) !&BloomFilter[T]
new_bloom_filter creates a new bloom_filter. `table_size` should be greater than 0, and `num_functions` should be 1~16.
fn new_bloom_filter_fast[T](hash_func fn (T) u32) &BloomFilter[T]
new_bloom_filter_fast creates a new bloom_filter. `table_size` is 16384, and `num_functions` is 4.
fn new_ringbuffer[T](s int) RingBuffer[T]
new_ringbuffer creates an empty ring buffer of size `s`.
fn (mut bst BSTree[T]) insert(value T) bool
insert give the possibility to insert an element in the BST.
fn (bst &BSTree[T]) contains(value T) bool
contains checks if an element with a given `value` is inside the BST.
fn (mut bst BSTree[T]) remove(value T) bool
remove removes an element with `value` from the BST.
fn (bst &BSTree[T]) is_empty() bool
is_empty checks if the BST is empty
fn (bst &BSTree[T]) in_order_traversal() []T
in_order_traversal traverses the BST in order, and returns the result as an array.
fn (bst &BSTree[T]) post_order_traversal() []T
post_order_traversal traverses the BST in post order, and returns the result in an array.
fn (bst &BSTree[T]) pre_order_traversal() []T
pre_order_traversal traverses the BST in pre order, and returns the result as an array.
fn (bst &BSTree[T]) to_left(value T) !T
to_left returns the value of the node to the left of the node with `value` specified if it exists, otherwise the a false value is returned.
An example of usage can be the following one
```v
left_value, exist := bst.to_left(10)
```
fn (bst &BSTree[T]) to_right(value T) !T
to_right return the value of the element to the right of the node with `value` specified, if exist otherwise, the boolean value is false An example of usage can be the following one
```v
left_value, exist := bst.to_right(10)
```
fn (bst &BSTree[T]) max() !T
max return the max element inside the BST. Time complexity O(N) if the BST is not balanced
fn (bst &BSTree[T]) min() !T
min return the minimum element in the BST. Time complexity O(N) if the BST is not balanced.
fn (mut b BloomFilter[T]) add(element T)
adds the element to bloom filter.
fn (b &BloomFilter[T]) exists(element T) bool
checks the element is exists.
fn (l &BloomFilter[T]) @union(r &BloomFilter[T]) !&BloomFilter[T]
@union returns the union of the two bloom filters.
fn (l &BloomFilter[T]) intersection(r &BloomFilter[T]) !&BloomFilter[T]
intersection returns the intersection of bloom filters.
fn (list DoublyLinkedList[T]) is_empty() bool
is_empty checks if the linked list is empty
fn (list DoublyLinkedList[T]) len() int
len returns the length of the linked list
fn (list DoublyLinkedList[T]) first() !T
first returns the first element of the linked list
fn (list DoublyLinkedList[T]) last() !T
last returns the last element of the linked list
fn (mut list DoublyLinkedList[T]) push_back(item T)
push_back adds an element to the end of the linked list
fn (mut list DoublyLinkedList[T]) push_front(item T)
push_front adds an element to the beginning of the linked list
fn (mut list DoublyLinkedList[T]) push_many(elements []T, direction Direction)
push_many adds array of elements to the beginning of the linked list
fn (mut list DoublyLinkedList[T]) pop_back() !T
pop_back removes the last element of the linked list
fn (mut list DoublyLinkedList[T]) pop_front() !T
pop_front removes the last element of the linked list
fn (mut list DoublyLinkedList[T]) insert(idx int, item T) !
insert adds an element to the linked list at the given index
fn (list &DoublyLinkedList[T]) index(item T) !int
index searches the linked list for item and returns the forward index or none if not found.
fn (mut list DoublyLinkedList[T]) delete(idx int)
delete removes index idx from the linked list and is safe to call for any idx.
fn (list DoublyLinkedList[T]) str() string
str returns a string representation of the linked list
fn (list DoublyLinkedList[T]) array() []T
array returns a array representation of the linked list
fn (mut list DoublyLinkedList[T]) next() ?T
next implements the iter interface to use DoublyLinkedList with V's `for x in list {` loop syntax.
fn (mut list DoublyLinkedList[T]) iterator() DoublyListIter[T]
iterator returns a new iterator instance for the `list`.
fn (mut list DoublyLinkedList[T]) back_iterator() DoublyListIterBack[T]
back_iterator returns a new backwards iterator instance for the `list`.
fn (mut iter DoublyListIterBack[T]) next() ?T
next returns *the previous* element of the list, or `none` when the start of the list is reached. It is called by V's `for x in iter{` on each iteration.
fn (mut iter DoublyListIter[T]) next() ?T
next returns *the next* element of the list, or `none` when the end of the list is reached. It is called by V's `for x in iter{` on each iteration.
fn (list LinkedList[T]) is_empty() bool
is_empty checks if the linked list is empty
fn (list LinkedList[T]) len() int
len returns the length of the linked list
fn (list LinkedList[T]) first() !T
first returns the first element of the linked list
fn (list LinkedList[T]) last() !T
last returns the last element of the linked list
fn (list LinkedList[T]) index(idx int) !T
index returns the element at the given index of the linked list
fn (mut list LinkedList[T]) push(item T)
push adds an element to the end of the linked list
fn (mut list LinkedList[T]) push_many(elements []T)
push adds an array of elements to the end of the linked list
fn (mut list LinkedList[T]) pop() !T
pop removes the last element of the linked list
fn (mut list LinkedList[T]) shift() !T
shift removes the first element of the linked list
fn (mut list LinkedList[T]) insert(idx int, item T) !
insert adds an element to the linked list at the given index
fn (mut list LinkedList[T]) prepend(item T)
prepend adds an element to the beginning of the linked list (equivalent to insert(0, item))
fn (list LinkedList[T]) str() string
str returns a string representation of the linked list
fn (list LinkedList[T]) array() []T
array returns a array representation of the linked list
fn (mut list LinkedList[T]) next() ?T
next implements the iteration interface to use LinkedList with V's `for` loop syntax.
fn (mut list LinkedList[T]) iterator() ListIter[T]
iterator returns a new iterator instance for the `list`.
fn (mut iter ListIter[T]) next() ?T
next returns the next element of the list, or `none` when the end of the list is reached. It is called by V's `for x in iter{` on each iteration.
fn (mut heap MinHeap[T]) insert(item T)
insert adds an element to the heap.
fn (mut heap MinHeap[T]) insert_many(elements []T)
insert array of elements to the heap.
fn (mut heap MinHeap[T]) pop() !T
pop removes the top-most element from the heap.
fn (heap MinHeap[T]) peek() !T
peek gets the top-most element from the heap without removing it.
fn (heap MinHeap[T]) len() int
len returns the number of elements in the heap.
fn (queue Queue[T]) is_empty() bool
is_empty checks if the queue is empty
fn (queue Queue[T]) len() int
len returns the length of the queue
fn (queue Queue[T]) peek() !T
peek returns the head of the queue (first element added)
fn (queue Queue[T]) last() !T
last returns the tail of the queue (last element added)
fn (queue Queue[T]) index(idx int) !T
index returns the element at the given index of the queue
fn (mut queue Queue[T]) push(item T)
push adds an element to the tail of the queue
fn (mut queue Queue[T]) pop() !T
pop removes the element at the head of the queue and returns it
fn (queue Queue[T]) str() string
str returns a string representation of the queue
fn (queue Queue[T]) array() []T
array returns a array representation of the queue
fn (mut rb RingBuffer[T]) push(element T) !
push adds an element to the ring buffer.
fn (mut rb RingBuffer[T]) pop() !T
pop returns the oldest element in the buffer.
fn (mut rb RingBuffer[T]) push_many(elements []T) !
push_many pushes an array to the buffer.
fn (mut rb RingBuffer[T]) pop_many(n u64) ![]T
pop_many returns `n` elements of the buffer starting with the oldest one.
fn (rb RingBuffer[T]) is_empty() bool
is_empty returns `true` if the ring buffer is empty, `false` otherwise.
fn (rb RingBuffer[T]) is_full() bool
is_full returns `true` if the ring buffer is full, `false` otherwise.
fn (rb RingBuffer[T]) capacity() int
capacity returns the capacity of the ring buffer.
fn (mut rb RingBuffer[T]) clear()
clear empties the ring buffer and all pushed elements.
fn (rb RingBuffer[T]) occupied() int
occupied returns the occupied capacity of the buffer.
fn (rb RingBuffer[T]) remaining() int
remaining returns the remaining capacity of the buffer.
fn (set Set[T]) exists(element T) bool
checks the element is exists.
fn (mut set Set[T]) add(element T)
adds the element to set, if it is not present already.
fn (mut set Set[T]) remove(element T)
removes the element from set.
fn (set Set[T]) pick() !T
pick returns an arbitrary element of set, if set is not empty.
fn (mut set Set[T]) rest() ![]T
rest returns the set consisting of all elements except for the arbitrary element.
fn (mut set Set[T]) pop() !T
pop returns an arbitrary element and deleting it from set.
fn (mut set Set[T]) clear()
delete all elements of set.
fn (l Set[T]) == (r Set[T]) bool
== checks whether the two given sets are equal (i.e. contain all and only the same elements).
fn (set Set[T]) is_empty() bool
is_empty checks whether the set is empty or not.
fn (set Set[T]) size() int
size returns the number of elements in the set.
fn (set Set[T]) copy() Set[T]
copy returns a copy of all the elements in the set.
fn (mut set Set[T]) add_all(elements []T)
add_all adds the whole `elements` array to the set
fn (l Set[T]) @union(r Set[T]) Set[T]
@union returns the union of the two sets.
fn (l Set[T]) intersection(r Set[T]) Set[T]
intersection returns the intersection of sets.
fn (l Set[T]) - (r Set[T]) Set[T]
- returns the difference of sets.
fn (l Set[T]) subset(r Set[T]) bool
subset returns true if the set `r` is a subset of the set `l`.
fn (stack Stack[T]) is_empty() bool
is_empty checks if the stack is empty
fn (stack Stack[T]) len() int
len returns the length of the stack
fn (stack Stack[T]) peek() !T
peek returns the top of the stack
fn (mut stack Stack[T]) push(item T)
push adds an element to the top of the stack
fn (mut stack Stack[T]) pop() !T
pop removes the element at the top of the stack and returns it
fn (stack Stack[T]) str() string
str returns a string representation of the stack
fn (stack Stack[T]) array() []T
array returns a array representation of the stack
enum Direction {
front
back
}
struct AABB {
pub mut:
x f64
y f64
width f64
height f64
}
struct BSTree[T] {
mut:
root &BSTreeNode[T] = unsafe { 0 }
}
Pure Binary Seach Tree implementation
Pure V implementation of the Binary Search Tree Time complexity of main operation O(log N) Space complexity O(N)
struct DoublyLinkedList[T] {
mut:
head &DoublyListNode[T] = unsafe { 0 }
tail &DoublyListNode[T] = unsafe { 0 }
// Internal iter pointer for allowing safe modification
// of the list while iterating. TODO: use an option
// instead of a pointer to determine it is initialized.
iter &DoublyListIter[T] = unsafe { 0 }
len int
}
DoublyLinkedList[T] represents a generic doubly linked list of elements, each of type T.
struct DoublyListIter[T] {
mut:
node &DoublyListNode[T] = unsafe { 0 }
}
DoublyListIter[T] is an iterator for DoublyLinkedList. It starts from *the start* and moves forwards to *the end* of the list. It can be used with V's `for x in iter {` construct. One list can have multiple independent iterators, pointing to different positions/places in the list. A DoublyListIter iterator instance always traverses the list from *start to finish*.
struct DoublyListIterBack[T] {
mut:
node &DoublyListNode[T] = unsafe { 0 }
}
DoublyListIterBack[T] is an iterator for DoublyLinkedList. It starts from *the end* and moves backwards to *the start* of the list. It can be used with V's `for x in iter {` construct. One list can have multiple independent iterators, pointing to different positions/places in the list. A DoublyListIterBack iterator instance always traverses the list from *finish to start*.
struct LinkedList[T] {
mut:
head &ListNode[T] = unsafe { 0 }
len int
// Internal iter pointer for allowing safe modification
// of the list while iterating. TODO: use an option
// instead of a pointer to determine if it is initialized.
iter &ListIter[T] = unsafe { 0 }
}
struct ListIter[T] {
mut:
node &ListNode[T] = unsafe { 0 }
}
ListIter[T] is an iterator for LinkedList. It can be used with V's `for x in iter {` construct. One list can have multiple independent iterators, pointing to different positions/places in the list. An iterator instance always traverses the list from start to finish.
struct ListNode[T] {
mut:
data T
next &ListNode[T] = unsafe { 0 }
}
struct MinHeap[T] {
mut:
data []T
}
MinHeap is a binary minimum heap data structure.
struct Quadtree {
pub mut:
perimeter AABB
capacity int
depth int
level int
particles []AABB
nodes []Quadtree
}
fn (mut q Quadtree) create(x f64, y f64, width f64, height f64, capacity int, depth int, level int) Quadtree
create returns a new configurable root node for the tree.
fn (mut q Quadtree) insert(p AABB)
insert recursively adds a particle in the correct index of the tree.
fn (mut q Quadtree) retrieve(p AABB) []AABB
retrieve recursively checks if a particle is in a specific index of the tree.
fn (mut q Quadtree) clear()
clear flushes out nodes and particles from the tree.
fn (q Quadtree) get_nodes() []Quadtree
get_nodes recursively returns the subdivisions the tree has.
struct Queue[T] {
mut:
elements LinkedList[T]
}
struct RingBuffer[T] {
mut:
reader int // index of the tail where data is going to be read
writer int // index of the head where data is going to be written
content []T
}
RingBuffer represents a ring buffer also known as a circular buffer.
struct Set[T] {
mut:
elements map[T]u8
}
struct Stack[T] {
mut:
elements []T
}

View File

@@ -1,79 +0,0 @@
## how internally a heroscript gets parsed for params
- example to show how a heroscript gets parsed in action with params
- params are part of action object
```heroscript
example text to parse (heroscript)
id:a1 name6:aaaaa
name:'need to do something 1'
description:
'
## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
name2: test
name3: hi
name10:'this is with space' name11:aaa11
name4: 'aaa'
//somecomment
name5: 'aab'
```
the params are part of the action and are represented as follow for the above:
```vlang
Params{
params: [Param{
key: 'id'
value: 'a1'
}, Param{
key: 'name6'
value: 'aaaaa'
}, Param{
key: 'name'
value: 'need to do something 1'
}, Param{
key: 'description'
value: '## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
}, Param{
key: 'name2'
value: 'test'
}, Param{
key: 'name3'
value: 'hi'
}, Param{
key: 'name10'
value: 'this is with space'
}, Param{
key: 'name11'
value: 'aaa11'
}, Param{
key: 'name4'
value: 'aaa'
}, Param{
key: 'name5'
value: 'aab'
}]
}
```

View File

@@ -1 +0,0 @@
../crystallib/virt/docker/readme.md

View File

@@ -0,0 +1,344 @@
# HeroLib Docusaurus Ebook Manual for AI Prompts
This manual provides a comprehensive guide on how to leverage HeroLib's Docusaurus integration, Doctree, and HeroScript to create and manage technical ebooks, optimized for AI-driven content generation and project management.
## 1. Core Concepts
To effectively create ebooks with HeroLib, it's crucial to understand the interplay of three core components:
* **HeroScript**: A concise scripting language used to define the structure, configuration, and content flow of your Docusaurus site. It acts as the declarative interface for the entire process.
* **Docusaurus**: A popular open-source static site generator. HeroLib uses Docusaurus as the underlying framework to render your ebook content into a navigable website.
* **Doctree**: HeroLib's content management system. Doctree organizes your markdown files into "collections" and "pages," allowing for structured content retrieval and reuse across multiple projects.
## 2. Setting Up a Docusaurus Project with HeroLib
The `docusaurus` module in HeroLib provides the primary interface for managing your ebook projects.
### 2.1. Defining the Docusaurus Factory (`docusaurus.define`)
The `docusaurus.define` HeroScript directive configures the global settings for your Docusaurus build environment. This is typically used once at the beginning of your main HeroScript configuration.
**HeroScript Example:**
```heroscript
!!docusaurus.define
path_build: "/tmp/my_ebook_build"
path_publish: "/tmp/my_ebook_publish"
production: true
update: true
```
**Arguments:**
* `path_build` (string, optional): The local path where the Docusaurus site will be built. Defaults to `~/hero/var/docusaurus/build`.
* `path_publish` (string, optional): The local path where the final Docusaurus site will be published (e.g., for deployment). Defaults to `~/hero/var/docusaurus/publish`.
* `production` (boolean, optional): If `true`, the site will be built for production (optimized). Default is `false`.
* `update` (boolean, optional): If `true`, the Docusaurus template and dependencies will be updated. Default is `false`.
### 2.2. Adding a Docusaurus Site (`docusaurus.add`)
The `docusaurus.add` directive defines an individual Docusaurus site (your ebook). You can specify the source of your documentation content, whether it's a local path or a Git repository.
**HeroScript Example (Local Content):**
```heroscript
!!docusaurus.add
name:"my_local_ebook"
path:"./my_ebook_content" // Path to your local docs directory
open:true // Open in browser after generation
```
**HeroScript Example (Git Repository Content):**
```heroscript
!!docusaurus.add
name:"tfgrid_tech_ebook"
git_url:"https://git.threefold.info/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech"
git_reset:true // Reset Git repository before pulling
git_pull:true // Pull latest changes
git_root:"/tmp/git_clones" // Optional: specify a root directory for git clones
```
**Arguments:**
* `name` (string, optional): A unique name for your Docusaurus site/ebook. Defaults to "main".
* `path` (string, optional): The local file system path to the root of your documentation content (e.g., where your `docs` and `cfg` directories are).
* `git_url` (string, optional): A Git URL to a repository containing your documentation content. HeroLib will clone/pull this repository.
* `git_reset` (boolean, optional): If `true`, the Git repository will be reset to a clean state before pulling. Default is `false`.
* `git_pull` (boolean, optional): If `true`, the Git repository will be pulled to get the latest changes. Default is `false`.
* `git_root` (string, optional): An optional root directory where Git repositories will be cloned.
* `nameshort` (string, optional): A shorter name for the Docusaurus site. Defaults to the value of `name`.
* `path_publish` (string, optional): Overrides the factory's `path_publish` for this specific site.
* `production` (boolean, optional): Overrides the factory's `production` setting for this specific site.
* `watch_changes` (boolean, optional): If `true`, HeroLib will watch for changes in your source `docs` directory and trigger rebuilds. Default is `true`.
* `update` (boolean, optional): If `true`, this specific documentation will be updated. Default is `false`.
* `open` (boolean, optional): If `true`, the Docusaurus site will be opened in your default browser after generation/development server start. Default is `false`.
* `init` (boolean, optional): If `true`, the Docusaurus site will be initialized (e.g., creating missing `docs` directories). Default is `false`.
## 3. Structuring Content with HeroScript and Doctree
The actual content and structure of your ebook are defined using HeroScript directives within your site's configuration files (e.g., in a `cfg` directory within your `path` or `git_url` source).
### 3.1. Site Configuration (`site.config`, `site.config_meta`)
These directives define the fundamental properties and metadata of your Docusaurus site.
**HeroScript Example:**
```heroscript
!!site.config
name:"my_awesome_ebook"
title:"My Awesome Ebook Title"
tagline:"A comprehensive guide to everything."
url:"https://my-ebook.example.com"
url_home:"docs/"
base_url:"/my-ebook/"
favicon:"img/favicon.png"
copyright:"© 2024 My Organization"
!!site.config_meta
description:"This ebook covers advanced topics in AI and software engineering."
image:"https://my-ebook.example.com/img/social_share.png"
title:"Advanced AI & Software Engineering Ebook"
keywords:"AI, software, engineering, manual, guide"
```
**Arguments:**
* **`site.config`**:
* `name` (string, required): Unique identifier for the site.
* `title` (string, optional): Main title of the site. Defaults to "My Documentation Site".
* `description` (string, optional): General site description.
* `tagline` (string, optional): Short tagline for the site.
* `favicon` (string, optional): Path to the favicon. Defaults to "img/favicon.png".
* `image` (string, optional): General site image (e.g., for social media previews). Defaults to "img/tf_graph.png".
* `copyright` (string, optional): Copyright notice. Defaults to "© [Current Year] Example Organization".
* `url` (string, optional): The main URL where the site will be hosted.
* `base_url` (string, optional): The base URL for Docusaurus (e.g., `/` or `/my-ebook/`).
* `url_home` (string, optional): The path to the home page relative to `base_url`.
* **`site.config_meta`**: Overrides for specific SEO metadata.
* `title` (string, optional): Specific title for SEO (e.g., `<meta property="og:title">`).
* `image` (string, optional): Specific image for SEO (e.g., `<meta property="og:image">`).
* `description` (string, optional): Specific description for SEO.
* `keywords` (string, optional): Comma-separated keywords for SEO.
### 3.2. Navigation Bar (`site.navbar`, `site.navbar_item`)
Define the main navigation menu of your Docusaurus site.
**HeroScript Example:**
```heroscript
!!site.navbar
title:"Ebook Navigation"
logo_alt:"Ebook Logo"
logo_src:"img/logo.svg"
logo_src_dark:"img/logo_dark.svg"
!!site.navbar_item
label:"Introduction"
to:"/docs/intro" // Internal Docusaurus path
position:"left"
!!site.navbar_item
label:"External Link"
href:"https://example.com/external" // External URL
position:"right"
```
**Arguments:**
* **`site.navbar`**:
* `title` (string, optional): Title displayed in the navbar. Defaults to `site.config.title`.
* `logo_alt` (string, optional): Alt text for the logo.
* `logo_src` (string, optional): Path to the light mode logo.
* `logo_src_dark` (string, optional): Path to the dark mode logo.
* **`site.navbar_item`**:
* `label` (string, required): Text displayed for the menu item.
* `href` (string, optional): External URL for the link.
* `to` (string, optional): Internal Docusaurus path (e.g., `/docs/my-page`).
* `position` (string, optional): "left" or "right" for placement in the navbar. Defaults to "right".
### 3.3. Footer (`site.footer`, `site.footer_item`)
Configure the footer section of your Docusaurus site.
**HeroScript Example:**
```heroscript
!!site.footer
style:"dark" // "dark" or "light"
!!site.footer_item
title:"Resources" // Grouping title for footer links
label:"API Documentation"
href:"https://api.example.com/docs"
!!site.footer_item
title:"Community"
label:"GitHub"
href:"https://github.com/my-org"
```
**Arguments:**
* **`site.footer`**:
* `style` (string, optional): "dark" or "light" style for the footer. Defaults to "dark".
* **`site.footer_item`**:
* `title` (string, required): The title under which this item will be grouped in the footer.
* `label` (string, required): Text displayed for the footer link.
* `href` (string, optional): External URL for the link.
* `to` (string, optional): Internal Docusaurus path.
### 3.4. Build Destinations (`site.build_dest`, `site.build_dest_dev`)
Specify where the built Docusaurus site should be deployed. This typically involves an SSH connection defined elsewhere (e.g., `!!site.ssh_connection`).
**HeroScript Example:**
```heroscript
!!site.build_dest
ssh_name:"production_server" // Name of a pre-defined SSH connection
path:"/var/www/my-ebook" // Remote path on the server
!!site.build_dest_dev
ssh_name:"dev_server"
path:"/tmp/dev-ebook"
```
**Arguments:**
* `ssh_name` (string, required): The name of the SSH connection to use for deployment.
* `path` (string, required): The destination path on the remote server.
### 3.5. Importing External Content (`site.import`)
This powerful feature allows you to pull markdown content and assets from other Git repositories directly into your Docusaurus site's `docs` directory, with optional text replacement. This is ideal for integrating shared documentation or specifications.
**HeroScript Example:**
```heroscript
!!site.import
url:'https://git.threefold.info/tfgrid/docs_tfgrid4/src/branch/main/collections/cloud_reinvented'
dest:'cloud_reinvented' // Destination subdirectory within your Docusaurus docs folder
replace:'NAME:MyName, URGENCY:red' // Optional: comma-separated key:value pairs for text replacement
```
**Arguments:**
* `url` (string, required): The Git URL of the repository or specific path within a repository to import.
* `dest` (string, required): The subdirectory within your Docusaurus `docs` folder where the imported content will be placed.
* `replace` (string, optional): A comma-separated string of `KEY:VALUE` pairs. During import, all occurrences of `${KEY}` in the imported content will be replaced with `VALUE`.
### 3.6. Defining Pages and Categories (`site.page_category`, `site.page`)
This is where you define the actual content pages and how they are organized into categories within your Docusaurus sidebar.
**HeroScript Example:**
```heroscript
// Define a category
!!site.page_category path:'introduction' label:"Introduction to Ebook" position:10
// Define a page within that category, linking to Doctree content
!!site.page path:'introduction' src:"my_doctree_collection:chapter_1_overview"
title:"Chapter 1: Overview"
description:"A brief introduction to the ebook's content."
position:1 // Order within the category
hide_title:true // Hide the title on the page itself
```
**Arguments:**
* **`site.page_category`**:
* `path` (string, required): The path to the category directory within your Docusaurus `docs` folder (e.g., `introduction` will create `docs/introduction/_category_.json`).
* `label` (string, required): The display name for the category in the sidebar.
* `position` (int, optional): The order of the category in the sidebar.
* `sitename` (string, optional): If you have multiple Docusaurus sites defined, specify which site this category belongs to. Defaults to the current site's name.
* **`site.page`**:
* `src` (string, required): **Crucial for Doctree integration.** This specifies the source of the page content in the format `collection_name:page_name`. HeroLib will fetch the markdown content from the specified Doctree collection and page.
* `path` (string, required): The relative path and filename for the generated markdown file within your Docusaurus `docs` folder (e.g., `introduction/chapter_1.md`). If only a directory is provided (e.g., `introduction/`), the `page_name` from `src` will be used as the filename.
* `title` (string, optional): The title of the page. If not provided, HeroLib will attempt to extract it from the markdown content or use the `page_name`.
* `description` (string, optional): A short description for the page, used in frontmatter.
* `position` (int, optional): The order of the page within its category.
* `hide_title` (boolean, optional): If `true`, the title will not be displayed on the page itself.
* `draft` (boolean, optional): If `true`, the page will be marked as a draft and not included in production builds.
* `title_nr` (int, optional): If set, HeroLib will re-number the markdown headings (e.g., `title_nr:3` will make `# Heading` become `### Heading`). Useful for consistent heading levels across imported content.
### 3.7. Doctree Integration Details
The `site.page` directive's `src` parameter (`collection_name:page_name`) is the bridge to your Doctree content.
**How Doctree Works:**
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.
## 4. Building and Developing Your Ebook
Once your HeroScript configuration is set up, HeroLib provides commands to build and serve your Docusaurus ebook.
### 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.
* Copies your source `docs` directory.
* Processes `site.page` and `site.page_category` directives using the `sitegen` module to create the final markdown files and `_category_.json` files in the Docusaurus `docs` directory, fetching content from Doctree.
* Handles `site.import` directives, pulling external content and performing replacements.
### 4.2. Local Development
HeroLib integrates with Docusaurus's development server for live preview.
**HeroScript Example:**
can be stored as example_docusaurus.vsh and then used to generate and develop an ebook
```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 os
const cfgpath = os.dir(@FILE)
docusaurus.new(
heroscript: '
// !!docusaurus.define
// path_build: "/tmp/docusaurus_build"
// path_publish: "/tmp/docusaurus_publish"
!!docusaurus.add name:"tfgrid_docs"
path:"${cfgpath}"
!!docusaurus.dev
'
)!
```
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
const cfgpath = os.dir(@FILE) + '/cfg'
docusaurus.new(heroscript_path:cfgpath)!
```
by just called do.vsh we can execute on the ebook

View File

@@ -1 +0,0 @@
../lib/develop/gittools/README.md

View File

@@ -0,0 +1,141 @@
# Pathlib Module: Advanced Listing and Filtering
The `pathlib` module provides powerful capabilities for listing and filtering files and directories, especially through its `list` method. This document explains how to leverage advanced features like regular expressions and various filtering options.
## Advanced File Listing with `path.list()`
The `path.list()` method allows you to retrieve a `PathList` object containing `Path` objects that match specified criteria.
### `ListArgs` Parameters
The `list` method accepts a `ListArgs` struct to control its behavior:
```v
pub struct ListArgs {
pub mut:
regex []string // A slice of regular expressions to filter files.
recursive bool = true // Whether to list files recursively (default true).
ignoredefault bool = true // Whether to ignore files starting with . and _ (default true).
include_links bool // Whether to include symbolic links in the list.
dirs_only bool // Whether to include only directories in the list.
files_only bool // Whether to include only files in the list.
}
```
### Usage Examples
Here are examples demonstrating how to use these advanced filtering options:
#### 1. Listing Files by Regex Pattern
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
// Get a directory path
mut dir := pathlib.get('/some/directory')!
// List only Vlang files (ending with .v)
mut vlang_files := dir.list(
regex: [r'.*\.v$']
)!
// List only image files (png, jpg, svg, jpeg)
mut image_files := dir.list(
regex: [r'.*\.png$', r'.*\.jpg$', r'.*\.svg$', r'.*\.jpeg$']
)!
// List files containing "test" in their name (case-insensitive)
mut test_files := dir.list(
regex: [r'(?i).*test.*'] // (?i) makes the regex case-insensitive
)!
for path_obj in vlang_files.paths {
println(path_obj.path)
}
```
#### 2. Controlling Recursion
By default, `list()` is recursive. You can disable recursion to list only items in the current directory.
```v
import freeflowuniverse.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
// List only top-level files and directories (non-recursive)
mut top_level_items := dir.list(
recursive: false
)!
for path_obj in top_level_items.paths {
println(path_obj.path)
}
```
#### 3. Including or Excluding Hidden Files
The `ignoredefault` parameter controls whether files and directories starting with `.` or `_` are ignored.
```v
import freeflowuniverse.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
// List all files and directories, including hidden ones
mut all_items := dir.list(
ignoredefault: false
)!
for path_obj in all_items.paths {
println(path_obj.path)
}
```
#### 4. Including Symbolic Links
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
mut dir := pathlib.get('/some/directory')!
// List files and directories, including symbolic links
mut items_with_links := dir.list(
include_links: true
)!
for path_obj in items_with_links.paths {
println(path_obj.path)
}
```
#### 5. Listing Only Directories or Only Files
Use `dirs_only` or `files_only` to restrict the results to only directories or only files.
```v
import freeflowuniverse.herolib.core.pathlib
mut dir := pathlib.get('/some/directory')!
// List only directories (recursive)
mut only_dirs := dir.list(
dirs_only: true
)!
// List only files (non-recursive)
mut only_files := dir.list(
files_only: true,
recursive: false
)!
for path_obj in only_dirs.paths {
println(path_obj.path)
}
```
By combining these parameters, you can create highly specific and powerful file system listing operations tailored to your needs.

View File

@@ -0,0 +1,323 @@
# Builder Module: System Automation and Remote Execution
The `builder` module in Herolib provides a powerful framework for automating system tasks and executing commands on both local and remote machines. It offers a unified interface to manage nodes, execute commands, perform file operations, and maintain persistent state.
## Key Components
- **`BuilderFactory`**: Responsible for creating and managing `Node` instances.
- **`Node`**: Represents a target system (local or remote). It encapsulates system properties (platform, CPU type, environment variables) and provides methods for interaction.
- **`Executor`**: An interface (implemented by `ExecutorLocal` and `ExecutorSSH`) that handles the actual command execution and file operations on the target system.
- **NodeDB (via `Node.done` map)**: A key-value store within each `Node` for persistent state, caching, and tracking execution history.
## Getting Started
### Initializing a Builder and Node
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
// Create a new builder factory
mut b := builder.new()!
// Create a node for the local machine
mut local_node := b.node_local()!
// Create a node for a remote server via SSH
// Format: "user@ip_address:port" or "ip_address:port" or "ip_address"
mut remote_node := b.node_new(ipaddr: "root@195.192.213.2:2222")!
// Node with custom name and debug enabled
mut named_debug_node := b.node_new(
name: "my_remote_server",
ipaddr: "user@server.example.com:22",
debug: true
)!
```
### `Node` Properties
A `Node` object automatically detects and caches system information. You can access these properties:
```v
// Get platform type (e.g., .osx, .ubuntu, .alpine, .arch)
println(node.platform)
// Get CPU architecture (e.g., .intel, .arm)
println(node.cputype)
// Get hostname
println(node.hostname)
// Get environment variables
env_vars := node.environ_get()!
println(env_vars['HOME'])
// Get node information (category, sshkey, user, ipaddress, port)
info := node.info()
println(info['category'])
```
## Command Execution
The `Node` object provides methods to execute commands on the target system.
### `node.exec(args ExecArgs) !string`
Executes a command and returns its standard output.
```v
import freeflowuniverse.herolib.builder { ExecArgs }
// Execute a command with stdout
result := node.exec(cmd: "ls -la /tmp", stdout: true)!
println(result)
// Execute silently (no stdout)
node.exec(cmd: "mkdir -p /tmp/my_dir", stdout: false)!
```
### `node.exec_silent(cmd string) !string`
Executes a command silently (no stdout) and returns its output.
```v
output := node.exec_silent("echo 'Hello from remote!'")!
println(output)
```
### `node.exec_interactive(cmd string) !`
Executes a command in an interactive shell.
```v
// This will open an interactive shell session
node.exec_interactive("bash")!
```
### `node.exec_cmd(args NodeExecCmd) !string`
A more advanced command execution method that supports caching, periodic execution, and temporary script handling.
```v
import freeflowuniverse.herolib.builder { NodeExecCmd }
// Execute a command, cache its result for 24 hours (48*3600 seconds)
// and provide a description for logging.
result := node.exec_cmd(
cmd: "apt-get update",
period: 48 * 3600,
description: "Update system packages"
)!
println(result)
// Execute a multi-line script
script_output := node.exec_cmd(
cmd: "
echo 'Starting script...'
ls -la /
echo 'Script finished.'
",
name: "my_custom_script",
stdout: true
)!
println(script_output)
```
### `node.exec_retry(args ExecRetryArgs) !string`
Executes a command with retries until it succeeds or a timeout is reached.
```v
import freeflowuniverse.herolib.builder { ExecRetryArgs }
// Try to connect to a service, retrying every 100ms for up to 10 seconds
result := node.exec_retry(
cmd: "curl --fail http://localhost:8080/health",
retrymax: 100, // 100 retries
period_milli: 100, // 100ms sleep between retries
timeout: 10 // 10 seconds total timeout
)!
println("Service is up: ${result}")
```
### `node.cmd_exists(cmd string) bool`
Checks if a command exists on the target system.
```v
if node.cmd_exists("docker") {
println("Docker is installed.")
} else {
println("Docker is not installed.")
}
```
## File System Operations
The `Node` object provides comprehensive file and directory management capabilities.
### `node.file_write(path string, text string) !`
Writes content to a file on the target system.
```v
node.file_write("/tmp/my_file.txt", "This is some content.")!
```
### `node.file_read(path string) !string`
Reads content from a file on the target system.
```v
content := node.file_read("/tmp/my_file.txt")!
println(content)
```
### `node.file_exists(path string) bool`
Checks if a file or directory exists on the target system.
```v
if node.file_exists("/tmp/my_file.txt") {
println("File exists.")
}
```
### `node.delete(path string) !`
Deletes a file or directory (recursively for directories) on the target system.
```v
node.delete("/tmp/my_dir")!
```
### `node.list(path string) ![]string`
Lists the contents of a directory on the target system.
```v
files := node.list("/home/user")!
for file in files {
println(file)
}
```
### `node.dir_exists(path string) bool`
Checks if a directory exists on the target system.
```v
if node.dir_exists("/var/log") {
println("Log directory exists.")
}
```
### File Transfers (`node.upload` and `node.download`)
Transfer files between the local machine and the target node using `rsync` or `scp`.
```v
import freeflowuniverse.herolib.builder { SyncArgs }
// Upload a local file to the remote node
node.upload(
source: "/local/path/to/my_script.sh",
dest: "/tmp/remote_script.sh",
stdout: true // Show rsync/scp output
)!
// Download a file from the remote node to the local machine
node.download(
source: "/var/log/syslog",
dest: "/tmp/local_syslog.log",
stdout: false
)!
// Upload a directory, ignoring .git and examples folders, and deleting extra files on destination
node.upload(
source: "/local/repo/",
dest: "~/code/my_project/",
ignore: [".git/*", "examples/"],
delete: true,
fast_rsync: true
)!
```
## Node Database (`node.done`)
The `node.done` map provides a simple key-value store for persistent data on the node. This data is cached in Redis.
```v
// Store a value
node.done_set("setup_complete", "true")!
// Retrieve a value
status := node.done_get("setup_complete") or { "false" }
println("Setup complete: ${status}")
// Check if a key exists
if node.done_exists("initial_config") {
println("Initial configuration done.")
}
// Print all stored 'done' items
node.done_print()
// Reset all stored 'done' items
node.done_reset()!
```
## Bootstrapping and Updates
The `bootstrapper` module provides functions for installing and updating Herolib components on nodes.
### `node.hero_install() !`
Installs the Herolib environment on the node.
```v
node.hero_install()!
```
### `node.hero_update(args HeroUpdateArgs) !`
Updates the Herolib code on the node, with options for syncing from local, git reset, or git pull.
```v
import freeflowuniverse.herolib.builder { HeroUpdateArgs }
// Sync local Herolib code to the remote node (full sync)
node.hero_update(sync_from_local: true, sync_full: true)!
// Reset git repository on the remote node and pull latest from 'dev' branch
node.hero_update(git_reset: true, branch: "dev")!
```
### `node.vscript(args VScriptArgs) !`
Uploads and executes a Vlang script (`.vsh` or `.v`) on the remote node.
```v
import freeflowuniverse.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)!
```
## Port Forwarding
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 }
// Forward remote port 8080 on 192.168.1.100 to local port 9000
portforward_to_local(
name: "my_app_forward",
address: "192.168.1.100",
remote_port: 8080,
local_port: 9000
)!
```

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import os
import flag
mut fp := flag.new_flag_parser(os.args)
fp.application('compile.vsh')
fp.version('v0.1.0')
fp.description('Compile hero binary in debug or production mode')
fp.skip_executable()
prod_mode := fp.bool('prod', `p`, false, 'Build production version (optimized)')
help_requested := fp.bool('help', `h`, false, 'Show help message')
if help_requested {
println(fp.usage())
exit(0)
}
additional_args := fp.finalize() or {
eprintln(err)
println(fp.usage())
exit(1)
}

View File

@@ -0,0 +1,420 @@
# OSAL Core Module (freeflowuniverse.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
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.
* `timeout` (int, default: 3600): Max execution time in seconds.
* `retry` (int): Number of retries on failure.
* `work_folder` (string): Working directory.
* `environment` (map[string]string): Environment variables.
* `stdout` (bool, default: true): Show command output.
* `raise_error` (bool, default: true): Raise V error on failure.
* `ignore_error` (bool): Do not raise error, just report.
* `debug` (bool): Enable debug output.
* `shell` (bool): Execute in interactive shell.
* `async` (bool): Run command asynchronously.
* `runtime` (`RunTime` enum): Specify runtime (`.bash`, `.python`, etc.).
* **Returns**: `Job` struct (contains `status`, `output`, `error`, `exit_code`, `start`, `end`).
* **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) !`
Executes a command in an interactive shell.
* **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.
* **Parameters**: `pid` (int): Parent Process ID.
* **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.whoami() !string`
Returns the current username.
* **Returns**: `string`.
## 2. Network Utilities
### `osal.ping(args: PingArgs) !PingResult`
Checks host reachability.
* **Parameters**:
* `args` (`PingArgs` struct):
* `address` (string, required): IP address or hostname.
* `count` (u8, default: 1): Number of pings.
* `timeout` (u16, default: 1): Timeout in seconds per ping.
* `retry` (u8): Number of retry attempts.
* **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.
* `port` (int, default: 22): TCP port number.
* `timeout` (u16, default: 2000): Total timeout in milliseconds.
* **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).
## 4. Environment Variables
### `osal.env_set(args: EnvSet)`
Sets an environment variable.
* **Parameters**:
* `args` (`EnvSet` struct):
* `key` (string, required): Environment variable name.
* `value` (string, required): Value to set.
* `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.
* `clear_before_set` (bool): Clear all existing variables before setting.
* `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).
* `source` (string, required): Path to the binary.
* `symlink` (bool): Create a symlink instead of copying.
* `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.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).
* `paths2add` (string): Comma/newline separated list of paths to add.
* `paths2delete` (string): Comma/newline separated list of paths to delete.
* `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`
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.
* `name` (string): Optional, derived from filename if empty.
* `reset` (bool): Force download, remove existing.
* `hash` (string): Hash for verification.
* `dest` (string): Destination path.
* `timeout` (int, default: 180): Download timeout in seconds.
* `retry` (int, default: 3): Number of retries.
* `minsize_kb` (u32, default: 10): Minimum expected size in KB.
* `maxsize_kb` (u32): Maximum expected size in KB.
* `expand_dir` (string): Directory to expand archive into.
* `expand_file` (string): File to expand archive into.
* **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.
* **Returns**: `int` (User ID of the added user).
## 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

@@ -0,0 +1,92 @@
# OurTime Module
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`)
- Unix timestamp conversion
- Time formatting and warping
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
// Current time
mut t := ourtime.now()
// From string
t2 := ourtime.new('2022-12-05 20:14:35')!
// Get formatted string
println(t2.str()) // e.g., 2022-12-05 20:14
// Get Unix timestamp
println(t2.unix()) // e.g., 1670271275
```
## Time Formats
### Relative Time
Use `s` (seconds), `h` (hours), `d` (days), `w` (weeks), `M` (months), `Q` (quarters), `Y` (years).
```v
// Create with relative time
mut t := ourtime.new('+1w +2d -4h')!
// Warp existing time
mut t2 := ourtime.now()
t2.warp('+1h')!
```
### Absolute Time
Supports `YYYY-MM-DD HH:mm:ss`, `YYYY-MM-DD HH:mm`, `YYYY-MM-DD HH`, `YYYY-MM-DD`, `DD-MM-YYYY`.
```v
t1 := ourtime.new('2022-12-05 20:14:35')!
t2 := ourtime.new('2022-12-05')! // Time defaults to 00:00:00
```
## Methods Overview
### Creation
```v
now_time := ourtime.now()
from_string := ourtime.new('2023-01-15')!
from_epoch := ourtime.new_from_epoch(1673788800)
```
### Formatting
```v
mut t := ourtime.now()
println(t.str()) // YYYY-MM-DD HH:mm
println(t.day()) // YYYY-MM-DD
println(t.key()) // YYYY_MM_DD_HH_mm_ss
println(t.md()) // Markdown format
```
### Operations
```v
mut t := ourtime.now()
t.warp('+1h')! // Move 1 hour forward
unix_ts := t.unix()
is_empty := t.empty()
```
## Error Handling
Time parsing methods return a `Result` type and should be handled with `!` or `or` blocks.
```v
t_valid := ourtime.new('2023-01-01')!
t_invalid := ourtime.new('bad-date') or {
println('Error: ${err}')
ourtime.now() // Fallback
}

View File

@@ -0,0 +1,204 @@
# Redisclient Module
The `redisclient` module in Herolib provides a comprehensive client for interacting with Redis, supporting various commands, caching, queues, and RPC mechanisms.
## Key Features
- **Direct Redis Commands**: Access to a wide range of Redis commands (strings, hashes, lists, keys, etc.).
- **Caching**: Built-in caching mechanism with namespace support and expiration.
- **Queues**: Simple queue implementation using Redis lists.
- **RPC**: Remote Procedure Call (RPC) functionality over Redis queues for inter-service communication.
## Basic Usage
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
// Connect to default Redis instance (127.0.0.1:6379)
mut redis := redisclient.core_get()!
// Or connect to a specific Redis instance
// mut redis_url := redisclient.RedisURL{address: 'my.redis.server', port: 6380}
// mut redis := redisclient.core_get(redis_url)!
// Example: Set and Get a key
redis.set('mykey', 'myvalue')!
value := redis.get('mykey')!
// assert value == 'myvalue'
// Example: Check if a key exists
exists := redis.exists('mykey')!
// assert exists == true
// Example: Delete a key
redis.del('mykey')!
```
## Redis Commands
The `Redis` object provides methods for most standard Redis commands. Here are some examples:
### String Commands
- `set(key string, value string) !`: Sets the string value of a key.
- `get(key string) !string`: Gets the string value of a key.
- `set_ex(key string, value string, ex string) !`: Sets a key with an expiration time in seconds.
- `incr(key string) !int`: Increments the integer value of a key by one.
- `decr(key string) !int`: Decrements the integer value of a key by one.
- `append(key string, value string) !int`: Appends a value to a key.
- `strlen(key string) !int`: Gets the length of the value stored in a key.
```v
redis.set('counter', '10')!
redis.incr('counter')! // counter is now 11
val := redis.get('counter')! // "11"
```
### Hash Commands
- `hset(key string, skey string, value string) !`: Sets the string value of a hash field.
- `hget(key string, skey string) !string`: Gets the value of a hash field.
- `hgetall(key string) !map[string]string`: Gets all fields and values in a hash.
- `hexists(key string, skey string) !bool`: Checks if a hash field exists.
- `hdel(key string, skey string) !int`: Deletes one or more hash fields.
```v
redis.hset('user:1', 'name', 'John Doe')!
redis.hset('user:1', 'email', 'john@example.com')!
user_name := redis.hget('user:1', 'name')! // "John Doe"
user_data := redis.hgetall('user:1')! // map['name':'John Doe', 'email':'john@example.com']
```
### List Commands
- `lpush(key string, element string) !int`: Inserts all specified values at the head of the list stored at key.
- `rpush(key string, element string) !int`: Inserts all specified values at the tail of the list stored at key.
- `lpop(key string) !string`: Removes and returns the first element of the list stored at key.
- `rpop(key string) !string`: Removes and returns the last element of the list stored at key.
- `llen(key string) !int`: Gets the length of a list.
- `lrange(key string, start int, end int) ![]resp.RValue`: Gets a range of elements from a list.
```v
redis.lpush('mylist', 'item1')!
redis.rpush('mylist', 'item2')!
first_item := redis.lpop('mylist')! // "item1"
```
### Set Commands
- `sadd(key string, members []string) !int`: Adds the specified members to the set stored at key.
- `smismember(key string, members []string) ![]int`: Returns if member is a member of the set stored at key.
```v
redis.sadd('myset', ['member1', 'member2'])!
is_member := redis.smismember('myset', ['member1', 'member3'])! // [1, 0]
```
### Key Management
- `keys(pattern string) ![]string`: Finds all keys matching the given pattern.
- `del(key string) !int`: Deletes a key.
- `expire(key string, seconds int) !int`: Sets a key's time to live in seconds.
- `ttl(key string) !int`: Gets the time to live for a key in seconds.
- `flushall() !`: Deletes all the keys of all the existing databases.
- `flushdb() !`: Deletes all the keys of the currently selected database.
- `selectdb(database int) !`: Changes the selected database.
```v
redis.set('temp_key', 'value')!
redis.expire('temp_key', 60)! // Expires in 60 seconds
```
## Redis Cache
The `RedisCache` struct provides a convenient way to implement caching using Redis.
```v
import freeflowuniverse.herolib.core.redisclient
mut redis := redisclient.core_get()!
mut cache := redis.cache('my_app_cache')
// Set a value in cache with expiration (e.g., 3600 seconds)
cache.set('user:profile:123', '{ "name": "Alice" }', 3600)!
// Get a value from cache
cached_data := cache.get('user:profile:123') or {
// Cache miss, fetch from source
println('Cache miss for user:profile:123')
return
}
// println('Cached data: ${cached_data}')
// Check if a key exists in cache
exists := cache.exists('user:profile:123')
// assert exists == true
// Reset the cache for the namespace
cache.reset()!
```
## Redis Queue
The `RedisQueue` struct provides a simple queue mechanism using Redis lists.
```v
import freeflowuniverse.herolib.core.redisclient
import time
mut redis := redisclient.core_get()!
mut my_queue := redis.queue_get('my_task_queue')
// Add items to the queue
my_queue.add('task1')!
my_queue.add('task2')!
// Get an item from the queue with a timeout (e.g., 1000 milliseconds)
task := my_queue.get(1000)!
// assert task == 'task1'
// Pop an item without timeout (returns error if no item)
task2 := my_queue.pop()!
// assert task2 == 'task2'
```
## Redis RPC
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 json
import time
mut redis := redisclient.core_get()!
mut rpc_client := redis.rpc_get('my_rpc_service')
// Define a function to process RPC requests (server-side)
fn my_rpc_processor(cmd string, data string) !string {
// Simulate some processing based on cmd and data
return 'Processed: cmd=${cmd}, data=${data}'
}
// --- Client Side (calling the RPC) ---
// Call the RPC service
response := rpc_client.call(
cmd: 'greet',
data: '{"name": "World"}',
wait: true,
timeout: 5000 // 5 seconds timeout
)!
// println('RPC Response: ${response}')
// assert response == 'Processed: cmd=greet, data={"name": "World"}'
// --- Server Side (processing RPC requests) ---
// In a separate goroutine or process, you would run:
// rpc_client.process(my_rpc_processor, timeout: 0)! // timeout 0 means no timeout, keeps processing
// Example of how to process a single request (for testing/demonstration)
// In a real application, this would be in a loop or a background worker
// return_queue_name := rpc_client.process(my_rpc_processor, timeout: 1000)!
// result := rpc_client.result(1000, return_queue_name)!
// println('Processed result: ${result}')

View File

@@ -0,0 +1,206 @@
# 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.
## 1. Core Concepts
The spreadsheet module revolves around three main entities: `Sheet`, `Row`, and `Cell`.
### 1.1. Sheet
The `Sheet` is the primary container, representing the entire spreadsheet.
* **Properties:**
* `name` (string): A unique identifier for the sheet.
* `rows` (map[string]&Row): A collection of `Row` objects, indexed by their names.
* `nrcol` (int): The number of columns in the sheet (e.g., 60 for 5 years of monthly data).
* `params` (SheetParams): Configuration parameters, e.g., `visualize_cur` (boolean to display currency symbols).
* `currency` (currency.Currency): The default currency for the sheet (e.g., USD), used for automatic conversions.
* **Creation:**
```v
import freeflowuniverse.herolib.biz.spreadsheet
// Create a new sheet named 'my_financial_sheet' with 60 columns (e.g., 60 months)
mut my_sheet := spreadsheet.sheet_new(
name: 'my_financial_sheet',
nrcol: 60,
visualize_cur: true, // Optional: display currency symbols
curr: 'USD' // Optional: set default currency
)!
// Get an existing sheet from the global store
mut existing_sheet := spreadsheet.sheet_get('my_financial_sheet')!
```
* **Key Operations:**
* `sheet.row_get(name string) !&Row`: Retrieves a row by its name.
* `sheet.cell_get(row string, col int) !&Cell`: Retrieves a cell by row name and column index.
* `sheet.row_delete(name string)` / `sheet.delete(name string)`: Deletes a row.
* `sheet.cells_width(colnr int) !int`: Finds the maximum string length of cells in a given column.
* `sheet.rows_names_width_max() int`: Returns the maximum width of row names/aliases.
* `sheet.rows_description_width_max() int`: Returns the maximum width of row descriptions.
* `sheet.header() ![]string`: Generates column headers (e.g., "M1", "Q1", "Y1") based on `nrcol`.
### 1.2. Row
A `Row` represents a single horizontal line of data within a `Sheet`.
* **Properties:**
* `name` (string): Unique identifier for the row.
* `alias` (string, optional): Alternative name.
* `description` (string): Textual description.
* `tags` (string): Space-separated tags for categorization (e.g., "department:hr location:belgium").
* `cells` ([]Cell): List of `Cell` objects.
* `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(
name: 'salaries',
tags: 'department:hr location:belgium',
descr: 'Monthly salaries for HR department in Belgium',
aggregatetype: .sum
)!
```
* **Key Operations:**
* `row.values_get() []f64`: Returns all cell values in the row as a list of floats.
### 1.3. Cell
A `Cell` is the fundamental unit of data, storing a numeric value.
* **Properties:**
* `val` (f64): The numeric value.
* `empty` (bool): `true` if the cell is empty.
* **Key Operations:**
* `cell.set(v string) !`: Sets the cell's value. Handles currency strings (e.g., "100 USD") by converting to the sheet's currency.
* `cell.add(v f64)`: Adds a numeric value to the existing cell value.
* `cell.repr() string`: Returns a formatted string representation of the value (e.g., "100.00", or "-" if empty).
## 2. Data Aggregation and Transformation
The module provides powerful tools for summarizing and transforming data.
### 2.1. Grouping Rows (`group2row`)
Aggregates selected rows into a new single row based on tags.
```v
// Aggregate rows tagged 'department:dev' or 'department:engineering' into a new row
mut total_salaries_row := my_sheet.group2row(
name: 'total_dev_engineering_salaries',
include: ['department:dev', 'department:engineering'],
tags: 'summary:dev_eng',
descr: 'Total salaries for Development and Engineering departments',
aggregatetype: .sum // Can be .sum, .avg, .max, .min
)!
```
### 2.2. Transforming Periodicity (`toyear`, `toquarter`)
Creates new sheets with data aggregated into larger time periods.
```v
// Assuming 'monthly_sheet' has 60 columns (monthly data)
mut monthly_sheet := spreadsheet.sheet_new(name: 'monthly_data', nrcol: 60)!
// ... populate monthly_sheet
// Create a new sheet 'yearly_data' with data aggregated by year
mut yearly_sheet := monthly_sheet.toyear(
name: 'yearly_data',
namefilter: ['revenue_row', 'expenses_row'], // Optional: filter specific rows
includefilter: ['category:income'] // Optional: filter by tags
)!
// Create a new sheet 'quarterly_data' with data aggregated by quarter
mut quarterly_sheet := monthly_sheet.toquarter(name: 'quarterly_data')!
```
## 3. Exporting Data
Export sheet data to CSV format.
### 3.1. Export to CSV (`export_csv`)
```v
import os
// Export to a CSV file with default pipe '|' separator
my_sheet.export_csv(path: '~/output.csv')!
// Export with custom comma ',' separator and include empty cells
csv_content_with_empty := my_sheet.export_csv(
path: '~/output_with_empty.csv',
separator: ',',
include_empty: true
)!
// Export to a string only (no file)
csv_string := my_sheet.export_csv(path: '')!
println(csv_string)
```
* **`ExportCSVArgs` Parameters:**
* `path` (string, optional): File path. Empty string returns content as string. `~` is expanded to home directory.
* `include_empty` (bool, optional, default: `false`): If `true`, empty cells are included.
* `separator` (string, optional, default: `'|'`): Delimiter character.
## 4. Charting Capabilities
Integrates with ECharts for data visualization. Charting functions return an `echarts.EChartsOption` object.
### 4.1. Common Charting Parameters (`RowGetArgs`)
Used across line, bar, and pie charts to specify data and presentation.
* `rowname` (string, optional): Single row name or comma-separated list.
* `namefilter` ([]string, optional): List of exact row names to include.
* `includefilter` ([]string, optional): List of tags to include.
* `excludefilter` ([]string, optional): List of tags to exclude.
* `period_type` (PeriodType, optional): X-axis period (`.month`, `.quarter`, `.year`).
* `aggregate` (bool, optional, default: `true`): Aggregate multiple matching rows.
* `aggregatetype` (RowAggregateType, optional, default: `.sum`): Aggregation type.
* `unit` (UnitType, optional): Data unit.
* `title`, `title_sub` (string, optional): Chart titles.
* `size` (string, optional): For pie charts, defines radius (e.g., "70%").
* `rowname_show` (bool, optional, default: `true`): Show row name in legend.
* `descr_show` (bool, optional, default: `false`): Show row description (overrides `rowname_show`).
* `description` (string, optional): General chart description.
### 4.2. Chart Types
* **Line Chart (`line_chart`)**: Visualizes trends over time.
```v
import freeflowuniverse.herolib.web.echarts // Required for EChartsOption type
line_chart_option := my_sheet.line_chart(
rowname: 'revenue_row,expenses_row',
period_type: .month,
title: 'Revenue vs. Expenses Over Time'
)!
```
* **Bar Chart (`bar_chart`)**: Compares discrete categories or values.
```v
bar_chart_option := my_sheet.bar_chart(
rowname: 'profit_row',
period_type: .quarter,
title: 'Quarterly Profit'
)!
```
* **Pie Chart (`pie_chart`)**: Shows proportions of categories.
```v
pie_chart_option := my_sheet.pie_chart(
rowname: 'budget_allocation_row',
period_type: .year,
title: 'Annual Budget Allocation',
size: '70%'
)!
```
This documentation should provide sufficient information for an AI to understand and utilize the `lib/biz/spreadsheet` module effectively for various data manipulation and visualization tasks.

View File

@@ -0,0 +1,11 @@
# 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.
```v
#!/usr/bin/env vsh
const script_path = os.dir(@FILE) + '/scripts'
echo "Current scripts directory: ${script_directory}"
```

View File

@@ -0,0 +1,44 @@
## how to remember clients, installers as a global
the following is a good pragmatic way to remember clients, installers as a global, use it as best practice.
```vmodule docsite
module docsite
import freeflowuniverse.herolib.core.texttools
__global (
siteconfigs map[string]&SiteConfig
)
@[params]
pub struct FactoryArgs {
pub mut:
name string = "default"
}
pub fn new(args FactoryArgs) !&SiteConfig {
name := texttools.name_fix(args.name)
siteconfigs[name] = &SiteConfig{
name: name
}
return get(name:name)!
}
pub fn get(args FactoryArgs) !&SiteConfig {
name := texttools.name_fix(args.name)
mut sc := siteconfigs[name] or {
return error('siteconfig with name "${name}" does not exist')
}
return sc
}
pub fn default() !&SiteConfig {
if siteconfigs.len == 0 {
return new(name:'default')!
}
return get()!
}
```

View File

@@ -0,0 +1,54 @@
# HeroScript: Vlang Integration
## HeroScript Structure
HeroScript is a concise scripting language with the following structure:
```heroscript
!!actor.action_name
param1: 'value1'
param2: 'value with spaces'
multiline_description: '
This is a multiline description.
It can span multiple lines.
'
arg1 arg2 // Arguments without keys
```
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`).
## 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
pub fn play(mut plbook PlayBook) ! {
if plbook.exists_once(filter: 'docusaurus.define') {
mut action := plbook.get(filter: 'docusaurus.define')!
mut p := action.params
//example how we get parameters from the action see core_params.md for more details
ds = new(
path: p.get_default('path_publish', '')!
production: p.get_default_false('production')
)!
}
// Process 'docusaurus.add' actions to configure individual Docusaurus sites
actions := plbook.find(filter: 'docusaurus.add')!
for action in actions {
mut p := action.params
//do more processing here
}
}
```
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

@@ -0,0 +1,25 @@
# PlayBook
## get & execute a playbook
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
// path string
// text string
// git_url string
// git_pull bool
// git_branch string
// git_reset bool
// session ?&base.Session is optional
mut plbook := playbook.new(path: "....")!
//now we run all the commands as they are pre-defined in herolib, this will execute the playbook and do all actions.
playcmds.run(mut plbook)!
```

View File

@@ -0,0 +1,107 @@
# HTTPConnection Module
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
- Caching
- URL encoding
## Basic Usage
```v
import freeflowuniverse.herolib.core.httpconnection
// Create a new HTTP connection
mut conn := httpconnection.new(
name: 'my_api_client'
url: 'https://api.example.com'
retry: 3 // Number of retries for failed requests
cache: true // Enable caching
)!
```
## Integration with Management Classes
To integrate `HTTPConnection` into a management class (e.g., `HetznerManager`), use a method to lazily initialize and return the connection:
```v
// Example: HetznerManager
pub fn (mut h HetznerManager) connection() !&httpconnection.HTTPConnection {
mut c := h.conn or {
mut c2 := httpconnection.new(
name: 'hetzner_${h.name}'
url: h.baseurl
cache: true
retry: 3
)!
c2.basic_auth(h.user, h.password)
c2
}
return c
}
```
## Examples
### GET Request with JSON Response
```v
struct User {
id int
name string
email string
}
user := conn.get_json_generic[User](
prefix: 'users/1'
)!
```
### POST Request with JSON Data
```v
struct NewUserResponse {
id int
status string
}
new_user_resp := conn.post_json_generic[NewUserResponse](
prefix: 'users'
params: {
'name': 'Jane Doe'
'email': 'jane@example.com'
}
)!
```
### Custom Headers
Set default headers or add them per request:
```v
import net.http { Header }
// Set default header
conn.default_header = http.new_header(key: .authorization, value: 'Bearer your-token')
// Add custom header for a specific request
response := conn.get_json(
prefix: 'protected/resource'
header: http.new_header(key: .content_type, value: 'application/json')
)!
```
### Error Handling
Methods return a `Result` type for error handling:
```v
user := conn.get_json_generic[User](
prefix: 'users/1'
) or {
println('Error fetching user: ${err}')
return
}

View File

@@ -0,0 +1,63 @@
# OSAL Core Module - Key Capabilities (freeflowuniverse.herolib.osal.core)
```v
//example how to get started
import freeflowuniverse.herolib.osal.core as osal
osal.exec(cmd:"ls /")!
```
this document has info about the most core functions, more detailed info can be found in `aiprompts/herolib_advanced/osal.md` if needed.
## Key Functions
### 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.
### 2. Network Utilities
* **`osal.ping(args: PingArgs) !PingResult`**: Check host reachability.
* **Key Parameters**: `address` (string).
* **Returns**: `PingResult` (`.ok`, `.timeout`, `.unknownhost`).
* **`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.
### 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.
### 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).
### 6. System Information
* **`osal.platform() !PlatformType`**: Identify the operating system.
* **`osal.cputype() !CPUType`**: Identify the CPU architecture.
* **`osal.hostname() !string`**: Get system hostname.
---

View File

@@ -0,0 +1,92 @@
# OurTime Module
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`)
- Unix timestamp conversion
- Time formatting and warping
## Basic Usage
```v
import freeflowuniverse.herolib.data.ourtime
// Current time
mut t := ourtime.now()
// From string
t2 := ourtime.new('2022-12-05 20:14:35')!
// Get formatted string
println(t2.str()) // e.g., 2022-12-05 20:14
// Get Unix timestamp
println(t2.unix()) // e.g., 1670271275
```
## Time Formats
### Relative Time
Use `s` (seconds), `h` (hours), `d` (days), `w` (weeks), `M` (months), `Q` (quarters), `Y` (years).
```v
// Create with relative time
mut t := ourtime.new('+1w +2d -4h')!
// Warp existing time
mut t2 := ourtime.now()
t2.warp('+1h')!
```
### Absolute Time
Supports `YYYY-MM-DD HH:mm:ss`, `YYYY-MM-DD HH:mm`, `YYYY-MM-DD HH`, `YYYY-MM-DD`, `DD-MM-YYYY`.
```v
t1 := ourtime.new('2022-12-05 20:14:35')!
t2 := ourtime.new('2022-12-05')! // Time defaults to 00:00:00
```
## Methods Overview
### Creation
```v
now_time := ourtime.now()
from_string := ourtime.new('2023-01-15')!
from_epoch := ourtime.new_from_epoch(1673788800)
```
### Formatting
```v
mut t := ourtime.now()
println(t.str()) // YYYY-MM-DD HH:mm
println(t.day()) // YYYY-MM-DD
println(t.key()) // YYYY_MM_DD_HH_mm_ss
println(t.md()) // Markdown format
```
### Operations
```v
mut t := ourtime.now()
t.warp('+1h')! // Move 1 hour forward
unix_ts := t.unix()
is_empty := t.empty()
```
## Error Handling
Time parsing methods return a `Result` type and should be handled with `!` or `or` blocks.
```v
t_valid := ourtime.new('2023-01-01')!
t_invalid := ourtime.new('bad-date') or {
println('Error: ${err}')
ourtime.now() // Fallback
}

View File

@@ -0,0 +1,109 @@
# Parameter Parsing in Vlang
This document details the `paramsparser` module, essential for handling parameters in HeroScript and other contexts.
## Obtaining a `paramsparser` Instance
```v
import freeflowuniverse.herolib.data.paramsparser
// Create new params from a string
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
// Or create an empty instance and add parameters programmatically
mut params := paramsparser.new_params()
params.set("color", "red")
```
## Parameter Formats
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)
Example:
```vlang
text := "name:'John Doe' age:30 active:true // user details"
params := paramsparser.new(text)!
```
## Parameter Retrieval Methods
The `paramsparser` module provides a comprehensive set of methods for retrieving and converting parameter values.
### Basic Retrieval
- `get(key string) !string`: Retrieves a string value by key. Returns an error if the key does not exist.
- `get_default(key string, defval string) !string`: Retrieves a string value by key, or returns `defval` if the key is not found.
- `exists(key string) bool`: Checks if a keyword argument (`key:value`) exists.
- `exists_arg(key string) bool`: Checks if an argument (value without a key) exists.
### Argument Retrieval (Positional)
- `get_arg(nr int) !string`: Retrieves an argument by its 0-based index. Returns an error if the index is out of bounds.
- `get_arg_default(nr int, defval string) !string`: Retrieves an argument by index, or returns `defval` if the index is out of bounds.
### Type-Specific Retrieval
- `get_int(key string) !int`: Converts and retrieves an integer (int32).
- `get_int_default(key string, defval int) !int`: Retrieves an integer with a default.
- `get_u32(key string) !u32`: Converts and retrieves an unsigned 32-bit integer.
- `get_u32_default(key string, defval u32) !u32`: Retrieves a u32 with a default.
- `get_u64(key string) !u64`: Converts and retrieves an unsigned 64-bit integer.
- `get_u64_default(key string, defval u64) !u64`: Retrieves a u64 with a default.
- `get_u8(key string) !u8`: Converts and retrieves an unsigned 8-bit integer.
- `get_u8_default(key string, defval u8) !u8`: Retrieves a u8 with a default.
- `get_float(key string) !f64`: Converts and retrieves a 64-bit float.
- `get_float_default(key string, defval f64) !f64`: Retrieves a float with a default.
- `get_percentage(key string) !f64`: Converts a percentage string (e.g., "80%") to a float (0.8).
- `get_percentage_default(key string, defval string) !f64`: Retrieves a percentage with a default.
### Boolean Retrieval
- `get_default_true(key string) bool`: Returns `true` if the value is empty, "1", "true", "y", or "yes". Otherwise `false`.
- `get_default_false(key string) bool`: Returns `false` if the value is empty, "0", "false", "n", or "no". Otherwise `true`.
### List Retrieval
Lists are typically comma-separated strings (e.g., `users: "john,jane,bob"`).
- `get_list(key string) ![]string`: Retrieves a list of strings.
- `get_list_default(key string, def []string) ![]string`: Retrieves a list of strings with a default.
- `get_list_int(key string) ![]int`: Retrieves a list of integers.
- `get_list_int_default(key string, def []int) []int`: Retrieves a list of integers with a default.
- `get_list_f32(key string) ![]f32`: Retrieves a list of 32-bit floats.
- `get_list_f32_default(key string, def []f32) []f32`: Retrieves a list of f32 with a default.
- `get_list_f64(key string) ![]f64`: Retrieves a list of 64-bit floats.
- `get_list_f64_default(key string, def []f64) []f64`: Retrieves a list of f64 with a default.
- `get_list_i8(key string) ![]i8`: Retrieves a list of 8-bit signed integers.
- `get_list_i8_default(key string, def []i8) []i8`: Retrieves a list of i8 with a default.
- `get_list_i16(key string) ![]i16`: Retrieves a list of 16-bit signed integers.
- `get_list_i16_default(key string, def []i16) []i16`: Retrieves a list of i16 with a default.
- `get_list_i64(key string) ![]i64`: Retrieves a list of 64-bit signed integers.
- `get_list_i64_default(key string, def []i64) []i64`: Retrieves a list of i64 with a default.
- `get_list_u16(key string) ![]u16`: Retrieves a list of 16-bit unsigned integers.
- `get_list_u16_default(key string, def []u16) []u16`: Retrieves a list of u16 with a default.
- `get_list_u32(key string) ![]u32`: Retrieves a list of 32-bit unsigned integers.
- `get_list_u32_default(key string, def []u32) []u32`: Retrieves a list of u32 with a default.
- `get_list_u64(key string) ![]u64`: Retrieves a list of 64-bit unsigned integers.
- `get_list_u64_default(key string, def []u64) []u64`: Retrieves a list of u64 with a default.
- `get_list_namefix(key string) ![]string`: Retrieves a list of strings, normalizing each item (e.g., "My Name" -> "my_name").
- `get_list_namefix_default(key string, def []string) ![]string`: Retrieves a list of name-fixed strings with a default.
### Specialized Retrieval
- `get_map() map[string]string`: Returns all parameters as a map.
- `get_path(key string) !string`: Retrieves a path string.
- `get_path_create(key string) !string`: Retrieves a path string, creating the directory if it doesn't exist.
- `get_from_hashmap(key string, defval string, hashmap map[string]string) !string`: Retrieves a value from a provided hashmap based on the parameter's value.
- `get_storagecapacity_in_bytes(key string) !u64`: Converts storage capacity strings (e.g., "10 GB", "500 MB") to bytes (u64).
- `get_storagecapacity_in_bytes_default(key string, defval u64) !u64`: Retrieves storage capacity in bytes with a default.
- `get_storagecapacity_in_gigabytes(key string) !u64`: Converts storage capacity strings to gigabytes (u64).
- `get_time(key string) !ourtime.OurTime`: Parses a time string (relative or absolute) into an `ourtime.OurTime` object.
- `get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime`: Retrieves time with a default.
- `get_time_interval(key string) !Duration`: Parses a time interval string into a `Duration` object.
- `get_timestamp(key string) !Duration`: Parses a timestamp string into a `Duration` object.
- `get_timestamp_default(key string, defval Duration) !Duration`: Retrieves a timestamp with a default.

View File

@@ -0,0 +1,150 @@
# Pathlib Usage Guide
## Overview
The pathlib module provides a comprehensive interface for handling file system operations. Key features include:
- Robust path handling for files, directories, and symlinks
- Support for both absolute and relative paths
- Automatic home directory expansion (~)
- Recursive directory operations
- Path filtering and listing
- File and directory metadata access
## Basic Usage
### Importing pathlib
```v
import freeflowuniverse.herolib.core.pathlib
```
### Creating Path Objects
```v
// Create a Path object for a file
mut file_path := pathlib.get("path/to/file.txt")
// Create a Path object for a directory
mut dir_path := pathlib.get("path/to/directory")
```
### Basic Path Operations
```v
// Get absolute path
abs_path := file_path.absolute()
// Get real path (resolves symlinks)
real_path := file_path.realpath()
// Check if path exists
if file_path.exists() {
// Path exists
}
```
## Path Properties and Methods
### Path Types
```v
// Check if path is a file
if file_path.is_file() {
// Handle as file
}
// Check if path is a directory
if dir_path.is_dir() {
// Handle as directory
}
// Check if path is a symlink
if file_path.is_link() {
// Handle as symlink
}
```
### Path Normalization
```v
// Normalize path (remove extra slashes, resolve . and ..)
normalized_path := file_path.path_normalize()
// Get path directory
dir_path := file_path.path_dir()
// Get path name without extension
name_no_ext := file_path.name_no_ext()
```
## File and Directory Operations
### File Operations
```v
// Write to file
file_path.write("Content to write")!
// Read from file
content := file_path.read()!
// Delete file
file_path.delete()!
```
### Directory Operations
```v
// Create directory
mut dir := pathlib.get_dir(
path: "path/to/new/dir"
create: true
)!
// List directory contents
mut dir_list := dir.list()!
// Delete directory
dir.delete()!
```
### Symlink Operations
```v
// Create symlink
file_path.link("path/to/symlink", delete_exists: true)!
// Resolve symlink
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)!
// Delete directory recursively
dir.delete()!
```
### Path Filtering
```v
// List files matching pattern
mut filtered_list := dir.list(
regex: [r".*\.txt$"],
recursive: true
)!
```
## Best Practices
### Error Handling
```v
if file_path.exists() {
// Safe to operate
} else {
// Handle missing file
}
```

View File

@@ -0,0 +1,99 @@
# TextTools Module
The `texttools` module provides a comprehensive set of utilities for text manipulation and processing.
## Functions and Examples:
```v
import freeflowuniverse.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")
// Result: {'name': 'root', 'pid': '1360', 'path': '/usr/sbin/distnoted'}
```

View File

@@ -3,13 +3,10 @@
this is how we want example scripts to be, see the first line
```vlang
#!/usr/bin/env -S v -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib...
mut ds := daguserver.get()!
println(ds)
```
the files are in ~/code/github/freeflowuniverse/herolib/examples for herolib
@@ -17,3 +14,5 @@ the files are in ~/code/github/freeflowuniverse/herolib/examples for herolib
## important instructions
- never use fn main() in a .vsh script
- always use the top line as in example above
- these scripts can be executed as is but can also use vrun $pathOfFile

View File

@@ -11,45 +11,22 @@
when I generate vlang scripts I will always use .vsh extension and use following as first line:
```
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
```
- a .vsh is a v shell script and can be executed as is, no need to use v ...
- in .vsh file there is no need for a main() function
- these scripts can be used for examples or instruction scripts e.g. an installs script
## to do argument parsing use following examples
## executing vlang scripts
```v
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import os
import flag
mut fp := flag.new_flag_parser(os.args)
fp.application('compile.vsh')
fp.version('v0.1.0')
fp.description('Compile hero binary in debug or production mode')
fp.skip_executable()
prod_mode := fp.bool('prod', `p`, false, 'Build production version (optimized)')
help_requested := fp.bool('help', `h`, false, 'Show help message')
if help_requested {
println(fp.usage())
exit(0)
}
additional_args := fp.finalize() or {
eprintln(err)
println(fp.usage())
exit(1)
}
As AI agent I should also execute v or .vsh scripts with vrun
```bash
vrun ~/code/github/freeflowuniverse/herolib/examples/biztools/bizmodel.vsh
```
## when creating a test script
## executing test scripts
instruct user to test as follows (vtest is an alias which gets installed when herolib gets installed), can be done for a dir and for a file
@@ -58,3 +35,4 @@ vtest ~/code/github/freeflowuniverse/herolib/lib/osal/package_test.v
```
- use ~ so it works over all machines
- don't use 'v test', we have vtest as alternative

View File

@@ -1 +0,0 @@
../lib/core/httpconnection/readme.md

View File

@@ -1 +0,0 @@
../lib/osal/readme.md

View File

@@ -1 +0,0 @@
../lib/data/ourdb/README.md

View File

@@ -1 +0,0 @@
../lib/data/ourtime/readme.md

View File

@@ -1 +0,0 @@
../lib/data/paramsparser/readme.md

View File

@@ -1,309 +0,0 @@
# how to work with heroscript in vlang
## heroscript
Heroscript is our small scripting language which has following structure
an example of a heroscript is
```heroscript
!!dagu.script_define
name: 'test_dag'
homedir:''
title:'a title'
reset:1
start:true //trie or 1 is same
colors: 'green,red,purple' //lists are comma separated
description: '
a description can be multiline
like this
'
!!dagu.add_step
dag: 'test_dag'
name: 'hello_world'
command: 'echo hello world'
!!dagu.add_step
dag: 'test_dag'
name: 'last_step'
command: 'echo last step'
```
Notice how:
- every action starts with !!
- the first part is the actor e.g. dagu in this case
- the 2e part is the action name
- multilines are supported see the description field
## how to process heroscript in Vlang
- heroscript can be converted to a struct,
- the methods available to get the params are in 'params' section further in this doc
```vlang
fn test_play_dagu() ! {
mut plbook := playbook.new(text: thetext_from_above)!
play_dagu(mut plbook)! //see below in vlang block there it all happens
}
pub fn play_dagu(mut plbook playbook.PlayBook) ! {
//find all actions are !!$actor.$actionname. in this case above the actor is !!dagu, we check with the fitler if it exists, if not we return
dagu_actions := plbook.find(filter: 'dagu.')!
if dagu_actions.len == 0 {
return
}
play_dagu_basic(mut plbook)!
}
pub struct DaguScript {
pub mut:
name string
homedir string
title string
reset bool
start bool
colors []string
}
// play_dagu plays the dagu play commands
pub fn play_dagu_basic(mut plbook playbook.PlayBook) ! {
//now find the specific ones for dagu.script_define
mut actions := plbook.find(filter: 'dagu.script_define')!
if actions.len > 0 {
for myaction in actions {
mut p := myaction.params //get the params object from the action object, this can then be processed using the param getters
mut obj := DaguScript{
//INFO: all details about the get methods can be found in 'params get methods' section
name : p.get('name')! //will give error if not exist
homedir : p.get('homedir')!
title : p.get_default('title', 'My Hero DAG')! //uses a default if not set
reset : p.get_default_false('reset')
start : p.get_default_true('start')
colors : p.get_list('colors')
description : p.get_default('description','')!
}
...
}
}
//there can be more actions which will have other filter
}
```
## params get methods (param getters)
```vlang
fn (params &Params) exists(key_ string) bool
//check if arg exist (arg is just a value in the string e.g. red, not value:something)
fn (params &Params) exists_arg(key_ string) bool
//see if the kwarg with the key exists if yes return as string trimmed
fn (params &Params) get(key_ string) !string
//return the arg with nr, 0 is the first
fn (params &Params) get_arg(nr int) !string
//return arg, if the nr is larger than amount of args, will return the defval
fn (params &Params) get_arg_default(nr int, defval string) !string
fn (params &Params) get_default(key string, defval string) !string
fn (params &Params) get_default_false(key string) bool
fn (params &Params) get_default_true(key string) bool
fn (params &Params) get_float(key string) !f64
fn (params &Params) get_float_default(key string, defval f64) !f64
fn (params &Params) get_from_hashmap(key_ string, defval string, hashmap map[string]string) !string
fn (params &Params) get_int(key string) !int
fn (params &Params) get_int_default(key string, defval int) !int
//Looks for a list of strings in the parameters. ',' are used as deliminator to list
fn (params &Params) get_list(key string) ![]string
fn (params &Params) get_list_default(key string, def []string) ![]string
fn (params &Params) get_list_f32(key string) ![]f32
fn (params &Params) get_list_f32_default(key string, def []f32) []f32
fn (params &Params) get_list_f64(key string) ![]f64
fn (params &Params) get_list_f64_default(key string, def []f64) []f64
fn (params &Params) get_list_i16(key string) ![]i16
fn (params &Params) get_list_i16_default(key string, def []i16) []i16
fn (params &Params) get_list_i64(key string) ![]i64
fn (params &Params) get_list_i64_default(key string, def []i64) []i64
fn (params &Params) get_list_i8(key string) ![]i8
fn (params &Params) get_list_i8_default(key string, def []i8) []i8
fn (params &Params) get_list_int(key string) ![]int
fn (params &Params) get_list_int_default(key string, def []int) []int
fn (params &Params) get_list_namefix(key string) ![]string
fn (params &Params) get_list_namefix_default(key string, def []string) ![]string
fn (params &Params) get_list_u16(key string) ![]u16
fn (params &Params) get_list_u16_default(key string, def []u16) []u16
fn (params &Params) get_list_u32(key string) ![]u32
fn (params &Params) get_list_u32_default(key string, def []u32) []u32
fn (params &Params) get_list_u64(key string) ![]u64
fn (params &Params) get_list_u64_default(key string, def []u64) []u64
fn (params &Params) get_list_u8(key string) ![]u8
fn (params &Params) get_list_u8_default(key string, def []u8) []u8
fn (params &Params) get_map() map[string]string
fn (params &Params) get_path(key string) !string
fn (params &Params) get_path_create(key string) !string
fn (params &Params) get_percentage(key string) !f64
fn (params &Params) get_percentage_default(key string, defval string) !f64
//convert GB, MB, KB to bytes e.g. 10 GB becomes bytes in u64
fn (params &Params) get_storagecapacity_in_bytes(key string) !u64
fn (params &Params) get_storagecapacity_in_bytes_default(key string, defval u64) !u64
fn (params &Params) get_storagecapacity_in_gigabytes(key string) !u64
//Get Expiration object from time string input input can be either relative or absolute## Relative time
fn (params &Params) get_time(key string) !ourtime.OurTime
fn (params &Params) get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime
fn (params &Params) get_time_interval(key string) !Duration
fn (params &Params) get_timestamp(key string) !Duration
fn (params &Params) get_timestamp_default(key string, defval Duration) !Duration
fn (params &Params) get_u32(key string) !u32
fn (params &Params) get_u32_default(key string, defval u32) !u32
fn (params &Params) get_u64(key string) !u64
fn (params &Params) get_u64_default(key string, defval u64) !u64
fn (params &Params) get_u8(key string) !u8
fn (params &Params) get_u8_default(key string, defval u8) !u8
```
## how internally a heroscript gets parsed for params
- example to show how a heroscript gets parsed in action with params
- params are part of action object
```heroscript
example text to parse (heroscript)
id:a1 name6:aaaaa
name:'need to do something 1'
description:
'
## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
name2: test
name3: hi
name10:'this is with space' name11:aaa11
name4: 'aaa'
//somecomment
name5: 'aab'
```
the params are part of the action and are represented as follow for the above:
```vlang
Params{
params: [Param{
key: 'id'
value: 'a1'
}, Param{
key: 'name6'
value: 'aaaaa'
}, Param{
key: 'name'
value: 'need to do something 1'
}, Param{
key: 'description'
value: '## markdown works in it
description can be multiline
lets see what happens
- a
- something else
### subtitle
'
}, Param{
key: 'name2'
value: 'test'
}, Param{
key: 'name3'
value: 'hi'
}, Param{
key: 'name10'
value: 'this is with space'
}, Param{
key: 'name11'
value: 'aaa11'
}, Param{
key: 'name4'
value: 'aaa'
}, Param{
key: 'name5'
value: 'aab'
}]
}
```

View File

@@ -0,0 +1,45 @@
The `compress` module in V provides low-level functionalities for compressing and decompressing byte arrays.
**Functions Overview (Low-Level):**
* **`compress(data []u8, flags int) ![]u8`**: Compresses an array of bytes.
* **`decompress(data []u8, flags int) ![]u8`**: Decompresses an array of bytes.
* **`decompress_with_callback(data []u8, cb ChunkCallback, userdata voidptr, flags int) !u64`**: Decompresses byte arrays using a callback function for chunks.
**Type Definition (Low-Level):**
* **`ChunkCallback`**: A function type `fn (chunk []u8, userdata voidptr) int` used to receive decompressed chunks.
---
**`compress.gzip` Module (High-Level Gzip Operations):**
For high-level gzip compression and decompression, use the `compress.gzip` module. This module provides a more convenient and recommended way to handle gzip operations compared to the low-level `compress` module.
**Key Features of `compress.gzip`:**
* **`compress(data []u8, params CompressParams) ![]u8`**: Compresses data using gzip, allowing specification of `CompressParams` like `compression_level` (0-4095).
* **`decompress(data []u8, params DecompressParams) ![]u8`**: Decompresses gzip-compressed data, allowing specification of `DecompressParams` for verification.
* **`decompress_with_callback(data []u8, cb compr.ChunkCallback, userdata voidptr, params DecompressParams) !int`**: Decompresses gzip data with a callback for chunks, similar to the low-level version but for gzip streams.
* **`validate(data []u8, params DecompressParams) !GzipHeader`**: Validates a gzip header and returns its details.
**Parameter Structures:**
* **`CompressParams`**: Configures compression, primarily `compression_level` (0-4095).
* **`DecompressParams`**: Configures decompression, including `verify_header_checksum`, `verify_length`, and `verify_checksum`.
* **`GzipHeader`**: Represents the structure of a gzip header.
**Inline Code Example (Gzip Compression/Decompression):**
```v
import compress.gzip
data := 'Hello, Gzip!'
compressed := gzip.compress(data.bytes(), compression_level: 4095)!
decompressed := gzip.decompress(compressed)!
// Check if decompressed data matches original
// if data.bytes() == decompressed { ... }
```
**Important Note:** Always prefer `compress.gzip` for general gzip compression/decompression tasks over the low-level `compress` module.

View File

@@ -0,0 +1,64 @@
```v
struct Repo[T] {
db DB
}
struct User {
id int
name string
}
struct Post {
id int
user_id int
title string
body string
}
fn new_repo[T](db DB) Repo[T] {
return Repo[T]{db: db}
}
// This is a generic function. V will generate it for every type it's used with.
fn (r Repo[T]) find_by_id(id int) ?T {
table_name := T.name // in this example getting the name of the type gives us the table name
return r.db.query_one[T]('select * from ${table_name} where id = ?', id)
}
db := new_db()
users_repo := new_repo[User](db) // returns Repo[User]
posts_repo := new_repo[Post](db) // returns Repo[Post]
user := users_repo.find_by_id(1)? // find_by_id[User]
post := posts_repo.find_by_id(1)? // find_by_id[Post]
```
Currently generic function definitions must declare their type parameters, but in future V will infer generic type parameters from single-letter type names in runtime parameter types. This is why find_by_id can omit [T], because the receiver argument r uses a generic type T.
```v
fn compare[T](a T, b T) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// compare[int]
println(compare(1, 0)) // Outputs: 1
println(compare(1, 1)) // 0
println(compare(1, 2)) // -1
// compare[string]
println(compare('1', '0')) // Outputs: 1
println(compare('1', '1')) // 0
println(compare('1', '2')) // -1
// compare[f64]
println(compare(1.1, 1.0)) // Outputs: 1
println(compare(1.1, 1.1)) // 0
println(compare(1.1, 1.2)) // -1
```

View File

@@ -0,0 +1,187 @@
## Compile time reflection
$ is used as a prefix for compile time (also referred to as 'comptime') operations.
Having built-in JSON support is nice, but V also allows you to create efficient serializers for any data format. V has compile time if and for constructs:
.fields
You can iterate over struct fields using .fields, it also works with generic types (e.g. T.fields) and generic arguments (e.g. param.fields where fn gen[T](param T) {).
struct User {
name string
age int
}
fn main() {
$for field in User.fields {
$if field.typ is string {
println('${field.name} is of type string')
}
}
}
// Output:
// name is of type string
.values
You can read Enum values and their attributes.
enum Color {
red @[RED] // first attribute
blue @[BLUE] // second attribute
}
fn main() {
$for e in Color.values {
println(e.name)
println(e.attrs)
}
}
// Output:
// red
// ['RED']
// blue
// ['BLUE']
.attributes
You can read Struct attributes.
@[COLOR]
struct Foo {
a int
}
fn main() {
$for e in Foo.attributes {
println(e)
}
}
// Output:
// StructAttribute{
// name: 'COLOR'
// has_arg: false
// arg: ''
// kind: plain
// }
.variants
You can read variant types from Sum type.
type MySum = int | string
fn main() {
$for v in MySum.variants {
$if v.typ is int {
println('has int type')
} $else $if v.typ is string {
println('has string type')
}
}
}
// Output:
// has int type
// has string type
.methods
You can retrieve information about struct methods.
struct Foo {
}
fn (f Foo) test() int {
return 123
}
fn (f Foo) test2() string {
return 'foo'
}
fn main() {
foo := Foo{}
$for m in Foo.methods {
$if m.return_type is int {
print('${m.name} returns int: ')
println(foo.$method())
} $else $if m.return_type is string {
print('${m.name} returns string: ')
println(foo.$method())
}
}
}
// Output:
// test returns int: 123
// test2 returns string: foo
.params
You can retrieve information about struct method params.
struct Test {
}
fn (t Test) foo(arg1 int, arg2 string) {
}
fn main() {
$for m in Test.methods {
$for param in m.params {
println('${typeof(param.typ).name}: ${param.name}')
}
}
}
// Output:
// int: arg1
// string: arg2
## Example
```v
// An example deserializer implementation
struct User {
name string
age int
}
fn main() {
data := 'name=Alice\nage=18'
user := decode[User](data)
println(user)
}
fn decode[T](data string) T {
mut result := T{}
// compile-time `for` loop
// T.fields gives an array of a field metadata type
$for field in T.fields {
$if field.typ is string {
// $(string_expr) produces an identifier
result.$(field.name) = get_string(data, field.name)
} $else $if field.typ is int {
result.$(field.name) = get_int(data, field.name)
}
}
return result
}
fn get_string(data string, field_name string) string {
for line in data.split_into_lines() {
key_val := line.split('=')
if key_val[0] == field_name {
return key_val[1]
}
}
return ''
}
fn get_int(data string, field string) int {
return get_string(data, field).int()
}
// `decode<User>` generates:
// fn decode_User(data string) User {
// mut result := User{}
// result.name = get_string(data, 'name')
// result.age = get_int(data, 'age')
// return result
// }
```

View File

@@ -1,907 +0,0 @@
# veb - the V Web Server
A simple yet powerful web server with built-in routing, parameter handling, templating, and other
features.
## Quick Start
Run your veb app with a live reload via `v -d veb_livereload watch run .`
Now modifying any file in your web app (whether it's a .v file with the backend logic
or a compiled .html template file) will
result in an instant refresh of your app
in the browser. No need to quit the app, rebuild it, and refresh the page in the browser!
## Deploying veb apps
All the code, including HTML templates, is in one binary file. That's all you need to deploy.
Use the `-prod` flag when building for production.
## Getting Started
To start, you must import the module `veb` and define a structure which will
represent your app and a structure which will represent the context of a request.
These structures must be declared with the `pub` keyword.
**Example:**
```v
module main
import veb
pub struct User {
pub mut:
name string
id int
}
// Our context struct must embed `veb.Context`!
pub struct Context {
veb.Context
pub mut:
// In the context struct we store data that could be different
// for each request. Like a User struct or a session id
user User
session_id string
}
pub struct App {
pub:
// In the app struct we store data that should be accessible by all endpoints.
// For example, a database or configuration values.
secret_key string
}
// This is how endpoints are defined in veb. This is the index route
pub fn (app &App) index(mut ctx Context) veb.Result {
return ctx.text('Hello V! The secret key is "${app.secret_key}"')
}
fn main() {
mut app := &App{
secret_key: 'secret'
}
// Pass the App and context type and start the web server on port 8080
veb.run[App, Context](mut app, 8080)
}
```
You can use the `App` struct for data you want to keep during the lifetime of your program,
or for data that you want to share between different routes.
A new `Context` struct is created every time a request is received,
so it can contain different data for each request.
## Defining endpoints
To add endpoints to your web server, you must extend the `App` struct.
For routing you can either use auto-mapping of function names or specify the path as an attribute.
The function expects a parameter of your Context type and a response of the type `veb.Result`.
**Example:**
```v ignore
// This endpoint can be accessed via http://server:port/hello
pub fn (app &App) hello(mut ctx Context) veb.Result {
return ctx.text('Hello')
}
// This endpoint can be accessed via http://server:port/foo
@['/foo']
pub fn (app &App) world(mut ctx Context) veb.Result {
return ctx.text('World')
}
```
### HTTP verbs
To use any HTTP verbs (or methods, as they are properly called),
such as `@[post]`, `@[get]`, `@[put]`, `@[patch]` or `@[delete]`
you can simply add the attribute before the function definition.
**Example:**
```v ignore
// only GET requests to http://server:port/world are handled by this method
@[get]
pub fn (app &App) world(mut ctx Context) veb.Result {
return ctx.text('World')
}
// only POST requests to http://server:port/product/create are handled by this method
@['/product/create'; post]
pub fn (app &App) create_product(mut ctx Context) veb.Result {
return ctx.text('product')
}
```
By default, endpoints are marked as GET requests only. It is also possible to
add multiple HTTP verbs per endpoint.
**Example:**
```v ignore
// only GET and POST requests to http://server:port/login are handled by this method
@['/login'; get; post]
pub fn (app &App) login(mut ctx Context) veb.Result {
if ctx.req.method == .get {
// show the login page on a GET request
return ctx.html('<h1>Login page</h1><p>todo: make form</p>')
} else {
// request method is POST
password := ctx.form['password']
// validate password length
if password.len < 12 {
return ctx.text('password is too weak!')
} else {
// we receive a POST request, so we want to explicitly tell the browser
// to send a GET request to the profile page.
return ctx.redirect('/profile')
}
}
}
```
### Routes with Parameters
Parameters are passed directly to an endpoint route using the colon sign `:`. The route
parameters are passed as arguments. V will cast the parameter to any of V's primitive types
(`string`, `int` etc,).
To pass a parameter to an endpoint, you simply define it inside an attribute, e. g.
`@['/hello/:user]`.
After it is defined in the attribute, you have to add it as a function parameter.
**Example:**
```v ignore
// V will pass the parameter 'user' as a string
vvvv
@['/hello/:user'] vvvv
pub fn (app &App) hello_user(mut ctx Context, user string) veb.Result {
return ctx.text('Hello ${user}')
}
// V will pass the parameter 'id' as an int
vv
@['/document/:id'] vv
pub fn (app &App) get_document(mut ctx Context, id int) veb.Result {
return ctx.text('Hello ${user}')
}
```
If we visit http://localhost:port/hello/vaesel we would see the text `Hello vaesel`.
### Routes with Parameter Arrays
If you want multiple parameters in your route and if you want to parse the parameters
yourself, or you want a wildcard route, you can add `...` after the `:` and name,
e.g. `@['/:path...']`.
This will match all routes after `'/'`. For example, the url `/path/to/test` would give
`path = '/path/to/test'`.
```v ignore
vvv
@['/:path...'] vvvv
pub fn (app &App) wildcard(mut ctx Context, path string) veb.Result {
return ctx.text('URL path = "${path}"')
}
```
### Query, Form and Files
You have direct access to query values by accessing the `query` field on your context struct.
You are also able to access any formdata or files that were sent
with the request with the fields `.form` and `.files` respectively.
In the following example, visiting http://localhost:port/user?name=veb we
will see the text `Hello veb!`. And if we access the route without the `name` parameter,
http://localhost:port/user, we will see the text `no user was found`,
**Example:**
```v ignore
@['/user'; get]
pub fn (app &App) get_user_by_id(mut ctx Context) veb.Result {
user_name := ctx.query['name'] or {
// we can exit early and send a different response if no `name` parameter was passed
return ctx.text('no user was found')
}
return ctx.text('Hello ${user_name}!')
}
```
### Host
To restrict an endpoint to a specific host, you can use the `host` attribute
followed by a colon `:` and the host name. You can test the Host feature locally
by adding a host to the "hosts" file of your device.
**Example:**
```v ignore
@['/'; host: 'example.com']
pub fn (app &App) hello_web(mut ctx Context) veb.Result {
return app.text('Hello World')
}
@['/'; host: 'api.example.org']
pub fn (app &App) hello_api(mut ctx Context) veb.Result {
return ctx.text('Hello API')
}
// define the handler without a host attribute last if you have conflicting paths.
@['/']
pub fn (app &App) hello_others(mut ctx Context) veb.Result {
return ctx.text('Hello Others')
}
```
You can also [create a controller](#controller-with-hostname) to handle all requests from a specific
host in one app struct.
### Route Matching Order
veb will match routes in the order that you define endpoints.
**Example:**
```v ignore
@['/:path']
pub fn (app &App) with_parameter(mut ctx Context, path string) veb.Result {
return ctx.text('from with_parameter, path: "${path}"')
}
@['/normal']
pub fn (app &App) normal(mut ctx Context) veb.Result {
return ctx.text('from normal')
}
```
In this example we defined an endpoint with a parameter first. If we access our app
on the url http://localhost:port/normal we will not see `from normal`, but
`from with_parameter, path: "normal"`.
### Custom not found page
You can implement a `not_found` endpoint that is called when a request is made, and no
matching route is found to replace the default HTTP 404 not found page. This route
has to be defined on our Context struct.
**Example:**
```v ignore
pub fn (mut ctx Context) not_found() veb.Result {
// set HTTP status 404
ctx.res.set_status(.not_found)
return ctx.html('<h1>Page not found!</h1>')
}
```
## Static files and website
veb also provides a way of handling static files. We can mount a folder at the root
of our web app, or at a custom route. To start using static files we have to embed
`veb.StaticHandler` on our app struct.
**Example:**
Let's say you have the following file structure:
```
.
├── static/
│ ├── css/
│ │ └── main.css
│ └── js/
│ └── main.js
└── main.v
```
If we want all the documents inside the `static` sub-directory to be publicly accessible, we can
use `handle_static`.
> **Note:**
> veb will recursively search the folder you mount; all the files inside that folder
> will be publicly available.
_main.v_
```v
module main
import veb
pub struct Context {
veb.Context
}
pub struct App {
veb.StaticHandler
}
fn main() {
mut app := &App{}
app.handle_static('static', false)!
veb.run[App, Context](mut app, 8080)
}
```
If we start the app with `v run main.v` we can access our `main.css` file at
http://localhost:8080/static/css/main.css
### Mounting folders at specific locations
In the previous example the folder `static` was mounted at `/static`. We could also choose
to mount the static folder at the root of our app: everything inside the `static` folder
is available at `/`.
**Example:**
```v ignore
// change the second argument to `true` to mount a folder at the app root
app.handle_static('static', true)!
```
We can now access `main.css` directly at http://localhost:8080/css/main.css.
If a request is made to the root of a static folder, veb will look for an
`index.html` or `ìndex.htm` file and serve it if available.
Thus, it's also a good way to host a complete website.
An example is available [here](/examples/veb/static_website).
It is also possible to mount the `static` folder at a custom path.
**Example:**
```v ignore
// mount the folder 'static' at path '/public', the path has to start with '/'
app.mount_static_folder_at('static', '/public')
```
If we run our app the `main.css` file is available at http://localhost:8080/public/main.css
### Adding a single static asset
If you don't want to mount an entire folder, but only a single file, you can use `serve_static`.
**Example:**
```v ignore
// serve the `main.css` file at '/path/main.css'
app.serve_static('/path/main.css', 'static/css/main.css')!
```
### Dealing with MIME types
By default, veb will map the extension of a file to a MIME type. If any of your static file's
extensions do not have a default MIME type in veb, veb will throw an error and you
have to add your MIME type to `.static_mime_types` yourself.
**Example:**
Given the following file structure:
```
.
├── static/
│ └── file.what
└── main.v
```
```v ignore
app.handle_static('static', true)!
```
This code will throw an error, because veb has no default MIME type for a `.what` file extension.
```
unknown MIME type for file extension ".what"
```
To fix this we have to provide a MIME type for the `.what` file extension:
```v ignore
app.static_mime_types['.what'] = 'txt/plain'
app.handle_static('static', true)!
```
## Middleware
Middleware in web development is (loosely defined) a hidden layer that sits between
what a user requests (the HTTP Request) and what a user sees (the HTTP Response).
We can use this middleware layer to provide "hidden" functionality to our apps endpoints.
To use veb's middleware we have to embed `veb.Middleware` on our app struct and provide
the type of which context struct should be used.
**Example:**
```v ignore
pub struct App {
veb.Middleware[Context]
}
```
### Use case
We could, for example, get the cookies for an HTTP request and check if the user has already
accepted our cookie policy. Let's modify our Context struct to store whether the user has
accepted our policy or not.
**Example:**
```v ignore
pub struct Context {
veb.Context
pub mut:
has_accepted_cookies bool
}
```
In veb middleware functions take a `mut` parameter with the type of your context struct
and must return `bool`. We have full access to modify our Context struct!
The return value indicates to veb whether it can continue or has to stop. If we send a
response to the client in a middleware function veb has to stop, so we return `false`.
**Example:**
```v ignore
pub fn check_cookie_policy(mut ctx Context) bool {
// get the cookie
cookie_value := ctx.get_cookie('accepted_cookies') or { '' }
// check if the cookie has been set
if cookie_value == 'true' {
ctx.has_accepted_cookies = true
}
// we don't send a response, so we must return true
return true
}
```
We can check this value in an endpoint and return a different response.
**Example:**
```v ignore
@['/only-cookies']
pub fn (app &App) only_cookie_route(mut ctx Context) veb.Result {
if ctx.has_accepted_cookies {
return ctx.text('Welcome!')
} else {
return ctx.text('You must accept the cookie policy!')
}
}
```
There is one thing left for our middleware to work: we have to register our `only_cookie_route`
function as middleware for our app. We must do this after the app is created and before the
app is started.
**Example:**
```v ignore
fn main() {
mut app := &App{}
// register middleware for all routes
app.use(handler: check_cookie_policy)
// Pass the App and context type and start the web server on port 8080
veb.run[App, Context](mut app, 8080)
}
```
### Types of middleware
In the previous example we used so called "global" middleware. This type of middleware
applies to every endpoint defined on our app struct; global. It is also possible
to register middleware for only a certain route(s).
**Example:**
```v ignore
// register middleware only for the route '/auth'
app.route_use('/auth', handler: auth_middleware)
// register middleware only for the route '/documents/' with a parameter
// e.g. '/documents/5'
app.route_use('/documents/:id')
// register middleware with a parameter array. The middleware will be registered
// for all routes that start with '/user/' e.g. '/user/profile/update'
app.route_use('/user/:path...')
```
### Evaluation moment
By default, the registered middleware functions are executed *before* a method on your
app struct is called. You can also change this behaviour to execute middleware functions
*after* a method on your app struct is called, but before the response is sent!
**Example:**
```v ignore
pub fn modify_headers(mut ctx Context) bool {
// add Content-Language: 'en-US' header to each response
ctx.res.header.add(.content_language, 'en-US')
return true
}
```
```v ignore
app.use(handler: modify_headers, after: true)
```
#### When to use which type
You could use "before" middleware to check and modify the HTTP request and you could use
"after" middleware to validate the HTTP response that will be sent or do some cleanup.
Anything you can do in "before" middleware, you can do in "after" middleware.
### Evaluation order
veb will handle requests in the following order:
1. Execute global "before" middleware
2. Execute "before" middleware that matches the requested route
3. Execute the endpoint handler on your app struct
4. Execute global "after" middleware
5. Execute "after" middleware that matches the requested route
In each step, except for step `3`, veb will evaluate the middleware in the order that
they are registered; when you call `app.use` or `app.route_use`.
### Early exit
If any middleware sends a response (and thus must return `false`) veb will not execute any
other middleware, or the endpoint method, and immediately send the response.
**Example:**
```v ignore
pub fn early_exit(mut ctx Context) bool {
ctx.text('early exit')
// we send a response from middleware, so we have to return false
return false
}
pub fn logger(mut ctx Context) bool {
println('received request for "${ctx.req.url}"')
return true
}
```
```v ignore
app.use(handler: early_exit)
app.use(handler: logger)
```
Because we register `early_exit` before `logger` our logging middleware will never be executed!
## Controllers
Controllers can be used to split up your app logic so you are able to have one struct
per "route group". E.g. a struct `Admin` for urls starting with `'/admin'` and a struct `Foo`
for urls starting with `'/foo'`.
To use controllers we have to embed `veb.Controller` on
our app struct and when we register a controller we also have to specify
what the type of the context struct will be. That means that it is possible
to have a different context struct for each controller and the main app struct.
**Example:**
```v
module main
import veb
pub struct Context {
veb.Context
}
pub struct App {
veb.Controller
}
// this endpoint will be available at '/'
pub fn (app &App) index(mut ctx Context) veb.Result {
return ctx.text('from app')
}
pub struct Admin {}
// this endpoint will be available at '/admin/'
pub fn (app &Admin) index(mut ctx Context) veb.Result {
return ctx.text('from admin')
}
pub struct Foo {}
// this endpoint will be available at '/foo/'
pub fn (app &Foo) index(mut ctx Context) veb.Result {
return ctx.text('from foo')
}
fn main() {
mut app := &App{}
// register the controllers the same way as how we start a veb app
mut admin_app := &Admin{}
app.register_controller[Admin, Context]('/admin', mut admin_app)!
mut foo_app := &Foo{}
app.register_controller[Foo, Context]('/foo', mut foo_app)!
veb.run[App, Context](mut app, 8080)
}
```
You can do everything with a controller struct as with a regular `App` struct.
Register middleware, add static files and you can even register other controllers!
### Routing
Any route inside a controller struct is treated as a relative route to its controller namespace.
```v ignore
@['/path']
pub fn (app &Admin) path(mut ctx Context) veb.Result {
return ctx.text('Admin')
}
```
When we registered the controller with
`app.register_controller[Admin, Context]('/admin', mut admin_app)!`
we told veb that the namespace of that controller is `'/admin'` so in this example we would
see the text "Admin" if we navigate to the url `'/admin/path'`.
veb doesn't support duplicate routes, so if we add the following
route to the example the code will produce an error.
```v ignore
@['/admin/path']
pub fn (app &App) admin_path(mut ctx Context) veb.Result {
return ctx.text('Admin overwrite')
}
```
There will be an error, because the controller `Admin` handles all routes starting with
`'/admin'`: the endpoint `admin_path` is unreachable.
### Controller with hostname
You can also set a host for a controller. All requests coming to that host will be handled
by the controller.
**Example:**
```v ignore
struct Example {}
// You can only access this route at example.com: http://example.com/
pub fn (app &Example) index(mut ctx Context) veb.Result {
return ctx.text('Example')
}
```
```v ignore
mut example_app := &Example{}
// set the controllers hostname to 'example.com' and handle all routes starting with '/',
// we handle requests with any route to 'example.com'
app.register_controller[Example, Context]('example.com', '/', mut example_app)!
```
## Context Methods
veb has a number of utility methods that make it easier to handle requests and send responses.
These methods are available on `veb.Context` and directly on your own context struct if you
embed `veb.Context`. Below are some of the most used methods, look at the
[standard library documentation](https://modules.vlang.io/) to see them all.
### Request methods
You can directly access the HTTP request on the `.req` field.
#### Get request headers
**Example:**
```v ignore
pub fn (app &App) index(mut ctx Context) veb.Result {
content_length := ctx.get_header(.content_length) or { '0' }
// get custom header
custom_header := ctx.get_custom_header('X-HEADER') or { '' }
// ...
}
```
#### Get a cookie
**Example:**
```v ignore
pub fn (app &App) index(mut ctx Context) veb.Result {
cookie_val := ctx.get_cookie('token') or { '' }
// ...
}
```
### Response methods
You can directly modify the HTTP response by changing the `res` field,
which is of the type `http.Response`.
#### Send response with different MIME types
```v ignore
// send response HTTP_OK with content-type `text/html`
ctx.html('<h1>Hello world!</h1>')
// send response HTTP_OK with content-type `text/plain`
ctx.text('Hello world!')
// stringify the object and send response HTTP_OK with content-type `application/json`
ctx.json(User{
name: 'test'
age: 20
})
```
#### Sending files
**Example:**
```v ignore
pub fn (app &App) file_response(mut ctx Context) veb.Result {
// send the file 'image.png' in folder 'data' to the user
return ctx.file('data/image.png')
}
```
#### Set response headers
**Example:**
```v ignore
pub fn (app &App) index(mut ctx Context) veb.Result {
ctx.set_header(.accept, 'text/html')
// set custom header
ctx.set_custom_header('X-HEADER', 'my-value')!
// ...
}
```
#### Set a cookie
**Example:**
```v ignore
pub fn (app &App) index(mut ctx Context) veb.Result {
ctx.set_cookie(http.Cookie{
name: 'token'
value: 'true'
path: '/'
secure: true
http_only: true
})
// ...
}
```
#### Redirect
You must pass the type of redirect to veb:
- `moved_permanently` HTTP code 301
- `found` HTTP code 302
- `see_other` HTTP code 303
- `temporary_redirect` HTTP code 307
- `permanent_redirect` HTTP code 308
**Common use cases:**
If you want to change the request method, for example when you receive a post request and
want to redirect to another page via a GET request, you should use `see_other`. If you want
the HTTP method to stay the same, you should use `found` generally speaking.
**Example:**
```v ignore
pub fn (app &App) index(mut ctx Context) veb.Result {
token := ctx.get_cookie('token') or { '' }
if token == '' {
// redirect the user to '/login' if the 'token' cookie is not set
// we explicitly tell the browser to send a GET request
return ctx.redirect('/login', typ: .see_other)
} else {
return ctx.text('Welcome!')
}
}
```
#### Sending error responses
**Example:**
```v ignore
pub fn (app &App) login(mut ctx Context) veb.Result {
if username := ctx.form['username'] {
return ctx.text('Hello "${username}"')
} else {
// send an HTTP 400 Bad Request response with a message
return ctx.request_error('missing form value "username"')
}
}
```
You can also use `ctx.server_error(msg string)` to send an HTTP 500 internal server
error with a message.
## Advanced usage
If you need more control over the TCP connection with a client, for example when
you want to keep the connection open. You can call `ctx.takeover_conn`.
When this function is called you are free to do anything you want with the TCP
connection and veb will not interfere. This means that we are responsible for
sending a response over the connection and closing it.
### Empty Result
Sometimes you want to send the response in another thread, for example when using
[Server Sent Events](sse/README.md). When you are sure that a response will be sent
over the TCP connection you can return `veb.no_result()`. This function does nothing
and returns an empty `veb.Result` struct, letting veb know that we sent a response ourselves.
> **Note:**
> It is important to call `ctx.takeover_conn` before you spawn a thread
**Example:**
```v
module main
import net
import time
import veb
pub struct Context {
veb.Context
}
pub struct App {}
pub fn (app &App) index(mut ctx Context) veb.Result {
return ctx.text('hello!')
}
@['/long']
pub fn (app &App) long_response(mut ctx Context) veb.Result {
// let veb know that the connection should not be closed
ctx.takeover_conn()
// use spawn to handle the connection in another thread
// if we don't the whole web server will block for 10 seconds,
// since veb is singlethreaded
spawn handle_connection(mut ctx.conn)
// we will send a custom response ourselves, so we can safely return an empty result
return veb.no_result()
}
fn handle_connection(mut conn net.TcpConn) {
defer {
conn.close() or {}
}
// block for 10 second
time.sleep(time.second * 10)
conn.write_string('HTTP/1.1 200 OK\r\nContent-type: text/html\r\nContent-length: 15\r\n\r\nHello takeover!') or {}
}
fn main() {
mut app := &App{}
veb.run[App, Context](mut app, 8080)
}
```

3
cli/.gitignore vendored
View File

@@ -1 +1,4 @@
hero
compile
compile_upload
vdo

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -parallel-cc -enable-globals run
// #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -n -g -cg -w -parallel-cc -showcc -enable-globals run
// #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import os
import flag
@@ -14,20 +14,20 @@ prod_mode := fp.bool('prod', `p`, false, 'Build production version (optimized)')
help_requested := fp.bool('help', `h`, false, 'Show help message')
if help_requested {
println(fp.usage())
exit(0)
println(fp.usage())
exit(0)
}
additional_args := fp.finalize() or {
eprintln(err)
println(fp.usage())
exit(1)
eprintln(err)
println(fp.usage())
exit(1)
}
if additional_args.len > 0 {
eprintln('Unexpected arguments: ${additional_args.join(' ')}')
println(fp.usage())
exit(1)
eprintln('Unexpected arguments: ${additional_args.join(' ')}')
println(fp.usage())
exit(1)
}
// Change to the hero directory
@@ -37,35 +37,38 @@ os.chdir(hero_dir) or { panic('Failed to change directory to ${hero_dir}: ${err}
// Set HEROPATH based on OS
mut heropath := '/usr/local/bin/hero'
if os.user_os() == 'macos' {
heropath = os.join_path(os.home_dir(), 'hero/bin/hero')
heropath = os.join_path(os.home_dir(), 'hero/bin/hero')
}
// Set compilation command based on OS and mode
compile_cmd := if os.user_os() == 'macos' {
if prod_mode {
'v -enable-globals -w -n -prod hero.v'
} else {
'v -w -cg -gc none -cc tcc -d use_openssl -enable-globals hero.v'
}
if prod_mode {
'v -enable-globals -g -w -n -prod hero.v'
} else {
'v -n -g -w -cg -gc none -cc tcc -d use_openssl -enable-globals hero.v'
}
} else {
if prod_mode {
'v -cg -enable-globals -parallel-cc -w -n hero.v'
} else {
'v -cg -enable-globals -w -n hero.v'
}
if prod_mode {
'v -cg -enable-globals -parallel-cc -w -n hero.v'
} else {
'v -cg -enable-globals -w -n hero.v'
}
}
println('Building in ${if prod_mode { 'production' } else { 'debug' }} mode...')
// eprintln(compile_cmd)
if os.system(compile_cmd) != 0 {
panic('Failed to compile hero.v with command: ${compile_cmd}')
panic('Failed to compile hero.v with command: ${compile_cmd}')
}
// Make executable
os.chmod('hero', 0o755) or { panic('Failed to make hero binary executable: ${err}') }
// Ensure destination directory exists
os.mkdir_all(os.dir(heropath)) or { panic('Failed to create directory ${os.dir(heropath)}: ${err}') }
os.mkdir_all(os.dir(heropath)) or {
panic('Failed to create directory ${os.dir(heropath)}: ${err}')
}
println(heropath)
// Copy to destination paths
os.cp('hero', heropath) or { panic('Failed to copy hero binary to ${heropath}: ${err}') }

View File

@@ -28,7 +28,7 @@ fn get_platform_id() string {
}
fn read_secrets() ! {
secret_file := os.join_path(os.home_dir(), 'code/git.ourworld.tf/despiegk/hero_secrets/mysecrets.sh')
secret_file := os.join_path(os.home_dir(), 'code/git.threefold.info/despiegk/hero_secrets/mysecrets.sh')
if os.exists(secret_file) {
println('Reading secrets from ${secret_file}')
content := os.read_file(secret_file)!
@@ -64,7 +64,9 @@ account = ${s3keyid}
key = ${s3appid}
hard_delete = true'
os.write_file(rclone_conf, config_content) or { return error('Failed to write rclone config: ${err}') }
os.write_file(rclone_conf, config_content) or {
return error('Failed to write rclone config: ${err}')
}
println('made S3 config on: ${rclone_conf}')
content := os.read_file(rclone_conf) or { return error('Failed to read rclone config: ${err}') }
@@ -72,8 +74,10 @@ hard_delete = true'
}
fn hero_upload() ! {
hero_path := os.find_abs_path_of_executable('hero') or { return error("Error: 'hero' command not found in PATH") }
hero_path := os.find_abs_path_of_executable('hero') or {
return error("Error: 'hero' command not found in PATH")
}
s3_configure()!
platform_id := get_platform_id()
@@ -83,15 +87,18 @@ fn hero_upload() ! {
// List contents
os.execute_or_panic('rclone --config="${rclone_conf}" lsl b2:threefold/${platform_id}/')
// Copy hero binary
os.execute_or_panic('rclone --config="${rclone_conf}" copy "${hero_path}" b2:threefold/${platform_id}/')
}
fn main() {
//os.execute_or_panic('${os.home_dir()}/code/github/freeflowuniverse/herolib/cli/compile.vsh -p')
println("compile hero can take 60 sec+ on osx.")
// os.execute_or_panic('${os.home_dir()}/code/github/freeflowuniverse/herolib/cli/compile.vsh -p')
println('compile hero can take 60 sec+ on osx.')
os.execute_or_panic('${os.home_dir()}/code/github/freeflowuniverse/herolib/cli/compile.vsh -p')
println( "upload:")
hero_upload() or { eprintln(err) exit(1) }
println('upload:')
hero_upload() or {
eprintln(err)
exit(1)
}
}

79
cli/compile_vdo.vsh Executable file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env -S v -n -cg -w -parallel-cc -enable-globals run
// #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import os
import flag
mut fp := flag.new_flag_parser(os.args)
fp.application('compile_vdo.vsh')
fp.version('v0.1.0')
fp.description('Compile vdo binary in debug or production mode')
fp.skip_executable()
prod_mode := fp.bool('prod', `p`, false, 'Build production version (optimized)')
help_requested := fp.bool('help', `h`, false, 'Show help message')
if help_requested {
println(fp.usage())
exit(0)
}
additional_args := fp.finalize() or {
eprintln(err)
println(fp.usage())
exit(1)
}
if additional_args.len > 0 {
eprintln('Unexpected arguments: ${additional_args.join(' ')}')
println(fp.usage())
exit(1)
}
// Change to the vdo directory
hero_dir := os.join_path(os.home_dir(), 'code/github/freeflowuniverse/herolib/cli')
os.chdir(hero_dir) or { panic('Failed to change directory to ${hero_dir}: ${err}') }
// Set HEROPATH based on OS
mut heropath := '/usr/local/bin/vdo'
if os.user_os() == 'macos' {
heropath = os.join_path(os.home_dir(), 'hero/bin/vdo')
}
// Set compilation command based on OS and mode
compile_cmd := if os.user_os() == 'macos' {
if prod_mode {
'v -enable-globals -w -n -prod vdo.v'
} else {
'v -w -cg -gc none -cc tcc -d use_openssl -enable-globals vdo.v'
}
} else {
if prod_mode {
'v -cg -enable-globals -parallel-cc -w -n vdo.v'
} else {
'v -cg -enable-globals -w -n vdo.v'
}
}
println('Building in ${if prod_mode { 'production' } else { 'debug' }} mode...')
if os.system(compile_cmd) != 0 {
panic('Failed to compile vdo.v with command: ${compile_cmd}')
}
// Make executable
os.chmod('vdo', 0o755) or { panic('Failed to make vdo binary executable: ${err}') }
// Ensure destination directory exists
os.mkdir_all(os.dir(heropath)) or {
panic('Failed to create directory ${os.dir(heropath)}: ${err}')
}
println(heropath)
// Copy to destination paths
os.cp('vdo', heropath) or { panic('Failed to copy vdo binary to ${heropath}: ${err}') }
os.cp('vdo', '/tmp/vdo') or { panic('Failed to copy vdo binary to /tmp/vdo: ${err}') }
// Clean up
os.rm('vdo') or { panic('Failed to remove temporary vdo binary: ${err}') }
println('**COMPILE OK**')

View File

@@ -3,22 +3,39 @@ module main
import os
import cli { Command }
import freeflowuniverse.herolib.core.herocmds
// import freeflowuniverse.herolib.hero.cmds
// import freeflowuniverse.herolib.hero.publishing
import freeflowuniverse.herolib.installers.base
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.ui
import freeflowuniverse.herolib.osal
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
fn playcmds_do(path string) ! {
mut plbook := playbook.new(path: path)!
playcmds.run(mut plbook, false)!
playcmds.run(plbook: plbook)!
}
fn do() ! {
if !core.is_osx()! {
if os.getenv('SUDO_COMMAND') != '' || os.getenv('SUDO_USER') != '' {
println('Error: Please do not run this program with sudo!')
exit(1) // Exit with error code
}
}
if os.getuid() == 0 {
if core.is_osx()! {
eprintln('please do not run hero as root in osx.')
exit(1)
}
} else {
if !core.is_osx()! {
eprintln("please do run hero as root, don't use sudo.")
exit(1)
}
}
if os.args.len == 2 {
mypath := os.args[1]
if mypath.to_lower().ends_with('.hero') {
@@ -31,7 +48,7 @@ fn do() ! {
mut cmd := Command{
name: 'hero'
description: 'Your HERO toolset.'
version: '1.0.6'
version: '1.0.28'
}
// herocmds.cmd_run_add_flags(mut cmd)
@@ -64,9 +81,14 @@ fn do() ! {
base.redis_install()!
// herocmds.cmd_bootstrap(mut cmd)
// herocmds.cmd_run(mut cmd)
herocmds.cmd_run(mut cmd)
herocmds.cmd_git(mut cmd)
herocmds.cmd_generator(mut cmd)
herocmds.cmd_docusaurus(mut cmd)
// herocmds.cmd_bootstrap(mut cmd)
// herocmds.cmd_init(mut cmd)
// herocmds.cmd_imagedownsize(mut cmd)
// herocmds.cmd_biztools(mut cmd)
@@ -75,13 +97,16 @@ fn do() ! {
// herocmds.cmd_installers(mut cmd)
// herocmds.cmd_configure(mut cmd)
// herocmds.cmd_postgres(mut cmd)
herocmds.cmd_mdbook(mut cmd)
// Ensure the herocmds module is imported so the remaining commands are visible
// `cmd_mdbook` is not part of the current code base it has been removed.
// If you need markdownbook support, reintroduce the command implementation
// and uncomment the line below.
// herocmds.cmd_mdbook(mut cmd)
// herocmds.cmd_luadns(mut cmd)
// herocmds.cmd_caddy(mut cmd)
// herocmds.cmd_zola(mut cmd)
// herocmds.cmd_juggler(mut cmd)
herocmds.cmd_generator(mut cmd)
herocmds.cmd_docusaurus(mut cmd)
// herocmds.cmd_starlight(mut cmd)
// herocmds.cmd_docsorter(mut cmd)
// cmd.add_command(publishing.cmd_publisher(pre_func))
cmd.setup()
@@ -89,9 +114,15 @@ fn do() ! {
}
fn main() {
do() or { panic(err) }
do() or {
$dbg;
eprintln('Error: ${err}')
print_backtrace()
exit(1)
}
}
fn pre_func(cmd Command) ! {
herocmds.plbook_run(cmd)!
}
// fn pre_func(cmd Command) ! {
// herocmds.plbook_run(cmd)!
// }

12
cli/vdo.v Normal file
View File

@@ -0,0 +1,12 @@
module main
import freeflowuniverse.herolib.mcp.v_do
fn main() {
// Create and start the MCP server
mut server := v_do.new_server()
server.start() or {
eprintln('Error starting server: ${err}')
exit(1)
}
}

480
compile.sh Executable file
View File

@@ -0,0 +1,480 @@
#!/bin/bash
# compile.sh - Script to compile each module in the herolib/lib directory
# This script compiles each module in the lib directory to ensure they build correctly
set -e # Exit on error
# Default settings
CONCURRENT=false
MAX_JOBS=4 # Default number of concurrent jobs
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-c|--concurrent)
CONCURRENT=true
shift
;;
-j|--jobs)
MAX_JOBS="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [options]"
echo "Options:"
echo " -c, --concurrent Enable concurrent compilation"
echo " -j, --jobs N Set maximum number of concurrent jobs (default: 4)"
echo " -h, --help Show this help message"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
# Color codes for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# Get the directory of this script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="$SCRIPT_DIR/lib"
# V compiler flags based on the project's test script
V_FLAGS="-stats -enable-globals -n -w -gc none -d use_openssl -shared"
# Log file for compilation results
LOG_FILE="$SCRIPT_DIR/compile_results.log"
> "$LOG_FILE" # Clear log file
# Summary log file
SUMMARY_FILE="$SCRIPT_DIR/compile_summary.log"
> "$SUMMARY_FILE" # Clear summary file
# Cache directory for storing timestamps of last successful compilation
CACHE_DIR="$SCRIPT_DIR/.compile_cache"
mkdir -p "$CACHE_DIR"
# Create temporary directory for compiled binaries
mkdir -p "$SCRIPT_DIR/tmp"
# Create a directory for temporary output files
TEMP_DIR="$SCRIPT_DIR/.temp_compile"
mkdir -p "$TEMP_DIR"
# Trap for cleaning up on exit
cleanup() {
echo "Cleaning up..."
# Kill any remaining child processes
jobs -p | xargs kill -9 2>/dev/null || true
# Remove temporary directories
rm -rf "$TEMP_DIR" "$SCRIPT_DIR/tmp" 2>/dev/null || true
exit 0
}
# Set up traps for various signals
trap cleanup EXIT INT TERM
# Define modules to skip entirely due to known compilation issues
SKIP_MODULES=("flist" "openai" "mycelium" "vastai" "rclone" "sendgrid" "mailclient" "ipapi" "runpod" "postgresql_client" "meilisearch" "livekit" "wireguard" "_archive" "clients")
# Function to check if a module should be skipped
should_skip_module() {
local module_name="$1"
for skip_module in "${SKIP_MODULES[@]}"; do
if [[ "$module_name" == "$skip_module" ]]; then
return 0 # true, should skip
fi
done
return 1 # false, should not skip
}
# Function to check if a module needs recompilation
needs_module_recompilation() {
local module_path="$1"
local module_name="$(basename "$module_path")"
local cache_file="$CACHE_DIR/$module_name.timestamp"
# If cache file doesn't exist, module needs recompilation
if [ ! -f "$cache_file" ]; then
return 0 # true, needs recompilation
fi
# Check if any .v file in the module is newer than the last compilation
if find "$module_path" -name "*.v" -type f -newer "$cache_file" | grep -q .; then
return 0 # true, needs recompilation
fi
return 1 # false, doesn't need recompilation
}
# Function to update the cache timestamp for a module
update_module_cache() {
local module_path="$1"
local module_name="$(basename "$module_path")"
local cache_file="$CACHE_DIR/$module_name.timestamp"
# Update the timestamp
touch "$cache_file"
}
# Function to check if a directory is a module (contains .v files directly, not just in subdirectories)
is_module() {
local dir_path="$1"
# Check if there are any .v files directly in this directory (not in subdirectories)
if [ -n "$(find "$dir_path" -maxdepth 1 -name "*.v" -type f -print -quit)" ]; then
return 0 # true, is a module
fi
return 1 # false, not a module
}
# Function to compile a module
compile_module() {
local module_path="$1"
local module_name="$(basename "$module_path")"
local output_file="$TEMP_DIR/${module_name}.log"
local result_file="$TEMP_DIR/${module_name}.result"
# Initialize the result file
echo "pending" > "$result_file"
# Check if this module should be skipped
if should_skip_module "$module_name"; then
echo "Skipping problematic module: $module_name" > "$output_file"
echo "skipped|${module_path#$LIB_DIR/}|" >> "$SUMMARY_FILE"
echo "skipped" > "$result_file"
return 0
fi
# Check if this is actually a module (has .v files directly)
if ! is_module "$module_path"; then
echo "$module_name is not a module (no direct .v files), skipping" > "$output_file"
echo "not_module|${module_path#$LIB_DIR/}|" >> "$SUMMARY_FILE"
echo "skipped" > "$result_file"
return 0
fi
echo "Compiling module: $module_name" > "$output_file"
# Check if the module needs recompilation
if ! needs_module_recompilation "$module_path"; then
echo " No changes detected in $module_name, skipping compilation" >> "$output_file"
echo "cached|${module_path#$LIB_DIR/}|" >> "$SUMMARY_FILE"
echo "cached" > "$result_file"
return 0
fi
# Record start time
local start_time=$(date +%s.%N)
# Try to compile the module - redirect both stdout and stderr to the output file
if v $V_FLAGS -o "$SCRIPT_DIR/tmp/$module_name" "$module_path" >> "$output_file" 2>&1; then
# Calculate compilation time
local end_time=$(date +%s.%N)
local compile_time=$(echo "$end_time - $start_time" | bc)
echo " Successfully compiled $module_name" >> "$output_file"
# Update the cache timestamp
update_module_cache "$module_path"
# Log result
echo "success|${module_path#$LIB_DIR/}|$compile_time" >> "$SUMMARY_FILE"
echo "success" > "$result_file"
return 0
else
echo " Failed to compile $module_name" >> "$output_file"
# Log result
echo "failed|${module_path#$LIB_DIR/}|" >> "$SUMMARY_FILE"
echo "failed" > "$result_file"
return 1
fi
}
# Function to run modules in parallel with a maximum number of concurrent jobs
run_parallel() {
local modules=("$@")
local total=${#modules[@]}
local completed=0
local running=0
local pids=()
local module_indices=()
echo "Running $total modules in parallel (max $MAX_JOBS jobs at once)"
# Initialize arrays to track jobs
for ((i=0; i<$total; i++)); do
pids[$i]=-1
done
# Start initial batch of jobs
local next_job=0
while [[ $next_job -lt $total && $running -lt $MAX_JOBS ]]; do
compile_module "${modules[$next_job]}" > /dev/null 2>&1 &
pids[$next_job]=$!
((running++))
((next_job++))
done
# Display progress indicator
display_progress() {
local current=$1
local total=$2
local percent=$((current * 100 / total))
local bar_length=50
local filled_length=$((percent * bar_length / 100))
printf "\r[" >&2
for ((i=0; i<bar_length; i++)); do
if [ $i -lt $filled_length ]; then
printf "#" >&2
else
printf " " >&2
fi
done
printf "] %d%% (%d/%d modules)" $percent $current $total >&2
}
# Monitor running jobs and start new ones as needed
while [[ $completed -lt $total ]]; do
display_progress $completed $total
# Check for completed jobs
for ((i=0; i<$total; i++)); do
if [[ ${pids[$i]} -gt 0 ]]; then
if ! kill -0 ${pids[$i]} 2>/dev/null; then
# Job completed
local module_path="${modules[$i]}"
local module_name="$(basename "$module_path")"
local output_file="$TEMP_DIR/${module_name}.log"
# Add output to log file
if [[ -f "$output_file" ]]; then
cat "$output_file" >> "$LOG_FILE"
fi
# Mark job as completed
pids[$i]=-2
((completed++))
((running--))
# Start a new job if available
if [[ $next_job -lt $total ]]; then
compile_module "${modules[$next_job]}" > /dev/null 2>&1 &
pids[$next_job]=$!
((running++))
((next_job++))
fi
fi
fi
done
# Brief pause to avoid excessive CPU usage
sleep 0.1
done
# Clear the progress line
printf "\r%$(tput cols)s\r" ""
# Wait for any remaining background jobs
wait
}
# Function to find all modules in a directory (recursively)
find_modules() {
local dir_path="$1"
local modules=()
# Check if this directory is a module itself
if is_module "$dir_path"; then
modules+=("$dir_path")
fi
# Look for modules in subdirectories (only one level deep)
for subdir in "$dir_path"/*; do
if [ -d "$subdir" ]; then
local subdir_name="$(basename "$subdir")"
# Skip if this is in the skip list
if should_skip_module "$subdir_name"; then
echo -e "${YELLOW}Skipping problematic module: $subdir_name${NC}"
echo "Skipping problematic module: $subdir_name" >> "$LOG_FILE"
echo "skipped|${subdir#$LIB_DIR/}|" >> "$SUMMARY_FILE"
continue
fi
# Check if this subdirectory is a module
if is_module "$subdir"; then
modules+=("$subdir")
fi
fi
done
echo "${modules[@]}"
}
echo "===== Starting compilation of all modules in lib ====="
echo "===== Starting compilation of all modules in lib =====" >> "$LOG_FILE"
# Define priority modules to compile first
PRIORITY_MODULES=("biz" "builder" "core" "crystallib" "jsonrpc" "jsonschema")
echo -e "${YELLOW}Attempting to compile each module as a whole...${NC}"
echo "Attempting to compile each module as a whole..." >> "$LOG_FILE"
# Collect all modules to compile
all_modules=()
# First add priority modules
for module_name in "${PRIORITY_MODULES[@]}"; do
module_dir="$LIB_DIR/$module_name"
if [ -d "$module_dir" ]; then
# Find all modules in this directory
modules=($(find_modules "$module_dir"))
all_modules+=("${modules[@]}")
fi
done
# Then add remaining modules
for module_dir in "$LIB_DIR"/*; do
if [ -d "$module_dir" ]; then
module_name="$(basename "$module_dir")"
# Skip modules already compiled in priority list
if [[ " ${PRIORITY_MODULES[*]} " =~ " $module_name " ]]; then
continue
fi
# Find all modules in this directory
modules=($(find_modules "$module_dir"))
all_modules+=("${modules[@]}")
fi
done
# Debug: print all modules found
echo "Found ${#all_modules[@]} modules to compile" >> "$LOG_FILE"
for module in "${all_modules[@]}"; do
echo " - $module" >> "$LOG_FILE"
done
# Compile modules (either in parallel or sequentially)
if $CONCURRENT; then
run_parallel "${all_modules[@]}"
else
# Sequential compilation
for module_path in "${all_modules[@]}"; do
# Display module being compiled
module_name="$(basename "$module_path")"
echo -e "${YELLOW}Compiling module: $module_name${NC}"
# Compile the module
compile_module "$module_path" > /dev/null 2>&1
# Display result
output_file="$TEMP_DIR/${module_name}.log"
result_file="$TEMP_DIR/${module_name}.result"
if [[ -f "$output_file" ]]; then
cat "$output_file" >> "$LOG_FILE"
# Display with color based on result
result=$(cat "$result_file")
if [[ "$result" == "success" ]]; then
echo -e "${GREEN} Successfully compiled $module_name${NC}"
elif [[ "$result" == "failed" ]]; then
echo -e "${RED} Failed to compile $module_name${NC}"
elif [[ "$result" == "cached" ]]; then
echo -e "${GREEN} No changes detected in $module_name, skipping compilation${NC}"
else
echo -e "${YELLOW} Skipped $module_name${NC}"
fi
fi
done
fi
# Count successes and failures
success_count=$(grep -c "^success|" "$SUMMARY_FILE" || echo 0)
failure_count=$(grep -c "^failed|" "$SUMMARY_FILE" || echo 0)
cached_count=$(grep -c "^cached|" "$SUMMARY_FILE" || echo 0)
skipped_count=$(grep -c "^skipped|" "$SUMMARY_FILE" || echo 0)
not_module_count=$(grep -c "^not_module|" "$SUMMARY_FILE" || echo 0)
echo "===== Compilation complete ====="
echo -e "${GREEN}Successfully compiled: $success_count modules${NC}"
echo -e "${GREEN}Cached (no changes): $cached_count modules${NC}"
echo -e "${YELLOW}Skipped: $skipped_count modules${NC}"
echo -e "${YELLOW}Not modules: $not_module_count directories${NC}"
echo -e "${RED}Failed to compile: $failure_count modules${NC}"
echo "See $LOG_FILE for detailed compilation results"
echo "===== Compilation complete =====" >> "$LOG_FILE"
echo "Successfully compiled: $success_count modules" >> "$LOG_FILE"
echo "Cached (no changes): $cached_count modules" >> "$LOG_FILE"
echo "Skipped: $skipped_count modules" >> "$LOG_FILE"
echo "Not modules: $not_module_count directories" >> "$LOG_FILE"
echo "Failed to compile: $failure_count modules" >> "$LOG_FILE"
# Print detailed summary
echo ""
echo "===== Module Compilation Summary ====="
echo ""
# Print successful modules first, sorted by compilation time
echo "Successful compilations:"
grep "^success|" "$SUMMARY_FILE" | sort -t'|' -k3,3n | while IFS='|' read -r status path time; do
# Color code based on compilation time
time_color="$GREEN"
if (( $(echo "$time > 10.0" | bc -l) )); then
time_color="$RED"
elif (( $(echo "$time > 1.0" | bc -l) )); then
time_color="$YELLOW"
fi
echo -e "$path\t${time_color}${time}s${NC}"
done
# Print cached modules
echo ""
echo "Cached modules (no changes detected):"
grep "^cached|" "$SUMMARY_FILE" | sort | while IFS='|' read -r status path time; do
echo -e "🔄 $path\t${GREEN}CACHED${NC}"
done
# Print skipped modules
echo ""
echo "Skipped modules:"
grep "^skipped|" "$SUMMARY_FILE" | sort | while IFS='|' read -r status path time; do
echo -e "⏭️ $path\t${YELLOW}SKIPPED${NC}"
done
# Print not modules
echo ""
echo "Not modules (directories without direct .v files):"
grep "^not_module|" "$SUMMARY_FILE" | sort | while IFS='|' read -r status path time; do
echo -e "📁 $path\t${YELLOW}NOT MODULE${NC}"
done
# Print failed modules
echo ""
echo "Failed modules:"
grep "^failed|" "$SUMMARY_FILE" | sort | while IFS='|' read -r status path time; do
echo -e "$path\t${RED}FAILED${NC}"
done
echo ""
echo "===== End of Summary ====="
# Exit with error code if any module failed to compile
if [ $failure_count -gt 0 ]; then
exit 1
fi
exit 0

40
doc.vsh
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import os
@@ -7,11 +7,13 @@ 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')
eprintln('Warning: Failed to format examples')
exit(1)
}
if os.system('v fmt -w ${abs_dir_of_script}/lib') != 0 {
eprintln('Warning: Failed to format herolib')
eprintln('Warning: Failed to format herolib')
exit(1)
}
// Clean existing docs
@@ -22,9 +24,7 @@ os.rmdir_all('docs') or {}
os.rmdir_all('vdocs') or {}
herolib_path := os.join_path(abs_dir_of_script, 'lib')
os.chdir(herolib_path) or {
panic('Failed to change directory to herolib: ${err}')
}
os.chdir(herolib_path) or { panic('Failed to change directory to herolib: ${err}') }
os.mkdir_all('_docs') or {}
os.mkdir_all('docs') or {}
@@ -33,13 +33,15 @@ os.mkdir_all('vdocs') or {}
// Generate HTML documentation
println('Generating HTML documentation...')
if os.system('v doc -m -f html . -readme -comments -no-timestamp -o ../docs') != 0 {
panic('Failed to generate HTML documentation')
panic('Failed to generate HTML documentation')
}
os.chdir(abs_dir_of_script) or {
panic('Failed to change directory to abs_dir_of_script: ${err}')
if os.system('v doc -m -f md . -no-color -o ../vdocs/') != 0 {
panic('Failed to generate Hero markdown documentation')
}
os.chdir(abs_dir_of_script) or { panic('Failed to change directory to abs_dir_of_script: ${err}') }
// Generate Markdown documentation
println('Generating Markdown documentation...')
@@ -47,18 +49,16 @@ println('Generating Markdown documentation...')
// panic('Failed to generate V markdown documentation')
// }
if os.system('v doc -m -no-color -f md -o vdocs/') != 0 {
panic('Failed to generate Hero markdown documentation')
}
// if os.system('v doc -m -no-color -f md . -o vdocs/') != 0 {
// panic('Failed to generate Hero markdown documentation')
// }
// Open documentation in browser on non-Linux systems
$if !linux {
os.chdir(abs_dir_of_script) or {
panic('Failed to change directory: ${err}')
}
if os.system('open docs/index.html') != 0 {
eprintln('Warning: Failed to open documentation in browser')
}
os.chdir(abs_dir_of_script) or { panic('Failed to change directory: ${err}') }
if os.system('open docs/index.html') != 0 {
eprintln('Warning: Failed to open documentation in browser')
}
}
// Create Jekyll required files
@@ -68,7 +68,7 @@ os.mkdir_all('docs/assets/css') or {}
// Create style.scss
style_content := '---\n---\n\n@import "{{ site.theme }}";'
os.write_file('docs/assets/css/style.scss', style_content) or {
panic('Failed to create style.scss: ${err}')
panic('Failed to create style.scss: ${err}')
}
// Create _config.yml
@@ -87,7 +87,7 @@ exclude:
- vendor/ruby/'
os.write_file('docs/_config.yml', config_content) or {
panic('Failed to create _config.yml: ${err}')
panic('Failed to create _config.yml: ${err}')
}
println('Documentation generation completed successfully!')

View File

@@ -4,46 +4,45 @@ import os
import flag
fn addtoscript(tofind string, toadd string) ! {
home_dir := os.home_dir()
mut rc_file := '${home_dir}/.zshrc'
if !os.exists(rc_file) {
rc_file = '${home_dir}/.bashrc'
if !os.exists(rc_file) {
return error('No .zshrc or .bashrc found in home directory')
}
}
home_dir := os.home_dir()
mut rc_file := '${home_dir}/.zshrc'
if !os.exists(rc_file) {
rc_file = '${home_dir}/.bashrc'
if !os.exists(rc_file) {
return error('No .zshrc or .bashrc found in home directory')
}
}
// Read current content
mut content := os.read_file(rc_file)!
// Remove existing alias if present
lines := content.split('\n')
mut new_lines := []string{}
mut prev_is_emtpy := false
for line in lines {
if prev_is_emtpy {
if line.trim_space() == ""{
continue
}else{
prev_is_emtpy = false
}
}
if line.trim_space() == ""{
prev_is_emtpy = true
}
// Read current content
mut content := os.read_file(rc_file)!
if !line.contains(tofind) {
new_lines << line
}
}
new_lines << toadd
new_lines << ""
// Write back to file
new_content := new_lines.join('\n')
os.write_file(rc_file, new_content)!
// Remove existing alias if present
lines := content.split('\n')
mut new_lines := []string{}
mut prev_is_emtpy := false
for line in lines {
if prev_is_emtpy {
if line.trim_space() == '' {
continue
} else {
prev_is_emtpy = false
}
}
if line.trim_space() == '' {
prev_is_emtpy = true
}
if !line.contains(tofind) {
new_lines << line
}
}
new_lines << toadd
new_lines << ''
// Write back to file
new_content := new_lines.join('\n')
os.write_file(rc_file, new_content)!
}
vroot := @VROOT
abs_dir_of_script := dir(@FILE)
@@ -52,20 +51,20 @@ println('Resetting all symlinks...')
os.rm('${os.home_dir()}/.vmodules/freeflowuniverse/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/freeflowuniverse') or {
panic('Failed to create directory ~/.vmodules/freeflowuniverse: ${err}')
}
// Create new symlinks
os.symlink('${abs_dir_of_script}/lib', '${os.home_dir()}/.vmodules/freeflowuniverse/herolib') or {
panic('Failed to create herolib symlink: ${err}')
panic('Failed to create herolib symlink: ${err}')
}
println('Herolib installation completed successfully!')
// Add vtest alias
addtoscript('alias vtest=', 'alias vtest=\'v -stats -enable-globals -n -w -cg -gc none -cc tcc test\' ') or {
eprintln('Failed to add vtest alias: ${err}')
addtoscript('alias vtest=', "alias vtest='v -stats -enable-globals -n -w -cg -gc none -cc tcc test' ") or {
eprintln('Failed to add vtest alias: ${err}')
}
println('Added vtest alias to shell configuration')

View File

@@ -73,9 +73,9 @@ function sshknownkeysadd {
then
ssh-keyscan github.com >> ~/.ssh/known_hosts
fi
if ! grep git.ourworld.tf ~/.ssh/known_hosts > /dev/null
if ! grep git.threefold.info ~/.ssh/known_hosts > /dev/null
then
ssh-keyscan git.ourworld.tf >> ~/.ssh/known_hosts
ssh-keyscan git.threefold.info >> ~/.ssh/known_hosts
fi
git config --global pull.rebase false

71
examples/aiexamples/groq.vsh Executable file
View File

@@ -0,0 +1,71 @@
#!/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

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

86
examples/aiexamples/jina.vsh Executable file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.jina
mut jina_client := jina.get()!
health := jina_client.health()!
println('Server health: ${health}')
// Create embeddings
embeddings := jina_client.create_embeddings(
input: ['Hello', 'World']
model: .jina_embeddings_v3
task: 'separation'
) or { panic('Error while creating embeddings: ${err}') }
println('Created embeddings: ${embeddings}')
// Rerank
rerank_result := jina_client.rerank(
model: .reranker_v2_base_multilingual
query: 'skincare products'
documents: ['Product A', 'Product B', 'Product C']
top_n: 2
) or { panic('Error while reranking: ${err}') }
println('Rerank result: ${rerank_result}')
// Train
train_result := jina_client.train(
model: .jina_clip_v1
input: [
jina.TrainingExample{
text: 'Sample text'
label: 'positive'
},
jina.TrainingExample{
image: 'https://letsenhance.io/static/73136da51c245e80edc6ccfe44888a99/1015f/MainBefore.jpg'
label: 'negative'
},
]
) or { panic('Error while training: ${err}') }
println('Train result: ${train_result}')
// Classify
classify_result := jina_client.classify(
model: .jina_clip_v1
input: [
jina.ClassificationInput{
text: 'A photo of a cat'
},
jina.ClassificationInput{
image: 'https://letsenhance.io/static/73136da51c245e80edc6ccfe44888a99/1015f/MainBefore.jpg'
},
]
labels: ['cat', 'dog']
) or { panic('Error while classifying: ${err}') }
println('Classification result: ${classify_result}')
// List classifiers
classifiers := jina_client.list_classifiers() or { panic('Error fetching classifiers: ${err}') }
println('Classifiers: ${classifiers}')
// Delete classifier
delete_result := jina_client.delete_classifier(classifier_id: classifiers[0].classifier_id) or {
panic('Error deleting classifier: ${err}')
}
println('Delete result: ${delete_result}')
// Create multi vector
multi_vector := jina_client.create_multi_vector(
input: [
jina.MultiVectorTextDoc{
text: 'Hello world'
input_type: .document
},
jina.MultiVectorTextDoc{
text: "What's up?"
input_type: .query
},
]
embedding_type: ['float']
// dimensions: 96
)!
println('Multi vector: ${multi_vector}')

128
examples/aiexamples/qdrant.vsh Executable file
View File

@@ -0,0 +1,128 @@
#!/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 rand
import os
println('Starting Qdrant example script')
// Print environment information
println('Current directory: ${os.getwd()}')
println('Home directory: ${os.home_dir()}')
mut i := qdrant_installer.get()!
i.install()!
// 1. Get the qdrant client
println('Getting Qdrant client...')
mut qdrant_client := qdrant.get()!
println('Qdrant client URL: ${qdrant_client.url}')
// Check if Qdrant server is running
println('Checking Qdrant server health...')
health := qdrant_client.health_check() or {
println('Error checking health: ${err}')
false
}
println('Qdrant server health: ${health}')
// Get service info
println('Getting Qdrant service info...')
service_info := qdrant_client.get_service_info() or {
println('Error getting service info: ${err}')
exit(1)
}
println('Qdrant service info: ${service_info}')
// 2. Generate collection name
collection_name := 'collection_' + rand.string(4)
println('Generated collection name: ${collection_name}')
// 3. Create a new collection
println('Creating collection...')
created_collection := qdrant_client.create_collection(
collection_name: collection_name
size: 15
distance: 'Cosine'
) or {
println('Error creating collection: ${err}')
exit(1)
}
println('Created Collection: ${created_collection}')
// 4. Get the created collection
println('Getting collection...')
get_collection := qdrant_client.get_collection(
collection_name: collection_name
) or {
println('Error getting collection: ${err}')
exit(1)
}
println('Get Collection: ${get_collection}')
// 5. List all collections
println('Listing collections...')
list_collection := qdrant_client.list_collections() or {
println('Error listing collections: ${err}')
exit(1)
}
println('List Collection: ${list_collection}')
// 6. Check collection existence
println('Checking collection existence...')
collection_existence := qdrant_client.is_collection_exists(
collection_name: collection_name
) or {
println('Error checking collection existence: ${err}')
exit(1)
}
println('Collection Existence: ${collection_existence}')
// 7. Retrieve points
println('Retrieving points...')
collection_points := qdrant_client.retrieve_points(
collection_name: collection_name
ids: [
0,
3,
100,
]
) or {
println('Error retrieving points: ${err}')
exit(1)
}
println('Collection Points: ${collection_points}')
// 8. Upsert points
println('Upserting points...')
upsert_points := qdrant_client.upsert_points(
collection_name: collection_name
points: [
qdrant.Point{
payload: {
'key': 'value'
}
vector: [1.0, 2.0, 3.0]
},
qdrant.Point{
payload: {
'key': 'value'
}
vector: [4.0, 5.0, 6.0]
},
qdrant.Point{
payload: {
'key': 'value'
}
vector: [7.0, 8.0, 9.0]
},
]
) or {
println('Error upserting points: ${err}')
exit(1)
}
println('Upsert Points: ${upsert_points}')
println('Qdrant example script completed successfully')

View File

@@ -0,0 +1,3 @@
methods.v
pet_store_actor
docs

View File

@@ -0,0 +1,9 @@
# Actor Generation Examples
## `generate_methods.vsh`
This example generates actor method prototypes from an actor specification.
## `generate_actor_module.vsh`
This example generates an entire actor module from an actor specification with the support for the specified interfaces.

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.baobab.generator
import freeflowuniverse.herolib.baobab.specification
import freeflowuniverse.herolib.schemas.openrpc
import os
const example_dir = os.dir(@FILE)
const openrpc_spec_path = os.join_path(example_dir, 'openrpc.json')
// the actor specification obtained from the OpenRPC Specification
openrpc_spec := openrpc.new(path: openrpc_spec_path)!
actor_spec := specification.from_openrpc(openrpc_spec)!
actor_module := generator.generate_actor_module(actor_spec,
interfaces: [.openrpc]
)!
actor_module.write(example_dir,
format: true
overwrite: true
)!

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.baobab.generator
import freeflowuniverse.herolib.baobab.specification
import freeflowuniverse.herolib.schemas.openrpc
import os
const example_dir = os.dir(@FILE)
const openrpc_spec_path = os.join_path(example_dir, 'openrpc.json')
// the actor specification obtained from the OpenRPC Specification
openrpc_spec := openrpc.new(path: openrpc_spec_path)!
actor_spec := specification.from_openrpc(openrpc_spec)!
methods_file := generator.generate_methods_file(actor_spec)!
methods_file.write(example_dir,
format: true
overwrite: true
)!

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.baobab.generator
import freeflowuniverse.herolib.baobab.specification
import freeflowuniverse.herolib.schemas.openrpc
import os
const example_dir = os.dir(@FILE)
const openrpc_spec_path = os.join_path(example_dir, 'openrpc.json')
// the actor specification obtained from the OpenRPC Specification
openrpc_spec_ := openrpc.new(path: openrpc_spec_path)!
actor_spec := specification.from_openrpc(openrpc_spec_)!
openrpc_spec := actor_spec.to_openrpc()
openrpc_file := generator.generate_openrpc_file(openrpc_spec)!
openrpc_file.write(os.join_path(example_dir, 'docs'),
overwrite: true
)!

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