@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.
Files changed (148) hide show
  1. package/ANALYSIS_LADDER.md +231 -0
  2. package/CHANGELOG.md +124 -0
  3. package/INTEGRATIONS.md +242 -0
  4. package/LICENSE +21 -0
  5. package/MEMORY.md +253 -0
  6. package/NIXOS.md +357 -0
  7. package/QUICKSTART.md +157 -0
  8. package/README.md +295 -0
  9. package/RELEASE.md +190 -0
  10. package/ValidationChecklist.md +598 -0
  11. package/docs/demo.md +338 -0
  12. package/docs/llm-integration.md +300 -0
  13. package/docs/parallel-execution-plan.md +160 -0
  14. package/flake.nix +228 -0
  15. package/integrations/README.md +242 -0
  16. package/integrations/demo-steps.sh +64 -0
  17. package/integrations/nvim-runebook.lua +140 -0
  18. package/integrations/tmux-status.sh +51 -0
  19. package/integrations/vim-runebook.vim +77 -0
  20. package/integrations/wezterm-status-simple.lua +48 -0
  21. package/integrations/wezterm-status.lua +76 -0
  22. package/nixos-module.nix +156 -0
  23. package/package.json +76 -0
  24. package/packages/design-dojo/index.js +4 -0
  25. package/packages/design-dojo/package.json +20 -0
  26. package/packages/design-dojo/tokens.css +69 -0
  27. package/playwright.config.ts +16 -0
  28. package/scripts/check-versions.cjs +62 -0
  29. package/scripts/demo.sh +220 -0
  30. package/shell.nix +31 -0
  31. package/src/app.html +13 -0
  32. package/src/cli/index.ts +1050 -0
  33. package/src/lib/agent/analysis-pipeline.ts +347 -0
  34. package/src/lib/agent/analysis-service.ts +171 -0
  35. package/src/lib/agent/analysis.ts +159 -0
  36. package/src/lib/agent/analyzers/heuristic.ts +289 -0
  37. package/src/lib/agent/analyzers/index.ts +7 -0
  38. package/src/lib/agent/analyzers/llm.ts +204 -0
  39. package/src/lib/agent/analyzers/local-search.ts +215 -0
  40. package/src/lib/agent/capture.ts +123 -0
  41. package/src/lib/agent/index.ts +244 -0
  42. package/src/lib/agent/integration.ts +81 -0
  43. package/src/lib/agent/llm/providers/base.ts +99 -0
  44. package/src/lib/agent/llm/providers/index.ts +60 -0
  45. package/src/lib/agent/llm/providers/mock.ts +67 -0
  46. package/src/lib/agent/llm/providers/ollama.ts +151 -0
  47. package/src/lib/agent/llm/providers/openai.ts +153 -0
  48. package/src/lib/agent/llm/sanitizer.ts +170 -0
  49. package/src/lib/agent/llm/types.ts +118 -0
  50. package/src/lib/agent/memory.ts +363 -0
  51. package/src/lib/agent/node-status.ts +56 -0
  52. package/src/lib/agent/node-suggestions.ts +64 -0
  53. package/src/lib/agent/status.ts +80 -0
  54. package/src/lib/agent/suggestions.ts +169 -0
  55. package/src/lib/components/Canvas.svelte +124 -0
  56. package/src/lib/components/ConnectionLine.svelte +46 -0
  57. package/src/lib/components/DisplayNode.svelte +167 -0
  58. package/src/lib/components/InputNode.svelte +158 -0
  59. package/src/lib/components/TerminalNode.svelte +237 -0
  60. package/src/lib/components/Toolbar.svelte +359 -0
  61. package/src/lib/components/TransformNode.svelte +327 -0
  62. package/src/lib/core/index.ts +31 -0
  63. package/src/lib/core/observer.ts +278 -0
  64. package/src/lib/core/redaction.ts +158 -0
  65. package/src/lib/core/shell-adapters/base.ts +325 -0
  66. package/src/lib/core/shell-adapters/bash.ts +110 -0
  67. package/src/lib/core/shell-adapters/index.ts +62 -0
  68. package/src/lib/core/shell-adapters/zsh.ts +105 -0
  69. package/src/lib/core/storage.ts +360 -0
  70. package/src/lib/core/types.ts +176 -0
  71. package/src/lib/design-dojo/Box.svelte +47 -0
  72. package/src/lib/design-dojo/Button.svelte +75 -0
  73. package/src/lib/design-dojo/Input.svelte +65 -0
  74. package/src/lib/design-dojo/List.svelte +38 -0
  75. package/src/lib/design-dojo/Select.svelte +48 -0
  76. package/src/lib/design-dojo/SplitPane.svelte +43 -0
  77. package/src/lib/design-dojo/StatusBar.svelte +61 -0
  78. package/src/lib/design-dojo/Table.svelte +47 -0
  79. package/src/lib/design-dojo/Text.svelte +36 -0
  80. package/src/lib/design-dojo/Toggle.svelte +48 -0
  81. package/src/lib/design-dojo/index.ts +10 -0
  82. package/src/lib/stores/canvas-praxis.ts +268 -0
  83. package/src/lib/stores/canvas.ts +58 -0
  84. package/src/lib/types/agent.ts +78 -0
  85. package/src/lib/types/canvas.ts +71 -0
  86. package/src/lib/utils/storage.ts +326 -0
  87. package/src/lib/utils/yaml-loader.ts +52 -0
  88. package/src/routes/+layout.svelte +5 -0
  89. package/src/routes/+layout.ts +5 -0
  90. package/src/routes/+page.svelte +32 -0
  91. package/src-tauri/Cargo.lock +5735 -0
  92. package/src-tauri/Cargo.toml +38 -0
  93. package/src-tauri/build.rs +3 -0
  94. package/src-tauri/capabilities/default.json +10 -0
  95. package/src-tauri/icons/128x128.png +0 -0
  96. package/src-tauri/icons/128x128@2x.png +0 -0
  97. package/src-tauri/icons/32x32.png +0 -0
  98. package/src-tauri/icons/Square107x107Logo.png +0 -0
  99. package/src-tauri/icons/Square142x142Logo.png +0 -0
  100. package/src-tauri/icons/Square150x150Logo.png +0 -0
  101. package/src-tauri/icons/Square284x284Logo.png +0 -0
  102. package/src-tauri/icons/Square30x30Logo.png +0 -0
  103. package/src-tauri/icons/Square310x310Logo.png +0 -0
  104. package/src-tauri/icons/Square44x44Logo.png +0 -0
  105. package/src-tauri/icons/Square71x71Logo.png +0 -0
  106. package/src-tauri/icons/Square89x89Logo.png +0 -0
  107. package/src-tauri/icons/StoreLogo.png +0 -0
  108. package/src-tauri/icons/icon.icns +0 -0
  109. package/src-tauri/icons/icon.ico +0 -0
  110. package/src-tauri/icons/icon.png +0 -0
  111. package/src-tauri/src/agents/agent1.rs +66 -0
  112. package/src-tauri/src/agents/agent2.rs +80 -0
  113. package/src-tauri/src/agents/agent3.rs +73 -0
  114. package/src-tauri/src/agents/agent4.rs +66 -0
  115. package/src-tauri/src/agents/agent5.rs +68 -0
  116. package/src-tauri/src/agents/agent6.rs +75 -0
  117. package/src-tauri/src/agents/base.rs +52 -0
  118. package/src-tauri/src/agents/mod.rs +17 -0
  119. package/src-tauri/src/core/coordination.rs +117 -0
  120. package/src-tauri/src/core/mod.rs +12 -0
  121. package/src-tauri/src/core/ownership.rs +61 -0
  122. package/src-tauri/src/core/types.rs +132 -0
  123. package/src-tauri/src/execution/mod.rs +5 -0
  124. package/src-tauri/src/execution/runner.rs +143 -0
  125. package/src-tauri/src/lib.rs +161 -0
  126. package/src-tauri/src/main.rs +6 -0
  127. package/src-tauri/src/memory/api.rs +422 -0
  128. package/src-tauri/src/memory/client.rs +156 -0
  129. package/src-tauri/src/memory/encryption.rs +79 -0
  130. package/src-tauri/src/memory/migration.rs +110 -0
  131. package/src-tauri/src/memory/mod.rs +28 -0
  132. package/src-tauri/src/memory/schema.rs +275 -0
  133. package/src-tauri/src/memory/tests.rs +192 -0
  134. package/src-tauri/src/orchestrator/coordinator.rs +232 -0
  135. package/src-tauri/src/orchestrator/mod.rs +13 -0
  136. package/src-tauri/src/orchestrator/planner.rs +304 -0
  137. package/src-tauri/tauri.conf.json +35 -0
  138. package/static/examples/date-time-example.yaml +147 -0
  139. package/static/examples/hello-world.yaml +74 -0
  140. package/static/examples/transform-example.yaml +157 -0
  141. package/static/favicon.png +0 -0
  142. package/static/svelte.svg +1 -0
  143. package/static/tauri.svg +6 -0
  144. package/static/vite.svg +1 -0
  145. package/svelte.config.js +18 -0
  146. package/tsconfig.json +19 -0
  147. package/vite.config.js +45 -0
  148. package/vitest.config.ts +21 -0
