@plures/runebook 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ANALYSIS_LADDER.md +231 -0
- package/CHANGELOG.md +124 -0
- package/INTEGRATIONS.md +242 -0
- package/LICENSE +21 -0
- package/MEMORY.md +253 -0
- package/NIXOS.md +357 -0
- package/QUICKSTART.md +157 -0
- package/README.md +295 -0
- package/RELEASE.md +190 -0
- package/ValidationChecklist.md +598 -0
- package/docs/demo.md +338 -0
- package/docs/llm-integration.md +300 -0
- package/docs/parallel-execution-plan.md +160 -0
- package/flake.nix +228 -0
- package/integrations/README.md +242 -0
- package/integrations/demo-steps.sh +64 -0
- package/integrations/nvim-runebook.lua +140 -0
- package/integrations/tmux-status.sh +51 -0
- package/integrations/vim-runebook.vim +77 -0
- package/integrations/wezterm-status-simple.lua +48 -0
- package/integrations/wezterm-status.lua +76 -0
- package/nixos-module.nix +156 -0
- package/package.json +76 -0
- package/packages/design-dojo/index.js +4 -0
- package/packages/design-dojo/package.json +20 -0
- package/packages/design-dojo/tokens.css +69 -0
- package/playwright.config.ts +16 -0
- package/scripts/check-versions.cjs +62 -0
- package/scripts/demo.sh +220 -0
- package/shell.nix +31 -0
- package/src/app.html +13 -0
- package/src/cli/index.ts +1050 -0
- package/src/lib/agent/analysis-pipeline.ts +347 -0
- package/src/lib/agent/analysis-service.ts +171 -0
- package/src/lib/agent/analysis.ts +159 -0
- package/src/lib/agent/analyzers/heuristic.ts +289 -0
- package/src/lib/agent/analyzers/index.ts +7 -0
- package/src/lib/agent/analyzers/llm.ts +204 -0
- package/src/lib/agent/analyzers/local-search.ts +215 -0
- package/src/lib/agent/capture.ts +123 -0
- package/src/lib/agent/index.ts +244 -0
- package/src/lib/agent/integration.ts +81 -0
- package/src/lib/agent/llm/providers/base.ts +99 -0
- package/src/lib/agent/llm/providers/index.ts +60 -0
- package/src/lib/agent/llm/providers/mock.ts +67 -0
- package/src/lib/agent/llm/providers/ollama.ts +151 -0
- package/src/lib/agent/llm/providers/openai.ts +153 -0
- package/src/lib/agent/llm/sanitizer.ts +170 -0
- package/src/lib/agent/llm/types.ts +118 -0
- package/src/lib/agent/memory.ts +363 -0
- package/src/lib/agent/node-status.ts +56 -0
- package/src/lib/agent/node-suggestions.ts +64 -0
- package/src/lib/agent/status.ts +80 -0
- package/src/lib/agent/suggestions.ts +169 -0
- package/src/lib/components/Canvas.svelte +124 -0
- package/src/lib/components/ConnectionLine.svelte +46 -0
- package/src/lib/components/DisplayNode.svelte +167 -0
- package/src/lib/components/InputNode.svelte +158 -0
- package/src/lib/components/TerminalNode.svelte +237 -0
- package/src/lib/components/Toolbar.svelte +359 -0
- package/src/lib/components/TransformNode.svelte +327 -0
- package/src/lib/core/index.ts +31 -0
- package/src/lib/core/observer.ts +278 -0
- package/src/lib/core/redaction.ts +158 -0
- package/src/lib/core/shell-adapters/base.ts +325 -0
- package/src/lib/core/shell-adapters/bash.ts +110 -0
- package/src/lib/core/shell-adapters/index.ts +62 -0
- package/src/lib/core/shell-adapters/zsh.ts +105 -0
- package/src/lib/core/storage.ts +360 -0
- package/src/lib/core/types.ts +176 -0
- package/src/lib/design-dojo/Box.svelte +47 -0
- package/src/lib/design-dojo/Button.svelte +75 -0
- package/src/lib/design-dojo/Input.svelte +65 -0
- package/src/lib/design-dojo/List.svelte +38 -0
- package/src/lib/design-dojo/Select.svelte +48 -0
- package/src/lib/design-dojo/SplitPane.svelte +43 -0
- package/src/lib/design-dojo/StatusBar.svelte +61 -0
- package/src/lib/design-dojo/Table.svelte +47 -0
- package/src/lib/design-dojo/Text.svelte +36 -0
- package/src/lib/design-dojo/Toggle.svelte +48 -0
- package/src/lib/design-dojo/index.ts +10 -0
- package/src/lib/stores/canvas-praxis.ts +268 -0
- package/src/lib/stores/canvas.ts +58 -0
- package/src/lib/types/agent.ts +78 -0
- package/src/lib/types/canvas.ts +71 -0
- package/src/lib/utils/storage.ts +326 -0
- package/src/lib/utils/yaml-loader.ts +52 -0
- package/src/routes/+layout.svelte +5 -0
- package/src/routes/+layout.ts +5 -0
- package/src/routes/+page.svelte +32 -0
- package/src-tauri/Cargo.lock +5735 -0
- package/src-tauri/Cargo.toml +38 -0
- package/src-tauri/build.rs +3 -0
- package/src-tauri/capabilities/default.json +10 -0
- package/src-tauri/icons/128x128.png +0 -0
- package/src-tauri/icons/128x128@2x.png +0 -0
- package/src-tauri/icons/32x32.png +0 -0
- package/src-tauri/icons/Square107x107Logo.png +0 -0
- package/src-tauri/icons/Square142x142Logo.png +0 -0
- package/src-tauri/icons/Square150x150Logo.png +0 -0
- package/src-tauri/icons/Square284x284Logo.png +0 -0
- package/src-tauri/icons/Square30x30Logo.png +0 -0
- package/src-tauri/icons/Square310x310Logo.png +0 -0
- package/src-tauri/icons/Square44x44Logo.png +0 -0
- package/src-tauri/icons/Square71x71Logo.png +0 -0
- package/src-tauri/icons/Square89x89Logo.png +0 -0
- package/src-tauri/icons/StoreLogo.png +0 -0
- package/src-tauri/icons/icon.icns +0 -0
- package/src-tauri/icons/icon.ico +0 -0
- package/src-tauri/icons/icon.png +0 -0
- package/src-tauri/src/agents/agent1.rs +66 -0
- package/src-tauri/src/agents/agent2.rs +80 -0
- package/src-tauri/src/agents/agent3.rs +73 -0
- package/src-tauri/src/agents/agent4.rs +66 -0
- package/src-tauri/src/agents/agent5.rs +68 -0
- package/src-tauri/src/agents/agent6.rs +75 -0
- package/src-tauri/src/agents/base.rs +52 -0
- package/src-tauri/src/agents/mod.rs +17 -0
- package/src-tauri/src/core/coordination.rs +117 -0
- package/src-tauri/src/core/mod.rs +12 -0
- package/src-tauri/src/core/ownership.rs +61 -0
- package/src-tauri/src/core/types.rs +132 -0
- package/src-tauri/src/execution/mod.rs +5 -0
- package/src-tauri/src/execution/runner.rs +143 -0
- package/src-tauri/src/lib.rs +161 -0
- package/src-tauri/src/main.rs +6 -0
- package/src-tauri/src/memory/api.rs +422 -0
- package/src-tauri/src/memory/client.rs +156 -0
- package/src-tauri/src/memory/encryption.rs +79 -0
- package/src-tauri/src/memory/migration.rs +110 -0
- package/src-tauri/src/memory/mod.rs +28 -0
- package/src-tauri/src/memory/schema.rs +275 -0
- package/src-tauri/src/memory/tests.rs +192 -0
- package/src-tauri/src/orchestrator/coordinator.rs +232 -0
- package/src-tauri/src/orchestrator/mod.rs +13 -0
- package/src-tauri/src/orchestrator/planner.rs +304 -0
- package/src-tauri/tauri.conf.json +35 -0
- package/static/examples/date-time-example.yaml +147 -0
- package/static/examples/hello-world.yaml +74 -0
- package/static/examples/transform-example.yaml +157 -0
- package/static/favicon.png +0 -0
- package/static/svelte.svg +1 -0
- package/static/tauri.svg +6 -0
- package/static/vite.svg +1 -0
- package/svelte.config.js +18 -0
- package/tsconfig.json +19 -0
- package/vite.config.js +45 -0
- package/vitest.config.ts +21 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
-- RuneBook Neovim plugin (Lua version)
|
|
2
|
+
-- Place this file in ~/.config/nvim/lua/runebook.lua or ~/.config/nvim/plugin/runebook.lua
|
|
3
|
+
|
|
4
|
+
local M = {}
|
|
5
|
+
|
|
6
|
+
local status_file = vim.fn.expand('~/.runebook/agent-status.json')
|
|
7
|
+
local suggestions_file = vim.fn.expand('~/.runebook/suggestions.json')
|
|
8
|
+
|
|
9
|
+
-- Simple JSON parser for reading status (minimal implementation)
|
|
10
|
+
local function read_json_file(filepath)
|
|
11
|
+
local file = io.open(filepath, 'r')
|
|
12
|
+
if not file then
|
|
13
|
+
return nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
local content = file:read('*all')
|
|
17
|
+
file:close()
|
|
18
|
+
|
|
19
|
+
-- Use vim.json if available (Neovim 0.10+)
|
|
20
|
+
if vim.json then
|
|
21
|
+
local ok, data = pcall(vim.json.decode, content)
|
|
22
|
+
if ok then
|
|
23
|
+
return data
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
-- Fallback: simple parsing for status field
|
|
28
|
+
local status = content:match('"status"%s*:%s*"([^"]*)"')
|
|
29
|
+
local high_priority = content:match('"highPriorityCount"%s*:%s*([0-9]+)')
|
|
30
|
+
local suggestion_count = content:match('"suggestionCount"%s*:%s*([0-9]+)')
|
|
31
|
+
|
|
32
|
+
if status then
|
|
33
|
+
return {
|
|
34
|
+
status = status,
|
|
35
|
+
highPriorityCount = high_priority and tonumber(high_priority) or 0,
|
|
36
|
+
suggestionCount = suggestion_count and tonumber(suggestion_count) or 0,
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
return nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
-- Get top suggestion
|
|
44
|
+
function M.get_top_suggestion()
|
|
45
|
+
local file = io.open(suggestions_file, 'r')
|
|
46
|
+
if not file then
|
|
47
|
+
return nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
local content = file:read('*all')
|
|
51
|
+
file:close()
|
|
52
|
+
|
|
53
|
+
-- Use vim.json if available
|
|
54
|
+
if vim.json then
|
|
55
|
+
local ok, data = pcall(vim.json.decode, content)
|
|
56
|
+
if ok and data.suggestions and #data.suggestions > 0 then
|
|
57
|
+
-- Sort by priority and return top
|
|
58
|
+
table.sort(data.suggestions, function(a, b)
|
|
59
|
+
local priority_order = { high = 3, medium = 2, low = 1 }
|
|
60
|
+
local a_prio = priority_order[a.priority] or 0
|
|
61
|
+
local b_prio = priority_order[b.priority] or 0
|
|
62
|
+
if a_prio ~= b_prio then
|
|
63
|
+
return a_prio > b_prio
|
|
64
|
+
end
|
|
65
|
+
return a.timestamp > b.timestamp
|
|
66
|
+
end)
|
|
67
|
+
return data.suggestions[1]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
-- Fallback: simple extraction
|
|
72
|
+
local title = content:match('"title"%s*:%s*"([^"]*)"')
|
|
73
|
+
local priority = content:match('"priority"%s*:%s*"([^"]*)"')
|
|
74
|
+
|
|
75
|
+
if title then
|
|
76
|
+
return {
|
|
77
|
+
title = title,
|
|
78
|
+
priority = priority or 'low',
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
return nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
-- Show suggestion in command line
|
|
86
|
+
function M.show_suggestion()
|
|
87
|
+
local suggestion = M.get_top_suggestion()
|
|
88
|
+
if not suggestion then
|
|
89
|
+
vim.notify('No suggestions available', vim.log.levels.INFO)
|
|
90
|
+
return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
local symbol = suggestion.priority == 'high' and '⚠'
|
|
94
|
+
or suggestion.priority == 'medium' and '▲'
|
|
95
|
+
or '•'
|
|
96
|
+
|
|
97
|
+
local text = string.format('%s %s', symbol, suggestion.title)
|
|
98
|
+
if suggestion.description then
|
|
99
|
+
text = text .. '\n' .. suggestion.description
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
vim.notify(text, vim.log.levels.INFO, { title = 'RuneBook Suggestion' })
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
-- Display in virtual text (optional)
|
|
106
|
+
function M.update_virtual_text()
|
|
107
|
+
if not vim.api.nvim_buf_is_valid(0) then
|
|
108
|
+
return
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
local ns = vim.api.nvim_create_namespace('runebook')
|
|
112
|
+
vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
|
|
113
|
+
|
|
114
|
+
local suggestion = M.get_top_suggestion()
|
|
115
|
+
if suggestion then
|
|
116
|
+
local symbol = suggestion.priority == 'high' and '⚠'
|
|
117
|
+
or suggestion.priority == 'medium' and '▲'
|
|
118
|
+
or '•'
|
|
119
|
+
local text = string.format('%s %s', symbol, suggestion.title)
|
|
120
|
+
|
|
121
|
+
-- Show at end of first line
|
|
122
|
+
vim.api.nvim_buf_set_extmark(0, ns, 0, -1, {
|
|
123
|
+
virt_text = {{ text, 'Comment' }},
|
|
124
|
+
virt_text_pos = 'eol',
|
|
125
|
+
})
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
-- Create command
|
|
130
|
+
vim.api.nvim_create_user_command('RunebookSuggestion', M.show_suggestion, {
|
|
131
|
+
desc = 'Show RuneBook suggestion',
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
-- Optional: Auto-update virtual text on buffer enter
|
|
135
|
+
-- vim.api.nvim_create_autocmd('BufEnter', {
|
|
136
|
+
-- callback = M.update_virtual_text,
|
|
137
|
+
-- })
|
|
138
|
+
|
|
139
|
+
return M
|
|
140
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# RuneBook tmux status line integration
|
|
3
|
+
# Add this to your ~/.tmux.conf:
|
|
4
|
+
# set -g status-right '#(bash ~/.runebook/integrations/tmux-status.sh)'
|
|
5
|
+
|
|
6
|
+
RUNebook_CLI="${RUNebook_CLI:-runebook}"
|
|
7
|
+
STATUS_FILE="$HOME/.runebook/agent-status.json"
|
|
8
|
+
|
|
9
|
+
if [ ! -f "$STATUS_FILE" ]; then
|
|
10
|
+
echo ""
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Read status from JSON file
|
|
15
|
+
STATUS=$(cat "$STATUS_FILE" 2>/dev/null | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
|
16
|
+
SUGGESTION_COUNT=$(cat "$STATUS_FILE" 2>/dev/null | grep -o '"suggestionCount":[0-9]*' | cut -d':' -f2)
|
|
17
|
+
HIGH_PRIORITY=$(cat "$STATUS_FILE" 2>/dev/null | grep -o '"highPriorityCount":[0-9]*' | cut -d':' -f2)
|
|
18
|
+
|
|
19
|
+
if [ -z "$STATUS" ]; then
|
|
20
|
+
echo ""
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
case "$STATUS" in
|
|
25
|
+
"idle")
|
|
26
|
+
SYMBOL="●"
|
|
27
|
+
COLOR="#[fg=green]"
|
|
28
|
+
;;
|
|
29
|
+
"analyzing")
|
|
30
|
+
SYMBOL="⟳"
|
|
31
|
+
COLOR="#[fg=yellow]"
|
|
32
|
+
;;
|
|
33
|
+
"issues_found")
|
|
34
|
+
SYMBOL="⚠"
|
|
35
|
+
COLOR="#[fg=red]"
|
|
36
|
+
if [ -n "$HIGH_PRIORITY" ] && [ "$HIGH_PRIORITY" -gt 0 ]; then
|
|
37
|
+
TEXT="${HIGH_PRIORITY}"
|
|
38
|
+
fi
|
|
39
|
+
;;
|
|
40
|
+
*)
|
|
41
|
+
echo ""
|
|
42
|
+
exit 0
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
if [ -z "$TEXT" ]; then
|
|
47
|
+
TEXT=""
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "${COLOR}${SYMBOL}${TEXT}#[fg=default]"
|
|
51
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
" RuneBook Vim/Neovim plugin
|
|
2
|
+
" Minimal plugin to display last suggestion
|
|
3
|
+
" Place this file in ~/.vim/plugin/ or ~/.config/nvim/plugin/
|
|
4
|
+
|
|
5
|
+
if exists('g:loaded_runebook')
|
|
6
|
+
finish
|
|
7
|
+
endif
|
|
8
|
+
let g:loaded_runebook = 1
|
|
9
|
+
|
|
10
|
+
let s:status_file = expand('~/.runebook/agent-status.json')
|
|
11
|
+
let s:suggestions_file = expand('~/.runebook/suggestions.json')
|
|
12
|
+
|
|
13
|
+
" Get top suggestion
|
|
14
|
+
function! s:GetTopSuggestion()
|
|
15
|
+
if !filereadable(s:suggestions_file)
|
|
16
|
+
return ''
|
|
17
|
+
endif
|
|
18
|
+
|
|
19
|
+
try
|
|
20
|
+
let content = readfile(s:suggestions_file)
|
|
21
|
+
let json_str = join(content, '')
|
|
22
|
+
" Simple JSON parsing for suggestions array
|
|
23
|
+
" This is a minimal implementation - for production, use a proper JSON parser
|
|
24
|
+
let suggestions = matchstr(json_str, '"suggestions"\s*:\s*\[.*\]')
|
|
25
|
+
if empty(suggestions)
|
|
26
|
+
return ''
|
|
27
|
+
endif
|
|
28
|
+
|
|
29
|
+
" Extract first suggestion title (simplified)
|
|
30
|
+
let title = matchstr(suggestions, '"title"\s*:\s*"\([^"]*\)"', 0, 1)
|
|
31
|
+
let priority = matchstr(suggestions, '"priority"\s*:\s*"\([^"]*\)"', 0, 1)
|
|
32
|
+
|
|
33
|
+
if empty(title)
|
|
34
|
+
return ''
|
|
35
|
+
endif
|
|
36
|
+
|
|
37
|
+
let symbol = priority ==# 'high' ? '⚠' : priority ==# 'medium' ? '▲' : '•'
|
|
38
|
+
return symbol . ' ' . title
|
|
39
|
+
catch
|
|
40
|
+
return ''
|
|
41
|
+
endtry
|
|
42
|
+
endfunction
|
|
43
|
+
|
|
44
|
+
" Display suggestion in command line
|
|
45
|
+
function! RunebookShowSuggestion()
|
|
46
|
+
let suggestion = s:GetTopSuggestion()
|
|
47
|
+
if empty(suggestion)
|
|
48
|
+
echo 'No suggestions available'
|
|
49
|
+
else
|
|
50
|
+
echo suggestion
|
|
51
|
+
endif
|
|
52
|
+
endfunction
|
|
53
|
+
|
|
54
|
+
" Command to show suggestion
|
|
55
|
+
command! RunebookSuggestion call RunebookShowSuggestion()
|
|
56
|
+
|
|
57
|
+
" Optional: Show suggestion in virtual text (Neovim only)
|
|
58
|
+
if has('nvim')
|
|
59
|
+
function! s:UpdateVirtualText()
|
|
60
|
+
if !exists('b:runebook_ns')
|
|
61
|
+
let b:runebook_ns = nvim_create_namespace('runebook')
|
|
62
|
+
endif
|
|
63
|
+
|
|
64
|
+
" Clear existing virtual text
|
|
65
|
+
call nvim_buf_clear_namespace(0, b:runebook_ns, 0, -1)
|
|
66
|
+
|
|
67
|
+
let suggestion = s:GetTopSuggestion()
|
|
68
|
+
if !empty(suggestion)
|
|
69
|
+
" Show at end of first line
|
|
70
|
+
call nvim_buf_set_virtual_text(0, b:runebook_ns, 0, [[suggestion, 'Comment']], {})
|
|
71
|
+
endif
|
|
72
|
+
endfunction
|
|
73
|
+
|
|
74
|
+
" Auto-update on buffer enter (optional)
|
|
75
|
+
" autocmd BufEnter * call s:UpdateVirtualText()
|
|
76
|
+
endif
|
|
77
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
-- RuneBook WezTerm right-status integration (simplified version)
|
|
2
|
+
-- Add this to your ~/.config/wezterm/wezterm.lua:
|
|
3
|
+
--
|
|
4
|
+
-- wezterm.on('update-right-status', function(window, pane)
|
|
5
|
+
-- local status_file = wezterm.home_dir .. '/.runebook/agent-status.json'
|
|
6
|
+
-- local file = io.open(status_file, 'r')
|
|
7
|
+
-- if not file then
|
|
8
|
+
-- window:set_right_status('')
|
|
9
|
+
-- return
|
|
10
|
+
-- end
|
|
11
|
+
--
|
|
12
|
+
-- local content = file:read('*all')
|
|
13
|
+
-- file:close()
|
|
14
|
+
--
|
|
15
|
+
-- -- Simple JSON parsing (for status field only)
|
|
16
|
+
-- local status = content:match('"status"%s*:%s*"([^"]*)"')
|
|
17
|
+
-- local high_priority = content:match('"highPriorityCount"%s*:%s*([0-9]+)')
|
|
18
|
+
--
|
|
19
|
+
-- local symbol = ''
|
|
20
|
+
-- local color = ''
|
|
21
|
+
-- local text = ''
|
|
22
|
+
--
|
|
23
|
+
-- if status == 'idle' then
|
|
24
|
+
-- symbol = '●'
|
|
25
|
+
-- color = '#00ff00'
|
|
26
|
+
-- elseif status == 'analyzing' then
|
|
27
|
+
-- symbol = '⟳'
|
|
28
|
+
-- color = '#ffff00'
|
|
29
|
+
-- elseif status == 'issues_found' then
|
|
30
|
+
-- symbol = '⚠'
|
|
31
|
+
-- color = '#ff0000'
|
|
32
|
+
-- if high_priority then
|
|
33
|
+
-- text = high_priority
|
|
34
|
+
-- end
|
|
35
|
+
-- end
|
|
36
|
+
--
|
|
37
|
+
-- if symbol ~= '' then
|
|
38
|
+
-- window:set_right_status(wezterm.format({
|
|
39
|
+
-- { Foreground = { Color = color } },
|
|
40
|
+
-- { Text = symbol .. text },
|
|
41
|
+
-- { Foreground = { Color = '#ffffff' } },
|
|
42
|
+
-- { Text = ' ' },
|
|
43
|
+
-- }))
|
|
44
|
+
-- else
|
|
45
|
+
-- window:set_right_status('')
|
|
46
|
+
-- end
|
|
47
|
+
-- end)
|
|
48
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
-- RuneBook WezTerm right-status integration
|
|
2
|
+
-- Add this to your ~/.config/wezterm/wezterm.lua:
|
|
3
|
+
-- local runebook_status = require('integrations/wezterm-status')
|
|
4
|
+
-- config.set_wezterm_config(runebook_status)
|
|
5
|
+
|
|
6
|
+
local wezterm = require 'wezterm'
|
|
7
|
+
local json = require 'json'
|
|
8
|
+
|
|
9
|
+
local function get_agent_status()
|
|
10
|
+
local status_file = wezterm.home_dir .. '/.runebook/agent-status.json'
|
|
11
|
+
local file = io.open(status_file, 'r')
|
|
12
|
+
|
|
13
|
+
if not file then
|
|
14
|
+
return nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
local content = file:read('*all')
|
|
18
|
+
file:close()
|
|
19
|
+
|
|
20
|
+
local ok, data = pcall(json.decode, content)
|
|
21
|
+
if not ok then
|
|
22
|
+
return nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return data
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
local function format_status(status_data)
|
|
29
|
+
if not status_data then
|
|
30
|
+
return ''
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
local status = status_data.status or 'idle'
|
|
34
|
+
local symbol = ''
|
|
35
|
+
local color = ''
|
|
36
|
+
local text = ''
|
|
37
|
+
|
|
38
|
+
if status == 'idle' then
|
|
39
|
+
symbol = '●'
|
|
40
|
+
color = '#00ff00'
|
|
41
|
+
elseif status == 'analyzing' then
|
|
42
|
+
symbol = '⟳'
|
|
43
|
+
color = '#ffff00'
|
|
44
|
+
elseif status == 'issues_found' then
|
|
45
|
+
symbol = '⚠'
|
|
46
|
+
color = '#ff0000'
|
|
47
|
+
local high_priority = status_data.highPriorityCount or 0
|
|
48
|
+
if high_priority > 0 then
|
|
49
|
+
text = tostring(high_priority)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if symbol == '' then
|
|
54
|
+
return ''
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
return wezterm.format({
|
|
58
|
+
{ Foreground = { Color = color } },
|
|
59
|
+
{ Text = symbol .. text },
|
|
60
|
+
{ Foreground = { Color = '#ffffff' } },
|
|
61
|
+
{ Text = ' ' },
|
|
62
|
+
})
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
wezterm.on('update-right-status', function(window, pane)
|
|
66
|
+
local status_data = get_agent_status()
|
|
67
|
+
local status_text = format_status(status_data)
|
|
68
|
+
|
|
69
|
+
window:set_right_status(status_text)
|
|
70
|
+
end)
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
get_agent_status = get_agent_status,
|
|
74
|
+
format_status = format_status,
|
|
75
|
+
}
|
|
76
|
+
|
package/nixos-module.nix
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{ config, lib, pkgs, ... }:
|
|
2
|
+
|
|
3
|
+
with lib;
|
|
4
|
+
|
|
5
|
+
let
|
|
6
|
+
cfg = config.services.runebook-agent;
|
|
7
|
+
|
|
8
|
+
# Configuration file path
|
|
9
|
+
configDir = "/var/lib/runebook-agent";
|
|
10
|
+
configFile = "${configDir}/agent-config.json";
|
|
11
|
+
observerConfigFile = "${configDir}/observer-config.json";
|
|
12
|
+
|
|
13
|
+
# Service script
|
|
14
|
+
serviceScript = pkgs.writeShellScript "runebook-agent-service" ''
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# Ensure config directory exists
|
|
19
|
+
mkdir -p ${configDir}
|
|
20
|
+
|
|
21
|
+
# Initialize config files if they don't exist
|
|
22
|
+
if [ ! -f ${configFile} ]; then
|
|
23
|
+
cat > ${configFile} <<EOF
|
|
24
|
+
{
|
|
25
|
+
"enabled": ${if cfg.enable then "true" else "false"},
|
|
26
|
+
"captureEvents": ${if cfg.captureEvents then "true" else "false"},
|
|
27
|
+
"analyzePatterns": ${if cfg.analyzePatterns then "true" else "false"},
|
|
28
|
+
"suggestImprovements": ${if cfg.suggestImprovements then "true" else "false"},
|
|
29
|
+
"storagePath": "${cfg.dataDir}",
|
|
30
|
+
"maxEvents": ${toString cfg.maxEvents},
|
|
31
|
+
"retentionDays": ${toString cfg.retentionDays}
|
|
32
|
+
}
|
|
33
|
+
EOF
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [ ! -f ${observerConfigFile} ]; then
|
|
37
|
+
cat > ${observerConfigFile} <<EOF
|
|
38
|
+
{
|
|
39
|
+
"enabled": ${if cfg.enable then "true" else "false"},
|
|
40
|
+
"redactSecrets": true,
|
|
41
|
+
"usePluresDB": false,
|
|
42
|
+
"chunkSize": 4096,
|
|
43
|
+
"maxEvents": ${toString cfg.maxEvents},
|
|
44
|
+
"retentionDays": ${toString cfg.retentionDays},
|
|
45
|
+
"storagePath": "${cfg.dataDir}"
|
|
46
|
+
}
|
|
47
|
+
EOF
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Set up environment
|
|
51
|
+
export HOME=${configDir}
|
|
52
|
+
export XDG_CONFIG_HOME=${configDir}
|
|
53
|
+
export XDG_DATA_HOME=${configDir}
|
|
54
|
+
|
|
55
|
+
# Inject secrets from environment/agenix/sops if available
|
|
56
|
+
# OpenAI key must be provided via environment variable
|
|
57
|
+
if [ -n "''${OPENAI_API_KEY:-}" ]; then
|
|
58
|
+
export OPENAI_API_KEY
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Run the agent in background mode
|
|
62
|
+
# Note: The actual agent runs as a shell hook, so this service
|
|
63
|
+
# mainly ensures the configuration is set up correctly.
|
|
64
|
+
# For a true background service, you would need to implement
|
|
65
|
+
# a daemon mode in the CLI.
|
|
66
|
+
|
|
67
|
+
# For now, we'll just ensure the config is ready
|
|
68
|
+
# The agent will be activated via shell hooks when enabled
|
|
69
|
+
exec sleep infinity
|
|
70
|
+
'';
|
|
71
|
+
|
|
72
|
+
in {
|
|
73
|
+
options.services.runebook-agent = {
|
|
74
|
+
enable = mkEnableOption "RuneBook agent service";
|
|
75
|
+
|
|
76
|
+
captureEvents = mkOption {
|
|
77
|
+
type = types.bool;
|
|
78
|
+
default = true;
|
|
79
|
+
description = "Enable event capture";
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
analyzePatterns = mkOption {
|
|
83
|
+
type = types.bool;
|
|
84
|
+
default = true;
|
|
85
|
+
description = "Enable pattern analysis";
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
suggestImprovements = mkOption {
|
|
89
|
+
type = types.bool;
|
|
90
|
+
default = true;
|
|
91
|
+
description = "Enable suggestion generation";
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
dataDir = mkOption {
|
|
95
|
+
type = types.str;
|
|
96
|
+
default = "/var/lib/runebook-agent/data";
|
|
97
|
+
description = "Data directory for agent storage";
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
maxEvents = mkOption {
|
|
101
|
+
type = types.int;
|
|
102
|
+
default = 10000;
|
|
103
|
+
description = "Maximum number of events to store";
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
retentionDays = mkOption {
|
|
107
|
+
type = types.int;
|
|
108
|
+
default = 30;
|
|
109
|
+
description = "Number of days to retain events";
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
openaiApiKey = mkOption {
|
|
113
|
+
type = types.nullOr types.str;
|
|
114
|
+
default = null;
|
|
115
|
+
description = ''
|
|
116
|
+
OpenAI API key (if using LLM features).
|
|
117
|
+
WARNING: This will be stored in the Nix store if set here.
|
|
118
|
+
Prefer using environment variables, agenix, or sops-nix instead.
|
|
119
|
+
'';
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
config = mkIf cfg.enable {
|
|
124
|
+
systemd.user.services.runebook-agent = {
|
|
125
|
+
description = "RuneBook Agent Service";
|
|
126
|
+
wantedBy = [ "default.target" ];
|
|
127
|
+
|
|
128
|
+
serviceConfig = {
|
|
129
|
+
Type = "simple";
|
|
130
|
+
ExecStart = "${serviceScript}";
|
|
131
|
+
Restart = "on-failure";
|
|
132
|
+
RestartSec = "5s";
|
|
133
|
+
|
|
134
|
+
# Security settings
|
|
135
|
+
PrivateTmp = true;
|
|
136
|
+
ProtectSystem = "strict";
|
|
137
|
+
ProtectHome = "read-only";
|
|
138
|
+
ReadWritePaths = [ configDir cfg.dataDir ];
|
|
139
|
+
|
|
140
|
+
# Environment
|
|
141
|
+
Environment = [
|
|
142
|
+
"HOME=${configDir}"
|
|
143
|
+
"XDG_CONFIG_HOME=${configDir}"
|
|
144
|
+
"XDG_DATA_HOME=${configDir}"
|
|
145
|
+
] ++ optional (cfg.openaiApiKey != null) "OPENAI_API_KEY=${cfg.openaiApiKey}";
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
# Create data directory
|
|
150
|
+
systemd.tmpfiles.rules = [
|
|
151
|
+
"d ${configDir} 0755 root root -"
|
|
152
|
+
"d ${cfg.dataDir} 0755 root root -"
|
|
153
|
+
];
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plures/runebook",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public",
|
|
6
|
+
"registry": "https://registry.npmjs.org/"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/plures/runebook.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/plures/runebook/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/plures/runebook#readme",
|
|
16
|
+
"description": "A reactive, canvas-native computing environment that merges terminals, notebooks, and web components",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"tauri",
|
|
20
|
+
"svelte",
|
|
21
|
+
"desktop-app",
|
|
22
|
+
"reactive",
|
|
23
|
+
"canvas",
|
|
24
|
+
"terminal",
|
|
25
|
+
"notebook",
|
|
26
|
+
"workflow",
|
|
27
|
+
"visual-programming",
|
|
28
|
+
"node-based"
|
|
29
|
+
],
|
|
30
|
+
"author": "Plures",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "vite dev",
|
|
33
|
+
"build": "vite build",
|
|
34
|
+
"preview": "vite preview",
|
|
35
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
36
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
37
|
+
"tauri": "tauri",
|
|
38
|
+
"version:check": "node scripts/check-versions.cjs",
|
|
39
|
+
"agent": "tsx src/cli/index.ts",
|
|
40
|
+
"test": "vitest",
|
|
41
|
+
"test:coverage": "vitest --coverage",
|
|
42
|
+
"test:e2e": "playwright test",
|
|
43
|
+
"test:all": "npm run test && npm run test:e2e"
|
|
44
|
+
},
|
|
45
|
+
"bin": {
|
|
46
|
+
"runebook": "./dist/cli/index.js"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"workspaces": [
|
|
50
|
+
"packages/*"
|
|
51
|
+
],
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@plures/design-dojo": "^0.1.0",
|
|
54
|
+
"@plures/praxis": "^1.2.13",
|
|
55
|
+
"@tauri-apps/api": "^2.9.1",
|
|
56
|
+
"@tauri-apps/plugin-opener": "^2.5.2",
|
|
57
|
+
"@types/js-yaml": "^4.0.9",
|
|
58
|
+
"js-yaml": "^4.1.1",
|
|
59
|
+
"pluresdb": "^1.3.1"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@playwright/test": "^1.50.1",
|
|
63
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
64
|
+
"@sveltejs/kit": "^2.49.2",
|
|
65
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
66
|
+
"@tauri-apps/cli": "^2.9.6",
|
|
67
|
+
"@types/node": "^20.0.0",
|
|
68
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
69
|
+
"svelte": "^5.46.1",
|
|
70
|
+
"svelte-check": "^4.3.5",
|
|
71
|
+
"tsx": "^4.7.0",
|
|
72
|
+
"typescript": "~5.6.3",
|
|
73
|
+
"vite": "^6.4.1",
|
|
74
|
+
"vitest": "^2.0.0"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plures/design-dojo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Design tokens and UI component library for the Plures ecosystem",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./tokens.css": "./tokens.css"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"index.js",
|
|
13
|
+
"tokens.css"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"registry": "https://registry.npmjs.org/"
|
|
19
|
+
}
|
|
20
|
+
}
|