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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { addSourceViaTransport } from '../../source/api/source-api.js';
|
|
3
|
+
import { Flags, parseReplArgs, toCommandFlags } from '../utils/arg-parser.js';
|
|
4
|
+
const sourceAddFlags = {
|
|
5
|
+
alias: Flags.string({
|
|
6
|
+
description: 'Custom alias for the source (defaults to directory name)',
|
|
7
|
+
}),
|
|
8
|
+
};
|
|
9
|
+
export const sourceAddSubCommand = {
|
|
10
|
+
async action(_context, args) {
|
|
11
|
+
const parsed = await parseReplArgs(args ?? '', { flags: sourceAddFlags, strict: false });
|
|
12
|
+
const targetArg = parsed.argv[0];
|
|
13
|
+
if (!targetArg) {
|
|
14
|
+
return {
|
|
15
|
+
content: 'Usage: /source add <path-to-project> [--alias <name>]',
|
|
16
|
+
messageType: 'error',
|
|
17
|
+
type: 'message',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const targetPath = resolve(targetArg);
|
|
21
|
+
try {
|
|
22
|
+
const result = await addSourceViaTransport(targetPath, parsed.flags.alias);
|
|
23
|
+
return {
|
|
24
|
+
content: result.message,
|
|
25
|
+
messageType: 'error',
|
|
26
|
+
type: 'message',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
return {
|
|
32
|
+
content: `Source add failed: ${message}`,
|
|
33
|
+
messageType: 'error',
|
|
34
|
+
type: 'message',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
args: [
|
|
39
|
+
{
|
|
40
|
+
description: 'Path to the target project containing .brv/',
|
|
41
|
+
name: 'path',
|
|
42
|
+
required: true,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
description: "Add a read-only knowledge source from another project's context tree",
|
|
46
|
+
flags: toCommandFlags(sourceAddFlags),
|
|
47
|
+
name: 'add',
|
|
48
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { listSourcesViaTransport } from '../../source/api/source-api.js';
|
|
3
|
+
export const sourceListSubCommand = {
|
|
4
|
+
async action() {
|
|
5
|
+
try {
|
|
6
|
+
const result = await listSourcesViaTransport();
|
|
7
|
+
if (result.error) {
|
|
8
|
+
return {
|
|
9
|
+
content: result.error,
|
|
10
|
+
messageType: 'error',
|
|
11
|
+
type: 'message',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (result.statuses.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
content: 'No knowledge sources configured.',
|
|
17
|
+
messageType: 'error',
|
|
18
|
+
type: 'message',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const lines = ['Knowledge Sources:'];
|
|
22
|
+
for (const source of result.statuses) {
|
|
23
|
+
if (source.valid) {
|
|
24
|
+
lines.push(` ${source.alias} → ${source.projectRoot} ${chalk.green('(valid)')}`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
lines.push(` ${source.alias} → ${source.projectRoot} ${chalk.red(`[BROKEN - run /source remove ${source.alias}]`)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
content: lines.join('\n'),
|
|
32
|
+
messageType: 'error',
|
|
33
|
+
type: 'message',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
return {
|
|
39
|
+
content: `Source list failed: ${message}`,
|
|
40
|
+
messageType: 'error',
|
|
41
|
+
type: 'message',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
description: 'List all knowledge sources and their status',
|
|
46
|
+
name: 'list',
|
|
47
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { removeSourceViaTransport } from '../../source/api/source-api.js';
|
|
2
|
+
export const sourceRemoveSubCommand = {
|
|
3
|
+
async action(_context, args) {
|
|
4
|
+
const argTrimmed = args?.trim();
|
|
5
|
+
if (!argTrimmed) {
|
|
6
|
+
return {
|
|
7
|
+
content: 'Usage: /source remove <alias-or-path>',
|
|
8
|
+
messageType: 'error',
|
|
9
|
+
type: 'message',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const result = await removeSourceViaTransport(argTrimmed);
|
|
14
|
+
return {
|
|
15
|
+
content: result.message,
|
|
16
|
+
messageType: 'error',
|
|
17
|
+
type: 'message',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
+
return {
|
|
23
|
+
content: `Source remove failed: ${message}`,
|
|
24
|
+
messageType: 'error',
|
|
25
|
+
type: 'message',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
args: [
|
|
30
|
+
{
|
|
31
|
+
description: 'Alias or path of the knowledge source to remove',
|
|
32
|
+
name: 'aliasOrPath',
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
description: 'Remove a knowledge source',
|
|
37
|
+
name: 'remove',
|
|
38
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { sourceAddSubCommand } from './source-add.js';
|
|
2
|
+
import { sourceListSubCommand } from './source-list.js';
|
|
3
|
+
import { sourceRemoveSubCommand } from './source-remove.js';
|
|
4
|
+
export const sourceCommand = {
|
|
5
|
+
description: "Manage knowledge sources from other projects' context trees",
|
|
6
|
+
name: 'source',
|
|
7
|
+
subCommands: [sourceAddSubCommand, sourceRemoveSubCommand, sourceListSubCommand],
|
|
8
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { addWorktreeViaTransport } from '../../worktree/api/worktree-api.js';
|
|
3
|
+
export const worktreeAddSubCommand = {
|
|
4
|
+
async action(_context, args) {
|
|
5
|
+
const cwd = resolve(process.cwd());
|
|
6
|
+
const argTrimmed = args?.trim();
|
|
7
|
+
// Resolve worktree path: if argument provided, resolve relative to cwd; otherwise use cwd itself
|
|
8
|
+
const worktreePath = argTrimmed ? resolve(argTrimmed) : cwd;
|
|
9
|
+
try {
|
|
10
|
+
const result = await addWorktreeViaTransport(worktreePath, true);
|
|
11
|
+
return {
|
|
12
|
+
content: result.success ? result.message + ' Run /status to verify.' : result.message,
|
|
13
|
+
messageType: 'error',
|
|
14
|
+
type: 'message',
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19
|
+
return {
|
|
20
|
+
content: `Worktree add failed: ${message}`,
|
|
21
|
+
messageType: 'error',
|
|
22
|
+
type: 'message',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
args: [
|
|
27
|
+
{
|
|
28
|
+
description: 'Path to the directory to register as a worktree (auto-detects parent if omitted)',
|
|
29
|
+
name: 'path',
|
|
30
|
+
required: false,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
description: 'Register a directory as a worktree of a project',
|
|
34
|
+
name: 'add',
|
|
35
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { listWorktreesViaTransport } from '../../worktree/api/worktree-api.js';
|
|
2
|
+
export const worktreeListSubCommand = {
|
|
3
|
+
async action() {
|
|
4
|
+
try {
|
|
5
|
+
const result = await listWorktreesViaTransport();
|
|
6
|
+
const lines = [];
|
|
7
|
+
if (result.source === 'linked') {
|
|
8
|
+
lines.push(`Worktree: ${result.worktreeRoot}`, `Linked to: ${result.projectRoot}`);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
lines.push(`Project: ${result.projectRoot}`);
|
|
12
|
+
}
|
|
13
|
+
if (result.worktrees.length > 0) {
|
|
14
|
+
lines.push('', 'Registered worktrees:');
|
|
15
|
+
for (const wt of result.worktrees) {
|
|
16
|
+
lines.push(` ${wt.name} → ${wt.worktreePath}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
content: lines.join('\n'),
|
|
21
|
+
messageType: 'error',
|
|
22
|
+
type: 'message',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27
|
+
return {
|
|
28
|
+
content: `Worktree list failed: ${message}`,
|
|
29
|
+
messageType: 'error',
|
|
30
|
+
type: 'message',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
description: 'Show the current worktree link and list all registered worktrees',
|
|
35
|
+
name: 'list',
|
|
36
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { removeWorktreeViaTransport } from '../../worktree/api/worktree-api.js';
|
|
3
|
+
export const worktreeRemoveSubCommand = {
|
|
4
|
+
async action(_context, args) {
|
|
5
|
+
const argTrimmed = args?.trim();
|
|
6
|
+
const targetPath = argTrimmed ? resolve(argTrimmed) : resolve(process.cwd());
|
|
7
|
+
try {
|
|
8
|
+
const result = await removeWorktreeViaTransport(targetPath);
|
|
9
|
+
return {
|
|
10
|
+
content: result.message,
|
|
11
|
+
messageType: 'error',
|
|
12
|
+
type: 'message',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
return {
|
|
18
|
+
content: `Worktree remove failed: ${message}`,
|
|
19
|
+
messageType: 'error',
|
|
20
|
+
type: 'message',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
args: [
|
|
25
|
+
{
|
|
26
|
+
description: 'Path to the worktree to remove (defaults to current directory)',
|
|
27
|
+
name: 'path',
|
|
28
|
+
required: false,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
description: 'Remove a worktree registration',
|
|
32
|
+
name: 'remove',
|
|
33
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { worktreeAddSubCommand } from './worktree-add.js';
|
|
2
|
+
import { worktreeListSubCommand } from './worktree-list.js';
|
|
3
|
+
import { worktreeRemoveSubCommand } from './worktree-remove.js';
|
|
4
|
+
export const worktreeCommand = {
|
|
5
|
+
description: 'Manage worktree links for nested directories',
|
|
6
|
+
name: 'worktree',
|
|
7
|
+
subCommands: [worktreeAddSubCommand, worktreeRemoveSubCommand, worktreeListSubCommand],
|
|
8
|
+
};
|
|
@@ -15,7 +15,7 @@ import { useTransportStore } from '../../../stores/transport-store.js';
|
|
|
15
15
|
* triggers the FolderPackExecutor on the server for full directory analysis.
|
|
16
16
|
*/
|
|
17
17
|
export const createCurateTask = async ({ content, files, folders }) => {
|
|
18
|
-
const { apiClient } = useTransportStore.getState();
|
|
18
|
+
const { apiClient, projectPath, worktreeRoot } = useTransportStore.getState();
|
|
19
19
|
if (!apiClient) {
|
|
20
20
|
throw new Error('Not connected to server');
|
|
21
21
|
}
|
|
@@ -33,8 +33,10 @@ export const createCurateTask = async ({ content, files, folders }) => {
|
|
|
33
33
|
content: resolvedContent,
|
|
34
34
|
...(hasFolder && folders ? { folderPath: folders[0] } : {}),
|
|
35
35
|
...(!hasFolder && files && files.length > 0 ? { files } : {}),
|
|
36
|
+
...(projectPath ? { projectPath } : {}),
|
|
36
37
|
taskId,
|
|
37
38
|
type: taskType,
|
|
39
|
+
...(worktreeRoot ? { worktreeRoot } : {}),
|
|
38
40
|
});
|
|
39
41
|
return { taskId };
|
|
40
42
|
};
|
|
@@ -12,7 +12,7 @@ import { useTransportStore } from '../../../stores/transport-store.js';
|
|
|
12
12
|
* Returns immediately after task is acknowledged - actual execution is async.
|
|
13
13
|
*/
|
|
14
14
|
export const createQueryTask = async ({ query }) => {
|
|
15
|
-
const { apiClient } = useTransportStore.getState();
|
|
15
|
+
const { apiClient, projectPath, worktreeRoot } = useTransportStore.getState();
|
|
16
16
|
if (!apiClient) {
|
|
17
17
|
throw new Error('Not connected to server');
|
|
18
18
|
}
|
|
@@ -20,8 +20,10 @@ export const createQueryTask = async ({ query }) => {
|
|
|
20
20
|
await apiClient.request(TaskEvents.CREATE, {
|
|
21
21
|
clientCwd: process.cwd(),
|
|
22
22
|
content: query,
|
|
23
|
+
...(projectPath ? { projectPath } : {}),
|
|
23
24
|
taskId,
|
|
24
25
|
type: 'query',
|
|
26
|
+
...(worktreeRoot ? { worktreeRoot } : {}),
|
|
25
27
|
});
|
|
26
28
|
return { taskId };
|
|
27
29
|
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type SourceAddResponse, type SourceListResponse, type SourceRemoveResponse } from '../../../../shared/transport/events/source-events.js';
|
|
2
|
+
export declare const addSourceViaTransport: (targetPath: string, alias?: string) => Promise<SourceAddResponse>;
|
|
3
|
+
export declare const removeSourceViaTransport: (aliasOrPath: string) => Promise<SourceRemoveResponse>;
|
|
4
|
+
export declare const listSourcesViaTransport: () => Promise<SourceListResponse>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SourceEvents, } from '../../../../shared/transport/events/source-events.js';
|
|
2
|
+
import { useTransportStore } from '../../../stores/transport-store.js';
|
|
3
|
+
export const addSourceViaTransport = (targetPath, alias) => {
|
|
4
|
+
const { apiClient } = useTransportStore.getState();
|
|
5
|
+
if (!apiClient)
|
|
6
|
+
return Promise.reject(new Error('Not connected'));
|
|
7
|
+
const request = { alias, targetPath };
|
|
8
|
+
return apiClient.request(SourceEvents.ADD, request);
|
|
9
|
+
};
|
|
10
|
+
export const removeSourceViaTransport = (aliasOrPath) => {
|
|
11
|
+
const { apiClient } = useTransportStore.getState();
|
|
12
|
+
if (!apiClient)
|
|
13
|
+
return Promise.reject(new Error('Not connected'));
|
|
14
|
+
const request = { aliasOrPath };
|
|
15
|
+
return apiClient.request(SourceEvents.REMOVE, request);
|
|
16
|
+
};
|
|
17
|
+
export const listSourcesViaTransport = () => {
|
|
18
|
+
const { apiClient } = useTransportStore.getState();
|
|
19
|
+
if (!apiClient)
|
|
20
|
+
return Promise.reject(new Error('Not connected'));
|
|
21
|
+
return apiClient.request(SourceEvents.LIST);
|
|
22
|
+
};
|
|
@@ -5,7 +5,8 @@ export const getStatus = () => {
|
|
|
5
5
|
const { apiClient } = useTransportStore.getState();
|
|
6
6
|
if (!apiClient)
|
|
7
7
|
return Promise.reject(new Error('Not connected'));
|
|
8
|
-
|
|
8
|
+
const request = { cwd: process.cwd() };
|
|
9
|
+
return apiClient.request(StatusEvents.GET, request);
|
|
9
10
|
};
|
|
10
11
|
export const getStatusQueryOptions = () => queryOptions({
|
|
11
12
|
queryFn: getStatus,
|
|
@@ -22,13 +22,35 @@ export function formatStatus(status, version) {
|
|
|
22
22
|
lines.push('Account: Unable to check');
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
lines.push(`
|
|
25
|
+
lines.push(`Project: ${status.projectRoot ?? status.currentDirectory}`);
|
|
26
|
+
if (status.worktreeRoot && status.worktreeRoot !== status.projectRoot) {
|
|
27
|
+
lines.push(`Worktree: ${status.worktreeRoot} (linked)`);
|
|
28
|
+
}
|
|
29
|
+
if (status.resolverError) {
|
|
30
|
+
lines.push(chalk.yellow(`⚠ ${status.resolverError}`));
|
|
31
|
+
}
|
|
26
32
|
if (status.teamName && status.spaceName) {
|
|
27
33
|
lines.push(`Space: ${status.teamName}/${status.spaceName}`);
|
|
28
34
|
}
|
|
29
35
|
else {
|
|
30
36
|
lines.push('Space: Not connected');
|
|
31
37
|
}
|
|
38
|
+
// Knowledge sources
|
|
39
|
+
if (status.sourcesError) {
|
|
40
|
+
lines.push(chalk.yellow(`⚠ ${status.sourcesError}`));
|
|
41
|
+
}
|
|
42
|
+
else if (status.sources && status.sources.length > 0) {
|
|
43
|
+
lines.push('Knowledge Sources:');
|
|
44
|
+
for (const source of status.sources) {
|
|
45
|
+
if (source.valid) {
|
|
46
|
+
const sizeInfo = source.contextTreeSize === undefined ? '' : ` [${source.contextTreeSize} files]`;
|
|
47
|
+
lines.push(` ${source.alias} → ${source.projectRoot} ${chalk.green('(valid)')}${sizeInfo}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push(` ${source.alias} → ${source.projectRoot} ${chalk.red(`[BROKEN - run brv source remove ${source.alias}]`)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
32
54
|
switch (status.contextTreeStatus) {
|
|
33
55
|
case 'git_vc': {
|
|
34
56
|
lines.push('Context Tree: Byterover version control (use /vc commands)');
|
|
@@ -8,6 +8,8 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
8
8
|
*/
|
|
9
9
|
import { connectToDaemon, createDaemonReconnector, } from '@campfirein/brv-transport-client';
|
|
10
10
|
import { useEffect } from 'react';
|
|
11
|
+
// eslint-disable-next-line no-restricted-imports -- fallback resolver when store has no projectPath
|
|
12
|
+
import { resolveProject } from '../../../../server/infra/project/resolve-project.js';
|
|
11
13
|
import { getAllEventValues } from '../../../../shared/transport/events/index.js';
|
|
12
14
|
import { initTransportLog, logTransportEvent } from '../../../lib/transport-logger.js';
|
|
13
15
|
import { useTransportStore } from '../../../stores/transport-store.js';
|
|
@@ -16,6 +18,7 @@ export function TransportInitializer({ children }) {
|
|
|
16
18
|
useEffect(() => {
|
|
17
19
|
let mounted = true;
|
|
18
20
|
let reconnectorHandle;
|
|
21
|
+
let unsubProjectSync;
|
|
19
22
|
const eventUnsubscribes = [];
|
|
20
23
|
function registerEventHandlers(client) {
|
|
21
24
|
// Clear old handlers first
|
|
@@ -36,12 +39,43 @@ export function TransportInitializer({ children }) {
|
|
|
36
39
|
try {
|
|
37
40
|
initTransportLog();
|
|
38
41
|
setConnectionState('connecting');
|
|
42
|
+
const getCurrentProjectPath = () => {
|
|
43
|
+
const storedProjectPath = useTransportStore.getState().projectPath;
|
|
44
|
+
if (storedProjectPath)
|
|
45
|
+
return storedProjectPath;
|
|
46
|
+
// Attempt live resolution as a last resort (e.g. store not yet populated).
|
|
47
|
+
// If resolution fails or returns null, throw — registering with raw cwd
|
|
48
|
+
// would put the client in the wrong room.
|
|
49
|
+
const resolution = resolveProject();
|
|
50
|
+
if (!resolution) {
|
|
51
|
+
throw new Error('No ByteRover project could be resolved. Ensure you are inside a brv project directory.');
|
|
52
|
+
}
|
|
53
|
+
return resolution.projectRoot;
|
|
54
|
+
};
|
|
39
55
|
// connectToDaemon = ensureDaemonRunning (no-op, already running) + connect + register + join rooms
|
|
56
|
+
// Use resolved projectPath from store (set by oclif main via resolveProject()),
|
|
57
|
+
// falling back to process.cwd() for backwards compatibility.
|
|
58
|
+
//
|
|
59
|
+
// connectOptions is a mutable object — the reconnector captures it by reference
|
|
60
|
+
// (daemon-reconnector.js line 60), so mutating .projectPath here is visible
|
|
61
|
+
// on subsequent reconnect attempts.
|
|
40
62
|
const connectOptions = {
|
|
41
63
|
clientType: 'tui',
|
|
42
64
|
joinRooms: ['broadcast-room'],
|
|
43
|
-
projectPath:
|
|
65
|
+
projectPath: getCurrentProjectPath(),
|
|
44
66
|
};
|
|
67
|
+
// Keep connectOptions.projectPath in sync with the store so reconnects
|
|
68
|
+
// use the latest value (e.g. after reassociation from worktree add/remove).
|
|
69
|
+
// If projectPath is cleared and resolver fails, keep the last good value
|
|
70
|
+
// rather than registering with raw cwd.
|
|
71
|
+
unsubProjectSync = useTransportStore.subscribe((state) => {
|
|
72
|
+
try {
|
|
73
|
+
connectOptions.projectPath = state.projectPath ?? getCurrentProjectPath();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Resolver failed — keep existing connectOptions.projectPath unchanged
|
|
77
|
+
}
|
|
78
|
+
});
|
|
45
79
|
const { client: newClient } = await connectToDaemon(connectOptions);
|
|
46
80
|
if (!mounted) {
|
|
47
81
|
await newClient.disconnect();
|
|
@@ -89,6 +123,7 @@ export function TransportInitializer({ children }) {
|
|
|
89
123
|
return () => {
|
|
90
124
|
mounted = false;
|
|
91
125
|
reconnectorHandle?.cancel();
|
|
126
|
+
unsubProjectSync?.();
|
|
92
127
|
// Clean up all event handlers
|
|
93
128
|
for (const unsub of eventUnsubscribes) {
|
|
94
129
|
unsub();
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type WorktreeAddResponse, type WorktreeListResponse, type WorktreeRemoveResponse } from '../../../../shared/transport/events/worktree-events.js';
|
|
2
|
+
export declare const addWorktreeViaTransport: (worktreePath: string, force?: boolean) => Promise<WorktreeAddResponse>;
|
|
3
|
+
export declare const removeWorktreeViaTransport: (worktreePath: string) => Promise<WorktreeRemoveResponse>;
|
|
4
|
+
export declare const listWorktreesViaTransport: () => Promise<WorktreeListResponse>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WorktreeEvents, } from '../../../../shared/transport/events/worktree-events.js';
|
|
2
|
+
import { useTransportStore } from '../../../stores/transport-store.js';
|
|
3
|
+
export const addWorktreeViaTransport = (worktreePath, force) => {
|
|
4
|
+
const { apiClient } = useTransportStore.getState();
|
|
5
|
+
if (!apiClient)
|
|
6
|
+
return Promise.reject(new Error('Not connected'));
|
|
7
|
+
const request = { force, worktreePath };
|
|
8
|
+
return apiClient.request(WorktreeEvents.ADD, request);
|
|
9
|
+
};
|
|
10
|
+
export const removeWorktreeViaTransport = (worktreePath) => {
|
|
11
|
+
const { apiClient } = useTransportStore.getState();
|
|
12
|
+
if (!apiClient)
|
|
13
|
+
return Promise.reject(new Error('Not connected'));
|
|
14
|
+
const request = { worktreePath };
|
|
15
|
+
return apiClient.request(WorktreeEvents.REMOVE, request);
|
|
16
|
+
};
|
|
17
|
+
export const listWorktreesViaTransport = () => {
|
|
18
|
+
const { apiClient } = useTransportStore.getState();
|
|
19
|
+
if (!apiClient)
|
|
20
|
+
return Promise.reject(new Error('Not connected'));
|
|
21
|
+
return apiClient.request(WorktreeEvents.LIST);
|
|
22
|
+
};
|
package/dist/tui/repl-startup.js
CHANGED
|
@@ -7,9 +7,11 @@ import { useTransportStore } from './stores/transport-store.js';
|
|
|
7
7
|
* Start the ByteRover REPL
|
|
8
8
|
*/
|
|
9
9
|
export async function startRepl(options) {
|
|
10
|
-
const { version } = options;
|
|
11
|
-
// Set version in store before rendering
|
|
12
|
-
useTransportStore.getState()
|
|
10
|
+
const { projectPath, version, worktreeRoot } = options;
|
|
11
|
+
// Set version and project info in store before rendering
|
|
12
|
+
const store = useTransportStore.getState();
|
|
13
|
+
store.setVersion(version);
|
|
14
|
+
store.setProjectInfo(projectPath, worktreeRoot);
|
|
13
15
|
const { waitUntilExit } = render(_jsx(AppProviders, { children: _jsx(App, {}) }));
|
|
14
16
|
await waitUntilExit();
|
|
15
17
|
}
|
|
@@ -18,10 +18,14 @@ export interface TransportState {
|
|
|
18
18
|
error: Error | null;
|
|
19
19
|
/** Whether the client is connected */
|
|
20
20
|
isConnected: boolean;
|
|
21
|
+
/** Resolved project path (where .brv/ lives) */
|
|
22
|
+
projectPath: null | string;
|
|
21
23
|
/** Number of reconnection attempts */
|
|
22
24
|
reconnectCount: number;
|
|
23
25
|
/** App version */
|
|
24
26
|
version: string;
|
|
27
|
+
/** Resolved workspace root (linked subdir or projectRoot if unlinked) */
|
|
28
|
+
worktreeRoot: null | string;
|
|
25
29
|
}
|
|
26
30
|
export interface TransportActions {
|
|
27
31
|
/** Increment reconnect count */
|
|
@@ -34,6 +38,8 @@ export interface TransportActions {
|
|
|
34
38
|
setConnectionState: (state: ConnectionState) => void;
|
|
35
39
|
/** Set connection error */
|
|
36
40
|
setError: (error: Error | null) => void;
|
|
41
|
+
/** Set resolved project info from oclif main */
|
|
42
|
+
setProjectInfo: (projectPath?: string, worktreeRoot?: string) => void;
|
|
37
43
|
/** Set app version */
|
|
38
44
|
setVersion: (version: string) => void;
|
|
39
45
|
}
|
|
@@ -13,8 +13,10 @@ const initialState = {
|
|
|
13
13
|
connectionState: 'disconnected',
|
|
14
14
|
error: null,
|
|
15
15
|
isConnected: false,
|
|
16
|
+
projectPath: null,
|
|
16
17
|
reconnectCount: 0,
|
|
17
18
|
version: '',
|
|
19
|
+
worktreeRoot: null,
|
|
18
20
|
};
|
|
19
21
|
export const useTransportStore = create()((set) => ({
|
|
20
22
|
...initialState,
|
|
@@ -36,5 +38,9 @@ export const useTransportStore = create()((set) => ({
|
|
|
36
38
|
error,
|
|
37
39
|
isConnected: false,
|
|
38
40
|
}),
|
|
41
|
+
setProjectInfo: (projectPath, worktreeRoot) => set({
|
|
42
|
+
projectPath: projectPath ?? null,
|
|
43
|
+
worktreeRoot: worktreeRoot ?? null,
|
|
44
|
+
}),
|
|
39
45
|
setVersion: (version) => set({ version }),
|
|
40
46
|
}));
|