byterover-cli 3.1.0 → 3.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 +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 +226 -103
- 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.d.ts +1 -0
- package/dist/oclif/commands/curate/index.js +19 -4
- package/dist/oclif/commands/curate/view.js +2 -2
- package/dist/oclif/commands/main.js +13 -0
- package/dist/oclif/commands/query.d.ts +1 -0
- package/dist/oclif/commands/query.js +19 -4
- package/dist/oclif/commands/search.d.ts +20 -0
- package/dist/oclif/commands/search.js +186 -0
- 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 +45 -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 -4
- package/dist/oclif/lib/search-format.d.ts +10 -0
- package/dist/oclif/lib/search-format.js +25 -0
- package/dist/oclif/lib/task-client.d.ts +6 -0
- package/dist/oclif/lib/task-client.js +10 -3
- package/dist/server/constants.d.ts +7 -1
- package/dist/server/constants.js +10 -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/errors/task-error.d.ts +2 -2
- package/dist/server/core/domain/errors/task-error.js +5 -4
- 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 +18 -10
- package/dist/server/core/domain/transport/schemas.js +7 -3
- 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/core/interfaces/executor/i-search-executor.d.ts +34 -0
- package/dist/server/core/interfaces/executor/i-search-executor.js +1 -0
- package/dist/server/core/interfaces/executor/index.d.ts +1 -0
- package/dist/server/core/interfaces/executor/index.js +1 -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 +35 -12
- 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/executor/search-executor.d.ts +17 -0
- package/dist/server/infra/executor/search-executor.js +30 -0
- 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/pull-handler.js +3 -3
- package/dist/server/infra/transport/handlers/push-handler.js +3 -3
- 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 +76 -27
- 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/templates/skill/SKILL.md +25 -5
- 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/search-content.d.ts +28 -0
- package/dist/shared/transport/search-content.js +38 -0
- package/dist/shared/transport/types/dto.d.ts +20 -1
- 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 +28 -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/dist/tui/utils/error-messages.js +2 -2
- package/oclif.manifest.json +380 -36
- package/package.json +1 -1
|
@@ -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;
|
|
@@ -127,13 +133,26 @@ export interface StatusDTO {
|
|
|
127
133
|
contextTreeDir?: string;
|
|
128
134
|
/** Relative path to the context tree directory from project root (e.g., '.brv/context-tree') */
|
|
129
135
|
contextTreeRelativeDir?: string;
|
|
130
|
-
contextTreeStatus: 'git_vc' | 'has_changes' | 'no_changes' | 'not_initialized' | 'unknown';
|
|
136
|
+
contextTreeStatus: 'git_vc' | 'has_changes' | 'no_changes' | 'no_vc' | '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
|
|
@@ -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)');
|
|
@@ -54,6 +76,10 @@ export function formatStatus(status, version) {
|
|
|
54
76
|
lines.push('Context Tree: No changes');
|
|
55
77
|
break;
|
|
56
78
|
}
|
|
79
|
+
case 'no_vc': {
|
|
80
|
+
lines.push('Context Tree: Managed by Byterover version control (use /vc commands)');
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
57
83
|
case 'not_initialized': {
|
|
58
84
|
lines.push('Context Tree: Not initialized');
|
|
59
85
|
break;
|
|
@@ -67,5 +93,6 @@ export function formatStatus(status, version) {
|
|
|
67
93
|
lines.push(chalk.yellow(`Pending Reviews: ${status.pendingReviewCount} ${fileLabel} need review`) +
|
|
68
94
|
(status.reviewUrl ? `\n Review: ${chalk.blue(status.reviewUrl)}` : ''));
|
|
69
95
|
}
|
|
96
|
+
lines.push('', 'Tip: Version control is now available for your context tree.', 'Learn more: https://docs.byterover.dev/git-semantic/overview');
|
|
70
97
|
return lines.join('\n');
|
|
71
98
|
}
|
|
@@ -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
|
}
|