byterover-cli 1.0.2 → 1.0.4
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/README.md +62 -10
- package/dist/commands/curate.js +2 -2
- package/dist/commands/main.js +2 -2
- package/dist/commands/query.js +2 -2
- package/dist/commands/status.js +2 -2
- package/dist/config/context-tree-domains.d.ts +14 -2
- package/dist/config/context-tree-domains.js +22 -27
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +3 -0
- package/dist/core/domain/cipher/file-system/types.d.ts +2 -0
- package/dist/core/domain/entities/auth-token.js +6 -3
- package/dist/core/domain/entities/event.d.ts +1 -1
- package/dist/core/domain/entities/event.js +2 -1
- package/dist/core/domain/knowledge/relation-parser.d.ts +16 -1
- package/dist/core/domain/knowledge/relation-parser.js +19 -2
- package/dist/core/domain/transport/schemas.d.ts +17 -1
- package/dist/core/domain/transport/schemas.js +9 -1
- package/dist/core/interfaces/cipher/i-blob-storage.d.ts +6 -0
- package/dist/core/interfaces/cipher/index.d.ts +0 -1
- package/dist/core/interfaces/executor/i-curate-executor.d.ts +2 -0
- package/dist/infra/cipher/agent/cipher-agent.js +4 -0
- package/dist/infra/cipher/file-system/file-system-service.d.ts +4 -0
- package/dist/infra/cipher/file-system/file-system-service.js +5 -0
- package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +4 -2
- package/dist/infra/cipher/tools/implementations/create-knowledge-topic-tool.js +24 -17
- package/dist/infra/cipher/tools/implementations/curate-tool.js +28 -33
- package/dist/infra/cipher/tools/implementations/read-file-tool.js +3 -12
- package/dist/infra/cipher/tools/implementations/spec-analyze-tool.js +18 -15
- package/dist/infra/cipher/tools/implementations/task-tool.js +53 -7
- package/dist/infra/context-tree/file-context-tree-service.js +4 -15
- package/dist/infra/core/executors/curate-executor.d.ts +2 -7
- package/dist/infra/core/executors/curate-executor.js +18 -53
- package/dist/infra/core/executors/query-executor.d.ts +1 -7
- package/dist/infra/core/executors/query-executor.js +10 -35
- package/dist/infra/core/task-processor.d.ts +2 -0
- package/dist/infra/core/task-processor.js +1 -0
- package/dist/infra/http/authenticated-http-client.js +5 -0
- package/dist/infra/process/agent-worker.js +113 -6
- package/dist/infra/process/constants.d.ts +1 -0
- package/dist/infra/process/constants.js +1 -0
- package/dist/infra/process/task-queue-manager.js +2 -1
- package/dist/infra/process/transport-handlers.js +4 -0
- package/dist/infra/process/transport-worker.js +89 -1
- package/dist/infra/repl/commands/curate-command.js +2 -2
- package/dist/infra/repl/commands/gen-rules-command.js +2 -2
- package/dist/infra/repl/commands/init-command.js +2 -2
- package/dist/infra/repl/commands/login-command.js +2 -2
- package/dist/infra/repl/commands/logout-command.js +2 -2
- package/dist/infra/repl/commands/pull-command.js +2 -2
- package/dist/infra/repl/commands/push-command.js +2 -2
- package/dist/infra/repl/commands/query-command.js +2 -2
- package/dist/infra/repl/commands/space/list-command.js +2 -2
- package/dist/infra/repl/commands/space/switch-command.js +2 -2
- package/dist/infra/repl/commands/status-command.js +2 -2
- package/dist/infra/repl/repl-startup.js +0 -2
- package/dist/infra/storage/file-token-store.d.ts +31 -0
- package/dist/infra/storage/file-token-store.js +98 -0
- package/dist/infra/storage/keychain-token-store.d.ts +4 -1
- package/dist/infra/storage/keychain-token-store.js +6 -4
- package/dist/infra/storage/token-store.d.ts +10 -0
- package/dist/infra/storage/token-store.js +14 -0
- package/dist/infra/usecase/curate-use-case.js +1 -1
- package/dist/infra/usecase/init-use-case.js +2 -4
- package/dist/infra/user/http-user-service.js +6 -11
- package/dist/resources/prompts/curate.yml +14 -5
- package/dist/resources/prompts/plan.yml +6 -0
- package/dist/tui/app.js +1 -1
- package/dist/tui/components/execution/log-item.js +2 -5
- package/dist/tui/components/header.d.ts +1 -1
- package/dist/tui/components/header.js +25 -4
- package/dist/tui/components/index.d.ts +5 -1
- package/dist/tui/components/index.js +3 -1
- package/dist/tui/components/init.d.ts +33 -0
- package/dist/tui/components/init.js +253 -0
- package/dist/tui/components/onboarding/index.d.ts +1 -0
- package/dist/tui/components/onboarding/index.js +1 -0
- package/dist/tui/components/onboarding/onboarding-flow.d.ts +2 -0
- package/dist/tui/components/onboarding/onboarding-flow.js +8 -229
- package/dist/tui/components/onboarding/onboarding-step.js +1 -1
- package/dist/tui/components/onboarding/welcome-box.d.ts +14 -0
- package/dist/tui/components/onboarding/welcome-box.js +23 -0
- package/dist/tui/components/status-badge.d.ts +22 -0
- package/dist/tui/components/status-badge.js +32 -0
- package/dist/tui/contexts/auth-context.js +2 -1
- package/dist/tui/contexts/index.d.ts +1 -0
- package/dist/tui/contexts/index.js +1 -0
- package/dist/tui/contexts/onboarding-context.d.ts +14 -0
- package/dist/tui/contexts/onboarding-context.js +17 -22
- package/dist/tui/contexts/status-context.d.ts +33 -0
- package/dist/tui/contexts/status-context.js +159 -0
- package/dist/tui/hooks/use-auth-polling.d.ts +4 -1
- package/dist/tui/hooks/use-auth-polling.js +21 -7
- package/dist/tui/hooks/use-tab-navigation.js +0 -2
- package/dist/tui/providers/app-providers.js +2 -2
- package/dist/tui/types/index.d.ts +2 -0
- package/dist/tui/types/index.js +2 -0
- package/dist/tui/types/status.d.ts +46 -0
- package/dist/tui/types/status.js +13 -0
- package/dist/tui/utils/index.d.ts +6 -0
- package/dist/tui/utils/index.js +6 -0
- package/dist/tui/utils/time.d.ts +10 -0
- package/dist/tui/utils/time.js +15 -0
- package/dist/tui/views/command-view.js +0 -2
- package/dist/tui/views/index.d.ts +1 -0
- package/dist/tui/views/index.js +1 -0
- package/dist/tui/views/init-view.d.ts +15 -0
- package/dist/tui/views/init-view.js +29 -0
- package/dist/tui/views/logs-view.js +22 -8
- package/dist/utils/environment-detector.d.ts +5 -0
- package/dist/utils/environment-detector.js +31 -0
- package/dist/utils/global-data-path.d.ts +11 -0
- package/dist/utils/global-data-path.js +32 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/dist/core/interfaces/cipher/i-agent-storage.d.ts +0 -152
- package/dist/core/interfaces/cipher/i-agent-storage.js +0 -1
- package/dist/infra/cipher/consumer/consumer-lock.d.ts +0 -20
- package/dist/infra/cipher/consumer/consumer-lock.js +0 -41
- package/dist/infra/cipher/consumer/consumer-service.d.ts +0 -99
- package/dist/infra/cipher/consumer/consumer-service.js +0 -166
- package/dist/infra/cipher/consumer/execution-consumer.d.ts +0 -126
- package/dist/infra/cipher/consumer/execution-consumer.js +0 -561
- package/dist/infra/cipher/consumer/index.d.ts +0 -33
- package/dist/infra/cipher/consumer/index.js +0 -34
- package/dist/infra/cipher/consumer/queue-polling-service.d.ts +0 -120
- package/dist/infra/cipher/consumer/queue-polling-service.js +0 -249
- package/dist/infra/cipher/storage/agent-storage.d.ts +0 -246
- package/dist/infra/cipher/storage/agent-storage.js +0 -956
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Logs View
|
|
4
4
|
*
|
|
5
5
|
* Activity log display using ScrollableList with dynamic height calculation
|
|
6
6
|
*/
|
|
7
|
-
import { Box
|
|
8
|
-
import { useCallback } from 'react';
|
|
9
|
-
import { LogItem, OnboardingFlow, ScrollableList } from '../components/index.js';
|
|
7
|
+
import { Box } from 'ink';
|
|
8
|
+
import { useCallback, useState } from 'react';
|
|
9
|
+
import { LogItem, OnboardingFlow, ScrollableList, WelcomeBox } from '../components/index.js';
|
|
10
|
+
import { useAuth } from '../contexts/index.js';
|
|
10
11
|
import { useActivityLogs, useMode, useTheme, useUIHeights } from '../hooks/index.js';
|
|
11
12
|
import { useOnboarding } from '../hooks/use-onboarding.js';
|
|
12
13
|
import { calculateActualLogHeight, calculateLogContentLimit } from '../utils/log.js';
|
|
14
|
+
import { InitView } from './init-view.js';
|
|
13
15
|
export const LogsView = ({ availableHeight }) => {
|
|
14
16
|
const { theme: { colors }, } = useTheme();
|
|
15
17
|
const { mode } = useMode();
|
|
16
18
|
const { logs } = useActivityLogs();
|
|
17
|
-
const { shouldShowOnboarding } = useOnboarding();
|
|
19
|
+
const { isLoadingDismissed, shouldShowOnboarding } = useOnboarding();
|
|
18
20
|
const { messageItem } = useUIHeights();
|
|
21
|
+
const { brvConfig } = useAuth();
|
|
22
|
+
// Track if user has completed init flow
|
|
23
|
+
const [initFlowCompleted, setInitFlowCompleted] = useState(Boolean(brvConfig));
|
|
19
24
|
// Calculate scrollable height for dynamic per-log calculations
|
|
20
25
|
const scrollableHeight = Math.max(1, availableHeight);
|
|
26
|
+
const handleInitEnd = () => {
|
|
27
|
+
setInitFlowCompleted(true);
|
|
28
|
+
};
|
|
21
29
|
const renderLogItem = useCallback((log) => {
|
|
22
30
|
// Calculate dynamic content limit for this specific log
|
|
23
31
|
const parts = calculateLogContentLimit(log, scrollableHeight, messageItem);
|
|
@@ -40,9 +48,15 @@ export const LogsView = ({ availableHeight }) => {
|
|
|
40
48
|
maxContentLines: maxContentLine,
|
|
41
49
|
});
|
|
42
50
|
}, [messageItem, scrollableHeight]);
|
|
43
|
-
|
|
51
|
+
if (isLoadingDismissed) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
44
54
|
if (shouldShowOnboarding) {
|
|
45
|
-
return _jsx(OnboardingFlow, { availableHeight: availableHeight });
|
|
55
|
+
return _jsx(OnboardingFlow, { availableHeight: availableHeight, onInitComplete: handleInitEnd });
|
|
56
|
+
}
|
|
57
|
+
// Show init view if config doesn't exist and user hasn't completed init flow
|
|
58
|
+
if (!initFlowCompleted) {
|
|
59
|
+
return _jsx(InitView, { availableHeight: availableHeight, onInitComplete: handleInitEnd });
|
|
46
60
|
}
|
|
47
|
-
return (_jsx(Box, { borderColor: colors.border, borderLeft: false, borderRight: false, borderStyle: "single", borderTop: false, flexDirection: "column", height: "100%", width: "100%", children: logs.length > 0 ? (_jsx(Box, { flexDirection: "column", height: "100%", paddingX: 2, children: _jsx(ScrollableList, { autoScrollToBottom: true, availableHeight: scrollableHeight, estimateItemHeight: heightEstimator, isActive: mode === 'activity', items: logs, keyExtractor: keyExtractor, renderItem: renderLogItem }) })) : (
|
|
61
|
+
return (_jsx(Box, { borderColor: colors.border, borderLeft: false, borderRight: false, borderStyle: "single", borderTop: false, flexDirection: "column", height: "100%", width: "100%", children: logs.length > 0 ? (_jsx(Box, { flexDirection: "column", height: "100%", paddingX: 2, children: _jsx(ScrollableList, { autoScrollToBottom: true, availableHeight: scrollableHeight, estimateItemHeight: heightEstimator, isActive: mode === 'activity', items: logs, keyExtractor: keyExtractor, renderItem: renderLogItem }) })) : (_jsx(WelcomeBox, { isCopyActive: mode === 'activity' && logs.length === 0 })) }));
|
|
48
62
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
let wslCached;
|
|
3
|
+
/**
|
|
4
|
+
* Detect if running in WSL (Windows Subsystem for Linux) environment.
|
|
5
|
+
* Checks WSL-specific environment variables first, then falls back to /proc/version.
|
|
6
|
+
*/
|
|
7
|
+
function detectWsl() {
|
|
8
|
+
if (process.platform !== 'linux') {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (process.env.WSL_DISTRO_NAME !== undefined || process.env.WSLENV !== undefined) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const version = readFileSync('/proc/version', 'utf8');
|
|
16
|
+
return /microsoft|wsl/i.test(version);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if running in WSL environment (cached).
|
|
24
|
+
* Detects both WSL1 and WSL2. Result is cached after first call for performance.
|
|
25
|
+
*/
|
|
26
|
+
export function isWsl() {
|
|
27
|
+
if (wslCached === undefined) {
|
|
28
|
+
wslCached = detectWsl();
|
|
29
|
+
}
|
|
30
|
+
return wslCached;
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the global data directory path following XDG spec:
|
|
3
|
+
* - Linux: $XDG_DATA_HOME/brv (defaults to ~/.local/share/brv)
|
|
4
|
+
* - macOS: ~/.local/share/brv
|
|
5
|
+
* - Windows: %LOCALAPPDATA%/brv
|
|
6
|
+
*
|
|
7
|
+
* Use this for user data and secrets (not config files).
|
|
8
|
+
*
|
|
9
|
+
* @returns Absolute path to the global data directory
|
|
10
|
+
*/
|
|
11
|
+
export declare const getGlobalDataDir: () => string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { homedir, platform } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { GLOBAL_DATA_DIR } from '../constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the global data directory path following XDG spec:
|
|
6
|
+
* - Linux: $XDG_DATA_HOME/brv (defaults to ~/.local/share/brv)
|
|
7
|
+
* - macOS: ~/.local/share/brv
|
|
8
|
+
* - Windows: %LOCALAPPDATA%/brv
|
|
9
|
+
*
|
|
10
|
+
* Use this for user data and secrets (not config files).
|
|
11
|
+
*
|
|
12
|
+
* @returns Absolute path to the global data directory
|
|
13
|
+
*/
|
|
14
|
+
export const getGlobalDataDir = () => {
|
|
15
|
+
const currentPlatform = platform();
|
|
16
|
+
if (currentPlatform === 'win32') {
|
|
17
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
18
|
+
if (localAppData !== undefined) {
|
|
19
|
+
return join(localAppData, GLOBAL_DATA_DIR);
|
|
20
|
+
}
|
|
21
|
+
return join(homedir(), 'AppData', 'Local', GLOBAL_DATA_DIR);
|
|
22
|
+
}
|
|
23
|
+
// Linux: respect XDG_DATA_HOME if set
|
|
24
|
+
if (currentPlatform === 'linux') {
|
|
25
|
+
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
26
|
+
if (xdgDataHome !== undefined) {
|
|
27
|
+
return join(xdgDataHome, GLOBAL_DATA_DIR);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Linux (default) and macOS: use ~/.local/share/brv
|
|
31
|
+
return join(homedir(), '.local', 'share', GLOBAL_DATA_DIR);
|
|
32
|
+
};
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import type { Execution, ExecutionStatus, ExecutionType, ToolCall, ToolCallInfo, ToolCallStatus, ToolCallUpdateOptions } from '../../domain/cipher/queue/types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Interface for agent execution storage.
|
|
4
|
-
*
|
|
5
|
-
* Manages the execution queue, tool call tracking, and consumer locks.
|
|
6
|
-
* Implementations can use different storage backends (SQLite, in-memory, etc.)
|
|
7
|
-
*/
|
|
8
|
-
export interface IAgentStorage {
|
|
9
|
-
/**
|
|
10
|
-
* Acquire consumer lock (register this consumer).
|
|
11
|
-
* Only ONE consumer can run at a time.
|
|
12
|
-
* @param consumerId - Unique ID for this consumer
|
|
13
|
-
* @returns true if lock acquired, false if another consumer is already running
|
|
14
|
-
*/
|
|
15
|
-
acquireConsumerLock(consumerId: string): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Add a tool call record.
|
|
18
|
-
* @returns tool call id
|
|
19
|
-
*/
|
|
20
|
-
addToolCall(executionId: string, info: ToolCallInfo): string;
|
|
21
|
-
/**
|
|
22
|
-
* Cleanup old executions, keep only maxKeep most recent completed/failed.
|
|
23
|
-
* @returns number of deleted executions
|
|
24
|
-
*/
|
|
25
|
-
cleanupOldExecutions(maxKeep?: number): number;
|
|
26
|
-
/**
|
|
27
|
-
* Cleanup orphaned executions (status='running') from previous session crash.
|
|
28
|
-
* @returns number of orphaned executions
|
|
29
|
-
*/
|
|
30
|
-
cleanupOrphanedExecutions(): number;
|
|
31
|
-
/**
|
|
32
|
-
* Cleanup stale consumers and orphan their executions.
|
|
33
|
-
* @param timeoutMs - heartbeat timeout (default 30 seconds)
|
|
34
|
-
* @returns number of orphaned executions
|
|
35
|
-
*/
|
|
36
|
-
cleanupStaleConsumers(timeoutMs?: number): number;
|
|
37
|
-
/**
|
|
38
|
-
* Close storage connection.
|
|
39
|
-
*/
|
|
40
|
-
close(): void;
|
|
41
|
-
/**
|
|
42
|
-
* Create a new execution.
|
|
43
|
-
* @param type - 'curate' or 'query'
|
|
44
|
-
* @param input - content (curate) or query string (query)
|
|
45
|
-
* @returns execution id
|
|
46
|
-
*/
|
|
47
|
-
createExecution(type: ExecutionType, input: string): string;
|
|
48
|
-
/**
|
|
49
|
-
* Dequeue multiple executions at once (atomic batch SELECT + UPDATE).
|
|
50
|
-
* @param limit - max number of executions to dequeue
|
|
51
|
-
* @param consumerId - ID of the consumer claiming these executions
|
|
52
|
-
* @returns array of executions (may be empty if queue is empty)
|
|
53
|
-
*/
|
|
54
|
-
dequeueBatch(limit: number, consumerId?: string): Execution[];
|
|
55
|
-
/**
|
|
56
|
-
* Dequeue next queued execution (atomic SELECT + UPDATE).
|
|
57
|
-
* @param consumerId - ID of the consumer claiming this execution
|
|
58
|
-
* @returns execution or null if queue is empty
|
|
59
|
-
*/
|
|
60
|
-
dequeueExecution(consumerId?: string): Execution | null;
|
|
61
|
-
/**
|
|
62
|
-
* Get execution by id.
|
|
63
|
-
*/
|
|
64
|
-
getExecution(id: string): Execution | null;
|
|
65
|
-
/**
|
|
66
|
-
* Get executions updated since timestamp (for incremental polling).
|
|
67
|
-
*/
|
|
68
|
-
getExecutionsSince(timestamp: number): Execution[];
|
|
69
|
-
/**
|
|
70
|
-
* Get execution with all its tool calls (for UI display).
|
|
71
|
-
*/
|
|
72
|
-
getExecutionWithToolCalls(id: string): null | {
|
|
73
|
-
execution: Execution;
|
|
74
|
-
toolCalls: ToolCall[];
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Get all queued executions.
|
|
78
|
-
*/
|
|
79
|
-
getQueuedExecutions(): Execution[];
|
|
80
|
-
/**
|
|
81
|
-
* Get recent executions (for UI display).
|
|
82
|
-
*/
|
|
83
|
-
getRecentExecutions(limit?: number): Execution[];
|
|
84
|
-
/**
|
|
85
|
-
* Get all running executions.
|
|
86
|
-
*/
|
|
87
|
-
getRunningExecutions(): Execution[];
|
|
88
|
-
/**
|
|
89
|
-
* Get all executions belonging to a specific consumer session.
|
|
90
|
-
* Returns executions ordered by created_at ASC (oldest first, newest last).
|
|
91
|
-
* @param consumerId - The consumer ID to filter by
|
|
92
|
-
*/
|
|
93
|
-
getSessionExecutions(consumerId: string): Execution[];
|
|
94
|
-
/**
|
|
95
|
-
* Get queue statistics (queries DB directly for accurate counts).
|
|
96
|
-
*/
|
|
97
|
-
getStats(): {
|
|
98
|
-
completed: number;
|
|
99
|
-
failed: number;
|
|
100
|
-
queued: number;
|
|
101
|
-
running: number;
|
|
102
|
-
total: number;
|
|
103
|
-
};
|
|
104
|
-
/**
|
|
105
|
-
* Get all tool calls for an execution.
|
|
106
|
-
*/
|
|
107
|
-
getToolCalls(executionId: string): ToolCall[];
|
|
108
|
-
/**
|
|
109
|
-
* Check if any consumer is currently active (has recent heartbeat).
|
|
110
|
-
* @param timeoutMs - heartbeat timeout (default 30 seconds)
|
|
111
|
-
*/
|
|
112
|
-
hasActiveConsumer(timeoutMs?: number): boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Check if a specific consumer lock exists in the database.
|
|
115
|
-
* Used by Consumer to verify its lock is still valid after DB reconnection.
|
|
116
|
-
*/
|
|
117
|
-
hasConsumerLock(consumerId: string): boolean;
|
|
118
|
-
/**
|
|
119
|
-
* Initialize storage.
|
|
120
|
-
*/
|
|
121
|
-
initialize(options?: {
|
|
122
|
-
cleanupOrphans?: boolean;
|
|
123
|
-
}): Promise<void>;
|
|
124
|
-
/** Whether the storage has been initialized */
|
|
125
|
-
readonly initialized: boolean;
|
|
126
|
-
/**
|
|
127
|
-
* Check if the DB file has been replaced (different inode).
|
|
128
|
-
* Returns true if DB needs reconnection.
|
|
129
|
-
*/
|
|
130
|
-
isDbFileChanged(): boolean;
|
|
131
|
-
/**
|
|
132
|
-
* Reconnect to the database (close and reinitialize).
|
|
133
|
-
* Use when DB file has been replaced by another process (e.g., brv init).
|
|
134
|
-
*/
|
|
135
|
-
reconnect(): Promise<void>;
|
|
136
|
-
/**
|
|
137
|
-
* Release consumer lock (unregister this consumer).
|
|
138
|
-
*/
|
|
139
|
-
releaseConsumerLock(consumerId: string): void;
|
|
140
|
-
/**
|
|
141
|
-
* Update consumer heartbeat.
|
|
142
|
-
*/
|
|
143
|
-
updateConsumerHeartbeat(consumerId: string): void;
|
|
144
|
-
/**
|
|
145
|
-
* Update execution status.
|
|
146
|
-
*/
|
|
147
|
-
updateExecutionStatus(id: string, status: ExecutionStatus, result?: string, error?: string): void;
|
|
148
|
-
/**
|
|
149
|
-
* Update tool call status and result.
|
|
150
|
-
*/
|
|
151
|
-
updateToolCall(id: string, status: ToolCallStatus, options?: ToolCallUpdateOptions): void;
|
|
152
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DB-based consumer lock utilities
|
|
3
|
-
*
|
|
4
|
-
* The actual locking is now handled by AgentStorage methods:
|
|
5
|
-
* - acquireConsumerLock(consumerId)
|
|
6
|
-
* - releaseConsumerLock(consumerId)
|
|
7
|
-
* - hasActiveConsumer(timeoutMs)
|
|
8
|
-
*
|
|
9
|
-
* These utility functions provide a simple interface for checking consumer status.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Check if a consumer is currently running (has active heartbeat in DB)
|
|
13
|
-
* Auto-detects .brv/blobs path from cwd
|
|
14
|
-
*/
|
|
15
|
-
export declare function isConsumerRunning(): Promise<boolean>;
|
|
16
|
-
/**
|
|
17
|
-
* Check if a consumer is currently running (sync version)
|
|
18
|
-
* Assumes storage is already initialized
|
|
19
|
-
*/
|
|
20
|
-
export declare function isConsumerRunningSync(): boolean;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// TODO(v0.5.0): Remove this file. Consumer locking is no longer needed (one CoreProcess per TUI).
|
|
2
|
-
import { getAgentStorage, getAgentStorageSync } from '../storage/agent-storage.js';
|
|
3
|
-
// Consumer is considered stale after 30 seconds without heartbeat
|
|
4
|
-
const STALE_TIMEOUT_MS = 30_000;
|
|
5
|
-
/**
|
|
6
|
-
* DB-based consumer lock utilities
|
|
7
|
-
*
|
|
8
|
-
* The actual locking is now handled by AgentStorage methods:
|
|
9
|
-
* - acquireConsumerLock(consumerId)
|
|
10
|
-
* - releaseConsumerLock(consumerId)
|
|
11
|
-
* - hasActiveConsumer(timeoutMs)
|
|
12
|
-
*
|
|
13
|
-
* These utility functions provide a simple interface for checking consumer status.
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Check if a consumer is currently running (has active heartbeat in DB)
|
|
17
|
-
* Auto-detects .brv/blobs path from cwd
|
|
18
|
-
*/
|
|
19
|
-
export async function isConsumerRunning() {
|
|
20
|
-
try {
|
|
21
|
-
const storage = await getAgentStorage();
|
|
22
|
-
return storage.hasActiveConsumer(STALE_TIMEOUT_MS);
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// If we can't check, assume not running
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if a consumer is currently running (sync version)
|
|
31
|
-
* Assumes storage is already initialized
|
|
32
|
-
*/
|
|
33
|
-
export function isConsumerRunningSync() {
|
|
34
|
-
try {
|
|
35
|
-
const storage = getAgentStorageSync();
|
|
36
|
-
return storage.hasActiveConsumer(STALE_TIMEOUT_MS);
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
export interface ConsumerServiceOptions {
|
|
2
|
-
/** Max concurrent jobs (default: 5) */
|
|
3
|
-
concurrency?: number;
|
|
4
|
-
/** Poll interval in ms (default: 1000) */
|
|
5
|
-
pollInterval?: number;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* ConsumerService - Singleton background worker that processes the execution queue
|
|
9
|
-
*
|
|
10
|
-
* Architecture:
|
|
11
|
-
* ```
|
|
12
|
-
* ┌─────────────────┐
|
|
13
|
-
* │ ConsumerService │ ← Singleton, start once in main
|
|
14
|
-
* │ (process jobs) │
|
|
15
|
-
* └────────┬────────┘
|
|
16
|
-
* │ writes
|
|
17
|
-
* ▼
|
|
18
|
-
* ┌─────────────────┐
|
|
19
|
-
* │ AgentStorage │ ← SQLite DB (source of truth)
|
|
20
|
-
* │ (agent.db) │
|
|
21
|
-
* └────────┬────────┘
|
|
22
|
-
* │ polls
|
|
23
|
-
* ▼
|
|
24
|
-
* ┌─────────────────┐
|
|
25
|
-
* │QueuePollingServ │ ← UI subscribes here for updates
|
|
26
|
-
* └─────────────────┘
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Usage:
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Main - start consumer singleton (once)
|
|
32
|
-
* const consumer = getConsumerService({ concurrency: 5 })
|
|
33
|
-
* await consumer.start()
|
|
34
|
-
*
|
|
35
|
-
* // UI components - use QueuePollingService for monitoring
|
|
36
|
-
* import { getQueuePollingService } from './queue-polling-service'
|
|
37
|
-
* const poller = getQueuePollingService({ pollInterval: 500 })
|
|
38
|
-
* poller.on('snapshot', (snapshot) => renderUI(snapshot))
|
|
39
|
-
* await poller.start()
|
|
40
|
-
*
|
|
41
|
-
* // Cleanup
|
|
42
|
-
* consumer.dispose()
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* Features:
|
|
46
|
-
* - Auto-loads auth token from Keychain
|
|
47
|
-
* - Auto-loads project config from .brv/config.json
|
|
48
|
-
* - Handles lock acquisition/release
|
|
49
|
-
* - Single dispose() for full cleanup
|
|
50
|
-
*/
|
|
51
|
-
export declare class ConsumerService {
|
|
52
|
-
private consumer;
|
|
53
|
-
private readonly options;
|
|
54
|
-
private running;
|
|
55
|
-
constructor(options?: ConsumerServiceOptions);
|
|
56
|
-
/**
|
|
57
|
-
* Stop the consumer and cleanup all resources
|
|
58
|
-
*/
|
|
59
|
-
dispose(): void;
|
|
60
|
-
/**
|
|
61
|
-
* Get the consumer ID (unique per session)
|
|
62
|
-
* Returns null if consumer hasn't started yet
|
|
63
|
-
*/
|
|
64
|
-
getConsumerId(): null | string;
|
|
65
|
-
/**
|
|
66
|
-
* Check if consumer is running
|
|
67
|
-
*/
|
|
68
|
-
isRunning(): boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Start the consumer
|
|
71
|
-
*
|
|
72
|
-
* - Loads auth token from Keychain
|
|
73
|
-
* - Loads project config from .brv/config.json
|
|
74
|
-
* - Acquires consumer lock
|
|
75
|
-
* - Starts processing queue
|
|
76
|
-
*
|
|
77
|
-
* @throws Error if not authenticated
|
|
78
|
-
* @throws Error if another consumer is already running
|
|
79
|
-
*/
|
|
80
|
-
start(): Promise<void>;
|
|
81
|
-
stop(): void;
|
|
82
|
-
private setupSignalHandlers;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Get or create singleton ConsumerService
|
|
86
|
-
*
|
|
87
|
-
* Usage:
|
|
88
|
-
* ```typescript
|
|
89
|
-
* const consumer = getConsumerService()
|
|
90
|
-
* await consumer.start()
|
|
91
|
-
* // later...
|
|
92
|
-
* consumer.dispose()
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
export declare function getConsumerService(options?: ConsumerServiceOptions): ConsumerService;
|
|
96
|
-
/**
|
|
97
|
-
* Dispose singleton and clear reference
|
|
98
|
-
*/
|
|
99
|
-
export declare function disposeConsumerService(): void;
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// TODO(v0.5.0): Remove this file. ConsumerService is replaced by CoreProcess → TaskProcessor.
|
|
2
|
-
import { ProjectConfigStore } from '../../config/file-config-store.js';
|
|
3
|
-
import { KeychainTokenStore } from '../../storage/keychain-token-store.js';
|
|
4
|
-
import { closeAgentStorage } from '../storage/agent-storage.js';
|
|
5
|
-
import { createExecutionConsumer } from './execution-consumer.js';
|
|
6
|
-
// ==================== SERVICE ====================
|
|
7
|
-
/**
|
|
8
|
-
* ConsumerService - Singleton background worker that processes the execution queue
|
|
9
|
-
*
|
|
10
|
-
* Architecture:
|
|
11
|
-
* ```
|
|
12
|
-
* ┌─────────────────┐
|
|
13
|
-
* │ ConsumerService │ ← Singleton, start once in main
|
|
14
|
-
* │ (process jobs) │
|
|
15
|
-
* └────────┬────────┘
|
|
16
|
-
* │ writes
|
|
17
|
-
* ▼
|
|
18
|
-
* ┌─────────────────┐
|
|
19
|
-
* │ AgentStorage │ ← SQLite DB (source of truth)
|
|
20
|
-
* │ (agent.db) │
|
|
21
|
-
* └────────┬────────┘
|
|
22
|
-
* │ polls
|
|
23
|
-
* ▼
|
|
24
|
-
* ┌─────────────────┐
|
|
25
|
-
* │QueuePollingServ │ ← UI subscribes here for updates
|
|
26
|
-
* └─────────────────┘
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Usage:
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Main - start consumer singleton (once)
|
|
32
|
-
* const consumer = getConsumerService({ concurrency: 5 })
|
|
33
|
-
* await consumer.start()
|
|
34
|
-
*
|
|
35
|
-
* // UI components - use QueuePollingService for monitoring
|
|
36
|
-
* import { getQueuePollingService } from './queue-polling-service'
|
|
37
|
-
* const poller = getQueuePollingService({ pollInterval: 500 })
|
|
38
|
-
* poller.on('snapshot', (snapshot) => renderUI(snapshot))
|
|
39
|
-
* await poller.start()
|
|
40
|
-
*
|
|
41
|
-
* // Cleanup
|
|
42
|
-
* consumer.dispose()
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* Features:
|
|
46
|
-
* - Auto-loads auth token from Keychain
|
|
47
|
-
* - Auto-loads project config from .brv/config.json
|
|
48
|
-
* - Handles lock acquisition/release
|
|
49
|
-
* - Single dispose() for full cleanup
|
|
50
|
-
*/
|
|
51
|
-
export class ConsumerService {
|
|
52
|
-
consumer = null;
|
|
53
|
-
options;
|
|
54
|
-
running = false;
|
|
55
|
-
constructor(options) {
|
|
56
|
-
this.options = options ?? {};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Stop the consumer and cleanup all resources
|
|
60
|
-
*/
|
|
61
|
-
dispose() {
|
|
62
|
-
if (!this.running)
|
|
63
|
-
return;
|
|
64
|
-
this.running = false;
|
|
65
|
-
if (this.consumer) {
|
|
66
|
-
this.consumer.stop();
|
|
67
|
-
this.consumer = null;
|
|
68
|
-
}
|
|
69
|
-
closeAgentStorage();
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Get the consumer ID (unique per session)
|
|
73
|
-
* Returns null if consumer hasn't started yet
|
|
74
|
-
*/
|
|
75
|
-
getConsumerId() {
|
|
76
|
-
return this.consumer?.getConsumerId() ?? null;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Check if consumer is running
|
|
80
|
-
*/
|
|
81
|
-
isRunning() {
|
|
82
|
-
return this.running && this.consumer !== null;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Start the consumer
|
|
86
|
-
*
|
|
87
|
-
* - Loads auth token from Keychain
|
|
88
|
-
* - Loads project config from .brv/config.json
|
|
89
|
-
* - Acquires consumer lock
|
|
90
|
-
* - Starts processing queue
|
|
91
|
-
*
|
|
92
|
-
* @throws Error if not authenticated
|
|
93
|
-
* @throws Error if another consumer is already running
|
|
94
|
-
*/
|
|
95
|
-
async start() {
|
|
96
|
-
if (this.running) {
|
|
97
|
-
throw new Error('Consumer already running');
|
|
98
|
-
}
|
|
99
|
-
// Load auth token
|
|
100
|
-
const tokenStore = new KeychainTokenStore();
|
|
101
|
-
const token = await tokenStore.load();
|
|
102
|
-
if (!token) {
|
|
103
|
-
throw new Error('Not authenticated. Please run "brv login" first.');
|
|
104
|
-
}
|
|
105
|
-
// Load project config (optional)
|
|
106
|
-
const configStore = new ProjectConfigStore();
|
|
107
|
-
const brvConfig = await configStore.read();
|
|
108
|
-
// Create consumer (auto-detects .brv/blobs from cwd)
|
|
109
|
-
this.consumer = createExecutionConsumer({
|
|
110
|
-
authToken: { accessToken: token.accessToken, sessionKey: token.sessionKey },
|
|
111
|
-
brvConfig: brvConfig ?? undefined,
|
|
112
|
-
maxConcurrency: this.options.concurrency ?? 5,
|
|
113
|
-
pollInterval: this.options.pollInterval ?? 1000,
|
|
114
|
-
});
|
|
115
|
-
// Start consumer
|
|
116
|
-
const started = await this.consumer.start();
|
|
117
|
-
if (!started) {
|
|
118
|
-
this.consumer = null;
|
|
119
|
-
throw new Error('Another consumer is already running in this directory');
|
|
120
|
-
}
|
|
121
|
-
this.running = true;
|
|
122
|
-
this.setupSignalHandlers();
|
|
123
|
-
}
|
|
124
|
-
// Alias for dispose
|
|
125
|
-
stop() {
|
|
126
|
-
this.dispose();
|
|
127
|
-
}
|
|
128
|
-
// ==================== PRIVATE ====================
|
|
129
|
-
setupSignalHandlers() {
|
|
130
|
-
// eslint-disable-next-line unicorn/consistent-function-scoping -- needs 'this' context
|
|
131
|
-
const cleanup = () => {
|
|
132
|
-
this.dispose();
|
|
133
|
-
};
|
|
134
|
-
process.on('SIGTERM', cleanup);
|
|
135
|
-
process.on('SIGINT', cleanup);
|
|
136
|
-
process.on('exit', cleanup);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// ==================== SINGLETON HELPER ====================
|
|
140
|
-
let instance = null;
|
|
141
|
-
/**
|
|
142
|
-
* Get or create singleton ConsumerService
|
|
143
|
-
*
|
|
144
|
-
* Usage:
|
|
145
|
-
* ```typescript
|
|
146
|
-
* const consumer = getConsumerService()
|
|
147
|
-
* await consumer.start()
|
|
148
|
-
* // later...
|
|
149
|
-
* consumer.dispose()
|
|
150
|
-
* ```
|
|
151
|
-
*/
|
|
152
|
-
export function getConsumerService(options) {
|
|
153
|
-
if (!instance) {
|
|
154
|
-
instance = new ConsumerService(options);
|
|
155
|
-
}
|
|
156
|
-
return instance;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Dispose singleton and clear reference
|
|
160
|
-
*/
|
|
161
|
-
export function disposeConsumerService() {
|
|
162
|
-
if (instance) {
|
|
163
|
-
instance.dispose();
|
|
164
|
-
instance = null;
|
|
165
|
-
}
|
|
166
|
-
}
|