byterover-cli 2.5.1 → 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.
Files changed (85) hide show
  1. package/.env.production +7 -0
  2. package/LICENSE +44 -0
  3. package/bin/dev.js +8 -1
  4. package/bin/run.js +8 -1
  5. package/dist/server/config/environment.d.ts +0 -19
  6. package/dist/server/config/environment.js +29 -38
  7. package/dist/server/constants.d.ts +0 -9
  8. package/dist/server/constants.js +0 -12
  9. package/dist/server/core/domain/errors/auth-error.d.ts +0 -6
  10. package/dist/server/core/domain/errors/auth-error.js +0 -12
  11. package/dist/server/core/domain/errors/task-error.d.ts +0 -3
  12. package/dist/server/core/domain/errors/task-error.js +0 -8
  13. package/dist/server/core/domain/errors/transport-error.d.ts +0 -31
  14. package/dist/server/core/domain/errors/transport-error.js +0 -50
  15. package/dist/server/infra/connectors/rules/rules-connector-config.d.ts +0 -4
  16. package/dist/server/infra/http/models-dev-client.d.ts +0 -4
  17. package/dist/server/infra/http/models-dev-client.js +0 -6
  18. package/dist/server/infra/http/openrouter-api-client.d.ts +0 -8
  19. package/dist/server/infra/http/openrouter-api-client.js +0 -13
  20. package/dist/server/infra/http/provider-model-fetcher-registry.d.ts +0 -5
  21. package/dist/server/infra/http/provider-model-fetcher-registry.js +0 -7
  22. package/dist/server/infra/provider/env-provider-detector.d.ts +0 -20
  23. package/dist/server/infra/provider/env-provider-detector.js +0 -27
  24. package/dist/server/infra/storage/file-provider-config-store.d.ts +0 -4
  25. package/dist/server/infra/storage/file-provider-config-store.js +0 -6
  26. package/dist/server/utils/file-content-reader.d.ts +2 -1
  27. package/dist/server/utils/file-helpers.d.ts +0 -24
  28. package/dist/server/utils/file-helpers.js +0 -81
  29. package/dist/server/utils/process-logger.d.ts +0 -13
  30. package/dist/server/utils/process-logger.js +1 -78
  31. package/node_modules/@campfirein/brv-transport-client/LICENSE +95 -0
  32. package/node_modules/@campfirein/brv-transport-client/README.md +3 -4
  33. package/node_modules/@campfirein/brv-transport-client/package.json +2 -2
  34. package/oclif.manifest.json +1 -1
  35. package/package.json +6 -4
  36. package/dist/server/core/domain/entities/bullet.d.ts +0 -51
  37. package/dist/server/core/domain/entities/bullet.js +0 -94
  38. package/dist/server/core/domain/entities/memory.d.ts +0 -55
  39. package/dist/server/core/domain/entities/memory.js +0 -90
  40. package/dist/server/core/domain/entities/playbook.d.ts +0 -80
  41. package/dist/server/core/domain/entities/playbook.js +0 -214
  42. package/dist/server/core/domain/entities/presigned-url.d.ts +0 -9
  43. package/dist/server/core/domain/entities/presigned-url.js +0 -18
  44. package/dist/server/core/domain/entities/presigned-urls-response.d.ts +0 -10
  45. package/dist/server/core/domain/entities/presigned-urls-response.js +0 -18
  46. package/dist/server/core/domain/entities/retrieve-result.d.ts +0 -35
  47. package/dist/server/core/domain/entities/retrieve-result.js +0 -35
  48. package/dist/server/core/domain/errors/headless-prompt-error.d.ts +0 -11
  49. package/dist/server/core/domain/errors/headless-prompt-error.js +0 -18
  50. package/dist/server/core/interfaces/services/i-legacy-rule-detector.d.ts +0 -56
  51. package/dist/server/core/interfaces/services/i-legacy-rule-detector.js +0 -1
  52. package/dist/server/core/interfaces/services/i-memory-retrieval-service.d.ts +0 -39
  53. package/dist/server/core/interfaces/services/i-memory-retrieval-service.js +0 -1
  54. package/dist/server/core/interfaces/services/i-memory-storage-service.d.ts +0 -53
  55. package/dist/server/core/interfaces/services/i-memory-storage-service.js +0 -1
  56. package/dist/server/core/interfaces/services/i-terminal.d.ts +0 -146
  57. package/dist/server/core/interfaces/services/i-terminal.js +0 -1
  58. package/dist/server/core/interfaces/services/i-workspace-detector-service.d.ts +0 -8
  59. package/dist/server/core/interfaces/services/i-workspace-detector-service.js +0 -1
  60. package/dist/server/core/interfaces/storage/i-onboarding-preference-store.d.ts +0 -20
  61. package/dist/server/core/interfaces/storage/i-onboarding-preference-store.js +0 -1
  62. package/dist/server/infra/connectors/rules/legacy-rule-detector.d.ts +0 -21
  63. package/dist/server/infra/connectors/rules/legacy-rule-detector.js +0 -106
  64. package/dist/server/infra/memory/http-memory-retrieval-service.d.ts +0 -18
  65. package/dist/server/infra/memory/http-memory-retrieval-service.js +0 -64
  66. package/dist/server/infra/memory/http-memory-storage-service.d.ts +0 -18
  67. package/dist/server/infra/memory/http-memory-storage-service.js +0 -72
  68. package/dist/server/infra/memory/memory-to-playbook-mapper.d.ts +0 -33
  69. package/dist/server/infra/memory/memory-to-playbook-mapper.js +0 -51
  70. package/dist/server/infra/storage/file-onboarding-preference-store.d.ts +0 -10
  71. package/dist/server/infra/storage/file-onboarding-preference-store.js +0 -45
  72. package/dist/server/infra/terminal/headless-terminal.d.ts +0 -91
  73. package/dist/server/infra/terminal/headless-terminal.js +0 -211
  74. package/dist/server/infra/workspace/workspace-detector-service.d.ts +0 -57
  75. package/dist/server/infra/workspace/workspace-detector-service.js +0 -165
  76. package/dist/server/utils/crash-log.d.ts +0 -14
  77. package/dist/server/utils/crash-log.js +0 -19
  78. package/dist/server/utils/emoji-helpers.d.ts +0 -38
  79. package/dist/server/utils/emoji-helpers.js +0 -42
  80. package/dist/server/utils/error-handler.d.ts +0 -51
  81. package/dist/server/utils/error-handler.js +0 -169
  82. package/dist/server/utils/oclif-error-helpers.d.ts +0 -40
  83. package/dist/server/utils/oclif-error-helpers.js +0 -46
  84. package/dist/server/utils/tool-display-formatter.d.ts +0 -53
  85. package/dist/server/utils/tool-display-formatter.js +0 -257
