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
|
@@ -7,6 +7,7 @@ export declare const TaskErrorCode: {
|
|
|
7
7
|
readonly AGENT_NOT_AVAILABLE: "ERR_AGENT_NOT_AVAILABLE";
|
|
8
8
|
readonly AGENT_NOT_INITIALIZED: "ERR_AGENT_NOT_INITIALIZED";
|
|
9
9
|
readonly CONTEXT_TREE_NOT_INITIALIZED: "ERR_CONTEXT_TREE_NOT_INIT";
|
|
10
|
+
readonly LEGACY_SYNC_UNAVAILABLE: "ERR_LEGACY_SYNC_UNAVAILABLE";
|
|
10
11
|
readonly LLM_ERROR: "ERR_LLM_ERROR";
|
|
11
12
|
readonly LLM_RATE_LIMIT: "ERR_LLM_RATE_LIMIT";
|
|
12
13
|
readonly LOCAL_CHANGES_EXIST: "ERR_LOCAL_CHANGES_EXIST";
|
|
@@ -15,7 +16,6 @@ export declare const TaskErrorCode: {
|
|
|
15
16
|
readonly OAUTH_TOKEN_EXPIRED: "ERR_OAUTH_TOKEN_EXPIRED";
|
|
16
17
|
readonly PROJECT_NOT_INIT: "ERR_PROJECT_NOT_INIT";
|
|
17
18
|
readonly PROVIDER_NOT_CONFIGURED: "ERR_PROVIDER_NOT_CONFIGURED";
|
|
18
|
-
readonly SPACE_NOT_CONFIGURED: "ERR_SPACE_NOT_CONFIGURED";
|
|
19
19
|
readonly SPACE_NOT_FOUND: "ERR_SPACE_NOT_FOUND";
|
|
20
20
|
readonly TASK_CANCELLED: "ERR_TASK_CANCELLED";
|
|
21
21
|
readonly TASK_EXECUTION: "ERR_TASK_EXECUTION";
|
|
@@ -73,7 +73,7 @@ export declare class FileValidationError extends Error {
|
|
|
73
73
|
export declare class LocalChangesExistError extends TaskError {
|
|
74
74
|
constructor(message?: string);
|
|
75
75
|
}
|
|
76
|
-
export declare class
|
|
76
|
+
export declare class LegacySyncUnavailableError extends TaskError {
|
|
77
77
|
constructor();
|
|
78
78
|
}
|
|
79
79
|
export declare class GitVcInitializedError extends TaskError {
|
|
@@ -9,6 +9,8 @@ export const TaskErrorCode = {
|
|
|
9
9
|
AGENT_NOT_INITIALIZED: 'ERR_AGENT_NOT_INITIALIZED',
|
|
10
10
|
// Context tree errors
|
|
11
11
|
CONTEXT_TREE_NOT_INITIALIZED: 'ERR_CONTEXT_TREE_NOT_INIT',
|
|
12
|
+
// Legacy sync (brv push/pull) no longer available because project has no team+space configured
|
|
13
|
+
LEGACY_SYNC_UNAVAILABLE: 'ERR_LEGACY_SYNC_UNAVAILABLE',
|
|
12
14
|
// LLM errors
|
|
13
15
|
LLM_ERROR: 'ERR_LLM_ERROR',
|
|
14
16
|
LLM_RATE_LIMIT: 'ERR_LLM_RATE_LIMIT',
|
|
@@ -21,7 +23,6 @@ export const TaskErrorCode = {
|
|
|
21
23
|
// Execution errors
|
|
22
24
|
PROJECT_NOT_INIT: 'ERR_PROJECT_NOT_INIT',
|
|
23
25
|
PROVIDER_NOT_CONFIGURED: 'ERR_PROVIDER_NOT_CONFIGURED',
|
|
24
|
-
SPACE_NOT_CONFIGURED: 'ERR_SPACE_NOT_CONFIGURED',
|
|
25
26
|
SPACE_NOT_FOUND: 'ERR_SPACE_NOT_FOUND',
|
|
26
27
|
TASK_CANCELLED: 'ERR_TASK_CANCELLED',
|
|
27
28
|
TASK_EXECUTION: 'ERR_TASK_EXECUTION',
|
|
@@ -153,10 +154,10 @@ export class LocalChangesExistError extends TaskError {
|
|
|
153
154
|
this.name = 'LocalChangesExistError';
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
|
-
export class
|
|
157
|
+
export class LegacySyncUnavailableError extends TaskError {
|
|
157
158
|
constructor() {
|
|
158
|
-
super('
|
|
159
|
-
this.name = '
|
|
159
|
+
super('Command brv push and brv pull are deprecated. Run `brv vc init` to start using Byterover version control.', TaskErrorCode.LEGACY_SYNC_UNAVAILABLE);
|
|
160
|
+
this.name = 'LegacySyncUnavailableError';
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
export class GitVcInitializedError extends TaskError {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for the `.brv` pointer file (when .brv is a FILE, not a directory).
|
|
4
|
+
* Like git's `.git` file in worktrees: contains a single `projectRoot` field
|
|
5
|
+
* pointing to the parent project's absolute path.
|
|
6
|
+
*/
|
|
7
|
+
export declare const WorktreePointerSchema: z.ZodObject<{
|
|
8
|
+
projectRoot: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
}, {
|
|
12
|
+
projectRoot: string;
|
|
13
|
+
}>;
|
|
14
|
+
export type WorktreePointer = z.infer<typeof WorktreePointerSchema>;
|
|
15
|
+
/**
|
|
16
|
+
* Schema for `.brv/worktrees/<name>/link.json` — metadata about a registered worktree.
|
|
17
|
+
* Stored in the parent project's `.brv/worktrees/` directory (like `.git/worktrees/`).
|
|
18
|
+
*/
|
|
19
|
+
export declare const WorktreeLinkMetadataSchema: z.ZodObject<{
|
|
20
|
+
addedAt: z.ZodOptional<z.ZodString>;
|
|
21
|
+
worktreePath: z.ZodString;
|
|
22
|
+
}, "strip", z.ZodTypeAny, {
|
|
23
|
+
worktreePath: string;
|
|
24
|
+
addedAt?: string | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
worktreePath: string;
|
|
27
|
+
addedAt?: string | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
export type WorktreeLinkMetadata = z.infer<typeof WorktreeLinkMetadataSchema>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for the `.brv` pointer file (when .brv is a FILE, not a directory).
|
|
4
|
+
* Like git's `.git` file in worktrees: contains a single `projectRoot` field
|
|
5
|
+
* pointing to the parent project's absolute path.
|
|
6
|
+
*/
|
|
7
|
+
export const WorktreePointerSchema = z.object({
|
|
8
|
+
projectRoot: z.string().min(1),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Schema for `.brv/worktrees/<name>/link.json` — metadata about a registered worktree.
|
|
12
|
+
* Stored in the parent project's `.brv/worktrees/` directory (like `.git/worktrees/`).
|
|
13
|
+
*/
|
|
14
|
+
export const WorktreeLinkMetadataSchema = z.object({
|
|
15
|
+
addedAt: z.string().optional(),
|
|
16
|
+
worktreePath: z.string().min(1),
|
|
17
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type SourceStatus } from './source-schema.js';
|
|
2
|
+
export interface OperationResult {
|
|
3
|
+
message: string;
|
|
4
|
+
success: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Adds a read-only knowledge source from another project's context tree.
|
|
8
|
+
*
|
|
9
|
+
* Validates: target is a brv project, not self, not duplicate, not circular.
|
|
10
|
+
* Writes to `.brv/sources.json`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function addSource(projectRoot: string, targetPath: string, alias?: string): OperationResult;
|
|
13
|
+
/**
|
|
14
|
+
* Removes a knowledge source by alias or path.
|
|
15
|
+
*/
|
|
16
|
+
export declare function removeSource(projectRoot: string, aliasOrPath: string): OperationResult;
|
|
17
|
+
export interface ListSourcesResult {
|
|
18
|
+
error?: string;
|
|
19
|
+
statuses: SourceStatus[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Returns status for all sources in the project.
|
|
23
|
+
* Surfaces malformed file errors instead of silently returning empty.
|
|
24
|
+
*/
|
|
25
|
+
export declare function listSourceStatuses(projectRoot: string): ListSourcesResult;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if adding projectRoot → targetRoot would create a circular dependency.
|
|
28
|
+
* A circular reference exists if the target project already has a source pointing
|
|
29
|
+
* back to the current project (direct cycle only — no transitive check in v1).
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectCircularSource(projectRoot: string, targetRoot: string): boolean;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { BRV_DIR, PROJECT_CONFIG_FILE, SOURCES_FILE } from '../../../constants.js';
|
|
4
|
+
import { getSourceStatuses, loadSources, SourcesFileSchema, } from './source-schema.js';
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Add source
|
|
7
|
+
// ============================================================================
|
|
8
|
+
/**
|
|
9
|
+
* Adds a read-only knowledge source from another project's context tree.
|
|
10
|
+
*
|
|
11
|
+
* Validates: target is a brv project, not self, not duplicate, not circular.
|
|
12
|
+
* Writes to `.brv/sources.json`.
|
|
13
|
+
*/
|
|
14
|
+
export function addSource(projectRoot, targetPath, alias) {
|
|
15
|
+
// 1. Local project must have .brv/
|
|
16
|
+
const localConfigPath = join(projectRoot, BRV_DIR, PROJECT_CONFIG_FILE);
|
|
17
|
+
if (!existsSync(localConfigPath)) {
|
|
18
|
+
return { message: `Current project has no .brv/ — run 'brv' first to initialize.`, success: false };
|
|
19
|
+
}
|
|
20
|
+
// 2. Resolve target to canonical path
|
|
21
|
+
let targetRoot;
|
|
22
|
+
try {
|
|
23
|
+
targetRoot = realpathSync(targetPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { message: `Target path does not exist: ${targetPath}`, success: false };
|
|
27
|
+
}
|
|
28
|
+
// 3. Target must be a brv project
|
|
29
|
+
const targetConfigPath = join(targetRoot, BRV_DIR, PROJECT_CONFIG_FILE);
|
|
30
|
+
if (!existsSync(targetConfigPath)) {
|
|
31
|
+
return { message: `Target "${targetRoot}" is not a ByteRover project (no .brv/config.json).`, success: false };
|
|
32
|
+
}
|
|
33
|
+
// 4. Not self
|
|
34
|
+
let canonicalProjectRoot;
|
|
35
|
+
try {
|
|
36
|
+
canonicalProjectRoot = realpathSync(projectRoot);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
canonicalProjectRoot = projectRoot;
|
|
40
|
+
}
|
|
41
|
+
if (targetRoot === canonicalProjectRoot) {
|
|
42
|
+
return { message: 'Cannot add a source pointing to the current project.', success: false };
|
|
43
|
+
}
|
|
44
|
+
// 5. Read existing file — refuse to mutate if malformed
|
|
45
|
+
const existing = readSourcesFile(projectRoot);
|
|
46
|
+
if (existing.error) {
|
|
47
|
+
return { message: existing.error, success: false };
|
|
48
|
+
}
|
|
49
|
+
// 6. Not duplicate
|
|
50
|
+
const isDuplicate = existing.data.sources.some((source) => {
|
|
51
|
+
try {
|
|
52
|
+
return realpathSync(source.projectRoot) === targetRoot;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return source.projectRoot === targetRoot;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
if (isDuplicate) {
|
|
59
|
+
return { message: `Source "${targetRoot}" already added.`, success: false };
|
|
60
|
+
}
|
|
61
|
+
// 7. Not circular
|
|
62
|
+
if (detectCircularSource(canonicalProjectRoot, targetRoot)) {
|
|
63
|
+
return {
|
|
64
|
+
message: `Circular source detected: "${basename(targetRoot)}" already references this project as a source.`,
|
|
65
|
+
success: false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// 8. Derive alias — reject empty/whitespace-only
|
|
69
|
+
if (alias !== undefined && alias.trim() === '') {
|
|
70
|
+
return { message: 'Alias must not be empty.', success: false };
|
|
71
|
+
}
|
|
72
|
+
const derivedAlias = alias ?? basename(targetRoot);
|
|
73
|
+
// 9. Ensure alias uniqueness — append suffix if collision
|
|
74
|
+
const finalAlias = ensureUniqueAlias(derivedAlias, existing.data.sources);
|
|
75
|
+
// 10. Append and write
|
|
76
|
+
const newSource = {
|
|
77
|
+
addedAt: new Date().toISOString(),
|
|
78
|
+
alias: finalAlias,
|
|
79
|
+
projectRoot: targetRoot,
|
|
80
|
+
readOnly: true,
|
|
81
|
+
};
|
|
82
|
+
existing.data.sources.push(newSource);
|
|
83
|
+
writeSourcesFile(projectRoot, existing.data);
|
|
84
|
+
return { message: `Added source "${targetRoot}" as "${finalAlias}".`, success: true };
|
|
85
|
+
}
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// Remove source
|
|
88
|
+
// ============================================================================
|
|
89
|
+
/**
|
|
90
|
+
* Removes a knowledge source by alias or path.
|
|
91
|
+
*/
|
|
92
|
+
export function removeSource(projectRoot, aliasOrPath) {
|
|
93
|
+
const existing = readSourcesFile(projectRoot);
|
|
94
|
+
if (existing.error) {
|
|
95
|
+
return { message: existing.error, success: false };
|
|
96
|
+
}
|
|
97
|
+
if (existing.data.sources.length === 0) {
|
|
98
|
+
return { message: 'No knowledge sources configured.', success: false };
|
|
99
|
+
}
|
|
100
|
+
// Try match by alias first, then by canonical path
|
|
101
|
+
let matchIndex = existing.data.sources.findIndex((source) => source.alias === aliasOrPath);
|
|
102
|
+
if (matchIndex === -1) {
|
|
103
|
+
// Try matching by path
|
|
104
|
+
let canonicalTarget;
|
|
105
|
+
try {
|
|
106
|
+
canonicalTarget = realpathSync(aliasOrPath);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
canonicalTarget = aliasOrPath;
|
|
110
|
+
}
|
|
111
|
+
matchIndex = existing.data.sources.findIndex((source) => {
|
|
112
|
+
try {
|
|
113
|
+
return realpathSync(source.projectRoot) === canonicalTarget;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return source.projectRoot === canonicalTarget;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (matchIndex === -1) {
|
|
121
|
+
return { message: `No source found matching "${aliasOrPath}".`, success: false };
|
|
122
|
+
}
|
|
123
|
+
const removed = existing.data.sources.splice(matchIndex, 1)[0];
|
|
124
|
+
writeSourcesFile(projectRoot, existing.data);
|
|
125
|
+
return { message: `Removed source "${removed.alias}" (${removed.projectRoot}).`, success: true };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns status for all sources in the project.
|
|
129
|
+
* Surfaces malformed file errors instead of silently returning empty.
|
|
130
|
+
*/
|
|
131
|
+
export function listSourceStatuses(projectRoot) {
|
|
132
|
+
const existing = readSourcesFile(projectRoot);
|
|
133
|
+
if (existing.error) {
|
|
134
|
+
return { error: existing.error, statuses: [] };
|
|
135
|
+
}
|
|
136
|
+
if (existing.data.sources.length === 0) {
|
|
137
|
+
return { statuses: [] };
|
|
138
|
+
}
|
|
139
|
+
return { statuses: getSourceStatuses(existing.data.sources) };
|
|
140
|
+
}
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Circular source detection
|
|
143
|
+
// ============================================================================
|
|
144
|
+
/**
|
|
145
|
+
* Checks if adding projectRoot → targetRoot would create a circular dependency.
|
|
146
|
+
* A circular reference exists if the target project already has a source pointing
|
|
147
|
+
* back to the current project (direct cycle only — no transitive check in v1).
|
|
148
|
+
*/
|
|
149
|
+
export function detectCircularSource(projectRoot, targetRoot) {
|
|
150
|
+
const targetSources = loadSources(targetRoot);
|
|
151
|
+
if (!targetSources) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
return targetSources.sources.some((source) => {
|
|
155
|
+
try {
|
|
156
|
+
return realpathSync(source.projectRoot) === projectRoot;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return source.projectRoot === projectRoot;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function readSourcesFile(projectRoot) {
|
|
164
|
+
const filePath = join(projectRoot, BRV_DIR, SOURCES_FILE);
|
|
165
|
+
if (!existsSync(filePath)) {
|
|
166
|
+
return { data: { sources: [], version: 1 } };
|
|
167
|
+
}
|
|
168
|
+
let raw;
|
|
169
|
+
try {
|
|
170
|
+
raw = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return {
|
|
174
|
+
data: { sources: [], version: 1 },
|
|
175
|
+
error: `Malformed ${SOURCES_FILE}: file is not valid JSON. Back up or delete the file to recover.`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const result = SourcesFileSchema.safeParse(raw);
|
|
179
|
+
if (!result.success) {
|
|
180
|
+
return {
|
|
181
|
+
data: { sources: [], version: 1 },
|
|
182
|
+
error: `Malformed ${SOURCES_FILE}: schema validation failed. Back up or delete the file to recover.`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return { data: result.data };
|
|
186
|
+
}
|
|
187
|
+
function writeSourcesFile(projectRoot, data) {
|
|
188
|
+
const filePath = join(projectRoot, BRV_DIR, SOURCES_FILE);
|
|
189
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
190
|
+
}
|
|
191
|
+
function ensureUniqueAlias(baseAlias, existingSources) {
|
|
192
|
+
const existingAliases = new Set(existingSources.map((source) => source.alias));
|
|
193
|
+
if (!existingAliases.has(baseAlias)) {
|
|
194
|
+
return baseAlias;
|
|
195
|
+
}
|
|
196
|
+
let counter = 2;
|
|
197
|
+
while (existingAliases.has(`${baseAlias}-${counter}`)) {
|
|
198
|
+
counter++;
|
|
199
|
+
}
|
|
200
|
+
return `${baseAlias}-${counter}`;
|
|
201
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SourceSchema: z.ZodObject<{
|
|
3
|
+
addedAt: z.ZodString;
|
|
4
|
+
alias: z.ZodString;
|
|
5
|
+
projectRoot: z.ZodString;
|
|
6
|
+
readOnly: z.ZodLiteral<true>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
addedAt: string;
|
|
9
|
+
alias: string;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
readOnly: true;
|
|
12
|
+
}, {
|
|
13
|
+
addedAt: string;
|
|
14
|
+
alias: string;
|
|
15
|
+
projectRoot: string;
|
|
16
|
+
readOnly: true;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const SourcesFileSchema: z.ZodObject<{
|
|
19
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
20
|
+
addedAt: z.ZodString;
|
|
21
|
+
alias: z.ZodString;
|
|
22
|
+
projectRoot: z.ZodString;
|
|
23
|
+
readOnly: z.ZodLiteral<true>;
|
|
24
|
+
}, "strip", z.ZodTypeAny, {
|
|
25
|
+
addedAt: string;
|
|
26
|
+
alias: string;
|
|
27
|
+
projectRoot: string;
|
|
28
|
+
readOnly: true;
|
|
29
|
+
}, {
|
|
30
|
+
addedAt: string;
|
|
31
|
+
alias: string;
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
readOnly: true;
|
|
34
|
+
}>, "many">;
|
|
35
|
+
version: z.ZodLiteral<1>;
|
|
36
|
+
}, "strip", z.ZodTypeAny, {
|
|
37
|
+
version: 1;
|
|
38
|
+
sources: {
|
|
39
|
+
addedAt: string;
|
|
40
|
+
alias: string;
|
|
41
|
+
projectRoot: string;
|
|
42
|
+
readOnly: true;
|
|
43
|
+
}[];
|
|
44
|
+
}, {
|
|
45
|
+
version: 1;
|
|
46
|
+
sources: {
|
|
47
|
+
addedAt: string;
|
|
48
|
+
alias: string;
|
|
49
|
+
projectRoot: string;
|
|
50
|
+
readOnly: true;
|
|
51
|
+
}[];
|
|
52
|
+
}>;
|
|
53
|
+
export type Source = z.infer<typeof SourceSchema>;
|
|
54
|
+
export type SourcesFile = z.infer<typeof SourcesFileSchema>;
|
|
55
|
+
export interface SearchOrigin {
|
|
56
|
+
alias?: string;
|
|
57
|
+
contextTreeRoot: string;
|
|
58
|
+
origin: 'local' | 'shared';
|
|
59
|
+
originKey: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Derives a stable, short origin key from a canonical path.
|
|
63
|
+
* Uses first 12 hex chars of SHA-256 to avoid alias-based collisions.
|
|
64
|
+
*/
|
|
65
|
+
export declare function deriveOriginKey(canonicalPath: string): string;
|
|
66
|
+
export interface LoadedSources {
|
|
67
|
+
mtime: number;
|
|
68
|
+
/** Search origins derived from valid sources (callers can search them) */
|
|
69
|
+
origins: SearchOrigin[];
|
|
70
|
+
/** All configured sources (including broken ones — for status display) */
|
|
71
|
+
sources: Source[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Loads and validates `.brv/sources.json` from a project root.
|
|
75
|
+
*
|
|
76
|
+
* Returns null if the file does not exist.
|
|
77
|
+
* Broken sources (target `.brv/` missing) are included in `sources` but excluded
|
|
78
|
+
* from `origins` — callers decide how to surface them (status vs search).
|
|
79
|
+
*/
|
|
80
|
+
export declare function loadSources(projectRoot: string): LoadedSources | null;
|
|
81
|
+
export interface SourceStatus {
|
|
82
|
+
alias: string;
|
|
83
|
+
contextTreeSize?: number;
|
|
84
|
+
projectRoot: string;
|
|
85
|
+
valid: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validates each source and returns status for display.
|
|
89
|
+
*
|
|
90
|
+
* A source is valid only when both `.brv/config.json` AND `.brv/context-tree/`
|
|
91
|
+
* exist — matching what loadSources() requires before including a source in
|
|
92
|
+
* search origins. When valid, `contextTreeSize` counts `.md` files.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getSourceStatuses(sources: Source[]): SourceStatus[];
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { BRV_DIR, CONTEXT_TREE_DIR, PROJECT_CONFIG_FILE, SOURCES_FILE } from '../../../constants.js';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Schema
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export const SourceSchema = z.object({
|
|
10
|
+
addedAt: z.string(),
|
|
11
|
+
alias: z.string().min(1),
|
|
12
|
+
projectRoot: z.string().min(1),
|
|
13
|
+
readOnly: z.literal(true),
|
|
14
|
+
});
|
|
15
|
+
export const SourcesFileSchema = z.object({
|
|
16
|
+
sources: z.array(SourceSchema),
|
|
17
|
+
version: z.literal(1),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Derives a stable, short origin key from a canonical path.
|
|
21
|
+
* Uses first 12 hex chars of SHA-256 to avoid alias-based collisions.
|
|
22
|
+
*/
|
|
23
|
+
export function deriveOriginKey(canonicalPath) {
|
|
24
|
+
return createHash('sha256').update(canonicalPath).digest('hex').slice(0, 12);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Loads and validates `.brv/sources.json` from a project root.
|
|
28
|
+
*
|
|
29
|
+
* Returns null if the file does not exist.
|
|
30
|
+
* Broken sources (target `.brv/` missing) are included in `sources` but excluded
|
|
31
|
+
* from `origins` — callers decide how to surface them (status vs search).
|
|
32
|
+
*/
|
|
33
|
+
export function loadSources(projectRoot) {
|
|
34
|
+
const filePath = join(projectRoot, BRV_DIR, SOURCES_FILE);
|
|
35
|
+
if (!existsSync(filePath)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const mtime = statSync(filePath).mtimeMs;
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return { mtime, origins: [], sources: [] };
|
|
45
|
+
}
|
|
46
|
+
const result = SourcesFileSchema.safeParse(raw);
|
|
47
|
+
if (!result.success) {
|
|
48
|
+
return { mtime, origins: [], sources: [] };
|
|
49
|
+
}
|
|
50
|
+
const origins = [];
|
|
51
|
+
for (const source of result.data.sources) {
|
|
52
|
+
const targetConfigPath = join(source.projectRoot, BRV_DIR, PROJECT_CONFIG_FILE);
|
|
53
|
+
if (!existsSync(targetConfigPath)) {
|
|
54
|
+
// Broken source — skip from origins but keep in sources for status display
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
let canonicalRoot;
|
|
58
|
+
try {
|
|
59
|
+
canonicalRoot = realpathSync(source.projectRoot);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const contextTreeRoot = join(canonicalRoot, BRV_DIR, CONTEXT_TREE_DIR);
|
|
65
|
+
if (!existsSync(contextTreeRoot)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
origins.push({
|
|
69
|
+
alias: source.alias,
|
|
70
|
+
contextTreeRoot,
|
|
71
|
+
origin: 'shared',
|
|
72
|
+
originKey: deriveOriginKey(canonicalRoot),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return { mtime, origins, sources: result.data.sources };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validates each source and returns status for display.
|
|
79
|
+
*
|
|
80
|
+
* A source is valid only when both `.brv/config.json` AND `.brv/context-tree/`
|
|
81
|
+
* exist — matching what loadSources() requires before including a source in
|
|
82
|
+
* search origins. When valid, `contextTreeSize` counts `.md` files.
|
|
83
|
+
*/
|
|
84
|
+
export function getSourceStatuses(sources) {
|
|
85
|
+
return sources.map((source) => {
|
|
86
|
+
const targetConfigPath = join(source.projectRoot, BRV_DIR, PROJECT_CONFIG_FILE);
|
|
87
|
+
const targetContextTree = join(source.projectRoot, BRV_DIR, CONTEXT_TREE_DIR);
|
|
88
|
+
const valid = existsSync(targetConfigPath) && existsSync(targetContextTree);
|
|
89
|
+
let contextTreeSize;
|
|
90
|
+
if (valid) {
|
|
91
|
+
contextTreeSize = countMarkdownFiles(targetContextTree);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
alias: source.alias,
|
|
95
|
+
contextTreeSize,
|
|
96
|
+
projectRoot: source.projectRoot,
|
|
97
|
+
valid,
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Recursively counts .md files in a directory.
|
|
103
|
+
*/
|
|
104
|
+
function countMarkdownFiles(dir) {
|
|
105
|
+
let count = 0;
|
|
106
|
+
try {
|
|
107
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
if (entry.isDirectory()) {
|
|
110
|
+
count += countMarkdownFiles(join(dir, entry.name));
|
|
111
|
+
}
|
|
112
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
113
|
+
count++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Directory unreadable — return 0
|
|
119
|
+
}
|
|
120
|
+
return count;
|
|
121
|
+
}
|
|
@@ -514,9 +514,11 @@ export declare const TaskExecuteSchema: z.ZodObject<{
|
|
|
514
514
|
/** Unique task identifier */
|
|
515
515
|
taskId: z.ZodString;
|
|
516
516
|
/** Task type */
|
|
517
|
-
type: z.ZodEnum<["curate", "curate-folder", "query"]>;
|
|
517
|
+
type: z.ZodEnum<["curate", "curate-folder", "query", "search"]>;
|
|
518
|
+
/** Workspace root for scoped query/curate */
|
|
519
|
+
worktreeRoot: z.ZodOptional<z.ZodString>;
|
|
518
520
|
}, "strip", z.ZodTypeAny, {
|
|
519
|
-
type: "curate" | "query" | "curate-folder";
|
|
521
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
520
522
|
content: string;
|
|
521
523
|
taskId: string;
|
|
522
524
|
clientId: string;
|
|
@@ -524,8 +526,9 @@ export declare const TaskExecuteSchema: z.ZodObject<{
|
|
|
524
526
|
clientCwd?: string | undefined;
|
|
525
527
|
folderPath?: string | undefined;
|
|
526
528
|
projectPath?: string | undefined;
|
|
529
|
+
worktreeRoot?: string | undefined;
|
|
527
530
|
}, {
|
|
528
|
-
type: "curate" | "query" | "curate-folder";
|
|
531
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
529
532
|
content: string;
|
|
530
533
|
taskId: string;
|
|
531
534
|
clientId: string;
|
|
@@ -533,6 +536,7 @@ export declare const TaskExecuteSchema: z.ZodObject<{
|
|
|
533
536
|
clientCwd?: string | undefined;
|
|
534
537
|
folderPath?: string | undefined;
|
|
535
538
|
projectPath?: string | undefined;
|
|
539
|
+
worktreeRoot?: string | undefined;
|
|
536
540
|
}>;
|
|
537
541
|
/**
|
|
538
542
|
* task:cancel - Transport tells Agent to cancel a task
|
|
@@ -683,16 +687,16 @@ export declare const TaskCreatedSchema: z.ZodObject<{
|
|
|
683
687
|
/** Unique task identifier */
|
|
684
688
|
taskId: z.ZodString;
|
|
685
689
|
/** Task type */
|
|
686
|
-
type: z.ZodEnum<["curate", "curate-folder", "query"]>;
|
|
690
|
+
type: z.ZodEnum<["curate", "curate-folder", "query", "search"]>;
|
|
687
691
|
}, "strip", z.ZodTypeAny, {
|
|
688
|
-
type: "curate" | "query" | "curate-folder";
|
|
692
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
689
693
|
content: string;
|
|
690
694
|
taskId: string;
|
|
691
695
|
files?: string[] | undefined;
|
|
692
696
|
clientCwd?: string | undefined;
|
|
693
697
|
folderPath?: string | undefined;
|
|
694
698
|
}, {
|
|
695
|
-
type: "curate" | "query" | "curate-folder";
|
|
699
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
696
700
|
content: string;
|
|
697
701
|
taskId: string;
|
|
698
702
|
files?: string[] | undefined;
|
|
@@ -941,7 +945,7 @@ export type TaskStartedEvent = z.infer<typeof TaskStartedEventSchema>;
|
|
|
941
945
|
export type TaskCompletedEvent = z.infer<typeof TaskCompletedEventSchema>;
|
|
942
946
|
export type TaskErrorData = z.infer<typeof TaskErrorDataSchema>;
|
|
943
947
|
export type TaskErrorEvent = z.infer<typeof TaskErrorEventSchema>;
|
|
944
|
-
export declare const TaskTypeSchema: z.ZodEnum<["curate", "curate-folder", "query"]>;
|
|
948
|
+
export declare const TaskTypeSchema: z.ZodEnum<["curate", "curate-folder", "query", "search"]>;
|
|
945
949
|
/**
|
|
946
950
|
* Request to create a new task
|
|
947
951
|
*/
|
|
@@ -959,23 +963,27 @@ export declare const TaskCreateRequestSchema: z.ZodObject<{
|
|
|
959
963
|
/** Task ID - generated by Client UseCase (UUID v4) */
|
|
960
964
|
taskId: z.ZodString;
|
|
961
965
|
/** Task type */
|
|
962
|
-
type: z.ZodEnum<["curate", "curate-folder", "query"]>;
|
|
966
|
+
type: z.ZodEnum<["curate", "curate-folder", "query", "search"]>;
|
|
967
|
+
/** Workspace root for scoped query/curate (stable linked root or projectRoot if unlinked) */
|
|
968
|
+
worktreeRoot: z.ZodOptional<z.ZodString>;
|
|
963
969
|
}, "strip", z.ZodTypeAny, {
|
|
964
|
-
type: "curate" | "query" | "curate-folder";
|
|
970
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
965
971
|
content: string;
|
|
966
972
|
taskId: string;
|
|
967
973
|
files?: string[] | undefined;
|
|
968
974
|
clientCwd?: string | undefined;
|
|
969
975
|
folderPath?: string | undefined;
|
|
970
976
|
projectPath?: string | undefined;
|
|
977
|
+
worktreeRoot?: string | undefined;
|
|
971
978
|
}, {
|
|
972
|
-
type: "curate" | "query" | "curate-folder";
|
|
979
|
+
type: "curate" | "query" | "search" | "curate-folder";
|
|
973
980
|
content: string;
|
|
974
981
|
taskId: string;
|
|
975
982
|
files?: string[] | undefined;
|
|
976
983
|
clientCwd?: string | undefined;
|
|
977
984
|
folderPath?: string | undefined;
|
|
978
985
|
projectPath?: string | undefined;
|
|
986
|
+
worktreeRoot?: string | undefined;
|
|
979
987
|
}>;
|
|
980
988
|
/**
|
|
981
989
|
* Response after task creation
|
|
@@ -314,7 +314,9 @@ export const TaskExecuteSchema = z.object({
|
|
|
314
314
|
/** Unique task identifier */
|
|
315
315
|
taskId: z.string(),
|
|
316
316
|
/** Task type */
|
|
317
|
-
type: z.enum(['curate', 'curate-folder', 'query']),
|
|
317
|
+
type: z.enum(['curate', 'curate-folder', 'query', 'search']),
|
|
318
|
+
/** Workspace root for scoped query/curate */
|
|
319
|
+
worktreeRoot: z.string().optional(),
|
|
318
320
|
});
|
|
319
321
|
/**
|
|
320
322
|
* task:cancel - Transport tells Agent to cancel a task
|
|
@@ -372,7 +374,7 @@ export const TaskCreatedSchema = z.object({
|
|
|
372
374
|
/** Unique task identifier */
|
|
373
375
|
taskId: z.string(),
|
|
374
376
|
/** Task type */
|
|
375
|
-
type: z.enum(['curate', 'curate-folder', 'query']),
|
|
377
|
+
type: z.enum(['curate', 'curate-folder', 'query', 'search']),
|
|
376
378
|
});
|
|
377
379
|
/**
|
|
378
380
|
* task:started - Agent begins processing the task
|
|
@@ -473,7 +475,7 @@ export const LlmToolResultEventSchema = z.object({
|
|
|
473
475
|
// ============================================================================
|
|
474
476
|
// Request/Response Schemas (for client → server commands)
|
|
475
477
|
// ============================================================================
|
|
476
|
-
export const TaskTypeSchema = z.enum(['curate', 'curate-folder', 'query']);
|
|
478
|
+
export const TaskTypeSchema = z.enum(['curate', 'curate-folder', 'query', 'search']);
|
|
477
479
|
/**
|
|
478
480
|
* Request to create a new task
|
|
479
481
|
*/
|
|
@@ -492,6 +494,8 @@ export const TaskCreateRequestSchema = z.object({
|
|
|
492
494
|
taskId: z.string().uuid('Invalid taskId format - must be UUID'),
|
|
493
495
|
/** Task type */
|
|
494
496
|
type: TaskTypeSchema,
|
|
497
|
+
/** Workspace root for scoped query/curate (stable linked root or projectRoot if unlinked) */
|
|
498
|
+
worktreeRoot: z.string().optional(),
|
|
495
499
|
});
|
|
496
500
|
/**
|
|
497
501
|
* Response after task creation
|