@colmbus72/yeehaw 0.1.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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/app.d.ts +1 -0
  4. package/dist/app.js +414 -0
  5. package/dist/components/BarnHeader.d.ts +6 -0
  6. package/dist/components/BarnHeader.js +21 -0
  7. package/dist/components/BottomBar.d.ts +16 -0
  8. package/dist/components/BottomBar.js +7 -0
  9. package/dist/components/Header.d.ts +8 -0
  10. package/dist/components/Header.js +83 -0
  11. package/dist/components/HelpOverlay.d.ts +7 -0
  12. package/dist/components/HelpOverlay.js +17 -0
  13. package/dist/components/List.d.ts +17 -0
  14. package/dist/components/List.js +53 -0
  15. package/dist/components/Markdown.d.ts +8 -0
  16. package/dist/components/Markdown.js +23 -0
  17. package/dist/components/Panel.d.ts +10 -0
  18. package/dist/components/Panel.js +5 -0
  19. package/dist/components/PathInput.d.ts +9 -0
  20. package/dist/components/PathInput.js +141 -0
  21. package/dist/components/ScrollableMarkdown.d.ts +11 -0
  22. package/dist/components/ScrollableMarkdown.js +56 -0
  23. package/dist/components/StatusBar.d.ts +5 -0
  24. package/dist/components/StatusBar.js +20 -0
  25. package/dist/components/TextArea.d.ts +17 -0
  26. package/dist/components/TextArea.js +140 -0
  27. package/dist/components/index.d.ts +5 -0
  28. package/dist/components/index.js +5 -0
  29. package/dist/hooks/index.d.ts +3 -0
  30. package/dist/hooks/index.js +3 -0
  31. package/dist/hooks/useConfig.d.ts +11 -0
  32. package/dist/hooks/useConfig.js +36 -0
  33. package/dist/hooks/useRemoteYeehaw.d.ts +13 -0
  34. package/dist/hooks/useRemoteYeehaw.js +49 -0
  35. package/dist/hooks/useSessions.d.ts +11 -0
  36. package/dist/hooks/useSessions.js +46 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +34 -0
  39. package/dist/lib/config.d.ts +27 -0
  40. package/dist/lib/config.js +150 -0
  41. package/dist/lib/detection.d.ts +16 -0
  42. package/dist/lib/detection.js +41 -0
  43. package/dist/lib/editor.d.ts +5 -0
  44. package/dist/lib/editor.js +35 -0
  45. package/dist/lib/errors.d.ts +28 -0
  46. package/dist/lib/errors.js +48 -0
  47. package/dist/lib/git.d.ts +11 -0
  48. package/dist/lib/git.js +73 -0
  49. package/dist/lib/github.d.ts +43 -0
  50. package/dist/lib/github.js +111 -0
  51. package/dist/lib/hotkeys.d.ts +27 -0
  52. package/dist/lib/hotkeys.js +92 -0
  53. package/dist/lib/index.d.ts +10 -0
  54. package/dist/lib/index.js +10 -0
  55. package/dist/lib/livestock.d.ts +51 -0
  56. package/dist/lib/livestock.js +233 -0
  57. package/dist/lib/mcp-validation.d.ts +33 -0
  58. package/dist/lib/mcp-validation.js +62 -0
  59. package/dist/lib/paths.d.ts +8 -0
  60. package/dist/lib/paths.js +28 -0
  61. package/dist/lib/shell.d.ts +34 -0
  62. package/dist/lib/shell.js +61 -0
  63. package/dist/lib/ssh.d.ts +15 -0
  64. package/dist/lib/ssh.js +77 -0
  65. package/dist/lib/tmux-config.d.ts +3 -0
  66. package/dist/lib/tmux-config.js +42 -0
  67. package/dist/lib/tmux.d.ts +32 -0
  68. package/dist/lib/tmux.js +397 -0
  69. package/dist/mcp-server.d.ts +23 -0
  70. package/dist/mcp-server.js +825 -0
  71. package/dist/types.d.ts +89 -0
  72. package/dist/types.js +2 -0
  73. package/dist/views/BarnContext.d.ts +22 -0
  74. package/dist/views/BarnContext.js +252 -0
  75. package/dist/views/GlobalDashboard.d.ts +16 -0
  76. package/dist/views/GlobalDashboard.js +253 -0
  77. package/dist/views/Home.d.ts +11 -0
  78. package/dist/views/Home.js +27 -0
  79. package/dist/views/IssuesView.d.ts +7 -0
  80. package/dist/views/IssuesView.js +157 -0
  81. package/dist/views/LivestockDetailView.d.ts +11 -0
  82. package/dist/views/LivestockDetailView.js +140 -0
  83. package/dist/views/LogsView.d.ts +8 -0
  84. package/dist/views/LogsView.js +84 -0
  85. package/dist/views/NightSkyView.d.ts +5 -0
  86. package/dist/views/NightSkyView.js +441 -0
  87. package/dist/views/ProjectContext.d.ts +18 -0
  88. package/dist/views/ProjectContext.js +333 -0
  89. package/dist/views/Projects.d.ts +8 -0
  90. package/dist/views/Projects.js +20 -0
  91. package/dist/views/WikiView.d.ts +8 -0
  92. package/dist/views/WikiView.js +138 -0
  93. package/dist/views/index.d.ts +2 -0
  94. package/dist/views/index.js +2 -0
  95. package/package.json +65 -0