@@ -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
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Emoji and message formatting helpers
3
- *
4
- * Provides utilities for checking and handling emoji prefixes in error messages
5
- * to prevent duplicate prefixes like "❌ Error: ❌ Billing error: ..."
6
- */
7
- /**
8
- * Check if a message already has an emoji prefix
9
- *
10
- * Detects common emoji prefixes used in CLI output:
11
- * - ❌ (error)
12
- * - ✓ (success)
13
- * - ⚠️ (warning)
14
- * - Any Unicode emoji in ranges U+1F300–U+1F9FF
15
- *
16
- * @param message - Message to check
17
- * @returns true if message starts with emoji, false otherwise
18
- *
19
- * @example
20
- * hasEmojiPrefix("❌ Error message") // true
21
- * hasEmojiPrefix("✓ Success") // true
22
- * hasEmojiPrefix("Normal message") // false
23
- */
24
- export declare function hasEmojiPrefix(message: string): boolean;
25
- /**
26
- * Add error prefix to message if it doesn't already have emoji prefix
27
- *
28
- * Prevents duplicate prefixes by checking if message already starts with emoji.
29
- * If message has emoji prefix, returns as-is. Otherwise, adds "❌ Error: " prefix.
30
- *
31
- * @param message - Error message to format
32
- * @returns Formatted error message with prefix
33
- *
34
- * @example
35
- * addErrorPrefix("❌ Billing error") // "❌ Billing error" (no duplicate)
36
- * addErrorPrefix("Something went wrong") // "❌ Error: Something went wrong"
37
- */
38
- export declare function addErrorPrefix(message: string): string;
@@ -1,42 +0,0 @@
1
- /**
2
- * Emoji and message formatting helpers
3
- *
4
- * Provides utilities for checking and handling emoji prefixes in error messages
5
- * to prevent duplicate prefixes like "❌ Error: ❌ Billing error: ..."
6
- */
7
- /**
8
- * Check if a message already has an emoji prefix
9
- *
10
- * Detects common emoji prefixes used in CLI output:
11
- * - ❌ (error)
12
- * - ✓ (success)
13
- * - ⚠️ (warning)
14
- * - Any Unicode emoji in ranges U+1F300–U+1F9FF
15
- *
16
- * @param message - Message to check
17
- * @returns true if message starts with emoji, false otherwise
18
- *
19
- * @example
20
- * hasEmojiPrefix("❌ Error message") // true
21
- * hasEmojiPrefix("✓ Success") // true
22
- * hasEmojiPrefix("Normal message") // false
23
- */
24
- export function hasEmojiPrefix(message) {
25
- return /^[\u{1F300}-\u{1F9FF}]|^❌|^✓|^⚠️/u.test(message);
26
- }
27
- /**
28
- * Add error prefix to message if it doesn't already have emoji prefix
29
- *
30
- * Prevents duplicate prefixes by checking if message already starts with emoji.
31
- * If message has emoji prefix, returns as-is. Otherwise, adds "❌ Error: " prefix.
32
- *
33
- * @param message - Error message to format
34
- * @returns Formatted error message with prefix
35
- *
36
- * @example
37
- * addErrorPrefix("❌ Billing error") // "❌ Billing error" (no duplicate)
38
- * addErrorPrefix("Something went wrong") // "❌ Error: Something went wrong"
39
- */
40
- export function addErrorPrefix(message) {
41
- return hasEmojiPrefix(message) ? message : `❌ Error: ${message}`;
42
- }