byterover-cli 3.1.0 → 3.2.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/.env.production +4 -0
- package/README.md +17 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +8 -0
- package/dist/agent/infra/agent/agent-schemas.js +1 -0
- package/dist/agent/infra/sandbox/curate-service.js +14 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +1 -0
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +10 -0
- package/dist/agent/infra/sandbox/tools-sdk.js +9 -1
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +214 -101
- package/dist/agent/infra/tools/implementations/write-file-tool.d.ts +2 -1
- package/dist/agent/infra/tools/implementations/write-file-tool.js +16 -2
- package/dist/agent/infra/tools/tool-registry.js +1 -1
- package/dist/agent/infra/tools/write-guard.d.ts +11 -0
- package/dist/agent/infra/tools/write-guard.js +48 -0
- package/dist/agent/resources/prompts/system-prompt.yml +9 -0
- package/dist/agent/resources/tools/expand_knowledge.txt +4 -0
- package/dist/agent/resources/tools/search_knowledge.txt +11 -1
- package/dist/oclif/commands/curate/index.js +4 -3
- package/dist/oclif/commands/curate/view.js +2 -2
- package/dist/oclif/commands/main.js +13 -0
- package/dist/oclif/commands/query.js +4 -3
- package/dist/oclif/commands/source/add.d.ts +12 -0
- package/dist/oclif/commands/source/add.js +42 -0
- package/dist/oclif/commands/source/index.d.ts +6 -0
- package/dist/oclif/commands/source/index.js +8 -0
- package/dist/oclif/commands/source/list.d.ts +6 -0
- package/dist/oclif/commands/source/list.js +32 -0
- package/dist/oclif/commands/source/remove.d.ts +9 -0
- package/dist/oclif/commands/source/remove.js +33 -0
- package/dist/oclif/commands/status.d.ts +5 -1
- package/dist/oclif/commands/status.js +41 -6
- package/dist/oclif/commands/worktree/add.d.ts +12 -0
- package/dist/oclif/commands/worktree/add.js +44 -0
- package/dist/oclif/commands/worktree/index.d.ts +6 -0
- package/dist/oclif/commands/worktree/index.js +8 -0
- package/dist/oclif/commands/worktree/list.d.ts +6 -0
- package/dist/oclif/commands/worktree/list.js +28 -0
- package/dist/oclif/commands/worktree/remove.d.ts +9 -0
- package/dist/oclif/commands/worktree/remove.js +35 -0
- package/dist/oclif/hooks/init/validate-brv-config.js +4 -0
- package/dist/oclif/lib/daemon-client.d.ts +4 -2
- package/dist/oclif/lib/daemon-client.js +19 -3
- package/dist/server/constants.d.ts +6 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/client/client-info.d.ts +7 -0
- package/dist/server/core/domain/client/client-info.js +11 -0
- package/dist/server/core/domain/project/worktrees-schema.d.ts +29 -0
- package/dist/server/core/domain/project/worktrees-schema.js +17 -0
- package/dist/server/core/domain/source/source-operations.d.ts +31 -0
- package/dist/server/core/domain/source/source-operations.js +201 -0
- package/dist/server/core/domain/source/source-schema.d.ts +94 -0
- package/dist/server/core/domain/source/source-schema.js +121 -0
- package/dist/server/core/domain/transport/schemas.d.ts +8 -0
- package/dist/server/core/domain/transport/schemas.js +4 -0
- package/dist/server/core/domain/transport/task-info.d.ts +2 -0
- package/dist/server/core/interfaces/client/i-client-manager.d.ts +13 -0
- package/dist/server/core/interfaces/executor/i-curate-executor.d.ts +4 -0
- package/dist/server/core/interfaces/executor/i-folder-pack-executor.d.ts +7 -3
- package/dist/server/core/interfaces/executor/i-query-executor.d.ts +2 -0
- package/dist/server/infra/client/client-manager.d.ts +1 -0
- package/dist/server/infra/client/client-manager.js +16 -0
- package/dist/server/infra/daemon/agent-process.js +15 -5
- package/dist/server/infra/executor/curate-executor.js +4 -2
- package/dist/server/infra/executor/direct-search-responder.js +5 -1
- package/dist/server/infra/executor/folder-pack-executor.js +23 -12
- package/dist/server/infra/executor/query-executor.d.ts +23 -0
- package/dist/server/infra/executor/query-executor.js +115 -21
- package/dist/server/infra/mcp/mcp-mode-detector.d.ts +7 -5
- package/dist/server/infra/mcp/mcp-mode-detector.js +11 -18
- package/dist/server/infra/mcp/mcp-server.d.ts +1 -0
- package/dist/server/infra/mcp/mcp-server.js +11 -6
- package/dist/server/infra/mcp/tools/brv-curate-tool.d.ts +2 -1
- package/dist/server/infra/mcp/tools/brv-curate-tool.js +9 -16
- package/dist/server/infra/mcp/tools/brv-query-tool.d.ts +2 -1
- package/dist/server/infra/mcp/tools/brv-query-tool.js +9 -16
- package/dist/server/infra/mcp/tools/mcp-project-context.d.ts +11 -0
- package/dist/server/infra/mcp/tools/mcp-project-context.js +54 -0
- package/dist/server/infra/process/connection-coordinator.js +11 -0
- package/dist/server/infra/process/feature-handlers.js +4 -1
- package/dist/server/infra/process/task-router.d.ts +1 -0
- package/dist/server/infra/process/task-router.js +60 -5
- package/dist/server/infra/project/resolve-project.d.ts +106 -0
- package/dist/server/infra/project/resolve-project.js +473 -0
- package/dist/server/infra/transport/handlers/index.d.ts +4 -0
- package/dist/server/infra/transport/handlers/index.js +2 -0
- package/dist/server/infra/transport/handlers/source-handler.d.ts +12 -0
- package/dist/server/infra/transport/handlers/source-handler.js +37 -0
- package/dist/server/infra/transport/handlers/status-handler.js +55 -13
- package/dist/server/infra/transport/handlers/worktree-handler.d.ts +12 -0
- package/dist/server/infra/transport/handlers/worktree-handler.js +67 -0
- package/dist/server/infra/transport/transport-connector.d.ts +10 -4
- package/dist/server/infra/transport/transport-connector.js +2 -2
- package/dist/server/utils/path-utils.d.ts +5 -0
- package/dist/server/utils/path-utils.js +11 -1
- package/dist/shared/transport/events/client-events.d.ts +3 -0
- package/dist/shared/transport/events/client-events.js +3 -0
- package/dist/shared/transport/events/index.d.ts +13 -0
- package/dist/shared/transport/events/index.js +9 -0
- package/dist/shared/transport/events/source-events.d.ts +30 -0
- package/dist/shared/transport/events/source-events.js +5 -0
- package/dist/shared/transport/events/status-events.d.ts +5 -0
- package/dist/shared/transport/events/task-events.d.ts +4 -1
- package/dist/shared/transport/events/worktree-events.d.ts +31 -0
- package/dist/shared/transport/events/worktree-events.js +5 -0
- package/dist/shared/transport/types/dto.d.ts +19 -0
- package/dist/tui/features/commands/definitions/index.js +6 -0
- package/dist/tui/features/commands/definitions/source-add.d.ts +2 -0
- package/dist/tui/features/commands/definitions/source-add.js +48 -0
- package/dist/tui/features/commands/definitions/source-list.d.ts +2 -0
- package/dist/tui/features/commands/definitions/source-list.js +47 -0
- package/dist/tui/features/commands/definitions/source-remove.d.ts +2 -0
- package/dist/tui/features/commands/definitions/source-remove.js +38 -0
- package/dist/tui/features/commands/definitions/source.d.ts +2 -0
- package/dist/tui/features/commands/definitions/source.js +8 -0
- package/dist/tui/features/commands/definitions/worktree-add.d.ts +2 -0
- package/dist/tui/features/commands/definitions/worktree-add.js +35 -0
- package/dist/tui/features/commands/definitions/worktree-list.d.ts +2 -0
- package/dist/tui/features/commands/definitions/worktree-list.js +36 -0
- package/dist/tui/features/commands/definitions/worktree-remove.d.ts +2 -0
- package/dist/tui/features/commands/definitions/worktree-remove.js +33 -0
- package/dist/tui/features/commands/definitions/worktree.d.ts +2 -0
- package/dist/tui/features/commands/definitions/worktree.js +8 -0
- package/dist/tui/features/curate/api/create-curate-task.js +3 -1
- package/dist/tui/features/query/api/create-query-task.js +3 -1
- package/dist/tui/features/source/api/source-api.d.ts +4 -0
- package/dist/tui/features/source/api/source-api.js +22 -0
- package/dist/tui/features/status/api/get-status.js +2 -1
- package/dist/tui/features/status/utils/format-status.js +23 -1
- package/dist/tui/features/transport/components/transport-initializer.js +36 -1
- package/dist/tui/features/worktree/api/worktree-api.d.ts +4 -0
- package/dist/tui/features/worktree/api/worktree-api.js +22 -0
- package/dist/tui/repl-startup.d.ts +2 -0
- package/dist/tui/repl-startup.js +5 -3
- package/dist/tui/stores/transport-store.d.ts +6 -0
- package/dist/tui/stores/transport-store.js +6 -0
- package/oclif.manifest.json +418 -158
- package/package.json +1 -1
|
@@ -11,6 +11,8 @@ export { PullHandler } from './pull-handler.js';
|
|
|
11
11
|
export { PushHandler } from './push-handler.js';
|
|
12
12
|
export { ResetHandler } from './reset-handler.js';
|
|
13
13
|
export { ReviewHandler } from './review-handler.js';
|
|
14
|
+
export { SourceHandler } from './source-handler.js';
|
|
14
15
|
export { SpaceHandler } from './space-handler.js';
|
|
15
16
|
export { StatusHandler } from './status-handler.js';
|
|
16
17
|
export { VcHandler } from './vc-handler.js';
|
|
18
|
+
export { WorktreeHandler } from './worktree-handler.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITransportServer } from '../../../core/interfaces/transport/i-transport-server.js';
|
|
2
|
+
import { type ProjectPathResolver } from './handler-types.js';
|
|
3
|
+
export interface SourceHandlerDeps {
|
|
4
|
+
resolveProjectPath: ProjectPathResolver;
|
|
5
|
+
transport: ITransportServer;
|
|
6
|
+
}
|
|
7
|
+
export declare class SourceHandler {
|
|
8
|
+
private readonly resolveProjectPath;
|
|
9
|
+
private readonly transport;
|
|
10
|
+
constructor(deps: SourceHandlerDeps);
|
|
11
|
+
setup(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SourceEvents, } from '../../../../shared/transport/events/source-events.js';
|
|
2
|
+
import { addSource, listSourceStatuses, removeSource } from '../../../core/domain/source/source-operations.js';
|
|
3
|
+
import { resolveRequiredProjectPath } from './handler-types.js';
|
|
4
|
+
export class SourceHandler {
|
|
5
|
+
resolveProjectPath;
|
|
6
|
+
transport;
|
|
7
|
+
constructor(deps) {
|
|
8
|
+
this.resolveProjectPath = deps.resolveProjectPath;
|
|
9
|
+
this.transport = deps.transport;
|
|
10
|
+
}
|
|
11
|
+
setup() {
|
|
12
|
+
this.transport.onRequest(SourceEvents.ADD, async (data, clientId) => {
|
|
13
|
+
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
14
|
+
const result = addSource(projectPath, data.targetPath, data.alias);
|
|
15
|
+
return {
|
|
16
|
+
message: result.message,
|
|
17
|
+
success: result.success,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
this.transport.onRequest(SourceEvents.REMOVE, async (data, clientId) => {
|
|
21
|
+
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
22
|
+
const result = removeSource(projectPath, data.aliasOrPath);
|
|
23
|
+
return {
|
|
24
|
+
message: result.message,
|
|
25
|
+
success: result.success,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
this.transport.onRequest(SourceEvents.LIST, async (_data, clientId) => {
|
|
29
|
+
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
30
|
+
const result = listSourceStatuses(projectPath);
|
|
31
|
+
return {
|
|
32
|
+
error: result.error,
|
|
33
|
+
statuses: result.statuses,
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -2,6 +2,8 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { StatusEvents } from '../../../../shared/transport/events/status-events.js';
|
|
4
4
|
import { BRV_DIR, CONTEXT_TREE_DIR } from '../../../constants.js';
|
|
5
|
+
import { listSourceStatuses } from '../../../core/domain/source/source-operations.js';
|
|
6
|
+
import { BrokenWorktreePointerError, MalformedWorktreePointerError, resolveProject } from '../../project/resolve-project.js';
|
|
5
7
|
import { resolveRequiredProjectPath } from './handler-types.js';
|
|
6
8
|
/**
|
|
7
9
|
* Handles status:get event.
|
|
@@ -25,18 +27,45 @@ export class StatusHandler {
|
|
|
25
27
|
this.transport = deps.transport;
|
|
26
28
|
}
|
|
27
29
|
setup() {
|
|
28
|
-
this.transport.onRequest(StatusEvents.GET, async (
|
|
30
|
+
this.transport.onRequest(StatusEvents.GET, async (data, clientId) => {
|
|
29
31
|
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
30
|
-
const
|
|
32
|
+
const request = data;
|
|
33
|
+
const cwd = request?.cwd;
|
|
34
|
+
const projectRootFlag = request?.projectRootFlag;
|
|
35
|
+
const status = await this.collectStatus(projectPath, cwd, projectRootFlag);
|
|
31
36
|
return { status };
|
|
32
37
|
});
|
|
33
38
|
}
|
|
34
|
-
async collectStatus(projectPath) {
|
|
39
|
+
async collectStatus(projectPath, clientCwd, projectRootFlag) {
|
|
35
40
|
const result = {
|
|
36
41
|
authStatus: 'unknown',
|
|
37
42
|
contextTreeStatus: 'unknown',
|
|
38
43
|
currentDirectory: projectPath,
|
|
44
|
+
projectRoot: projectPath,
|
|
39
45
|
};
|
|
46
|
+
// Resolve workspace awareness from client cwd (if provided)
|
|
47
|
+
// Use resolved projectRoot for all downstream checks to avoid inconsistency
|
|
48
|
+
let effectiveProjectPath = projectPath;
|
|
49
|
+
if (clientCwd || projectRootFlag) {
|
|
50
|
+
try {
|
|
51
|
+
const resolution = resolveProject({ cwd: clientCwd, projectRootFlag });
|
|
52
|
+
if (resolution) {
|
|
53
|
+
result.projectRoot = resolution.projectRoot;
|
|
54
|
+
result.worktreeRoot = resolution.worktreeRoot;
|
|
55
|
+
result.resolutionSource = resolution.source;
|
|
56
|
+
effectiveProjectPath = resolution.projectRoot;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// Surface broken/malformed link errors as actionable status info
|
|
61
|
+
if (error instanceof BrokenWorktreePointerError || error instanceof MalformedWorktreePointerError) {
|
|
62
|
+
result.resolverError = error.message;
|
|
63
|
+
}
|
|
64
|
+
// Fall through with projectPath defaults for config/context checks
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Preserve actual client working directory for backward compat
|
|
68
|
+
result.currentDirectory = clientCwd ?? projectPath;
|
|
40
69
|
// Auth status
|
|
41
70
|
try {
|
|
42
71
|
const token = await this.tokenStore.load();
|
|
@@ -54,11 +83,11 @@ export class StatusHandler {
|
|
|
54
83
|
catch {
|
|
55
84
|
result.authStatus = 'unknown';
|
|
56
85
|
}
|
|
57
|
-
// Project status
|
|
86
|
+
// Project status — use effectiveProjectPath for consistency with resolved root
|
|
58
87
|
try {
|
|
59
|
-
const isInitialized = await this.projectConfigStore.exists(
|
|
88
|
+
const isInitialized = await this.projectConfigStore.exists(effectiveProjectPath);
|
|
60
89
|
if (isInitialized) {
|
|
61
|
-
const config = await this.projectConfigStore.read(
|
|
90
|
+
const config = await this.projectConfigStore.read(effectiveProjectPath);
|
|
62
91
|
if (config) {
|
|
63
92
|
result.teamName = config.teamName;
|
|
64
93
|
result.spaceName = config.spaceName;
|
|
@@ -75,22 +104,22 @@ export class StatusHandler {
|
|
|
75
104
|
catch {
|
|
76
105
|
// File doesn't exist yet — no queue running
|
|
77
106
|
}
|
|
78
|
-
// Context tree status
|
|
107
|
+
// Context tree status — use effectiveProjectPath for consistency with resolved root
|
|
79
108
|
try {
|
|
80
|
-
const contextTreeExists = await this.contextTreeService.exists(
|
|
109
|
+
const contextTreeExists = await this.contextTreeService.exists(effectiveProjectPath);
|
|
81
110
|
if (contextTreeExists) {
|
|
82
|
-
const hasGitVc = await this.contextTreeService.hasGitRepo(
|
|
111
|
+
const hasGitVc = await this.contextTreeService.hasGitRepo(effectiveProjectPath);
|
|
83
112
|
if (hasGitVc) {
|
|
84
113
|
result.contextTreeStatus = 'git_vc';
|
|
85
114
|
}
|
|
86
115
|
else {
|
|
87
|
-
result.contextTreeDir = join(
|
|
116
|
+
result.contextTreeDir = join(effectiveProjectPath, BRV_DIR, CONTEXT_TREE_DIR);
|
|
88
117
|
result.contextTreeRelativeDir = join(BRV_DIR, CONTEXT_TREE_DIR);
|
|
89
|
-
const hasSnapshot = await this.contextTreeSnapshotService.hasSnapshot(
|
|
118
|
+
const hasSnapshot = await this.contextTreeSnapshotService.hasSnapshot(effectiveProjectPath);
|
|
90
119
|
if (!hasSnapshot) {
|
|
91
|
-
await this.contextTreeSnapshotService.initEmptySnapshot(
|
|
120
|
+
await this.contextTreeSnapshotService.initEmptySnapshot(effectiveProjectPath);
|
|
92
121
|
}
|
|
93
|
-
const changes = await this.contextTreeSnapshotService.getChanges(
|
|
122
|
+
const changes = await this.contextTreeSnapshotService.getChanges(effectiveProjectPath);
|
|
94
123
|
const hasChanges = changes.added.length > 0 || changes.modified.length > 0 || changes.deleted.length > 0;
|
|
95
124
|
if (hasChanges) {
|
|
96
125
|
result.contextTreeStatus = 'has_changes';
|
|
@@ -139,6 +168,19 @@ export class StatusHandler {
|
|
|
139
168
|
catch {
|
|
140
169
|
// Best-effort — if the log is unavailable, skip review info
|
|
141
170
|
}
|
|
171
|
+
// Knowledge sources status
|
|
172
|
+
try {
|
|
173
|
+
const sourcesResult = listSourceStatuses(effectiveProjectPath);
|
|
174
|
+
if (sourcesResult.error) {
|
|
175
|
+
result.sourcesError = sourcesResult.error;
|
|
176
|
+
}
|
|
177
|
+
else if (sourcesResult.statuses.length > 0) {
|
|
178
|
+
result.sources = sourcesResult.statuses;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Best-effort — swallow errors
|
|
183
|
+
}
|
|
142
184
|
return result;
|
|
143
185
|
}
|
|
144
186
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITransportServer } from '../../../core/interfaces/transport/i-transport-server.js';
|
|
2
|
+
import { type ProjectPathResolver } from './handler-types.js';
|
|
3
|
+
export interface WorktreeHandlerDeps {
|
|
4
|
+
resolveProjectPath: ProjectPathResolver;
|
|
5
|
+
transport: ITransportServer;
|
|
6
|
+
}
|
|
7
|
+
export declare class WorktreeHandler {
|
|
8
|
+
private readonly resolveProjectPath;
|
|
9
|
+
private readonly transport;
|
|
10
|
+
constructor(deps: WorktreeHandlerDeps);
|
|
11
|
+
setup(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { WorktreeEvents, } from '../../../../shared/transport/events/worktree-events.js';
|
|
2
|
+
import { addWorktree, findParentProject, listWorktrees, removeWorktree, resolveProject } from '../../project/resolve-project.js';
|
|
3
|
+
import { resolveRequiredProjectPath } from './handler-types.js';
|
|
4
|
+
export class WorktreeHandler {
|
|
5
|
+
resolveProjectPath;
|
|
6
|
+
transport;
|
|
7
|
+
constructor(deps) {
|
|
8
|
+
this.resolveProjectPath = deps.resolveProjectPath;
|
|
9
|
+
this.transport = deps.transport;
|
|
10
|
+
}
|
|
11
|
+
setup() {
|
|
12
|
+
this.transport.onRequest(WorktreeEvents.ADD, async (data, clientId) => {
|
|
13
|
+
// Resolve the parent project from client registration
|
|
14
|
+
let projectPath;
|
|
15
|
+
try {
|
|
16
|
+
projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Client not associated — fall through to auto-detect
|
|
20
|
+
}
|
|
21
|
+
// Auto-detect: if no project resolved, or client's project IS the worktree path
|
|
22
|
+
// (user ran `brv worktree add` from a child dir with no args), walk up to find parent
|
|
23
|
+
if (!projectPath || projectPath === data.worktreePath) {
|
|
24
|
+
const parent = findParentProject(data.worktreePath);
|
|
25
|
+
if (parent) {
|
|
26
|
+
projectPath = parent;
|
|
27
|
+
}
|
|
28
|
+
else if (!projectPath) {
|
|
29
|
+
return { message: 'No parent project found for the target directory.', success: false };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const result = addWorktree(projectPath, data.worktreePath, { force: data.force });
|
|
33
|
+
return {
|
|
34
|
+
backedUp: result.backedUp,
|
|
35
|
+
message: result.message,
|
|
36
|
+
success: result.success,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
this.transport.onRequest(WorktreeEvents.REMOVE, async (data) => {
|
|
40
|
+
const targetPath = data.worktreePath;
|
|
41
|
+
const result = removeWorktree(targetPath);
|
|
42
|
+
return {
|
|
43
|
+
message: result.message,
|
|
44
|
+
success: result.success,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
this.transport.onRequest(WorktreeEvents.LIST, async (_data, clientId) => {
|
|
48
|
+
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
49
|
+
const resolution = resolveProject({ cwd: projectPath });
|
|
50
|
+
if (!resolution) {
|
|
51
|
+
return {
|
|
52
|
+
projectRoot: projectPath,
|
|
53
|
+
source: 'direct',
|
|
54
|
+
worktreeRoot: projectPath,
|
|
55
|
+
worktrees: [],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const worktrees = listWorktrees(resolution.projectRoot);
|
|
59
|
+
return {
|
|
60
|
+
projectRoot: resolution.projectRoot,
|
|
61
|
+
source: resolution.source,
|
|
62
|
+
worktreeRoot: resolution.worktreeRoot,
|
|
63
|
+
worktrees,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { type ConnectionResult } from '@campfirein/brv-transport-client';
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Function type for transport connection (for DI/testing in use cases).
|
|
4
|
+
*
|
|
5
|
+
* Callers must pass an explicit resolved projectPath. This avoids silently
|
|
6
|
+
* falling back to the transport library's own walk-up discovery, which is
|
|
7
|
+
* not workspace-link-aware.
|
|
8
|
+
*/
|
|
9
|
+
export type TransportConnector = (fromDir: string | undefined, projectPath: string) => Promise<ConnectionResult>;
|
|
4
10
|
/**
|
|
5
11
|
* Creates a transport connector that auto-starts the daemon if needed.
|
|
6
12
|
*
|
|
7
13
|
* Thin wrapper around connectToDaemon() for DI compatibility with use cases
|
|
8
14
|
* (QueryUseCase, CurateUseCase, StatusUseCase).
|
|
9
15
|
*
|
|
10
|
-
* projectPath is
|
|
11
|
-
*
|
|
16
|
+
* When an explicit projectPath is provided it takes priority over the
|
|
17
|
+
* transport library's walk-up discovery, making the connector workspace-link-aware.
|
|
12
18
|
*/
|
|
13
19
|
export declare function createDaemonAwareConnector(projectPath?: string): TransportConnector;
|
|
@@ -6,8 +6,8 @@ import { resolveLocalServerMainPath } from '../../utils/server-main-resolver.js'
|
|
|
6
6
|
* Thin wrapper around connectToDaemon() for DI compatibility with use cases
|
|
7
7
|
* (QueryUseCase, CurateUseCase, StatusUseCase).
|
|
8
8
|
*
|
|
9
|
-
* projectPath is
|
|
10
|
-
*
|
|
9
|
+
* When an explicit projectPath is provided it takes priority over the
|
|
10
|
+
* transport library's walk-up discovery, making the connector workspace-link-aware.
|
|
11
11
|
*/
|
|
12
12
|
export function createDaemonAwareConnector(projectPath) {
|
|
13
13
|
return (fromDir) => connectToDaemon({
|
|
@@ -36,3 +36,8 @@ export declare const sanitizeProjectPath: (resolvedPath: string) => string;
|
|
|
36
36
|
* @returns Absolute path to the project's data directory
|
|
37
37
|
*/
|
|
38
38
|
export declare const getProjectDataDir: (cwd: string) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Checks that candidate is an ancestor of (or equal to) descendant.
|
|
41
|
+
* Both paths are normalized via resolve() before comparison.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isDescendantOf(descendant: string, ancestor: string): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { realpathSync } from 'node:fs';
|
|
3
|
-
import { join } from 'node:path';
|
|
3
|
+
import { join, resolve, sep } from 'node:path';
|
|
4
4
|
import { GLOBAL_PROJECTS_DIR } from '../constants.js';
|
|
5
5
|
import { getGlobalDataDir } from './global-data-path.js';
|
|
6
6
|
/**
|
|
@@ -90,3 +90,13 @@ export const getProjectDataDir = (cwd) => {
|
|
|
90
90
|
const sanitized = sanitizeProjectPath(resolved);
|
|
91
91
|
return join(getGlobalDataDir(), GLOBAL_PROJECTS_DIR, sanitized);
|
|
92
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Checks that candidate is an ancestor of (or equal to) descendant.
|
|
95
|
+
* Both paths are normalized via resolve() before comparison.
|
|
96
|
+
*/
|
|
97
|
+
export function isDescendantOf(descendant, ancestor) {
|
|
98
|
+
const normalizedDescendant = resolve(descendant);
|
|
99
|
+
const normalizedAncestor = resolve(ancestor);
|
|
100
|
+
const ancestorPrefix = normalizedAncestor.endsWith(sep) ? normalizedAncestor : normalizedAncestor + sep;
|
|
101
|
+
return normalizedDescendant === normalizedAncestor || normalizedDescendant.startsWith(ancestorPrefix);
|
|
102
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from '../types/dto.js';
|
|
2
2
|
export * from './agent-events.js';
|
|
3
3
|
export * from './auth-events.js';
|
|
4
|
+
export * from './client-events.js';
|
|
4
5
|
export * from './config-events.js';
|
|
5
6
|
export * from './connector-events.js';
|
|
6
7
|
export * from './hub-events.js';
|
|
@@ -15,9 +16,11 @@ export * from './push-events.js';
|
|
|
15
16
|
export * from './reset-events.js';
|
|
16
17
|
export * from './review-events.js';
|
|
17
18
|
export * from './session-events.js';
|
|
19
|
+
export * from './source-events.js';
|
|
18
20
|
export * from './space-events.js';
|
|
19
21
|
export * from './status-events.js';
|
|
20
22
|
export * from './task-events.js';
|
|
23
|
+
export * from './worktree-events.js';
|
|
21
24
|
/**
|
|
22
25
|
* Array of all event group objects for iteration.
|
|
23
26
|
* Use this to subscribe to all events without key collisions.
|
|
@@ -41,6 +44,8 @@ export declare const AllEventGroups: readonly [{
|
|
|
41
44
|
readonly START_LOGIN: "auth:startLogin";
|
|
42
45
|
readonly STATE_CHANGED: "auth:stateChanged";
|
|
43
46
|
readonly UPDATED: "auth:updated";
|
|
47
|
+
}, {
|
|
48
|
+
readonly ASSOCIATE_PROJECT: "client:associateProject";
|
|
44
49
|
}, {
|
|
45
50
|
readonly GET_ENVIRONMENT: "config:getEnvironment";
|
|
46
51
|
readonly GET_PROJECT: "config:getProject";
|
|
@@ -117,6 +122,10 @@ export declare const AllEventGroups: readonly [{
|
|
|
117
122
|
readonly SWITCHED: "session:switched";
|
|
118
123
|
}, {
|
|
119
124
|
readonly GET: "locations:get";
|
|
125
|
+
}, {
|
|
126
|
+
readonly ADD: "source:add";
|
|
127
|
+
readonly LIST: "source:list";
|
|
128
|
+
readonly REMOVE: "source:remove";
|
|
120
129
|
}, {
|
|
121
130
|
readonly LIST: "space:list";
|
|
122
131
|
readonly SWITCH: "space:switch";
|
|
@@ -130,6 +139,10 @@ export declare const AllEventGroups: readonly [{
|
|
|
130
139
|
readonly CREATED: "task:created";
|
|
131
140
|
readonly ERROR: "task:error";
|
|
132
141
|
readonly STARTED: "task:started";
|
|
142
|
+
}, {
|
|
143
|
+
readonly ADD: "worktree:add";
|
|
144
|
+
readonly LIST: "worktree:list";
|
|
145
|
+
readonly REMOVE: "worktree:remove";
|
|
133
146
|
}];
|
|
134
147
|
/**
|
|
135
148
|
* Get all unique event values from all event groups.
|
|
@@ -3,6 +3,7 @@ export * from '../types/dto.js';
|
|
|
3
3
|
// Event constants and types
|
|
4
4
|
export * from './agent-events.js';
|
|
5
5
|
export * from './auth-events.js';
|
|
6
|
+
export * from './client-events.js';
|
|
6
7
|
export * from './config-events.js';
|
|
7
8
|
export * from './connector-events.js';
|
|
8
9
|
export * from './hub-events.js';
|
|
@@ -17,12 +18,15 @@ export * from './push-events.js';
|
|
|
17
18
|
export * from './reset-events.js';
|
|
18
19
|
export * from './review-events.js';
|
|
19
20
|
export * from './session-events.js';
|
|
21
|
+
export * from './source-events.js';
|
|
20
22
|
export * from './space-events.js';
|
|
21
23
|
export * from './status-events.js';
|
|
22
24
|
export * from './task-events.js';
|
|
25
|
+
export * from './worktree-events.js';
|
|
23
26
|
// Utility exports
|
|
24
27
|
import { AgentEvents } from './agent-events.js';
|
|
25
28
|
import { AuthEvents } from './auth-events.js';
|
|
29
|
+
import { ClientEvents } from './client-events.js';
|
|
26
30
|
import { ConfigEvents } from './config-events.js';
|
|
27
31
|
import { ConnectorEvents } from './connector-events.js';
|
|
28
32
|
import { HubEvents } from './hub-events.js';
|
|
@@ -37,9 +41,11 @@ import { PushEvents } from './push-events.js';
|
|
|
37
41
|
import { ResetEvents } from './reset-events.js';
|
|
38
42
|
import { ReviewEvents } from './review-events.js';
|
|
39
43
|
import { SessionEvents } from './session-events.js';
|
|
44
|
+
import { SourceEvents } from './source-events.js';
|
|
40
45
|
import { SpaceEvents } from './space-events.js';
|
|
41
46
|
import { StatusEvents } from './status-events.js';
|
|
42
47
|
import { TaskEvents } from './task-events.js';
|
|
48
|
+
import { WorktreeEvents } from './worktree-events.js';
|
|
43
49
|
/**
|
|
44
50
|
* Array of all event group objects for iteration.
|
|
45
51
|
* Use this to subscribe to all events without key collisions.
|
|
@@ -47,6 +53,7 @@ import { TaskEvents } from './task-events.js';
|
|
|
47
53
|
export const AllEventGroups = [
|
|
48
54
|
AgentEvents,
|
|
49
55
|
AuthEvents,
|
|
56
|
+
ClientEvents,
|
|
50
57
|
ConfigEvents,
|
|
51
58
|
ConnectorEvents,
|
|
52
59
|
HubEvents,
|
|
@@ -61,9 +68,11 @@ export const AllEventGroups = [
|
|
|
61
68
|
ReviewEvents,
|
|
62
69
|
SessionEvents,
|
|
63
70
|
LocationsEvents,
|
|
71
|
+
SourceEvents,
|
|
64
72
|
SpaceEvents,
|
|
65
73
|
StatusEvents,
|
|
66
74
|
TaskEvents,
|
|
75
|
+
WorktreeEvents,
|
|
67
76
|
];
|
|
68
77
|
/**
|
|
69
78
|
* Get all unique event values from all event groups.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const SourceEvents: {
|
|
2
|
+
readonly ADD: "source:add";
|
|
3
|
+
readonly LIST: "source:list";
|
|
4
|
+
readonly REMOVE: "source:remove";
|
|
5
|
+
};
|
|
6
|
+
export interface SourceAddRequest {
|
|
7
|
+
alias?: string;
|
|
8
|
+
targetPath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SourceAddResponse {
|
|
11
|
+
message: string;
|
|
12
|
+
success: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SourceRemoveRequest {
|
|
15
|
+
aliasOrPath: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SourceRemoveResponse {
|
|
18
|
+
message: string;
|
|
19
|
+
success: boolean;
|
|
20
|
+
}
|
|
21
|
+
export type SourceListRequest = void;
|
|
22
|
+
export interface SourceListResponse {
|
|
23
|
+
error?: string;
|
|
24
|
+
statuses: Array<{
|
|
25
|
+
alias: string;
|
|
26
|
+
contextTreeSize?: number;
|
|
27
|
+
projectRoot: string;
|
|
28
|
+
valid: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
@@ -2,6 +2,11 @@ import type { StatusDTO } from '../types/dto.js';
|
|
|
2
2
|
export declare const StatusEvents: {
|
|
3
3
|
readonly GET: "status:get";
|
|
4
4
|
};
|
|
5
|
+
export interface StatusGetRequest {
|
|
6
|
+
cwd?: string;
|
|
7
|
+
projectRootFlag?: string;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
}
|
|
5
10
|
export interface StatusGetResponse {
|
|
6
11
|
status: StatusDTO;
|
|
7
12
|
}
|
|
@@ -11,8 +11,11 @@ export interface TaskCreateRequest {
|
|
|
11
11
|
clientCwd?: string;
|
|
12
12
|
content: string;
|
|
13
13
|
files?: string[];
|
|
14
|
+
folderPath?: string;
|
|
15
|
+
projectPath?: string;
|
|
14
16
|
taskId: string;
|
|
15
|
-
type: 'curate' | 'query';
|
|
17
|
+
type: 'curate' | 'curate-folder' | 'query';
|
|
18
|
+
worktreeRoot?: string;
|
|
16
19
|
}
|
|
17
20
|
export interface TaskAckResponse {
|
|
18
21
|
taskId: string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const WorktreeEvents: {
|
|
2
|
+
readonly ADD: "worktree:add";
|
|
3
|
+
readonly LIST: "worktree:list";
|
|
4
|
+
readonly REMOVE: "worktree:remove";
|
|
5
|
+
};
|
|
6
|
+
export interface WorktreeAddRequest {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
worktreePath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface WorktreeAddResponse {
|
|
11
|
+
backedUp?: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
success: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface WorktreeRemoveRequest {
|
|
16
|
+
worktreePath: string;
|
|
17
|
+
}
|
|
18
|
+
export interface WorktreeRemoveResponse {
|
|
19
|
+
message: string;
|
|
20
|
+
success: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type WorktreeListRequest = void;
|
|
23
|
+
export interface WorktreeListResponse {
|
|
24
|
+
projectRoot: string;
|
|
25
|
+
source: 'direct' | 'flag' | 'linked';
|
|
26
|
+
worktreeRoot: string;
|
|
27
|
+
worktrees: Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
worktreePath: string;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
@@ -102,6 +102,12 @@ export interface HubEntryDTO {
|
|
|
102
102
|
type: 'agent-skill' | 'bundle';
|
|
103
103
|
version: string;
|
|
104
104
|
}
|
|
105
|
+
export interface SourceStatusDTO {
|
|
106
|
+
alias: string;
|
|
107
|
+
contextTreeSize?: number;
|
|
108
|
+
projectRoot: string;
|
|
109
|
+
valid: boolean;
|
|
110
|
+
}
|
|
105
111
|
export interface ProjectLocationDTO {
|
|
106
112
|
/** Absolute path to the context tree directory (e.g., '/Users/foo/project/.brv/context-tree') */
|
|
107
113
|
contextTreePath: string;
|
|
@@ -128,12 +134,25 @@ export interface StatusDTO {
|
|
|
128
134
|
/** Relative path to the context tree directory from project root (e.g., '.brv/context-tree') */
|
|
129
135
|
contextTreeRelativeDir?: string;
|
|
130
136
|
contextTreeStatus: 'git_vc' | 'has_changes' | 'no_changes' | 'not_initialized' | 'unknown';
|
|
137
|
+
/** @deprecated Use projectRoot instead. Kept for backward compatibility. */
|
|
131
138
|
currentDirectory: string;
|
|
132
139
|
/** Number of files with pending HITL review (0 if none or unavailable). */
|
|
133
140
|
pendingReviewCount?: number;
|
|
141
|
+
/** Absolute path to the project root (directory containing .brv/) */
|
|
142
|
+
projectRoot?: string;
|
|
143
|
+
/** How the project root was discovered */
|
|
144
|
+
resolutionSource?: 'direct' | 'flag' | 'linked';
|
|
145
|
+
/** Actionable error message when resolver fails (broken/malformed worktree pointer) */
|
|
146
|
+
resolverError?: string;
|
|
134
147
|
/** URL to the local review UI (only set when pendingReviewCount > 0). */
|
|
135
148
|
reviewUrl?: string;
|
|
149
|
+
/** Knowledge sources from other projects' context trees (read-only) */
|
|
150
|
+
sources?: SourceStatusDTO[];
|
|
151
|
+
/** Error message when sources.json is malformed */
|
|
152
|
+
sourcesError?: string;
|
|
136
153
|
spaceName?: string;
|
|
137
154
|
teamName?: string;
|
|
138
155
|
userEmail?: string;
|
|
156
|
+
/** Stable workspace root (link directory), or projectRoot if unlinked */
|
|
157
|
+
worktreeRoot?: string;
|
|
139
158
|
}
|
|
@@ -12,9 +12,11 @@ import { pullCommand } from './pull.js';
|
|
|
12
12
|
import { pushCommand } from './push.js';
|
|
13
13
|
import { queryCommand } from './query.js';
|
|
14
14
|
import { resetCommand } from './reset.js';
|
|
15
|
+
import { sourceCommand } from './source.js';
|
|
15
16
|
import { spaceCommand } from './space.js';
|
|
16
17
|
import { statusCommand } from './status.js';
|
|
17
18
|
import { vcCommand } from './vc.js';
|
|
19
|
+
import { worktreeCommand } from './worktree.js';
|
|
18
20
|
/**
|
|
19
21
|
* Load all REPL slash commands.
|
|
20
22
|
*
|
|
@@ -41,6 +43,10 @@ export const load = () => [
|
|
|
41
43
|
spaceCommand,
|
|
42
44
|
// Git semantic (vc commands)
|
|
43
45
|
vcCommand,
|
|
46
|
+
// Workspace management
|
|
47
|
+
worktreeCommand,
|
|
48
|
+
// Knowledge sources
|
|
49
|
+
sourceCommand,
|
|
44
50
|
// Context tree management
|
|
45
51
|
resetCommand,
|
|
46
52
|
// Session management
|