byterover-cli 2.5.2 → 2.6.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 +7 -0
- package/LICENSE +44 -0
- package/bin/dev.js +8 -1
- package/bin/run.js +8 -1
- package/dist/server/config/environment.d.ts +0 -19
- package/dist/server/config/environment.js +29 -38
- package/dist/server/constants.d.ts +0 -9
- package/dist/server/constants.js +0 -12
- package/dist/server/core/domain/errors/auth-error.d.ts +0 -6
- package/dist/server/core/domain/errors/auth-error.js +0 -12
- package/dist/server/core/domain/errors/task-error.d.ts +0 -3
- package/dist/server/core/domain/errors/task-error.js +0 -8
- package/dist/server/core/domain/errors/transport-error.d.ts +0 -31
- package/dist/server/core/domain/errors/transport-error.js +0 -50
- package/dist/server/infra/connectors/rules/rules-connector-config.d.ts +0 -4
- package/dist/server/infra/http/models-dev-client.d.ts +0 -4
- package/dist/server/infra/http/models-dev-client.js +0 -6
- package/dist/server/infra/http/openrouter-api-client.d.ts +0 -8
- package/dist/server/infra/http/openrouter-api-client.js +0 -13
- package/dist/server/infra/http/provider-model-fetcher-registry.d.ts +0 -5
- package/dist/server/infra/http/provider-model-fetcher-registry.js +0 -7
- package/dist/server/infra/provider/env-provider-detector.d.ts +0 -20
- package/dist/server/infra/provider/env-provider-detector.js +0 -27
- package/dist/server/infra/storage/file-provider-config-store.d.ts +0 -4
- package/dist/server/infra/storage/file-provider-config-store.js +0 -6
- package/dist/server/utils/file-content-reader.d.ts +2 -1
- package/dist/server/utils/file-helpers.d.ts +0 -24
- package/dist/server/utils/file-helpers.js +0 -81
- package/dist/server/utils/process-logger.d.ts +0 -13
- package/dist/server/utils/process-logger.js +1 -78
- package/node_modules/@campfirein/brv-transport-client/LICENSE +95 -0
- package/node_modules/@campfirein/brv-transport-client/README.md +3 -4
- package/node_modules/@campfirein/brv-transport-client/package.json +2 -2
- package/oclif.manifest.json +132 -132
- package/package.json +5 -3
- package/dist/server/core/domain/entities/bullet.d.ts +0 -51
- package/dist/server/core/domain/entities/bullet.js +0 -94
- package/dist/server/core/domain/entities/memory.d.ts +0 -55
- package/dist/server/core/domain/entities/memory.js +0 -90
- package/dist/server/core/domain/entities/playbook.d.ts +0 -80
- package/dist/server/core/domain/entities/playbook.js +0 -214
- package/dist/server/core/domain/entities/presigned-url.d.ts +0 -9
- package/dist/server/core/domain/entities/presigned-url.js +0 -18
- package/dist/server/core/domain/entities/presigned-urls-response.d.ts +0 -10
- package/dist/server/core/domain/entities/presigned-urls-response.js +0 -18
- package/dist/server/core/domain/entities/retrieve-result.d.ts +0 -35
- package/dist/server/core/domain/entities/retrieve-result.js +0 -35
- package/dist/server/core/domain/errors/headless-prompt-error.d.ts +0 -11
- package/dist/server/core/domain/errors/headless-prompt-error.js +0 -18
- package/dist/server/core/interfaces/services/i-legacy-rule-detector.d.ts +0 -56
- package/dist/server/core/interfaces/services/i-legacy-rule-detector.js +0 -1
- package/dist/server/core/interfaces/services/i-memory-retrieval-service.d.ts +0 -39
- package/dist/server/core/interfaces/services/i-memory-retrieval-service.js +0 -1
- package/dist/server/core/interfaces/services/i-memory-storage-service.d.ts +0 -53
- package/dist/server/core/interfaces/services/i-memory-storage-service.js +0 -1
- package/dist/server/core/interfaces/services/i-terminal.d.ts +0 -146
- package/dist/server/core/interfaces/services/i-terminal.js +0 -1
- package/dist/server/core/interfaces/services/i-workspace-detector-service.d.ts +0 -8
- package/dist/server/core/interfaces/services/i-workspace-detector-service.js +0 -1
- package/dist/server/core/interfaces/storage/i-onboarding-preference-store.d.ts +0 -20
- package/dist/server/core/interfaces/storage/i-onboarding-preference-store.js +0 -1
- package/dist/server/infra/connectors/rules/legacy-rule-detector.d.ts +0 -21
- package/dist/server/infra/connectors/rules/legacy-rule-detector.js +0 -106
- package/dist/server/infra/memory/http-memory-retrieval-service.d.ts +0 -18
- package/dist/server/infra/memory/http-memory-retrieval-service.js +0 -64
- package/dist/server/infra/memory/http-memory-storage-service.d.ts +0 -18
- package/dist/server/infra/memory/http-memory-storage-service.js +0 -72
- package/dist/server/infra/memory/memory-to-playbook-mapper.d.ts +0 -33
- package/dist/server/infra/memory/memory-to-playbook-mapper.js +0 -51
- package/dist/server/infra/storage/file-onboarding-preference-store.d.ts +0 -10
- package/dist/server/infra/storage/file-onboarding-preference-store.js +0 -45
- package/dist/server/infra/terminal/headless-terminal.d.ts +0 -91
- package/dist/server/infra/terminal/headless-terminal.js +0 -211
- package/dist/server/infra/workspace/workspace-detector-service.d.ts +0 -57
- package/dist/server/infra/workspace/workspace-detector-service.js +0 -165
- package/dist/server/utils/crash-log.d.ts +0 -14
- package/dist/server/utils/crash-log.js +0 -19
- package/dist/server/utils/emoji-helpers.d.ts +0 -38
- package/dist/server/utils/emoji-helpers.js +0 -42
- package/dist/server/utils/error-handler.d.ts +0 -51
- package/dist/server/utils/error-handler.js +0 -169
- package/dist/server/utils/oclif-error-helpers.d.ts +0 -40
- package/dist/server/utils/oclif-error-helpers.js +0 -46
- package/dist/server/utils/tool-display-formatter.d.ts +0 -53
- package/dist/server/utils/tool-display-formatter.js +0 -257
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Bullet } from '../../core/domain/entities/bullet.js';
|
|
2
|
-
import { Playbook } from '../../core/domain/entities/playbook.js';
|
|
3
|
-
/**
|
|
4
|
-
* Transforms a Memory entity into a Bullet entity for playbook storage.
|
|
5
|
-
*
|
|
6
|
-
* Mapping:
|
|
7
|
-
* - memory.bulletId -> bullet.id
|
|
8
|
-
* - memory.section -> bullet.section
|
|
9
|
-
* - memory.content -> bullet.content
|
|
10
|
-
* - memory.tags -> bullet.metadata.tags
|
|
11
|
-
* - memory.nodeKeys -> bullet.metadata.relatedFiles
|
|
12
|
-
* - memory.timestamp -> bullet.metadata.timestamp
|
|
13
|
-
* - memory.id -> bullet.memoryId
|
|
14
|
-
*
|
|
15
|
-
* @param memory The Memory entity to transform
|
|
16
|
-
* @returns A Bullet entity
|
|
17
|
-
*/
|
|
18
|
-
export const transformMemoryToBullet = (memory) => {
|
|
19
|
-
const metadata = {
|
|
20
|
-
relatedFiles: [...memory.nodeKeys],
|
|
21
|
-
tags: [...memory.tags],
|
|
22
|
-
timestamp: memory.timestamp,
|
|
23
|
-
};
|
|
24
|
-
return new Bullet(memory.bulletId, memory.section, memory.content, metadata, memory.id);
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Transforms a RetrieveResult into a Playbook.
|
|
28
|
-
*
|
|
29
|
-
* This function:
|
|
30
|
-
* 1. Combines both memories and relatedMemories from the result
|
|
31
|
-
* 2. Transforms each Memory into a Bullet
|
|
32
|
-
* 3. Organizes bullets by section
|
|
33
|
-
* 4. Creates a new Playbook with nextId set to 1 (reset value)
|
|
34
|
-
*
|
|
35
|
-
* @param result The RetrieveResult containing memories from Memora service
|
|
36
|
-
* @returns A Playbook containing all retrieved memories as bullets
|
|
37
|
-
*/
|
|
38
|
-
export const transformRetrieveResultToPlaybook = (result) => {
|
|
39
|
-
const bulletsMap = new Map();
|
|
40
|
-
const sectionsMap = new Map();
|
|
41
|
-
const allMemories = [...result.memories, ...result.relatedMemories];
|
|
42
|
-
for (const memory of allMemories) {
|
|
43
|
-
const bullet = transformMemoryToBullet(memory);
|
|
44
|
-
bulletsMap.set(bullet.id, bullet);
|
|
45
|
-
if (!sectionsMap.has(bullet.section)) {
|
|
46
|
-
sectionsMap.set(bullet.section, []);
|
|
47
|
-
}
|
|
48
|
-
sectionsMap.get(bullet.section).push(bullet.id);
|
|
49
|
-
}
|
|
50
|
-
return new Playbook(bulletsMap, sectionsMap, bulletsMap.size + 1);
|
|
51
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { IOnboardingPreferenceStore } from '../../core/interfaces/storage/i-onboarding-preference-store.js';
|
|
2
|
-
/**
|
|
3
|
-
* Onboarding preference store implementation using a lock file.
|
|
4
|
-
* Stores last dismissed timestamp in XDG data directory.
|
|
5
|
-
*/
|
|
6
|
-
export declare class FileOnboardingPreferenceStore implements IOnboardingPreferenceStore {
|
|
7
|
-
clear(): Promise<void>;
|
|
8
|
-
getLastDismissedAt(): Promise<number | undefined>;
|
|
9
|
-
setLastDismissedAt(timestamp: number): Promise<void>;
|
|
10
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { getGlobalDataDir } from '../../utils/global-data-path.js';
|
|
4
|
-
const ONBOARDING_LOCK_FILE = join(getGlobalDataDir(), '.onboarding-dismissed');
|
|
5
|
-
/**
|
|
6
|
-
* Onboarding preference store implementation using a lock file.
|
|
7
|
-
* Stores last dismissed timestamp in XDG data directory.
|
|
8
|
-
*/
|
|
9
|
-
export class FileOnboardingPreferenceStore {
|
|
10
|
-
async clear() {
|
|
11
|
-
try {
|
|
12
|
-
if (existsSync(ONBOARDING_LOCK_FILE)) {
|
|
13
|
-
rmSync(ONBOARDING_LOCK_FILE);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
// Ignore errors
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
async getLastDismissedAt() {
|
|
21
|
-
try {
|
|
22
|
-
if (!existsSync(ONBOARDING_LOCK_FILE)) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
const content = readFileSync(ONBOARDING_LOCK_FILE, 'utf8').trim();
|
|
26
|
-
const timestamp = Number.parseInt(content, 10);
|
|
27
|
-
return Number.isNaN(timestamp) ? undefined : timestamp;
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async setLastDismissedAt(timestamp) {
|
|
34
|
-
try {
|
|
35
|
-
const parentDir = dirname(ONBOARDING_LOCK_FILE);
|
|
36
|
-
if (!existsSync(parentDir)) {
|
|
37
|
-
mkdirSync(parentDir, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
writeFileSync(ONBOARDING_LOCK_FILE, String(timestamp), 'utf8');
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
// Silently ignore errors - onboarding preference is non-critical
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { ConfirmOptions, FileSelectorItem, FileSelectorOptions, InputOptions, ITerminal, SearchOptions, SelectOptions } from '../../core/interfaces/services/i-terminal.js';
|
|
2
|
-
/**
|
|
3
|
-
* Output format for headless terminal.
|
|
4
|
-
* - 'text': Human-readable text output
|
|
5
|
-
* - 'json': NDJSON (newline-delimited JSON) for machine parsing
|
|
6
|
-
*/
|
|
7
|
-
export type HeadlessOutputFormat = 'json' | 'text';
|
|
8
|
-
/**
|
|
9
|
-
* JSON message types for structured output.
|
|
10
|
-
*/
|
|
11
|
-
export type HeadlessMessageType = 'action_start' | 'action_stop' | 'error' | 'log' | 'result' | 'warning';
|
|
12
|
-
/**
|
|
13
|
-
* Structured JSON output message.
|
|
14
|
-
*/
|
|
15
|
-
export interface HeadlessJsonMessage {
|
|
16
|
-
actionId?: string;
|
|
17
|
-
id: string;
|
|
18
|
-
message: string;
|
|
19
|
-
timestamp: string;
|
|
20
|
-
type: HeadlessMessageType;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Options for creating a HeadlessTerminal.
|
|
24
|
-
*/
|
|
25
|
-
export interface HeadlessTerminalOptions {
|
|
26
|
-
/**
|
|
27
|
-
* Stream for errors (defaults to process.stderr).
|
|
28
|
-
*/
|
|
29
|
-
errorStream?: NodeJS.WritableStream;
|
|
30
|
-
/**
|
|
31
|
-
* If true, throw HeadlessPromptError when a prompt cannot be answered.
|
|
32
|
-
* If false, use sensible defaults (first choice, false for confirm, etc.)
|
|
33
|
-
* @default true
|
|
34
|
-
*/
|
|
35
|
-
failOnPrompt?: boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Output format: 'text' for human readable, 'json' for machine parsing.
|
|
38
|
-
* @default 'text'
|
|
39
|
-
*/
|
|
40
|
-
outputFormat?: HeadlessOutputFormat;
|
|
41
|
-
/**
|
|
42
|
-
* Stream for output (defaults to process.stdout).
|
|
43
|
-
*/
|
|
44
|
-
outputStream?: NodeJS.WritableStream;
|
|
45
|
-
/**
|
|
46
|
-
* Default values for prompts, keyed by prompt message or prompt type.
|
|
47
|
-
* Used to answer prompts automatically in headless mode.
|
|
48
|
-
*/
|
|
49
|
-
promptDefaults?: Record<string, unknown>;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Terminal implementation for headless/non-interactive mode.
|
|
53
|
-
* Outputs to stdout/stderr and handles prompts via defaults or fails gracefully.
|
|
54
|
-
*/
|
|
55
|
-
export declare class HeadlessTerminal implements ITerminal {
|
|
56
|
-
private currentActionId;
|
|
57
|
-
private readonly errorOutput;
|
|
58
|
-
private readonly failOnPrompt;
|
|
59
|
-
private readonly output;
|
|
60
|
-
private readonly outputFormat;
|
|
61
|
-
private readonly promptDefaults;
|
|
62
|
-
constructor(options?: HeadlessTerminalOptions);
|
|
63
|
-
actionStart(message: string): void;
|
|
64
|
-
actionStop(message?: string): void;
|
|
65
|
-
confirm(options: ConfirmOptions): Promise<boolean>;
|
|
66
|
-
error(message: string): void;
|
|
67
|
-
fileSelector(options: FileSelectorOptions): Promise<FileSelectorItem | null>;
|
|
68
|
-
input(options: InputOptions): Promise<string>;
|
|
69
|
-
log(message?: string): void;
|
|
70
|
-
search<T>(options: SearchOptions<T>): Promise<T>;
|
|
71
|
-
select<T>(options: SelectOptions<T>): Promise<T>;
|
|
72
|
-
warn(message: string): void;
|
|
73
|
-
/**
|
|
74
|
-
* Write final response with success/error status.
|
|
75
|
-
*/
|
|
76
|
-
writeFinalResponse(response: {
|
|
77
|
-
command: string;
|
|
78
|
-
data?: unknown;
|
|
79
|
-
error?: {
|
|
80
|
-
code: string;
|
|
81
|
-
message: string;
|
|
82
|
-
};
|
|
83
|
-
success: boolean;
|
|
84
|
-
}): void;
|
|
85
|
-
/**
|
|
86
|
-
* Write final result in JSON format (convenience method for commands).
|
|
87
|
-
*/
|
|
88
|
-
writeResult(data: Record<string, unknown>): void;
|
|
89
|
-
private getDefault;
|
|
90
|
-
private writeJson;
|
|
91
|
-
}
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { HeadlessPromptError } from '../../core/domain/errors/headless-prompt-error.js';
|
|
3
|
-
/**
|
|
4
|
-
* Terminal implementation for headless/non-interactive mode.
|
|
5
|
-
* Outputs to stdout/stderr and handles prompts via defaults or fails gracefully.
|
|
6
|
-
*/
|
|
7
|
-
export class HeadlessTerminal {
|
|
8
|
-
currentActionId = null;
|
|
9
|
-
errorOutput;
|
|
10
|
-
failOnPrompt;
|
|
11
|
-
output;
|
|
12
|
-
outputFormat;
|
|
13
|
-
promptDefaults;
|
|
14
|
-
constructor(options = {}) {
|
|
15
|
-
this.outputFormat = options.outputFormat ?? 'text';
|
|
16
|
-
this.promptDefaults = options.promptDefaults ?? {};
|
|
17
|
-
this.failOnPrompt = options.failOnPrompt ?? true;
|
|
18
|
-
this.output = options.outputStream ?? process.stdout;
|
|
19
|
-
this.errorOutput = options.errorStream ?? process.stderr;
|
|
20
|
-
}
|
|
21
|
-
// ==================== Output Methods ====================
|
|
22
|
-
actionStart(message) {
|
|
23
|
-
this.currentActionId = randomUUID();
|
|
24
|
-
if (this.outputFormat === 'json') {
|
|
25
|
-
this.writeJson({
|
|
26
|
-
actionId: this.currentActionId,
|
|
27
|
-
id: randomUUID(),
|
|
28
|
-
message,
|
|
29
|
-
timestamp: new Date().toISOString(),
|
|
30
|
-
type: 'action_start',
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
// In text mode, suppress action start for cleaner output
|
|
34
|
-
}
|
|
35
|
-
actionStop(message) {
|
|
36
|
-
if (this.outputFormat === 'json' && this.currentActionId) {
|
|
37
|
-
this.writeJson({
|
|
38
|
-
actionId: this.currentActionId,
|
|
39
|
-
id: randomUUID(),
|
|
40
|
-
message: message ?? '',
|
|
41
|
-
timestamp: new Date().toISOString(),
|
|
42
|
-
type: 'action_stop',
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
this.currentActionId = null;
|
|
46
|
-
}
|
|
47
|
-
async confirm(options) {
|
|
48
|
-
// Check for explicit default in promptDefaults
|
|
49
|
-
const defaultValue = this.getDefault('confirm', options.message);
|
|
50
|
-
if (defaultValue !== undefined) {
|
|
51
|
-
return Boolean(defaultValue);
|
|
52
|
-
}
|
|
53
|
-
// Use options.default if provided
|
|
54
|
-
if (options.default !== undefined) {
|
|
55
|
-
return options.default;
|
|
56
|
-
}
|
|
57
|
-
// Fail or return false
|
|
58
|
-
if (this.failOnPrompt) {
|
|
59
|
-
throw new HeadlessPromptError('confirm', options.message);
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
error(message) {
|
|
64
|
-
if (this.outputFormat === 'json') {
|
|
65
|
-
this.writeJson({
|
|
66
|
-
id: randomUUID(),
|
|
67
|
-
message,
|
|
68
|
-
timestamp: new Date().toISOString(),
|
|
69
|
-
type: 'error',
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
this.errorOutput.write(`Error: ${message}\n`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async fileSelector(options) {
|
|
77
|
-
// Check for explicit default in promptDefaults
|
|
78
|
-
const defaultValue = this.getDefault('file_selector', options.message);
|
|
79
|
-
if (defaultValue !== undefined && typeof defaultValue === 'string') {
|
|
80
|
-
return {
|
|
81
|
-
isDirectory: options.type === 'directory',
|
|
82
|
-
name: defaultValue.split('/').pop() ?? defaultValue,
|
|
83
|
-
path: defaultValue,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
// Allow cancel if specified
|
|
87
|
-
if (options.allowCancel) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
// Fail
|
|
91
|
-
if (this.failOnPrompt) {
|
|
92
|
-
throw new HeadlessPromptError('file_selector', options.message);
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
// ==================== Input Methods ====================
|
|
97
|
-
async input(options) {
|
|
98
|
-
// Check for explicit default in promptDefaults
|
|
99
|
-
const defaultValue = this.getDefault('input', options.message);
|
|
100
|
-
if (defaultValue !== undefined) {
|
|
101
|
-
const value = String(defaultValue);
|
|
102
|
-
// Validate if validator is provided
|
|
103
|
-
if (options.validate) {
|
|
104
|
-
const validationResult = options.validate(value);
|
|
105
|
-
if (validationResult !== true) {
|
|
106
|
-
const errorMsg = typeof validationResult === 'string' ? validationResult : 'Validation failed';
|
|
107
|
-
throw new HeadlessPromptError('input', `${options.message} (validation error: ${errorMsg})`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
// Fail
|
|
113
|
-
if (this.failOnPrompt) {
|
|
114
|
-
throw new HeadlessPromptError('input', options.message);
|
|
115
|
-
}
|
|
116
|
-
return '';
|
|
117
|
-
}
|
|
118
|
-
log(message) {
|
|
119
|
-
if (this.outputFormat === 'json') {
|
|
120
|
-
this.writeJson({
|
|
121
|
-
id: randomUUID(),
|
|
122
|
-
message: message ?? '',
|
|
123
|
-
timestamp: new Date().toISOString(),
|
|
124
|
-
type: 'log',
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
this.output.write((message ?? '') + '\n');
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
async search(options) {
|
|
132
|
-
// Search prompts require user interaction - always fail in headless mode
|
|
133
|
-
// unless a default is explicitly provided
|
|
134
|
-
const defaultValue = this.getDefault('search', options.message);
|
|
135
|
-
if (defaultValue !== undefined) {
|
|
136
|
-
return defaultValue;
|
|
137
|
-
}
|
|
138
|
-
throw new HeadlessPromptError('search', options.message);
|
|
139
|
-
}
|
|
140
|
-
async select(options) {
|
|
141
|
-
// Check for explicit default in promptDefaults (by value or name)
|
|
142
|
-
const defaultValue = this.getDefault('select', options.message);
|
|
143
|
-
if (defaultValue !== undefined) {
|
|
144
|
-
const choice = options.choices.find((c) => c.value === defaultValue || c.name === defaultValue);
|
|
145
|
-
if (choice) {
|
|
146
|
-
return choice.value;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
// Fail or return first choice
|
|
150
|
-
if (this.failOnPrompt) {
|
|
151
|
-
throw new HeadlessPromptError('select', options.message, options.choices.map((c) => c.name));
|
|
152
|
-
}
|
|
153
|
-
// Return first choice as fallback
|
|
154
|
-
if (options.choices.length > 0) {
|
|
155
|
-
return options.choices[0].value;
|
|
156
|
-
}
|
|
157
|
-
throw new HeadlessPromptError('select', options.message, []);
|
|
158
|
-
}
|
|
159
|
-
warn(message) {
|
|
160
|
-
if (this.outputFormat === 'json') {
|
|
161
|
-
this.writeJson({
|
|
162
|
-
id: randomUUID(),
|
|
163
|
-
message,
|
|
164
|
-
timestamp: new Date().toISOString(),
|
|
165
|
-
type: 'warning',
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
this.errorOutput.write(`Warning: ${message}\n`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// ==================== Helper Methods ====================
|
|
173
|
-
/**
|
|
174
|
-
* Write final response with success/error status.
|
|
175
|
-
*/
|
|
176
|
-
writeFinalResponse(response) {
|
|
177
|
-
if (this.outputFormat === 'json') {
|
|
178
|
-
this.output.write(JSON.stringify({
|
|
179
|
-
...response,
|
|
180
|
-
timestamp: new Date().toISOString(),
|
|
181
|
-
}) + '\n');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Write final result in JSON format (convenience method for commands).
|
|
186
|
-
*/
|
|
187
|
-
writeResult(data) {
|
|
188
|
-
if (this.outputFormat === 'json') {
|
|
189
|
-
this.writeJson({
|
|
190
|
-
id: randomUUID(),
|
|
191
|
-
message: JSON.stringify(data),
|
|
192
|
-
timestamp: new Date().toISOString(),
|
|
193
|
-
type: 'result',
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
getDefault(promptType, promptMessage) {
|
|
198
|
-
// First check by exact message
|
|
199
|
-
if (this.promptDefaults[promptMessage] !== undefined) {
|
|
200
|
-
return this.promptDefaults[promptMessage];
|
|
201
|
-
}
|
|
202
|
-
// Then check by prompt type
|
|
203
|
-
if (this.promptDefaults[promptType] !== undefined) {
|
|
204
|
-
return this.promptDefaults[promptType];
|
|
205
|
-
}
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
writeJson(data) {
|
|
209
|
-
this.output.write(JSON.stringify(data) + '\n');
|
|
210
|
-
}
|
|
211
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { Agent } from '../../core/domain/entities/agent.js';
|
|
2
|
-
import type { IWorkspaceDetectorService, WorkspaceInfo } from '../../core/interfaces/services/i-workspace-detector-service.js';
|
|
3
|
-
/**
|
|
4
|
-
* Service to detect IDE workspaces that contain the current working directory
|
|
5
|
-
* Supports: VS Code (Github Copilot), Cursor, Claude, and Codex
|
|
6
|
-
*/
|
|
7
|
-
export declare class WorkspaceDetectorService implements IWorkspaceDetectorService {
|
|
8
|
-
private readonly claudeUserPath;
|
|
9
|
-
private readonly codexUserPath;
|
|
10
|
-
private readonly cursorUserPath;
|
|
11
|
-
private readonly cwd;
|
|
12
|
-
private readonly vscodeUserPath;
|
|
13
|
-
constructor(cwd?: string);
|
|
14
|
-
/**
|
|
15
|
-
* Detect workspaces for the given IDE
|
|
16
|
-
*
|
|
17
|
-
* Supports: Github Copilot (VSCode), Cursor, Claude Code, Codex
|
|
18
|
-
*
|
|
19
|
-
* chatLogPath:
|
|
20
|
-
* - For Cursor/VSCode: Path to workspace storage folder if workspace.json matches cwd
|
|
21
|
-
* - For Claude Code: Path to claude project folder matching cwd (with special naming pattern)
|
|
22
|
-
* - For Codex: Direct path to codex sessions folder
|
|
23
|
-
*/
|
|
24
|
-
detectWorkspaces(agent: Agent): WorkspaceInfo;
|
|
25
|
-
/**
|
|
26
|
-
* Convert current working directory to Claude Code folder name format
|
|
27
|
-
* Example: /Users/datpham/dpmemories/byterover-cli -> -Users-datpham-dpmemories-byterover-cli
|
|
28
|
-
*/
|
|
29
|
-
private cwdToClaudeFolderName;
|
|
30
|
-
/**
|
|
31
|
-
* Detect Claude Code workspaces
|
|
32
|
-
* Claude Code stores projects in ~/.claude/projects with folder names like "-Users-datpham-dpmemories-byterover-cli"
|
|
33
|
-
* These folder names are derived from the project path with slashes replaced by dashes
|
|
34
|
-
*/
|
|
35
|
-
private detectClaudeWorkspaces;
|
|
36
|
-
/**
|
|
37
|
-
* Detect Codex workspaces
|
|
38
|
-
* Codex uses a single sessions folder
|
|
39
|
-
*/
|
|
40
|
-
private detectCodexWorkspaces;
|
|
41
|
-
/**
|
|
42
|
-
* Detect Cursor workspaces
|
|
43
|
-
*/
|
|
44
|
-
private detectCursorWorkspaces;
|
|
45
|
-
/**
|
|
46
|
-
* Detect VSCode workspaces (Github Copilot)
|
|
47
|
-
*/
|
|
48
|
-
private detectVSCodeWorkspaces;
|
|
49
|
-
/**
|
|
50
|
-
* Detect workspaces using workspace.json file (VSCode, Cursor)
|
|
51
|
-
*/
|
|
52
|
-
private detectWorkspacesByFile;
|
|
53
|
-
/**
|
|
54
|
-
* Check if current working directory is within the given workspace folder
|
|
55
|
-
*/
|
|
56
|
-
private isCurrentDirInWorkspace;
|
|
57
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
/**
|
|
5
|
-
* Service to detect IDE workspaces that contain the current working directory
|
|
6
|
-
* Supports: VS Code (Github Copilot), Cursor, Claude, and Codex
|
|
7
|
-
*/
|
|
8
|
-
export class WorkspaceDetectorService {
|
|
9
|
-
claudeUserPath;
|
|
10
|
-
codexUserPath;
|
|
11
|
-
cursorUserPath;
|
|
12
|
-
cwd;
|
|
13
|
-
vscodeUserPath;
|
|
14
|
-
constructor(cwd = process.cwd()) {
|
|
15
|
-
this.cwd = cwd;
|
|
16
|
-
this.vscodeUserPath = join(homedir(), 'Library/Application Support/Code/User/workspaceStorage');
|
|
17
|
-
this.cursorUserPath = join(homedir(), 'Library/Application Support/Cursor/User/workspaceStorage');
|
|
18
|
-
this.claudeUserPath = join(homedir(), '.claude/projects');
|
|
19
|
-
this.codexUserPath = join(homedir(), '.codex/sessions');
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Detect workspaces for the given IDE
|
|
23
|
-
*
|
|
24
|
-
* Supports: Github Copilot (VSCode), Cursor, Claude Code, Codex
|
|
25
|
-
*
|
|
26
|
-
* chatLogPath:
|
|
27
|
-
* - For Cursor/VSCode: Path to workspace storage folder if workspace.json matches cwd
|
|
28
|
-
* - For Claude Code: Path to claude project folder matching cwd (with special naming pattern)
|
|
29
|
-
* - For Codex: Direct path to codex sessions folder
|
|
30
|
-
*/
|
|
31
|
-
detectWorkspaces(agent) {
|
|
32
|
-
const chatLogPath = '';
|
|
33
|
-
switch (agent) {
|
|
34
|
-
case 'Claude Code': {
|
|
35
|
-
return this.detectClaudeWorkspaces(chatLogPath);
|
|
36
|
-
}
|
|
37
|
-
case 'Codex': {
|
|
38
|
-
return this.detectCodexWorkspaces(chatLogPath);
|
|
39
|
-
}
|
|
40
|
-
case 'Cursor': {
|
|
41
|
-
return this.detectCursorWorkspaces(chatLogPath);
|
|
42
|
-
}
|
|
43
|
-
case 'Github Copilot': {
|
|
44
|
-
return this.detectVSCodeWorkspaces(chatLogPath);
|
|
45
|
-
}
|
|
46
|
-
default: {
|
|
47
|
-
return { chatLogPath, cwd: this.cwd };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Convert current working directory to Claude Code folder name format
|
|
53
|
-
* Example: /Users/datpham/dpmemories/byterover-cli -> -Users-datpham-dpmemories-byterover-cli
|
|
54
|
-
*/
|
|
55
|
-
cwdToClaudeFolderName(cwd) {
|
|
56
|
-
// Remove leading slash and replace all slashes with dashes, then prepend dash
|
|
57
|
-
return '-' + cwd.slice(1).replaceAll('/', '-');
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Detect Claude Code workspaces
|
|
61
|
-
* Claude Code stores projects in ~/.claude/projects with folder names like "-Users-datpham-dpmemories-byterover-cli"
|
|
62
|
-
* These folder names are derived from the project path with slashes replaced by dashes
|
|
63
|
-
*/
|
|
64
|
-
detectClaudeWorkspaces(chatLogPath) {
|
|
65
|
-
try {
|
|
66
|
-
if (!existsSync(this.claudeUserPath)) {
|
|
67
|
-
return { chatLogPath, cwd: this.cwd };
|
|
68
|
-
}
|
|
69
|
-
// Convert cwd to Claude folder name format: /Users/datpham/dpmemories/byterover-cli -> -Users-datpham-dpmemories-byterover-cli
|
|
70
|
-
const claudeFolderName = this.cwdToClaudeFolderName(this.cwd);
|
|
71
|
-
const projectFolders = readdirSync(this.claudeUserPath);
|
|
72
|
-
for (const folderName of projectFolders) {
|
|
73
|
-
const folderPath = join(this.claudeUserPath, folderName);
|
|
74
|
-
// Check if this folder matches the current working directory
|
|
75
|
-
if (folderName === claudeFolderName) {
|
|
76
|
-
chatLogPath = folderPath;
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
// Ignore directory read errors
|
|
83
|
-
}
|
|
84
|
-
return { chatLogPath, cwd: this.cwd };
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Detect Codex workspaces
|
|
88
|
-
* Codex uses a single sessions folder
|
|
89
|
-
*/
|
|
90
|
-
detectCodexWorkspaces(chatLogPath) {
|
|
91
|
-
try {
|
|
92
|
-
if (existsSync(this.codexUserPath)) {
|
|
93
|
-
chatLogPath = this.codexUserPath;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
// Ignore errors
|
|
98
|
-
}
|
|
99
|
-
return { chatLogPath, cwd: this.cwd };
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Detect Cursor workspaces
|
|
103
|
-
*/
|
|
104
|
-
detectCursorWorkspaces(chatLogPath) {
|
|
105
|
-
return this.detectWorkspacesByFile(this.cursorUserPath, chatLogPath);
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Detect VSCode workspaces (Github Copilot)
|
|
109
|
-
*/
|
|
110
|
-
detectVSCodeWorkspaces(chatLogPath) {
|
|
111
|
-
return this.detectWorkspacesByFile(this.vscodeUserPath, chatLogPath);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Detect workspaces using workspace.json file (VSCode, Cursor)
|
|
115
|
-
*/
|
|
116
|
-
detectWorkspacesByFile(userPath, chatLogPath) {
|
|
117
|
-
try {
|
|
118
|
-
if (!existsSync(userPath)) {
|
|
119
|
-
return { chatLogPath, cwd: this.cwd };
|
|
120
|
-
}
|
|
121
|
-
const workspaceIds = readdirSync(userPath);
|
|
122
|
-
for (const wsId of workspaceIds) {
|
|
123
|
-
const wsPath = join(userPath, wsId);
|
|
124
|
-
const workspaceFile = join(wsPath, 'workspace.json');
|
|
125
|
-
if (!existsSync(workspaceFile)) {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
const content = readFileSync(workspaceFile, 'utf8');
|
|
130
|
-
const data = JSON.parse(content);
|
|
131
|
-
// Only handle single folder windows (workspace files are ignored)
|
|
132
|
-
if (!data.folder) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
const folderPath = decodeURIComponent(data.folder.replace('file://', ''));
|
|
136
|
-
// Set chatLogPath ONLY if folder exactly matches cwd
|
|
137
|
-
if (folderPath === this.cwd) {
|
|
138
|
-
chatLogPath = wsPath;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
// Ignore JSON parse errors
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
// Ignore directory read errors
|
|
148
|
-
}
|
|
149
|
-
return { chatLogPath, cwd: this.cwd };
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Check if current working directory is within the given workspace folder
|
|
153
|
-
*/
|
|
154
|
-
isCurrentDirInWorkspace(folderPath) {
|
|
155
|
-
// Exact match
|
|
156
|
-
if (this.cwd === folderPath) {
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
// Check if current dir is a subdirectory
|
|
160
|
-
if (this.cwd.startsWith(folderPath + '/')) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crash Log - Re-exports from unified process-logger.
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Use crashLog from process-logger.ts directly.
|
|
5
|
-
* This file is kept for backwards compatibility.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* @deprecated Use crashLog from process-logger.ts
|
|
9
|
-
*/
|
|
10
|
-
export declare function writeCrashLog(error: Error | string, context?: string): Promise<string>;
|
|
11
|
-
/**
|
|
12
|
-
* @deprecated Use getSessionLogPath from process-logger.ts
|
|
13
|
-
*/
|
|
14
|
-
export declare function getLogsDir(): string;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crash Log - Re-exports from unified process-logger.
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Use crashLog from process-logger.ts directly.
|
|
5
|
-
* This file is kept for backwards compatibility.
|
|
6
|
-
*/
|
|
7
|
-
import { crashLog, getSessionLogPath } from './process-logger.js';
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated Use crashLog from process-logger.ts
|
|
10
|
-
*/
|
|
11
|
-
export async function writeCrashLog(error, context) {
|
|
12
|
-
return crashLog(error, context);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* @deprecated Use getSessionLogPath from process-logger.ts
|
|
16
|
-
*/
|
|
17
|
-
export function getLogsDir() {
|
|
18
|
-
return getSessionLogPath();
|
|
19
|
-
}
|