@@ -0,0 +1,441 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
3
+ import { Box, Text, useInput, useStdout } from 'ink';
4
+ // Easing function for smooth transitions (ease-in-out cubic)
5
+ function easeInOutCubic(t) {
6
+ return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
7
+ }
8
+ // Static star characters (dimmer, always visible)
9
+ const STATIC_STAR_CHARS = ['.', '·', '+'];
10
+ // Test messages for cloud demo
11
+ const TEST_MESSAGES = [
12
+ 'Hello from the desert!',
13
+ 'New commit pushed',
14
+ 'Build succeeded',
15
+ 'PR #42 merged',
16
+ 'Deploy complete',
17
+ 'Tests passing',
18
+ ];
19
+ // Cactus templates - block-style saguaros
20
+ const CACTUS_TEMPLATES = [
21
+ // Tall saguaro with both arms
22
+ [
23
+ ' █ ',
24
+ '█ █ ',
25
+ ' █ █',
26
+ ' █ ',
27
+ ' █ ',
28
+ ],
29
+ // Medium saguaro with left arm
30
+ [
31
+ ' █ ',
32
+ '█ █ ',
33
+ ' █ ',
34
+ ' █ ',
35
+ ],
36
+ // Medium saguaro with right arm
37
+ [
38
+ ' █ ',
39
+ ' █ █',
40
+ ' █ ',
41
+ ' █ ',
42
+ ],
43
+ // Small saguaro
44
+ [
45
+ ' █ ',
46
+ ' █ ',
47
+ ' █ ',
48
+ ],
49
+ // Tiny cactus
50
+ [
51
+ ' █ ',
52
+ ' █ ',
53
+ ],
54
+ ];
55
+ // Green gradient colors for cacti - all vibrant greens (lighter top to darker bottom)
56
+ const CACTUS_COLORS = ['#5fa33a', '#4a9030', '#3d8028', '#307020'];
57
+ // Animation parameters
58
+ const FRAME_INTERVAL = 50; // 20 FPS
59
+ const TARGET_WINKING_STARS = { min: 5, max: 10 };
60
+ const STATIC_STAR_COUNT = { min: 30, max: 50 };
61
+ const SPAWN_CHANCE = 0.05;
62
+ const LANDSCAPE_HEIGHT = 9; // Taller to fit full saguaros
63
+ function randomFloat(min, max) {
64
+ return Math.random() * (max - min) + min;
65
+ }
66
+ function randomInt(min, max) {
67
+ return Math.floor(Math.random() * (max - min + 1)) + min;
68
+ }
69
+ function createWinkingStar(width, height, existingStars) {
70
+ const maxAttempts = 20;
71
+ for (let i = 0; i < maxAttempts; i++) {
72
+ const x = randomInt(0, width - 1);
73
+ const y = randomInt(0, height - 1);
74
+ const occupied = existingStars.some((s) => s.x === x && s.y === y);
75
+ if (!occupied) {
76
+ return {
77
+ type: 'winking',
78
+ x,
79
+ y,
80
+ progress: 0,
81
+ speed: randomFloat(0.025, 0.06),
82
+ holdDuration: randomFloat(0.3, 0.8),
83
+ };
84
+ }
85
+ }
86
+ return null;
87
+ }
88
+ function createStaticStar(width, height, existingStars) {
89
+ const maxAttempts = 30;
90
+ for (let i = 0; i < maxAttempts; i++) {
91
+ const x = randomInt(0, width - 1);
92
+ const y = randomInt(0, height - 1);
93
+ const occupied = existingStars.some((s) => s.x === x && s.y === y);
94
+ if (!occupied) {
95
+ return {
96
+ type: 'static',
97
+ x,
98
+ y,
99
+ char: STATIC_STAR_CHARS[randomInt(0, STATIC_STAR_CHARS.length - 1)],
100
+ baseBrightness: randomFloat(0.2, 0.6),
101
+ pulsePhase: randomFloat(0, Math.PI * 2),
102
+ pulseSpeed: randomFloat(0.04, 0.12),
103
+ pulseAmount: randomFloat(0.05, 0.2),
104
+ };
105
+ }
106
+ }
107
+ return null;
108
+ }
109
+ function createMessageCloud(text, width, skyHeight) {
110
+ const startX = randomInt(5, Math.max(6, width - text.length - 10));
111
+ const startY = randomInt(2, Math.max(3, Math.floor(skyHeight / 2)));
112
+ return {
113
+ text,
114
+ x: startX,
115
+ y: startY,
116
+ targetX: startX + randomInt(-5, 5),
117
+ targetY: startY + randomInt(-2, 2),
118
+ progress: 0,
119
+ speed: 0.012,
120
+ };
121
+ }
122
+ function generateCacti(width) {
123
+ const cacti = [];
124
+ let pos = randomInt(15, 30);
125
+ while (pos < width - 15) {
126
+ // Only use the tall saguaro templates (first 3)
127
+ const templateIndex = randomInt(0, 2);
128
+ const template = CACTUS_TEMPLATES[templateIndex];
129
+ const colorIndex = randomInt(0, CACTUS_COLORS.length - 1);
130
+ // Random vertical offset: some cacti sit higher, some lower
131
+ const yOffset = randomInt(-1, 1);
132
+ cacti.push({ x: pos, yOffset, template, colorIndex });
133
+ pos += randomInt(25, 45);
134
+ }
135
+ return cacti;
136
+ }
137
+ function generateGround(width, height) {
138
+ const rows = [];
139
+ const groundLineY = 5; // Ground line - leaves room for tall cacti above
140
+ for (let y = 0; y < height; y++) {
141
+ const row = [];
142
+ for (let x = 0; x < width; x++) {
143
+ if (y === groundLineY) {
144
+ // Ground line - simple texture
145
+ const r = Math.random();
146
+ row.push(r < 0.6 ? '~' : r < 0.8 ? '-' : r < 0.95 ? '_' : '.');
147
+ }
148
+ else if (y > groundLineY) {
149
+ // Below ground line - sparse sand specs
150
+ const r = Math.random();
151
+ row.push(r < 0.03 ? '.' : r < 0.05 ? ',' : ' ');
152
+ }
153
+ else {
154
+ // Above ground line (cactus area)
155
+ row.push(' ');
156
+ }
157
+ }
158
+ rows.push(row);
159
+ }
160
+ return rows;
161
+ }
162
+ function initializeStars(width, skyHeight) {
163
+ const staticCount = randomInt(STATIC_STAR_COUNT.min, STATIC_STAR_COUNT.max);
164
+ const stars = [];
165
+ for (let i = 0; i < staticCount; i++) {
166
+ const star = createStaticStar(width, skyHeight, stars);
167
+ if (star)
168
+ stars.push(star);
169
+ }
170
+ return stars;
171
+ }
172
+ export function NightSkyView({ onExit }) {
173
+ const { stdout } = useStdout();
174
+ const width = stdout?.columns || 80;
175
+ const height = (stdout?.rows || 24) - 1;
176
+ const skyHeight = height - LANDSCAPE_HEIGHT;
177
+ // Single state object for all animated elements
178
+ const [state, setState] = useState(() => ({
179
+ stars: initializeStars(width, skyHeight),
180
+ clouds: [],
181
+ }));
182
+ const [isPaused, setIsPaused] = useState(false);
183
+ const dimsRef = useRef({ width, skyHeight });
184
+ dimsRef.current = { width, skyHeight };
185
+ // Generate landscape elements once
186
+ const cacti = useMemo(() => generateCacti(width), [width]);
187
+ const groundBase = useMemo(() => generateGround(width, LANDSCAPE_HEIGHT), [width]);
188
+ // Reinitialize stars when dimensions change
189
+ useEffect(() => {
190
+ setState(prev => ({
191
+ ...prev,
192
+ stars: initializeStars(width, skyHeight),
193
+ }));
194
+ }, [width, skyHeight]);
195
+ const randomize = useCallback(() => {
196
+ const { width, skyHeight } = dimsRef.current;
197
+ setState({
198
+ stars: initializeStars(width, skyHeight),
199
+ clouds: [],
200
+ });
201
+ }, []);
202
+ const spawnCloud = useCallback(() => {
203
+ const { width, skyHeight } = dimsRef.current;
204
+ const message = TEST_MESSAGES[randomInt(0, TEST_MESSAGES.length - 1)];
205
+ const cloud = createMessageCloud(message, width, skyHeight);
206
+ setState(prev => ({
207
+ ...prev,
208
+ clouds: [...prev.clouds, cloud],
209
+ }));
210
+ }, []);
211
+ useInput((input, key) => {
212
+ if (key.escape) {
213
+ onExit();
214
+ }
215
+ else if (input === 'r') {
216
+ randomize();
217
+ }
218
+ else if (input === 'c') {
219
+ spawnCloud();
220
+ }
221
+ else if (input === ' ') {
222
+ setIsPaused(p => !p);
223
+ }
224
+ });
225
+ // Single animation loop with batched state update
226
+ useEffect(() => {
227
+ if (isPaused)
228
+ return;
229
+ const interval = setInterval(() => {
230
+ const { width, skyHeight } = dimsRef.current;
231
+ setState(prev => {
232
+ // Update stars
233
+ const updatedStars = [];
234
+ for (const star of prev.stars) {
235
+ if (star.type === 'static') {
236
+ updatedStars.push({
237
+ ...star,
238
+ pulsePhase: star.pulsePhase + star.pulseSpeed,
239
+ });
240
+ }
241
+ else {
242
+ const newProgress = star.progress + star.speed;
243
+ if (newProgress < 2 + star.holdDuration) {
244
+ updatedStars.push({ ...star, progress: newProgress });
245
+ }
246
+ }
247
+ }
248
+ // Spawn new winking stars
249
+ const winkingCount = updatedStars.filter(s => s.type === 'winking').length;
250
+ if (winkingCount < TARGET_WINKING_STARS.min && Math.random() < SPAWN_CHANCE) {
251
+ const newStar = createWinkingStar(width, skyHeight, updatedStars);
252
+ if (newStar)
253
+ updatedStars.push(newStar);
254
+ }
255
+ // Update clouds
256
+ const updatedClouds = prev.clouds
257
+ .map(cloud => {
258
+ const newProgress = cloud.progress + cloud.speed;
259
+ let newX = cloud.x;
260
+ let newY = cloud.y;
261
+ if (newProgress > 0.5 && newProgress < 2.5) {
262
+ newX += (cloud.targetX - cloud.x) * 0.02;
263
+ newY += (cloud.targetY - cloud.y) * 0.02;
264
+ }
265
+ return { ...cloud, x: newX, y: newY, progress: newProgress };
266
+ })
267
+ .filter(cloud => cloud.progress < 3);
268
+ return {
269
+ stars: updatedStars,
270
+ clouds: updatedClouds,
271
+ };
272
+ });
273
+ }, FRAME_INTERVAL);
274
+ return () => clearInterval(interval);
275
+ }, [isPaused]);
276
+ // Rendering helpers
277
+ const getWinkingStarDisplay = (star) => {
278
+ const { progress, holdDuration } = star;
279
+ let brightness;
280
+ if (progress < 1) {
281
+ brightness = easeInOutCubic(progress);
282
+ }
283
+ else if (progress < 1 + holdDuration) {
284
+ brightness = 1;
285
+ }
286
+ else {
287
+ brightness = 1 - easeInOutCubic(progress - 1 - holdDuration);
288
+ }
289
+ const chars = [' ', '.', '·', '+', '*'];
290
+ return { char: chars[Math.round(brightness * 4)], dim: brightness < 0.5 };
291
+ };
292
+ const getStaticStarDisplay = (star) => {
293
+ const brightness = star.baseBrightness + Math.sin(star.pulsePhase) * star.pulseAmount;
294
+ return { char: star.char, dim: brightness < 0.4 };
295
+ };
296
+ // Cloud display - simple opacity-based fading
297
+ const getCloudOpacity = (cloud) => {
298
+ const { progress } = cloud;
299
+ if (progress < 0.3) {
300
+ // Fading in - dim
301
+ return { dim: true, visible: true };
302
+ }
303
+ else if (progress < 2.7) {
304
+ // Fully visible
305
+ return { dim: false, visible: true };
306
+ }
307
+ else {
308
+ // Fading out - dim
309
+ return { dim: true, visible: true };
310
+ }
311
+ };
312
+ // Render sky
313
+ const skyRows = [];
314
+ for (let y = 0; y < skyHeight; y++) {
315
+ let rowChars = ' '.repeat(width).split('');
316
+ let rowDims = new Array(width).fill(false);
317
+ let rowColors = new Array(width).fill(undefined);
318
+ // Place stars
319
+ for (const star of state.stars) {
320
+ if (star.y === y && star.x >= 0 && star.x < width) {
321
+ const display = star.type === 'winking' ? getWinkingStarDisplay(star) : getStaticStarDisplay(star);
322
+ if (display.char !== ' ') {
323
+ rowChars[star.x] = display.char;
324
+ rowDims[star.x] = display.dim;
325
+ }
326
+ }
327
+ }
328
+ // Place clouds
329
+ for (const cloud of state.clouds) {
330
+ const display = getCloudOpacity(cloud);
331
+ if (!display.visible)
332
+ continue;
333
+ const cloudY = Math.round(cloud.y);
334
+ const cloudX = Math.round(cloud.x);
335
+ // Simple box cloud
336
+ const textLen = cloud.text.length + 2;
337
+ const lines = [
338
+ '╭' + '─'.repeat(textLen) + '╮',
339
+ '│ ' + cloud.text + ' │',
340
+ '╰' + '─'.repeat(textLen) + '╯',
341
+ ];
342
+ const lineIdx = y - cloudY;
343
+ if (lineIdx >= 0 && lineIdx < 3) {
344
+ const line = lines[lineIdx];
345
+ for (let lx = 0; lx < line.length; lx++) {
346
+ const cellX = cloudX + lx;
347
+ if (cellX >= 0 && cellX < width) {
348
+ rowChars[cellX] = line[lx];
349
+ rowDims[cellX] = display.dim;
350
+ rowColors[cellX] = '#87CEEB';
351
+ }
352
+ }
353
+ }
354
+ }
355
+ // Build segments for efficient rendering
356
+ const segments = [];
357
+ let seg = { text: rowChars[0], dim: rowDims[0], color: rowColors[0] };
358
+ for (let x = 1; x < width; x++) {
359
+ if (rowDims[x] === seg.dim && rowColors[x] === seg.color) {
360
+ seg.text += rowChars[x];
361
+ }
362
+ else {
363
+ segments.push(seg);
364
+ seg = { text: rowChars[x], dim: rowDims[x], color: rowColors[x] };
365
+ }
366
+ }
367
+ segments.push(seg);
368
+ skyRows.push(_jsx(Text, { children: segments.map((s, i) => (_jsx(Text, { color: s.color || 'white', dimColor: s.dim, children: s.text }, i))) }, y));
369
+ }
370
+ // Render landscape with cacti and ground
371
+ const renderLandscape = () => {
372
+ const GROUND_LINE_Y = 5; // Ground line position in landscape
373
+ // Create ground grid
374
+ const ground = groundBase.map(row => [...row]);
375
+ // Place cacti - they sit on the ground line with vertical variation
376
+ for (const cactus of cacti) {
377
+ const cactusHeight = cactus.template.length;
378
+ // Cactus bottom aligns with ground line, plus offset for depth variation
379
+ const cactusStartY = GROUND_LINE_Y - cactusHeight + 1 + cactus.yOffset;
380
+ for (let cy = 0; cy < cactusHeight; cy++) {
381
+ const groundY = cactusStartY + cy;
382
+ if (groundY >= 0 && groundY < LANDSCAPE_HEIGHT) {
383
+ const line = cactus.template[cy];
384
+ for (let cx = 0; cx < line.length; cx++) {
385
+ const groundX = cactus.x + cx;
386
+ if (groundX >= 0 && groundX < width && line[cx] !== ' ') {
387
+ ground[groundY][groundX] = line[cx];
388
+ }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ // Render ground rows with coloring
394
+ const rows = [];
395
+ for (let y = 0; y < LANDSCAPE_HEIGHT; y++) {
396
+ const segments = [];
397
+ let currentColor = '#C2B280';
398
+ let currentDim = false;
399
+ let currentText = '';
400
+ for (let x = 0; x < width; x++) {
401
+ const char = ground[y][x];
402
+ let charColor = '#C2B280'; // Sand/dirt color
403
+ let charDim = y > GROUND_LINE_Y; // Dim the sand specs below ground
404
+ // Check if this char is part of a cactus (█ character)
405
+ if (char === '█') {
406
+ // Find which cactus this belongs to for gradient
407
+ for (const cactus of cacti) {
408
+ const cactusHeight = cactus.template.length;
409
+ const cactusStartY = GROUND_LINE_Y - cactusHeight + 1 + cactus.yOffset;
410
+ const relY = y - cactusStartY;
411
+ const relX = x - cactus.x;
412
+ if (relY >= 0 && relY < cactusHeight && relX >= 0 && relX < cactus.template[relY].length) {
413
+ if (cactus.template[relY][relX] === '█') {
414
+ // Gradient: lighter at top, darker at bottom
415
+ const gradientIndex = Math.min(CACTUS_COLORS.length - 1, Math.floor(relY / cactusHeight * CACTUS_COLORS.length));
416
+ charColor = CACTUS_COLORS[gradientIndex];
417
+ charDim = false;
418
+ break;
419
+ }
420
+ }
421
+ }
422
+ }
423
+ if (charColor === currentColor && charDim === currentDim) {
424
+ currentText += char;
425
+ }
426
+ else {
427
+ if (currentText)
428
+ segments.push({ text: currentText, color: currentColor, dim: currentDim });
429
+ currentText = char;
430
+ currentColor = charColor;
431
+ currentDim = charDim;
432
+ }
433
+ }
434
+ if (currentText)
435
+ segments.push({ text: currentText, color: currentColor, dim: currentDim });
436
+ rows.push(_jsx(Text, { children: segments.map((s, i) => (_jsx(Text, { color: s.color, dimColor: s.dim, children: s.text }, i))) }, `land-${y}`));
437
+ }
438
+ return rows;
439
+ };
440
+ return (_jsxs(Box, { flexDirection: "column", height: height, children: [_jsx(Box, { flexDirection: "column", children: skyRows }), _jsx(Box, { flexDirection: "column", children: renderLandscape() })] }));
441
+ }
@@ -0,0 +1,18 @@
1
+ import type { Project, Barn, Livestock } from '../types.js';
2
+ import { type TmuxWindow } from '../lib/tmux.js';
3
+ interface ProjectContextProps {
4
+ project: Project;
5
+ barns: Barn[];
6
+ windows: TmuxWindow[];
7
+ onBack: () => void;
8
+ onNewClaude: () => void;
9
+ onSelectWindow: (window: TmuxWindow) => void;
10
+ onSelectLivestock: (livestock: Livestock, barn: Barn | null) => void;
11
+ onOpenLivestockSession: (livestock: Livestock, barn: Barn | null) => void;
12
+ onUpdateProject: (project: Project) => void;
13
+ onDeleteProject: (projectName: string) => void;
14
+ onOpenWiki: () => void;
15
+ onOpenIssues: () => void;
16
+ }
17
+ export declare function ProjectContext({ project, barns, windows, onBack, onNewClaude, onSelectWindow, onSelectLivestock, onOpenLivestockSession, onUpdateProject, onDeleteProject, onOpenWiki, onOpenIssues, }: ProjectContextProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};