@@ -0,0 +1,326 @@
1
+ // Storage utility for RuneBook canvases
2
+ // Integrated with PluresDB for persistent storage
3
+
4
+ import type { Canvas } from '../types/canvas';
5
+
6
+ export interface StorageAdapter {
7
+ save(canvas: Canvas): Promise<void>;
8
+ load(id: string): Promise<Canvas | null>;
9
+ list(): Promise<{ id: string; name: string; timestamp: number }[]>;
10
+ delete(id: string): Promise<void>;
11
+ }
12
+
13
+ /**
14
+ * LocalStorage adapter for browser-based storage
15
+ * Fallback option when PluresDB is not available
16
+ */
17
+ export class LocalStorageAdapter implements StorageAdapter {
18
+ private readonly prefix = 'runebook_canvas_';
19
+
20
+ private validateCanvas(data: any): data is { canvas: Canvas; timestamp: number } {
21
+ return (
22
+ data &&
23
+ typeof data === 'object' &&
24
+ 'canvas' in data &&
25
+ 'timestamp' in data &&
26
+ typeof data.timestamp === 'number' &&
27
+ data.canvas &&
28
+ typeof data.canvas === 'object' &&
29
+ 'id' in data.canvas &&
30
+ 'name' in data.canvas &&
31
+ 'nodes' in data.canvas &&
32
+ Array.isArray(data.canvas.nodes)
33
+ );
34
+ }
35
+
36
+ async save(canvas: Canvas): Promise<void> {
37
+ const key = this.prefix + canvas.id;
38
+ const data = {
39
+ canvas,
40
+ timestamp: Date.now(),
41
+ };
42
+ localStorage.setItem(key, JSON.stringify(data));
43
+ }
44
+
45
+ async load(id: string): Promise<Canvas | null> {
46
+ const key = this.prefix + id;
47
+ const item = localStorage.getItem(key);
48
+ if (!item) return null;
49
+
50
+ try {
51
+ const data = JSON.parse(item);
52
+ if (!this.validateCanvas(data)) {
53
+ console.error('Invalid canvas data structure');
54
+ return null;
55
+ }
56
+ return data.canvas;
57
+ } catch (e) {
58
+ console.error('Failed to parse canvas data:', e);
59
+ return null;
60
+ }
61
+ }
62
+
63
+ async list(): Promise<{ id: string; name: string; timestamp: number }[]> {
64
+ const canvases: { id: string; name: string; timestamp: number }[] = [];
65
+
66
+ for (let i = 0; i < localStorage.length; i++) {
67
+ const key = localStorage.key(i);
68
+ if (key && key.startsWith(this.prefix)) {
69
+ try {
70
+ const item = localStorage.getItem(key);
71
+ if (item) {
72
+ const data = JSON.parse(item);
73
+ if (this.validateCanvas(data)) {
74
+ canvases.push({
75
+ id: data.canvas.id,
76
+ name: data.canvas.name,
77
+ timestamp: data.timestamp,
78
+ });
79
+ }
80
+ }
81
+ } catch (e) {
82
+ console.error('Failed to parse canvas metadata:', e);
83
+ }
84
+ }
85
+ }
86
+
87
+ return canvases.sort((a, b) => b.timestamp - a.timestamp);
88
+ }
89
+
90
+ async delete(id: string): Promise<void> {
91
+ const key = this.prefix + id;
92
+ localStorage.removeItem(key);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * PluresDB adapter for persistent, P2P-enabled storage
98
+ * Uses PluresDB's key-value API for storing canvas data
99
+ */
100
+ export class PluresDBAdapter implements StorageAdapter {
101
+ private db: any = null;
102
+ private readonly prefix = 'runebook:canvas:';
103
+ private readonly metaPrefix = 'runebook:meta:';
104
+ private initialized = false;
105
+ private config: {
106
+ port?: number;
107
+ host?: string;
108
+ dataDir?: string;
109
+ };
110
+
111
+ constructor(config?: { port?: number; host?: string; dataDir?: string }) {
112
+ // Configuration can be provided or will use defaults
113
+ this.config = {
114
+ port: config?.port ?? 34567,
115
+ host: config?.host ?? 'localhost',
116
+ dataDir: config?.dataDir ?? './pluresdb-data',
117
+ };
118
+ }
119
+
120
+ private async ensureInitialized(): Promise<void> {
121
+ if (this.initialized && this.db) {
122
+ return;
123
+ }
124
+
125
+ try {
126
+ // Dynamic import to avoid bundling issues
127
+ const { SQLiteCompatibleAPI } = await import('pluresdb');
128
+
129
+ this.db = new SQLiteCompatibleAPI({
130
+ config: this.config,
131
+ autoStart: true,
132
+ });
133
+
134
+ // Wait for initialization
135
+ await this.db.start();
136
+ this.initialized = true;
137
+ console.log('PluresDB initialized successfully with config:', this.config);
138
+ } catch (error) {
139
+ console.error('Failed to initialize PluresDB:', error);
140
+ throw new Error('PluresDB initialization failed. Make sure PluresDB server is running or use LocalStorageAdapter as fallback.');
141
+ }
142
+ }
143
+
144
+ private validateCanvas(data: any): data is { canvas: Canvas; timestamp: number } {
145
+ return (
146
+ data &&
147
+ typeof data === 'object' &&
148
+ 'canvas' in data &&
149
+ 'timestamp' in data &&
150
+ typeof data.timestamp === 'number' &&
151
+ data.canvas &&
152
+ typeof data.canvas === 'object' &&
153
+ 'id' in data.canvas &&
154
+ 'name' in data.canvas &&
155
+ 'nodes' in data.canvas &&
156
+ Array.isArray(data.canvas.nodes)
157
+ );
158
+ }
159
+
160
+ async save(canvas: Canvas): Promise<void> {
161
+ await this.ensureInitialized();
162
+
163
+ const key = this.prefix + canvas.id;
164
+ const metaKey = this.metaPrefix + canvas.id;
165
+ const timestamp = Date.now();
166
+
167
+ const data = {
168
+ canvas,
169
+ timestamp,
170
+ };
171
+
172
+ // Save the full canvas data
173
+ await this.db.put(key, data);
174
+
175
+ // Save metadata for efficient listing
176
+ await this.db.put(metaKey, {
177
+ id: canvas.id,
178
+ name: canvas.name,
179
+ timestamp,
180
+ });
181
+ }
182
+
183
+ async load(id: string): Promise<Canvas | null> {
184
+ await this.ensureInitialized();
185
+
186
+ const key = this.prefix + id;
187
+
188
+ try {
189
+ const data = await this.db.getValue(key);
190
+
191
+ if (!data) {
192
+ return null;
193
+ }
194
+
195
+ if (!this.validateCanvas(data)) {
196
+ console.error('Invalid canvas data structure in PluresDB');
197
+ return null;
198
+ }
199
+
200
+ return data.canvas;
201
+ } catch (error) {
202
+ console.error('Failed to load canvas from PluresDB:', error);
203
+ return null;
204
+ }
205
+ }
206
+
207
+ async list(): Promise<{ id: string; name: string; timestamp: number }[]> {
208
+ await this.ensureInitialized();
209
+
210
+ try {
211
+ // Get all metadata keys
212
+ const keys = await this.db.list(this.metaPrefix);
213
+ const canvases: { id: string; name: string; timestamp: number }[] = [];
214
+
215
+ // Fetch each metadata entry
216
+ for (const key of keys) {
217
+ try {
218
+ const meta = await this.db.getValue(key);
219
+ if (meta && meta.id && meta.name && typeof meta.timestamp === 'number') {
220
+ canvases.push({
221
+ id: meta.id,
222
+ name: meta.name,
223
+ timestamp: meta.timestamp,
224
+ });
225
+ }
226
+ } catch (error) {
227
+ console.error('Failed to load canvas metadata:', error);
228
+ }
229
+ }
230
+
231
+ // Sort by timestamp, newest first
232
+ return canvases.sort((a, b) => b.timestamp - a.timestamp);
233
+ } catch (error) {
234
+ console.error('Failed to list canvases from PluresDB:', error);
235
+ return [];
236
+ }
237
+ }
238
+
239
+ async delete(id: string): Promise<void> {
240
+ await this.ensureInitialized();
241
+
242
+ const key = this.prefix + id;
243
+ const metaKey = this.metaPrefix + id;
244
+
245
+ try {
246
+ // Delete both the canvas data and metadata
247
+ await this.db.delete(key);
248
+ await this.db.delete(metaKey);
249
+ } catch (error) {
250
+ console.error('Failed to delete canvas from PluresDB:', error);
251
+ throw error;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Stop the PluresDB server (cleanup)
257
+ */
258
+ async stop(): Promise<void> {
259
+ if (this.db && this.initialized) {
260
+ try {
261
+ await this.db.stop();
262
+ this.initialized = false;
263
+ console.log('PluresDB stopped');
264
+ } catch (error) {
265
+ console.error('Failed to stop PluresDB:', error);
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ // Default storage adapter - use LocalStorage for browser compatibility
272
+ // Users can switch to PluresDBAdapter if they have PluresDB server running
273
+ export const storage: StorageAdapter = new LocalStorageAdapter();
274
+
275
+ // Storage adapter management
276
+ let currentAdapter: StorageAdapter = storage;
277
+
278
+ /**
279
+ * Switch to LocalStorage adapter
280
+ */
281
+ export function useLocalStorage(): void {
282
+ currentAdapter = new LocalStorageAdapter();
283
+ }
284
+
285
+ /**
286
+ * Switch to PluresDB adapter
287
+ * @param config Optional PluresDB configuration
288
+ */
289
+ export function usePluresDB(config?: { port?: number; host?: string; dataDir?: string }): void {
290
+ currentAdapter = new PluresDBAdapter(config);
291
+ }
292
+
293
+ /**
294
+ * Get the current storage adapter
295
+ */
296
+ export function getCurrentAdapter(): StorageAdapter {
297
+ return currentAdapter;
298
+ }
299
+
300
+ /**
301
+ * Save canvas to persistent storage
302
+ */
303
+ export async function saveCanvas(canvas: Canvas): Promise<void> {
304
+ await currentAdapter.save(canvas);
305
+ }
306
+
307
+ /**
308
+ * Load canvas from persistent storage
309
+ */
310
+ export async function loadCanvas(id: string): Promise<Canvas | null> {
311
+ return await currentAdapter.load(id);
312
+ }
313
+
314
+ /**
315
+ * List all saved canvases
316
+ */
317
+ export async function listCanvases(): Promise<{ id: string; name: string; timestamp: number }[]> {
318
+ return await currentAdapter.list();
319
+ }
320
+
321
+ /**
322
+ * Delete a saved canvas
323
+ */
324
+ export async function deleteCanvas(id: string): Promise<void> {
325
+ await currentAdapter.delete(id);
326
+ }
@@ -0,0 +1,52 @@
1
+ import yaml from 'js-yaml';
2
+ import type { Canvas } from '../types/canvas';
3
+
4
+ export async function loadCanvasFromYAML(yamlContent: string): Promise<Canvas> {
5
+ try {
6
+ const data = yaml.load(yamlContent) as any;
7
+
8
+ // Validate required fields
9
+ if (!data.id || !data.name || !data.nodes || !data.connections) {
10
+ throw new Error('Invalid canvas YAML: missing required fields');
11
+ }
12
+
13
+ return {
14
+ id: data.id,
15
+ name: data.name,
16
+ description: data.description || '',
17
+ nodes: data.nodes || [],
18
+ connections: data.connections || [],
19
+ version: data.version || '1.0.0'
20
+ };
21
+ } catch (error) {
22
+ console.error('Error parsing canvas YAML:', error);
23
+ throw error;
24
+ }
25
+ }
26
+
27
+ export function saveCanvasToYAML(canvas: Canvas): string {
28
+ try {
29
+ return yaml.dump(canvas, {
30
+ indent: 2,
31
+ lineWidth: 120,
32
+ noRefs: true
33
+ });
34
+ } catch (error) {
35
+ console.error('Error serializing canvas to YAML:', error);
36
+ throw error;
37
+ }
38
+ }
39
+
40
+ export async function loadCanvasFromFile(filePath: string): Promise<Canvas> {
41
+ try {
42
+ const response = await fetch(filePath);
43
+ if (!response.ok) {
44
+ throw new Error(`Failed to load canvas file: ${response.statusText}`);
45
+ }
46
+ const yamlContent = await response.text();
47
+ return loadCanvasFromYAML(yamlContent);
48
+ } catch (error) {
49
+ console.error('Error loading canvas file:', error);
50
+ throw error;
51
+ }
52
+ }
@@ -0,0 +1,5 @@
1
+ <script lang="ts">
2
+ import "@plures/design-dojo/tokens.css";
3
+ </script>
4
+
5
+ <slot />
@@ -0,0 +1,5 @@
1
+ // Tauri doesn't have a Node.js server to do proper SSR
2
+ // so we use adapter-static with a fallback to index.html to put the site in SPA mode
3
+ // See: https://svelte.dev/docs/kit/single-page-apps
4
+ // See: https://v2.tauri.app/start/frontend/sveltekit/ for more info
5
+ export const ssr = false;
@@ -0,0 +1,32 @@
1
+ <script lang="ts">
2
+ import Canvas from '$lib/components/Canvas.svelte';
3
+ import Toolbar from '$lib/components/Toolbar.svelte';
4
+
5
+ const tui = false;
6
+ </script>
7
+
8
+ <div class="app">
9
+ <Toolbar {tui} />
10
+ <div class="canvas-wrapper">
11
+ <Canvas {tui} />
12
+ </div>
13
+ </div>
14
+
15
+ <style>
16
+ :global(body) {
17
+ margin: 0;
18
+ padding: 0;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .app {
23
+ display: flex;
24
+ height: 100vh;
25
+ width: 100vw;
26
+ }
27
+
28
+ .canvas-wrapper {
29
+ flex: 1;
30
+ margin-left: 200px;
31
+ }
32
+ </style>