byterover-cli 1.2.0 → 1.3.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/README.md +87 -9
- package/dist/constants.d.ts +0 -5
- package/dist/constants.js +0 -5
- package/dist/core/domain/cipher/agent/agent-info.d.ts +17 -17
- package/dist/core/domain/cipher/llm/schemas.d.ts +14 -14
- package/dist/core/domain/cipher/session/session-metadata.d.ts +2 -2
- package/dist/core/domain/entities/agent.js +6 -6
- package/dist/core/domain/entities/connector-type.d.ts +2 -1
- package/dist/core/domain/entities/connector-type.js +2 -1
- package/dist/core/domain/transport/schemas.d.ts +66 -66
- package/dist/core/interfaces/cipher/i-chat-session.d.ts +3 -1
- package/dist/core/interfaces/connectors/i-connector.d.ts +2 -2
- package/dist/core/interfaces/i-file-service.d.ts +7 -0
- package/dist/infra/auth/oauth-service.d.ts +15 -0
- package/dist/infra/auth/oauth-service.js +38 -2
- package/dist/infra/cipher/agent/agent-schemas.d.ts +42 -42
- package/dist/infra/cipher/llm/context/context-manager.js +7 -9
- package/dist/infra/cipher/llm/internal-llm-service.d.ts +5 -1
- package/dist/infra/cipher/llm/internal-llm-service.js +57 -46
- package/dist/infra/cipher/session/chat-session.d.ts +3 -1
- package/dist/infra/cipher/session/chat-session.js +5 -3
- package/dist/infra/cipher/system-prompt/contributor-schemas.d.ts +8 -8
- package/dist/infra/cipher/system-prompt/schemas.d.ts +5 -5
- package/dist/infra/cipher/tools/implementations/task-tool.js +3 -3
- package/dist/infra/connectors/connector-manager.js +2 -0
- package/dist/infra/connectors/hook/hook-connector.d.ts +1 -1
- package/dist/infra/connectors/hook/hook-connector.js +3 -3
- package/dist/infra/connectors/mcp/mcp-connector.d.ts +1 -1
- package/dist/infra/connectors/mcp/mcp-connector.js +4 -4
- package/dist/infra/connectors/rules/rules-connector.d.ts +1 -1
- package/dist/infra/connectors/rules/rules-connector.js +4 -4
- package/dist/infra/connectors/shared/template-service.js +4 -0
- package/dist/infra/connectors/skill/index.d.ts +1 -0
- package/dist/infra/connectors/skill/index.js +1 -0
- package/dist/infra/connectors/skill/skill-connector-config.d.ts +45 -0
- package/dist/infra/connectors/skill/skill-connector-config.js +26 -0
- package/dist/infra/connectors/skill/skill-connector.d.ts +39 -0
- package/dist/infra/connectors/skill/skill-connector.js +160 -0
- package/dist/infra/connectors/skill/skill-content-loader.d.ts +18 -0
- package/dist/infra/connectors/skill/skill-content-loader.js +33 -0
- package/dist/infra/file/fs-file-service.d.ts +7 -0
- package/dist/infra/file/fs-file-service.js +15 -1
- package/dist/infra/mcp/tools/task-result-waiter.js +8 -0
- package/dist/infra/process/agent-worker.js +30 -14
- package/dist/infra/process/task-queue-manager.d.ts +23 -34
- package/dist/infra/process/task-queue-manager.js +57 -118
- package/dist/infra/process/transport-handlers.js +1 -7
- package/dist/infra/repl/commands/connectors-command.js +1 -1
- package/dist/infra/transport/socket-io-transport-client.d.ts +9 -0
- package/dist/infra/transport/socket-io-transport-client.js +21 -2
- package/dist/infra/usecase/connectors-use-case.js +8 -2
- package/dist/infra/usecase/init-use-case.js +1 -1
- package/dist/infra/usecase/reset-use-case.d.ts +1 -0
- package/dist/infra/usecase/reset-use-case.js +4 -1
- package/dist/{commands → oclif/commands}/curate.d.ts +1 -1
- package/dist/{commands → oclif/commands}/curate.js +6 -6
- package/dist/{commands → oclif/commands}/hook-prompt-submit.d.ts +1 -1
- package/dist/{commands → oclif/commands}/hook-prompt-submit.js +3 -3
- package/dist/{commands → oclif/commands}/main.js +10 -10
- package/dist/{commands → oclif/commands}/mcp.js +2 -2
- package/dist/{commands → oclif/commands}/query.d.ts +1 -1
- package/dist/{commands → oclif/commands}/query.js +6 -6
- package/dist/{commands → oclif/commands}/status.d.ts +1 -1
- package/dist/{commands → oclif/commands}/status.js +8 -8
- package/dist/{commands → oclif/commands}/watch.d.ts +3 -3
- package/dist/{commands → oclif/commands}/watch.js +6 -6
- package/dist/oclif/constants.d.ts +11 -0
- package/dist/oclif/constants.js +11 -0
- package/dist/{hooks → oclif/hooks}/prerun/validate-brv-config-version.d.ts +1 -1
- package/dist/{hooks → oclif/hooks}/prerun/validate-brv-config-version.js +2 -2
- package/dist/templates/sections/command-reference.md +5 -96
- package/dist/templates/sections/workflow.md +21 -16
- package/dist/templates/skill/SKILL.md +91 -0
- package/dist/templates/skill/TROUBLESHOOTING.md +50 -0
- package/dist/templates/skill/WORKFLOWS.md +229 -0
- package/dist/utils/type-guards.d.ts +11 -0
- package/dist/utils/type-guards.js +13 -0
- package/oclif.manifest.json +8 -1
- package/package.json +9 -9
- package/dist/infra/process/constants.d.ts +0 -1
- package/dist/infra/process/constants.js +0 -1
- /package/dist/{commands → oclif/commands}/main.d.ts +0 -0
- /package/dist/{commands → oclif/commands}/mcp.d.ts +0 -0
- /package/dist/{hooks → oclif/hooks}/command_not_found/handle-invalid-commands.d.ts +0 -0
- /package/dist/{hooks → oclif/hooks}/command_not_found/handle-invalid-commands.js +0 -0
- /package/dist/{hooks → oclif/hooks}/error/clean-errors.d.ts +0 -0
- /package/dist/{hooks → oclif/hooks}/error/clean-errors.js +0 -0
- /package/dist/{hooks → oclif/hooks}/init/update-notifier.d.ts +0 -0
- /package/dist/{hooks → oclif/hooks}/init/update-notifier.js +0 -0
- /package/dist/{hooks → oclif/hooks}/init/welcome.d.ts +0 -0
- /package/dist/{hooks → oclif/hooks}/init/welcome.js +0 -0
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TaskQueueManager - Manages in-memory task
|
|
2
|
+
* TaskQueueManager - Manages in-memory task queue with FIFO sequential execution.
|
|
3
3
|
*
|
|
4
4
|
* Features:
|
|
5
|
-
* -
|
|
6
|
-
* - Configurable concurrency
|
|
5
|
+
* - Unified queue for all task types (curate, query)
|
|
6
|
+
* - Configurable concurrency limit (default: 1 for sequential execution)
|
|
7
7
|
* - Task deduplication (same taskId can't be queued twice)
|
|
8
8
|
* - Cancel tasks from queue before processing
|
|
9
|
-
* - FIFO processing order
|
|
9
|
+
* - Strict FIFO processing order across all task types
|
|
10
10
|
*
|
|
11
11
|
* This class is extracted from agent-worker.ts to enable unit testing.
|
|
12
12
|
*/
|
|
13
|
-
import type { TaskExecute } from '../../core/domain/transport/schemas.js';
|
|
14
|
-
export type TaskType
|
|
15
|
-
export interface QueueConfig {
|
|
16
|
-
/** Maximum concurrent tasks for this queue */
|
|
17
|
-
maxConcurrent: number;
|
|
18
|
-
}
|
|
13
|
+
import type { TaskExecute, TaskType } from '../../core/domain/transport/schemas.js';
|
|
14
|
+
export type { TaskType } from '../../core/domain/transport/schemas.js';
|
|
19
15
|
export interface TaskQueueStats {
|
|
20
16
|
/** Number of tasks currently being processed */
|
|
21
17
|
active: number;
|
|
@@ -25,10 +21,10 @@ export interface TaskQueueStats {
|
|
|
25
21
|
queued: number;
|
|
26
22
|
}
|
|
27
23
|
export interface TaskQueueManagerConfig {
|
|
28
|
-
|
|
24
|
+
/** Maximum concurrent tasks (default: 1 for sequential execution) */
|
|
25
|
+
maxConcurrent?: number;
|
|
29
26
|
/** Optional callback for executor errors (for logging/debugging) */
|
|
30
27
|
onExecutorError?: (taskId: string, error: unknown) => void;
|
|
31
|
-
query: QueueConfig;
|
|
32
28
|
}
|
|
33
29
|
/**
|
|
34
30
|
* Result of attempting to enqueue a task.
|
|
@@ -56,16 +52,14 @@ export type CancelResult = {
|
|
|
56
52
|
*/
|
|
57
53
|
export type TaskExecutor = (task: TaskExecute) => Promise<void>;
|
|
58
54
|
export declare class TaskQueueManager {
|
|
59
|
-
private
|
|
60
|
-
private activeQueryTasks;
|
|
61
|
-
private readonly config;
|
|
62
|
-
private readonly curateQueue;
|
|
55
|
+
private activeTasks;
|
|
63
56
|
/** Maps taskId → taskType for tracking (replaces Set for type awareness) */
|
|
64
57
|
private readonly knownTasks;
|
|
58
|
+
private readonly maxConcurrent;
|
|
65
59
|
private readonly onExecutorError?;
|
|
66
|
-
private readonly
|
|
60
|
+
private readonly queue;
|
|
67
61
|
private taskExecutor;
|
|
68
|
-
constructor(config?:
|
|
62
|
+
constructor(config?: TaskQueueManagerConfig);
|
|
69
63
|
/**
|
|
70
64
|
* Cancel a task by taskId.
|
|
71
65
|
* Removes from queue if waiting, or marks for cancellation if processing.
|
|
@@ -82,21 +76,22 @@ export declare class TaskQueueManager {
|
|
|
82
76
|
*/
|
|
83
77
|
enqueue(task: TaskExecute): EnqueueResult;
|
|
84
78
|
/**
|
|
85
|
-
* Get total active task count
|
|
79
|
+
* Get total active task count.
|
|
86
80
|
*/
|
|
87
81
|
getActiveCount(): number;
|
|
88
82
|
/**
|
|
89
|
-
* Get
|
|
83
|
+
* Get total queued task count.
|
|
90
84
|
*/
|
|
91
|
-
|
|
85
|
+
getQueuedCount(): number;
|
|
92
86
|
/**
|
|
93
|
-
* Get
|
|
87
|
+
* Get a copy of all queued tasks (not including active tasks).
|
|
88
|
+
* Useful for notifying clients before clearing the queue.
|
|
94
89
|
*/
|
|
95
|
-
|
|
90
|
+
getQueuedTasks(): readonly TaskExecute[];
|
|
96
91
|
/**
|
|
97
|
-
* Get statistics for
|
|
92
|
+
* Get statistics for the queue.
|
|
98
93
|
*/
|
|
99
|
-
getStats(
|
|
94
|
+
getStats(): TaskQueueStats;
|
|
100
95
|
/**
|
|
101
96
|
* Check if there are any active tasks (currently being processed).
|
|
102
97
|
* Used to prevent reinit during task execution.
|
|
@@ -111,7 +106,7 @@ export declare class TaskQueueManager {
|
|
|
111
106
|
* Should be called by executor when task finishes.
|
|
112
107
|
* Guards against underflow from duplicate/invalid calls.
|
|
113
108
|
*/
|
|
114
|
-
markCompleted(taskId: string
|
|
109
|
+
markCompleted(taskId: string): void;
|
|
115
110
|
/**
|
|
116
111
|
* Set the task executor callback.
|
|
117
112
|
* Called when a task is ready to be processed.
|
|
@@ -119,18 +114,12 @@ export declare class TaskQueueManager {
|
|
|
119
114
|
*/
|
|
120
115
|
setExecutor(executor: TaskExecutor): void;
|
|
121
116
|
/**
|
|
122
|
-
* Process all possible tasks from
|
|
123
|
-
* Handles Infinity maxConcurrent safely by using queue length as bound.
|
|
117
|
+
* Process all possible tasks from the queue (up to maxConcurrent).
|
|
124
118
|
*/
|
|
125
119
|
private drainQueue;
|
|
126
120
|
private executeTask;
|
|
127
121
|
/**
|
|
128
|
-
*
|
|
129
|
-
*/
|
|
130
|
-
private getQueueState;
|
|
131
|
-
/**
|
|
132
|
-
* Try to process the next task from a specific queue.
|
|
133
|
-
* Unified method replacing tryProcessNextCurate/tryProcessNextQuery.
|
|
122
|
+
* Try to process the next task from the queue.
|
|
134
123
|
*/
|
|
135
124
|
private tryProcessNext;
|
|
136
125
|
}
|
|
@@ -1,32 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TaskQueueManager - Manages in-memory task
|
|
2
|
+
* TaskQueueManager - Manages in-memory task queue with FIFO sequential execution.
|
|
3
3
|
*
|
|
4
4
|
* Features:
|
|
5
|
-
* -
|
|
6
|
-
* - Configurable concurrency
|
|
5
|
+
* - Unified queue for all task types (curate, query)
|
|
6
|
+
* - Configurable concurrency limit (default: 1 for sequential execution)
|
|
7
7
|
* - Task deduplication (same taskId can't be queued twice)
|
|
8
8
|
* - Cancel tasks from queue before processing
|
|
9
|
-
* - FIFO processing order
|
|
9
|
+
* - Strict FIFO processing order across all task types
|
|
10
10
|
*
|
|
11
11
|
* This class is extracted from agent-worker.ts to enable unit testing.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { isValidTaskType } from '../../utils/type-guards.js';
|
|
14
14
|
export class TaskQueueManager {
|
|
15
|
-
|
|
16
|
-
activeQueryTasks = 0;
|
|
17
|
-
config;
|
|
18
|
-
curateQueue = [];
|
|
15
|
+
activeTasks = 0;
|
|
19
16
|
/** Maps taskId → taskType for tracking (replaces Set for type awareness) */
|
|
20
17
|
knownTasks = new Map();
|
|
18
|
+
maxConcurrent;
|
|
21
19
|
onExecutorError;
|
|
22
|
-
|
|
20
|
+
queue = [];
|
|
23
21
|
taskExecutor;
|
|
24
22
|
constructor(config) {
|
|
25
|
-
this.
|
|
26
|
-
curate: { maxConcurrent: config?.curate?.maxConcurrent ?? CURATE_MAX_CONCURRENT },
|
|
27
|
-
// Query tasks are unlimited (Infinity) - lightweight and fast
|
|
28
|
-
query: { maxConcurrent: config?.query?.maxConcurrent ?? Infinity },
|
|
29
|
-
};
|
|
23
|
+
this.maxConcurrent = config?.maxConcurrent ?? 1;
|
|
30
24
|
this.onExecutorError = config?.onExecutorError;
|
|
31
25
|
}
|
|
32
26
|
/**
|
|
@@ -34,21 +28,15 @@ export class TaskQueueManager {
|
|
|
34
28
|
* Removes from queue if waiting, or marks for cancellation if processing.
|
|
35
29
|
*/
|
|
36
30
|
cancel(taskId) {
|
|
37
|
-
// Try to remove from
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
this.
|
|
41
|
-
this.
|
|
42
|
-
return { success: true, taskType: 'curate', wasQueued: true };
|
|
43
|
-
}
|
|
44
|
-
// Try to remove from query queue
|
|
45
|
-
const queryIndex = this.queryQueue.findIndex((t) => t.taskId === taskId);
|
|
46
|
-
if (queryIndex !== -1) {
|
|
47
|
-
this.queryQueue.splice(queryIndex, 1);
|
|
31
|
+
// Try to remove from queue
|
|
32
|
+
const index = this.queue.findIndex((t) => t.taskId === taskId);
|
|
33
|
+
if (index !== -1) {
|
|
34
|
+
const task = this.queue[index];
|
|
35
|
+
this.queue.splice(index, 1);
|
|
48
36
|
this.knownTasks.delete(taskId);
|
|
49
|
-
return { success: true, taskType:
|
|
37
|
+
return { success: true, taskType: task.type, wasQueued: true };
|
|
50
38
|
}
|
|
51
|
-
// Check if task is currently processing -
|
|
39
|
+
// Check if task is currently processing - get type from knownTasks
|
|
52
40
|
const taskType = this.knownTasks.get(taskId);
|
|
53
41
|
if (taskType) {
|
|
54
42
|
// Task is processing - caller should handle cancellation via taskProcessor
|
|
@@ -61,10 +49,8 @@ export class TaskQueueManager {
|
|
|
61
49
|
* Useful for testing or shutdown.
|
|
62
50
|
*/
|
|
63
51
|
clear() {
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.activeCurateTasks = 0;
|
|
67
|
-
this.activeQueryTasks = 0;
|
|
52
|
+
this.queue.length = 0;
|
|
53
|
+
this.activeTasks = 0;
|
|
68
54
|
this.knownTasks.clear();
|
|
69
55
|
}
|
|
70
56
|
/**
|
|
@@ -76,57 +62,43 @@ export class TaskQueueManager {
|
|
|
76
62
|
if (this.knownTasks.has(task.taskId)) {
|
|
77
63
|
return { reason: 'duplicate', success: false };
|
|
78
64
|
}
|
|
79
|
-
// Validate task type
|
|
80
|
-
if (task.type
|
|
65
|
+
// Validate task type using type guard for compile-time safety
|
|
66
|
+
if (!isValidTaskType(task.type)) {
|
|
81
67
|
return { reason: 'unknown_type', success: false };
|
|
82
68
|
}
|
|
83
69
|
// Register with type and enqueue
|
|
84
70
|
this.knownTasks.set(task.taskId, task.type);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return { position: this.curateQueue.length, success: true };
|
|
89
|
-
}
|
|
90
|
-
this.queryQueue.push(task);
|
|
91
|
-
this.tryProcessNext('query');
|
|
92
|
-
return { position: this.queryQueue.length, success: true };
|
|
71
|
+
this.queue.push(task);
|
|
72
|
+
this.tryProcessNext();
|
|
73
|
+
return { position: this.queue.length, success: true };
|
|
93
74
|
}
|
|
94
75
|
/**
|
|
95
|
-
* Get total active task count
|
|
76
|
+
* Get total active task count.
|
|
96
77
|
*/
|
|
97
78
|
getActiveCount() {
|
|
98
|
-
return this.
|
|
79
|
+
return this.activeTasks;
|
|
99
80
|
}
|
|
100
81
|
/**
|
|
101
|
-
* Get
|
|
82
|
+
* Get total queued task count.
|
|
102
83
|
*/
|
|
103
|
-
|
|
104
|
-
return
|
|
105
|
-
curate: this.getStats('curate'),
|
|
106
|
-
query: this.getStats('query'),
|
|
107
|
-
};
|
|
84
|
+
getQueuedCount() {
|
|
85
|
+
return this.queue.length;
|
|
108
86
|
}
|
|
109
87
|
/**
|
|
110
|
-
* Get
|
|
88
|
+
* Get a copy of all queued tasks (not including active tasks).
|
|
89
|
+
* Useful for notifying clients before clearing the queue.
|
|
111
90
|
*/
|
|
112
|
-
|
|
113
|
-
return this.
|
|
91
|
+
getQueuedTasks() {
|
|
92
|
+
return [...this.queue];
|
|
114
93
|
}
|
|
115
94
|
/**
|
|
116
|
-
* Get statistics for
|
|
95
|
+
* Get statistics for the queue.
|
|
117
96
|
*/
|
|
118
|
-
getStats(
|
|
119
|
-
if (type === 'curate') {
|
|
120
|
-
return {
|
|
121
|
-
active: this.activeCurateTasks,
|
|
122
|
-
maxConcurrent: this.config.curate.maxConcurrent,
|
|
123
|
-
queued: this.curateQueue.length,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
97
|
+
getStats() {
|
|
126
98
|
return {
|
|
127
|
-
active: this.
|
|
128
|
-
maxConcurrent: this.
|
|
129
|
-
queued: this.
|
|
99
|
+
active: this.activeTasks,
|
|
100
|
+
maxConcurrent: this.maxConcurrent,
|
|
101
|
+
queued: this.queue.length,
|
|
130
102
|
};
|
|
131
103
|
}
|
|
132
104
|
/**
|
|
@@ -134,7 +106,7 @@ export class TaskQueueManager {
|
|
|
134
106
|
* Used to prevent reinit during task execution.
|
|
135
107
|
*/
|
|
136
108
|
hasActiveTasks() {
|
|
137
|
-
return this.
|
|
109
|
+
return this.activeTasks > 0;
|
|
138
110
|
}
|
|
139
111
|
/**
|
|
140
112
|
* Check if a taskId is known (queued or processing).
|
|
@@ -147,24 +119,16 @@ export class TaskQueueManager {
|
|
|
147
119
|
* Should be called by executor when task finishes.
|
|
148
120
|
* Guards against underflow from duplicate/invalid calls.
|
|
149
121
|
*/
|
|
150
|
-
markCompleted(taskId
|
|
122
|
+
markCompleted(taskId) {
|
|
151
123
|
// Guard: only decrement if task was actually known (prevents underflow)
|
|
152
124
|
if (!this.knownTasks.has(taskId)) {
|
|
153
125
|
return;
|
|
154
126
|
}
|
|
155
127
|
this.knownTasks.delete(taskId);
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
this.activeCurateTasks--;
|
|
159
|
-
}
|
|
160
|
-
this.tryProcessNext('curate');
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
if (this.activeQueryTasks > 0) {
|
|
164
|
-
this.activeQueryTasks--;
|
|
165
|
-
}
|
|
166
|
-
this.tryProcessNext('query');
|
|
128
|
+
if (this.activeTasks > 0) {
|
|
129
|
+
this.activeTasks--;
|
|
167
130
|
}
|
|
131
|
+
this.tryProcessNext();
|
|
168
132
|
}
|
|
169
133
|
/**
|
|
170
134
|
* Set the task executor callback.
|
|
@@ -174,26 +138,22 @@ export class TaskQueueManager {
|
|
|
174
138
|
setExecutor(executor) {
|
|
175
139
|
this.taskExecutor = executor;
|
|
176
140
|
// Process any tasks that were queued before executor was set
|
|
177
|
-
|
|
178
|
-
this.drainQueue('curate');
|
|
179
|
-
this.drainQueue('query');
|
|
141
|
+
this.drainQueue();
|
|
180
142
|
}
|
|
181
143
|
/**
|
|
182
|
-
* Process all possible tasks from
|
|
183
|
-
* Handles Infinity maxConcurrent safely by using queue length as bound.
|
|
144
|
+
* Process all possible tasks from the queue (up to maxConcurrent).
|
|
184
145
|
*/
|
|
185
|
-
drainQueue(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const toProcess = Math.min(state.queue.length, state.config.maxConcurrent);
|
|
146
|
+
drainQueue() {
|
|
147
|
+
// Process up to maxConcurrent tasks
|
|
148
|
+
const toProcess = Math.min(this.queue.length, this.maxConcurrent);
|
|
189
149
|
for (let i = 0; i < toProcess; i++) {
|
|
190
|
-
this.tryProcessNext(
|
|
150
|
+
this.tryProcessNext();
|
|
191
151
|
}
|
|
192
152
|
}
|
|
193
153
|
// ============================================================================
|
|
194
154
|
// Private Methods
|
|
195
155
|
// ============================================================================
|
|
196
|
-
executeTask(task
|
|
156
|
+
executeTask(task) {
|
|
197
157
|
this.taskExecutor(task)
|
|
198
158
|
.catch((error) => {
|
|
199
159
|
// Notify caller of executor error (for logging/debugging)
|
|
@@ -201,46 +161,25 @@ export class TaskQueueManager {
|
|
|
201
161
|
this.onExecutorError?.(task.taskId, error);
|
|
202
162
|
})
|
|
203
163
|
.finally(() => {
|
|
204
|
-
this.markCompleted(task.taskId
|
|
164
|
+
this.markCompleted(task.taskId);
|
|
205
165
|
});
|
|
206
166
|
}
|
|
207
167
|
/**
|
|
208
|
-
*
|
|
209
|
-
*/
|
|
210
|
-
getQueueState(type) {
|
|
211
|
-
if (type === 'curate') {
|
|
212
|
-
return {
|
|
213
|
-
active: this.activeCurateTasks,
|
|
214
|
-
config: this.config.curate,
|
|
215
|
-
incrementActive: () => this.activeCurateTasks++,
|
|
216
|
-
queue: this.curateQueue,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
active: this.activeQueryTasks,
|
|
221
|
-
config: this.config.query,
|
|
222
|
-
incrementActive: () => this.activeQueryTasks++,
|
|
223
|
-
queue: this.queryQueue,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Try to process the next task from a specific queue.
|
|
228
|
-
* Unified method replacing tryProcessNextCurate/tryProcessNextQuery.
|
|
168
|
+
* Try to process the next task from the queue.
|
|
229
169
|
*/
|
|
230
|
-
tryProcessNext(
|
|
170
|
+
tryProcessNext() {
|
|
231
171
|
// Don't process without executor - tasks stay in queue
|
|
232
172
|
if (!this.taskExecutor) {
|
|
233
173
|
return;
|
|
234
174
|
}
|
|
235
|
-
|
|
236
|
-
if (state.active >= state.config.maxConcurrent) {
|
|
175
|
+
if (this.activeTasks >= this.maxConcurrent) {
|
|
237
176
|
return;
|
|
238
177
|
}
|
|
239
|
-
if (
|
|
178
|
+
if (this.queue.length === 0) {
|
|
240
179
|
return;
|
|
241
180
|
}
|
|
242
|
-
const task =
|
|
243
|
-
|
|
244
|
-
this.executeTask(task
|
|
181
|
+
const task = this.queue.shift();
|
|
182
|
+
this.activeTasks++;
|
|
183
|
+
this.executeTask(task);
|
|
245
184
|
}
|
|
246
185
|
}
|
|
@@ -33,13 +33,7 @@
|
|
|
33
33
|
import { AgentDisconnectedError, AgentNotAvailableError, AgentNotInitializedError, serializeTaskError, } from '../../core/domain/errors/task-error.js';
|
|
34
34
|
import { AgentStatusEventNames, LlmEventNames, TransportAgentEventNames, TransportLlmEventList, TransportTaskEventNames, } from '../../core/domain/transport/schemas.js';
|
|
35
35
|
import { eventLog, transportLog } from '../../utils/process-logger.js';
|
|
36
|
-
|
|
37
|
-
* Type guard for valid task types.
|
|
38
|
-
* Replaces unsafe `as` assertion per CLAUDE.md standards.
|
|
39
|
-
*/
|
|
40
|
-
function isValidTaskType(type) {
|
|
41
|
-
return type === 'curate' || type === 'query';
|
|
42
|
-
}
|
|
36
|
+
import { isValidTaskType } from '../../utils/type-guards.js';
|
|
43
37
|
// All message types are imported from core/domain/transport/schemas.ts
|
|
44
38
|
// - TaskExecute: Transport → Agent (command)
|
|
45
39
|
// - TaskStartedEvent, TaskCompletedEvent, TaskErrorEvent: Agent → Transport (task lifecycle events)
|
|
@@ -43,7 +43,7 @@ export const connectorsCommand = {
|
|
|
43
43
|
}),
|
|
44
44
|
aliases: [],
|
|
45
45
|
autoExecute: true,
|
|
46
|
-
description: 'Manage agent connectors (rules,
|
|
46
|
+
description: 'Manage agent connectors (rules, hook, mcp, or skill)',
|
|
47
47
|
kind: CommandKind.BUILT_IN,
|
|
48
48
|
name: 'connectors',
|
|
49
49
|
};
|
|
@@ -72,6 +72,15 @@ export declare class SocketIOTransportClient implements ITransportClient {
|
|
|
72
72
|
* Used when initiating new connection attempt - counter preserved for backoff continuity.
|
|
73
73
|
*/
|
|
74
74
|
private clearForceReconnectTimer;
|
|
75
|
+
/**
|
|
76
|
+
* Remove all registered event listeners from socket.
|
|
77
|
+
* Used before re-registering to prevent listener accumulation across reconnects.
|
|
78
|
+
*
|
|
79
|
+
* Why this is needed: Socket.IO preserves the Socket instance across internal reconnects.
|
|
80
|
+
* If we clear registeredSocketEvents without calling socket.off(), the old listeners
|
|
81
|
+
* remain attached, and registerPendingEventHandlers() adds new ones - causing duplicates.
|
|
82
|
+
*/
|
|
83
|
+
private clearSocketEventListeners;
|
|
75
84
|
/**
|
|
76
85
|
* Handle system wake from sleep/hibernate.
|
|
77
86
|
* Re-triggers reconnection if not connected and force reconnect has given up.
|
|
@@ -145,8 +145,10 @@ export class SocketIOTransportClient {
|
|
|
145
145
|
clientLog(`Socket.IO built-in reconnect succeeded after ${attemptNumber} attempts`);
|
|
146
146
|
this.setState('connected');
|
|
147
147
|
// Re-register event handlers after reconnect
|
|
148
|
-
//
|
|
149
|
-
|
|
148
|
+
// FIX: Remove existing socket listeners before re-registering to prevent
|
|
149
|
+
// listener accumulation. Socket.IO preserves the Socket instance across
|
|
150
|
+
// internal reconnects, so old listeners remain attached if not removed.
|
|
151
|
+
this.clearSocketEventListeners();
|
|
150
152
|
this.registerPendingEventHandlers();
|
|
151
153
|
// Auto-rejoin rooms after reconnect
|
|
152
154
|
// Use process.nextTick to ensure socket.connected is true
|
|
@@ -408,6 +410,23 @@ export class SocketIOTransportClient {
|
|
|
408
410
|
this.forceReconnectTimer = undefined;
|
|
409
411
|
}
|
|
410
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Remove all registered event listeners from socket.
|
|
415
|
+
* Used before re-registering to prevent listener accumulation across reconnects.
|
|
416
|
+
*
|
|
417
|
+
* Why this is needed: Socket.IO preserves the Socket instance across internal reconnects.
|
|
418
|
+
* If we clear registeredSocketEvents without calling socket.off(), the old listeners
|
|
419
|
+
* remain attached, and registerPendingEventHandlers() adds new ones - causing duplicates.
|
|
420
|
+
*/
|
|
421
|
+
clearSocketEventListeners() {
|
|
422
|
+
const { socket } = this;
|
|
423
|
+
if (!socket)
|
|
424
|
+
return;
|
|
425
|
+
for (const event of this.registeredSocketEvents) {
|
|
426
|
+
socket.off(event);
|
|
427
|
+
}
|
|
428
|
+
this.registeredSocketEvents.clear();
|
|
429
|
+
}
|
|
411
430
|
/**
|
|
412
431
|
* Handle system wake from sleep/hibernate.
|
|
413
432
|
* Re-triggers reconnection if not connected and force reconnect has given up.
|
|
@@ -74,6 +74,9 @@ export class ConnectorsUseCase {
|
|
|
74
74
|
case 'rules': {
|
|
75
75
|
return `Agent reads instructions from rule file (${configPath})`;
|
|
76
76
|
}
|
|
77
|
+
case 'skill': {
|
|
78
|
+
return `Agent reads skill files from project directory (${configPath})`;
|
|
79
|
+
}
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
82
|
/**
|
|
@@ -90,6 +93,9 @@ export class ConnectorsUseCase {
|
|
|
90
93
|
case 'rules': {
|
|
91
94
|
return 'Rules';
|
|
92
95
|
}
|
|
96
|
+
case 'skill': {
|
|
97
|
+
return 'Skill';
|
|
98
|
+
}
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
/**
|
|
@@ -136,8 +142,8 @@ export class ConnectorsUseCase {
|
|
|
136
142
|
this.terminal.log(` Installed: ${result.installResult.configPath}`);
|
|
137
143
|
}
|
|
138
144
|
// Show restart message for hook connector
|
|
139
|
-
if (
|
|
140
|
-
this.terminal.warn(`\
|
|
145
|
+
if (['hook', 'mcp', 'skill'].includes(result.toType) && !result.installResult.alreadyInstalled) {
|
|
146
|
+
this.terminal.warn(`\n⚠️ Please restart ${agent} to apply the new ${result.toType}.`);
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
else {
|
|
@@ -178,7 +178,7 @@ export class InitUseCase {
|
|
|
178
178
|
this.terminal.log(`${selectedAgent} connected via ${defaultType}`);
|
|
179
179
|
this.terminal.log(` Installed: ${result.configPath}`);
|
|
180
180
|
// Show restart message for hook connector
|
|
181
|
-
if (
|
|
181
|
+
if (['hook', 'mcp', 'skill'].includes(defaultType)) {
|
|
182
182
|
this.terminal.warn(`\n⚠️ Please restart ${selectedAgent} to apply the new ${defaultType}.`);
|
|
183
183
|
}
|
|
184
184
|
}
|
|
@@ -13,6 +13,7 @@ export declare class ResetUseCase implements IResetUseCase {
|
|
|
13
13
|
private readonly terminal;
|
|
14
14
|
constructor(options: ResetUseCaseOptions);
|
|
15
15
|
protected confirmReset(): Promise<boolean>;
|
|
16
|
+
protected deleteContextTree(contextTreeDir: string): Promise<void>;
|
|
16
17
|
run(options: {
|
|
17
18
|
directory?: string;
|
|
18
19
|
skipConfirmation: boolean;
|
|
@@ -17,6 +17,9 @@ export class ResetUseCase {
|
|
|
17
17
|
message: 'Are you sure you want to reset the context tree? This will remove all existing context. Your context tree will be empty.',
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
+
async deleteContextTree(contextTreeDir) {
|
|
21
|
+
await rm(contextTreeDir, { force: true, recursive: true });
|
|
22
|
+
}
|
|
20
23
|
async run(options) {
|
|
21
24
|
try {
|
|
22
25
|
// Check if context tree exists
|
|
@@ -36,7 +39,7 @@ export class ResetUseCase {
|
|
|
36
39
|
// Remove existing context tree directory
|
|
37
40
|
const baseDir = options.directory ?? process.cwd();
|
|
38
41
|
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
39
|
-
await
|
|
42
|
+
await this.deleteContextTree(contextTreeDir);
|
|
40
43
|
// Re-initialize empty context tree
|
|
41
44
|
await this.contextTreeService.initialize(options.directory);
|
|
42
45
|
// Re-initialize empty snapshot
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { ICurateUseCase } from '
|
|
2
|
+
import { ICurateUseCase } from '../../core/interfaces/usecase/i-curate-use-case.js';
|
|
3
3
|
export default class Curate extends Command {
|
|
4
4
|
static args: {
|
|
5
5
|
context: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
-
import { isDevelopment } from '
|
|
3
|
-
import { FileGlobalConfigStore } from '
|
|
4
|
-
import { createTokenStore } from '
|
|
5
|
-
import { OclifTerminal } from '
|
|
6
|
-
import { MixpanelTrackingService } from '
|
|
7
|
-
import { CurateUseCase } from '
|
|
2
|
+
import { isDevelopment } from '../../config/environment.js';
|
|
3
|
+
import { FileGlobalConfigStore } from '../../infra/storage/file-global-config-store.js';
|
|
4
|
+
import { createTokenStore } from '../../infra/storage/token-store.js';
|
|
5
|
+
import { OclifTerminal } from '../../infra/terminal/oclif-terminal.js';
|
|
6
|
+
import { MixpanelTrackingService } from '../../infra/tracking/mixpanel-tracking-service.js';
|
|
7
|
+
import { CurateUseCase } from '../../infra/usecase/curate-use-case.js';
|
|
8
8
|
export default class Curate extends Command {
|
|
9
9
|
static args = {
|
|
10
10
|
context: Args.string({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { ITemplateLoader } from '
|
|
2
|
+
import { ITemplateLoader } from '../../core/interfaces/i-template-loader.js';
|
|
3
3
|
/**
|
|
4
4
|
* Dependencies required by HookPromptSubmit command.
|
|
5
5
|
* Exported for test mocking.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { isDevelopment } from '
|
|
3
|
-
import { FsFileService } from '
|
|
4
|
-
import { FsTemplateLoader } from '
|
|
2
|
+
import { isDevelopment } from '../../config/environment.js';
|
|
3
|
+
import { FsFileService } from '../../infra/file/fs-file-service.js';
|
|
4
|
+
import { FsTemplateLoader } from '../../infra/template/fs-template-loader.js';
|
|
5
5
|
/**
|
|
6
6
|
* Hidden command for coding agent pre-prompt hooks.
|
|
7
7
|
* Outputs ByteRover workflow instructions to stdout.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { DEFAULT_SESSION_RETENTION } from '
|
|
4
|
-
import { SessionMetadataStore } from '
|
|
5
|
-
import { ProjectConfigStore } from '
|
|
6
|
-
import { getProcessManager } from '
|
|
7
|
-
import { startRepl } from '
|
|
8
|
-
import { FileGlobalConfigStore } from '
|
|
9
|
-
import { FileOnboardingPreferenceStore } from '
|
|
10
|
-
import { createTokenStore } from '
|
|
11
|
-
import { MixpanelTrackingService } from '
|
|
12
|
-
import { initSessionLog, processManagerLog } from '
|
|
3
|
+
import { DEFAULT_SESSION_RETENTION } from '../../core/domain/cipher/session/session-metadata.js';
|
|
4
|
+
import { SessionMetadataStore } from '../../infra/cipher/session/session-metadata-store.js';
|
|
5
|
+
import { ProjectConfigStore } from '../../infra/config/file-config-store.js';
|
|
6
|
+
import { getProcessManager } from '../../infra/process/index.js';
|
|
7
|
+
import { startRepl } from '../../infra/repl/repl-startup.js';
|
|
8
|
+
import { FileGlobalConfigStore } from '../../infra/storage/file-global-config-store.js';
|
|
9
|
+
import { FileOnboardingPreferenceStore } from '../../infra/storage/file-onboarding-preference-store.js';
|
|
10
|
+
import { createTokenStore } from '../../infra/storage/token-store.js';
|
|
11
|
+
import { MixpanelTrackingService } from '../../infra/tracking/mixpanel-tracking-service.js';
|
|
12
|
+
import { initSessionLog, processManagerLog } from '../../utils/process-logger.js';
|
|
13
13
|
/**
|
|
14
14
|
* Main command - Entry point for ByteRover CLI.
|
|
15
15
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { NoInstanceRunningError } from '
|
|
3
|
-
import { ByteRoverMcpServer } from '
|
|
2
|
+
import { NoInstanceRunningError } from '../../core/domain/errors/connection-error.js';
|
|
3
|
+
import { ByteRoverMcpServer } from '../../infra/mcp/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* MCP command - starts the MCP server for coding agent integration.
|
|
6
6
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { IQueryUseCase } from '
|
|
2
|
+
import { IQueryUseCase } from '../../core/interfaces/usecase/i-query-use-case.js';
|
|
3
3
|
export default class Query extends Command {
|
|
4
4
|
static args: {
|
|
5
5
|
query: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|