codehere 0.7.1 → 1.0.1

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 (139) hide show
  1. package/README.md +22 -13
  2. package/dist/application/services/verdict-service.js +154 -0
  3. package/dist/application/use-cases/assess-cross-vendor.js +126 -0
  4. package/dist/application/use-cases/build-cross-vendor-verdict.js +118 -0
  5. package/dist/application/use-cases/export-aat.js +107 -0
  6. package/dist/application/use-cases/generate-acceptance-criteria.js +223 -0
  7. package/dist/application/use-cases/generate-final-report.js +140 -15
  8. package/dist/application/use-cases/generate-narration.js +5 -3
  9. package/dist/application/use-cases/generate-thread-title.js +5 -2
  10. package/dist/application/use-cases/narrator-prompt-template.js +1 -1
  11. package/dist/application/use-cases/plan-auto-review.js +57 -0
  12. package/dist/application/use-cases/reconcile-audit.js +100 -0
  13. package/dist/application/use-cases/rerun-tests.js +226 -0
  14. package/dist/application/use-cases/search-sessions.js +70 -0
  15. package/dist/application/use-cases/should-auto-review.js +71 -0
  16. package/dist/application/use-cases/thread-export.js +90 -0
  17. package/dist/application/use-cases/verify-claim.js +187 -5
  18. package/dist/domain/audit.js +11 -0
  19. package/dist/domain/services/codebase-detector.js +0 -6
  20. package/dist/domain/task.js +91 -0
  21. package/dist/error-handler.js +3 -115
  22. package/dist/index.js +279 -31
  23. package/dist/infrastructure/completion/bash-completion.js +7 -3
  24. package/dist/infrastructure/completion/fish-completion.js +7 -12
  25. package/dist/infrastructure/completion/zsh-completion.js +7 -12
  26. package/dist/infrastructure/config/config-manager.js +4 -3
  27. package/dist/infrastructure/config/product-context.js +1 -19
  28. package/dist/infrastructure/context/adapters/figma-source.js +37 -2
  29. package/dist/infrastructure/context/adapters/github-issue-source.js +3 -2
  30. package/dist/infrastructure/context/github-api.js +110 -0
  31. package/dist/infrastructure/context/github-device-flow.js +65 -0
  32. package/dist/infrastructure/context/oauth-store.js +5 -2
  33. package/dist/infrastructure/context/registry-bootstrap.js +0 -4
  34. package/dist/infrastructure/cost/budget-config.js +4 -3
  35. package/dist/infrastructure/cost/cost-router.js +16 -23
  36. package/dist/infrastructure/cost/spend-aggregator.js +91 -16
  37. package/dist/infrastructure/cost/team-ledger.js +355 -0
  38. package/dist/infrastructure/discovery/discovery-log.js +85 -0
  39. package/dist/infrastructure/hooks/audit-tip-signature.js +336 -0
  40. package/dist/infrastructure/hooks/claude-sdk-hook.js +139 -3
  41. package/dist/infrastructure/hooks/hook-mode.js +20 -4
  42. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +8 -2
  43. package/dist/infrastructure/hooks/pre-prompt-scan.js +3 -3
  44. package/dist/infrastructure/observability/execution-tracer.js +1 -1
  45. package/dist/infrastructure/orchestration/agents-config-seed.js +23 -11
  46. package/dist/infrastructure/orchestration/aider-adapter.js +188 -24
  47. package/dist/infrastructure/orchestration/artifacts-extractor.js +60 -2
  48. package/dist/infrastructure/orchestration/cassette-recorder.js +1 -1
  49. package/dist/infrastructure/orchestration/claude-code-adapter.js +117 -3
  50. package/dist/infrastructure/orchestration/codex-adapter.js +52 -16
  51. package/dist/infrastructure/orchestration/conductor-adapter.js +46 -7
  52. package/dist/infrastructure/orchestration/context-handoff.js +32 -14
  53. package/dist/infrastructure/orchestration/detect-ollama.js +75 -0
  54. package/dist/infrastructure/orchestration/failover-config.js +1 -11
  55. package/dist/infrastructure/orchestration/gemini-adapter.js +92 -12
  56. package/dist/infrastructure/orchestration/generic-cli-adapter.js +134 -3
  57. package/dist/infrastructure/orchestration/graphify-context.js +14 -59
  58. package/dist/infrastructure/orchestration/memory-injector.js +4 -1
  59. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +167 -9
  60. package/dist/infrastructure/orchestration/opencode-adapter.js +84 -14
  61. package/dist/infrastructure/orchestration/progress-aggregator.js +275 -23
  62. package/dist/infrastructure/orchestration/session-manager.js +593 -94
  63. package/dist/infrastructure/orchestration/session-persistence.js +177 -41
  64. package/dist/infrastructure/orchestration/thread-key-store.js +1 -1
  65. package/dist/infrastructure/orchestration/write-pass-store.js +0 -8
  66. package/dist/infrastructure/protocols/cloud-sync.js +2 -2
  67. package/dist/infrastructure/protocols/mcp-helpers.js +1 -1
  68. package/dist/infrastructure/protocols/mcp-server-impl.js +1498 -354
  69. package/dist/infrastructure/protocols/mcp-tools.js +401 -0
  70. package/dist/infrastructure/protocols/ui/app-script-artifacts.js +121 -0
  71. package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +44 -0
  72. package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +56 -0
  73. package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +588 -0
  74. package/dist/infrastructure/protocols/ui/app-script-context-sources.js +168 -0
  75. package/dist/infrastructure/protocols/ui/app-script-conversation.js +67 -0
  76. package/dist/infrastructure/protocols/ui/app-script-drawer.js +115 -0
  77. package/dist/infrastructure/protocols/ui/app-script-failover.js +133 -0
  78. package/dist/infrastructure/protocols/ui/app-script-github.js +113 -0
  79. package/dist/infrastructure/protocols/ui/app-script-observer.js +104 -0
  80. package/dist/infrastructure/protocols/ui/app-script-onboarding.js +80 -0
  81. package/dist/infrastructure/protocols/ui/app-script-overlay.js +203 -0
  82. package/dist/infrastructure/protocols/ui/app-script-recovery.js +136 -0
  83. package/dist/infrastructure/protocols/ui/app-script-render.js +166 -0
  84. package/dist/infrastructure/protocols/ui/app-script-share.js +78 -0
  85. package/dist/infrastructure/protocols/ui/app-script-sidebar.js +194 -0
  86. package/dist/infrastructure/protocols/ui/app-script-tour.js +78 -0
  87. package/dist/infrastructure/protocols/ui/app-script-wpass.js +312 -0
  88. package/dist/infrastructure/protocols/ui/app-script.js +2998 -0
  89. package/dist/infrastructure/protocols/ui/font-faces.js +7 -0
  90. package/dist/infrastructure/protocols/ui/styles.js +2147 -0
  91. package/dist/infrastructure/protocols/ui/tokens.js +96 -0
  92. package/dist/infrastructure/protocols/ui-page-v2.js +116 -4126
  93. package/dist/infrastructure/protocols/verify-page.js +884 -148
  94. package/dist/infrastructure/security/fix-code.js +144 -0
  95. package/dist/infrastructure/security/fix-secret.js +89 -0
  96. package/dist/infrastructure/security/permissions-config.js +3 -2
  97. package/dist/infrastructure/security/scan-types.js +10 -0
  98. package/dist/infrastructure/security/ship-scan.js +195 -0
  99. package/dist/infrastructure/security/trust-scorer.js +70 -3
  100. package/dist/infrastructure/security/vibe-checks.js +99 -0
  101. package/dist/infrastructure/storage/atomic-write.js +86 -0
  102. package/dist/infrastructure/storage/project-thread-mirror.js +151 -4
  103. package/dist/infrastructure/storage/project-thread-reader.js +262 -25
  104. package/dist/infrastructure/storage/project-thread-title-backfill.js +1 -1
  105. package/dist/monitoring.js +2 -2
  106. package/dist/presentation/cli/commands/audit-command.js +79 -4
  107. package/dist/presentation/cli/commands/budget-command.js +2 -2
  108. package/dist/presentation/cli/commands/check-command.js +96 -0
  109. package/dist/presentation/cli/commands/context-source-command.js +20 -1
  110. package/dist/presentation/cli/commands/help-command.js +5 -5
  111. package/dist/presentation/cli/commands/hook-command.js +5 -5
  112. package/dist/presentation/cli/commands/init-command.js +89 -66
  113. package/dist/presentation/cli/commands/memory-command.js +28 -28
  114. package/dist/presentation/cli/commands/permission-command.js +1 -12
  115. package/dist/presentation/cli/commands/protocols-builder.js +2 -2
  116. package/dist/presentation/cli/commands/protocols-command.js +4 -4
  117. package/dist/presentation/cli/commands/repo-map-builder.js +1 -1
  118. package/dist/presentation/cli/commands/report-command.js +48 -32
  119. package/dist/presentation/cli/commands/scan-command.js +52 -0
  120. package/dist/presentation/cli/commands/scan-tool-command.js +24 -8
  121. package/dist/presentation/cli/commands/search-command.js +51 -0
  122. package/dist/presentation/cli/commands/setup-command.js +31 -8
  123. package/dist/presentation/cli/commands/status-command.js +39 -86
  124. package/dist/presentation/cli/commands/team-command.js +256 -0
  125. package/dist/presentation/cli/commands/thread-command.js +87 -5
  126. package/dist/presentation/cli/commands/trust-command.js +53 -31
  127. package/dist/presentation/cli/commands/verify-command.js +74 -9
  128. package/dist/presentation/cli/error-display.js +0 -8
  129. package/dist/presentation/cli/repl.js +15 -7
  130. package/dist/presentation/cli/task-deliverable.js +36 -10
  131. package/dist/testing/replay-adapter.js +0 -19
  132. package/dist/ui.js +51 -239
  133. package/dist/utils/version.js +0 -6
  134. package/package.json +30 -10
  135. package/dist/domain/entities/task.js +0 -61
  136. package/dist/infrastructure/protocols/ui-page.js +0 -2377
  137. package/dist/infrastructure/security/input-validator.js +0 -152
  138. package/dist/infrastructure/storage/embeddings-path.js +0 -37
  139. package/dist/infrastructure/storage/task-repository.js +0 -206
@@ -1,152 +0,0 @@
1
- /**
2
- * Infrastructure: Input Validator
3
- * Enterprise-grade input validation and sanitization
4
- *
5
- * Clean Architecture: Infrastructure Layer
6
- * Security: Prevents injection attacks, validates user input
7
- */
8
- /**
9
- * Validate file path to prevent directory traversal
10
- */
11
- export function validateFilePath(filepath) {
12
- const errors = [];
13
- // Check for directory traversal attempts
14
- if (filepath.includes('..') || filepath.includes('~')) {
15
- errors.push('Directory traversal detected in file path');
16
- }
17
- // Check for absolute paths (should be relative)
18
- if (filepath.startsWith('/') || /^[A-Z]:\\/.test(filepath)) {
19
- errors.push('Absolute paths not allowed');
20
- }
21
- // Check for null bytes
22
- if (filepath.includes('\0')) {
23
- errors.push('Null bytes not allowed in file path');
24
- }
25
- // Check for dangerous characters
26
- const dangerousChars = /[<>:"|?*\x00-\x1f]/;
27
- if (dangerousChars.test(filepath)) {
28
- errors.push('Invalid characters in file path');
29
- }
30
- // Sanitize path
31
- let sanitized = filepath
32
- .replace(/\.\./g, '') // Remove ..
33
- .replace(/~/g, '') // Remove ~
34
- .replace(/\0/g, '') // Remove null bytes
35
- .replace(/[<>:"|?*\x00-\x1f]/g, '_'); // Replace dangerous chars
36
- // Normalize path separators
37
- sanitized = sanitized.replace(/\\/g, '/');
38
- return {
39
- valid: errors.length === 0,
40
- errors,
41
- sanitized: errors.length > 0 ? sanitized : undefined,
42
- };
43
- }
44
- /**
45
- * Validate query string to prevent injection
46
- */
47
- export function validateQuery(query) {
48
- const errors = [];
49
- // Check for null bytes
50
- if (query.includes('\0')) {
51
- errors.push('Null bytes not allowed in query');
52
- }
53
- // Check for command injection patterns
54
- const commandInjectionPatterns = [
55
- /[;&|`$(){}[\]]/, // Shell metacharacters
56
- /<script/i, // XSS attempts
57
- /javascript:/i, // JavaScript protocol
58
- /on\w+\s*=/i, // Event handlers
59
- ];
60
- for (const pattern of commandInjectionPatterns) {
61
- if (pattern.test(query)) {
62
- errors.push('Potentially dangerous characters detected in query');
63
- break;
64
- }
65
- }
66
- // Sanitize query
67
- let sanitized = query
68
- .replace(/\0/g, '') // Remove null bytes
69
- .replace(/[;&|`$(){}[\]]/g, '') // Remove shell metacharacters
70
- .replace(/<script/gi, '&lt;script') // Escape script tags
71
- .replace(/javascript:/gi, '') // Remove javascript protocol
72
- .replace(/on\w+\s*=/gi, ''); // Remove event handlers
73
- // Trim and limit length
74
- sanitized = sanitized.trim();
75
- const MAX_QUERY_LENGTH = 10000; // Reasonable limit
76
- if (sanitized.length > MAX_QUERY_LENGTH) {
77
- errors.push(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);
78
- sanitized = sanitized.substring(0, MAX_QUERY_LENGTH);
79
- }
80
- return {
81
- valid: errors.length === 0,
82
- errors,
83
- sanitized: errors.length > 0 ? sanitized : undefined,
84
- };
85
- }
86
- /**
87
- * Validate API key format
88
- */
89
- export function validateAPIKey(apiKey) {
90
- const errors = [];
91
- if (!apiKey || apiKey.trim().length === 0) {
92
- errors.push('API key is required');
93
- }
94
- // Check minimum length
95
- if (apiKey.length < 10) {
96
- errors.push('API key is too short');
97
- }
98
- // Check for null bytes
99
- if (apiKey.includes('\0')) {
100
- errors.push('Null bytes not allowed in API key');
101
- }
102
- // Check for whitespace (API keys shouldn't have spaces)
103
- if (apiKey !== apiKey.trim()) {
104
- errors.push('API key should not have leading or trailing whitespace');
105
- }
106
- return {
107
- valid: errors.length === 0,
108
- errors,
109
- sanitized: errors.length > 0 ? apiKey.trim() : undefined,
110
- };
111
- }
112
- /**
113
- * Validate file content before processing
114
- */
115
- export function validateFileContent(content, maxSize = 10 * 1024 * 1024) {
116
- const errors = [];
117
- // Check size
118
- const sizeInBytes = new Blob([content]).size;
119
- if (sizeInBytes > maxSize) {
120
- errors.push(`File content exceeds maximum size of ${maxSize} bytes`);
121
- }
122
- // Check for null bytes (shouldn't be in text files)
123
- if (content.includes('\0')) {
124
- errors.push('Null bytes detected in file content');
125
- }
126
- return {
127
- valid: errors.length === 0,
128
- errors,
129
- };
130
- }
131
- /**
132
- * Sanitize user input for logging (prevent sensitive data leakage)
133
- */
134
- export function sanitizeForLogging(input) {
135
- // Remove potential secrets (API keys, tokens, etc.)
136
- let sanitized = input
137
- // Remove API keys (Cohere format: alphanumeric, 40+ chars)
138
- .replace(/[A-Za-z0-9]{40,}/g, '[REDACTED]')
139
- // Remove email addresses
140
- .replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, '[EMAIL_REDACTED]')
141
- // Remove potential tokens
142
- .replace(/token[=:]\s*[A-Za-z0-9_-]+/gi, 'token=[REDACTED]')
143
- .replace(/password[=:]\s*[^\s]+/gi, 'password=[REDACTED]')
144
- .replace(/secret[=:]\s*[^\s]+/gi, 'secret=[REDACTED]');
145
- // Limit length for logging
146
- const MAX_LOG_LENGTH = 1000;
147
- if (sanitized.length > MAX_LOG_LENGTH) {
148
- sanitized = sanitized.substring(0, MAX_LOG_LENGTH) + '...[TRUNCATED]';
149
- }
150
- return sanitized;
151
- }
152
- //# sourceMappingURL=input-validator.js.map
@@ -1,37 +0,0 @@
1
- /**
2
- * Infrastructure: Embeddings Path Helper
3
- * Determines per-codebase embeddings database path
4
- */
5
- import { join } from 'path';
6
- import { existsSync, mkdirSync } from 'fs';
7
- import { findCodebaseRoot } from '../../domain/services/codebase-detector.js';
8
- /**
9
- * Get embeddings database path for a specific codebase
10
- * Uses codebase root detection to ensure per-repo isolation
11
- *
12
- * @param cwd - Current working directory (defaults to process.cwd())
13
- * @returns Object with root path, database path, and cache directory
14
- */
15
- export function getEmbeddingsDbPath(cwd = process.cwd()) {
16
- const codebaseInfo = findCodebaseRoot(cwd);
17
- if (!codebaseInfo) {
18
- // Fallback to cwd if codebase root can't be determined
19
- const root = cwd;
20
- const dbPath = join(root, '.codehere-cache', 'embeddings.sqlite');
21
- const cacheDir = join(root, '.codehere-cache');
22
- // Ensure cache directory exists
23
- if (!existsSync(cacheDir)) {
24
- mkdirSync(cacheDir, { recursive: true });
25
- }
26
- return { root, dbPath, cacheDir };
27
- }
28
- const root = codebaseInfo.rootPath;
29
- const dbPath = join(root, '.codehere-cache', 'embeddings.sqlite');
30
- const cacheDir = join(root, '.codehere-cache');
31
- // Ensure cache directory exists
32
- if (!existsSync(cacheDir)) {
33
- mkdirSync(cacheDir, { recursive: true });
34
- }
35
- return { root, dbPath, cacheDir };
36
- }
37
- //# sourceMappingURL=embeddings-path.js.map
@@ -1,206 +0,0 @@
1
- /**
2
- * Infrastructure: Task Repository
3
- * Task storage and retrieval using JSONL format
4
- *
5
- * Phase 1: v0.5.0-alpha
6
- * See: .internal/ARCHITECTURE.md (internal docs)
7
- */
8
- import { appendFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
9
- import { join, dirname } from 'path';
10
- import { findCodebaseRoot } from '../../domain/services/codebase-detector.js';
11
- /**
12
- * JSONL-based task repository
13
- * Stores tasks in .codehere/tasks.jsonl at codebase root
14
- */
15
- export class JsonlTaskRepository {
16
- tasksPath;
17
- tasksCache = new Map();
18
- cacheLoaded = false;
19
- constructor(customPath) {
20
- if (customPath) {
21
- this.tasksPath = customPath;
22
- }
23
- else {
24
- // Use environment variable or detect from codebase root
25
- const envPath = process.env.CODEHERE_TASKS_PATH;
26
- if (envPath) {
27
- this.tasksPath = envPath;
28
- }
29
- else {
30
- // Detect codebase root and use .codehere/tasks.jsonl
31
- const codebaseInfo = findCodebaseRoot(process.cwd());
32
- const codebaseRoot = codebaseInfo?.rootPath || process.cwd();
33
- const codehereDir = join(codebaseRoot, '.codehere');
34
- // Ensure .codehere directory exists
35
- if (!existsSync(codehereDir)) {
36
- mkdirSync(codehereDir, { recursive: true });
37
- }
38
- this.tasksPath = join(codehereDir, 'tasks.jsonl');
39
- }
40
- }
41
- // Ensure directory exists
42
- const tasksDir = dirname(this.tasksPath);
43
- if (!existsSync(tasksDir)) {
44
- mkdirSync(tasksDir, { recursive: true });
45
- }
46
- }
47
- /**
48
- * Load tasks from JSONL file into cache
49
- * For duplicate IDs, keeps the latest version (by updatedAt)
50
- */
51
- loadTasks() {
52
- if (this.cacheLoaded) {
53
- return;
54
- }
55
- if (!existsSync(this.tasksPath)) {
56
- this.cacheLoaded = true;
57
- return;
58
- }
59
- try {
60
- const content = readFileSync(this.tasksPath, 'utf-8');
61
- const lines = content
62
- .trim()
63
- .split('\n')
64
- .filter((line) => line.trim());
65
- // Load all tasks, then keep only the latest version of each ID
66
- const allTasks = [];
67
- for (const line of lines) {
68
- try {
69
- const task = JSON.parse(line);
70
- allTasks.push(task);
71
- }
72
- catch {
73
- // Skip invalid lines
74
- }
75
- }
76
- // Group by ID and keep latest version
77
- const taskMap = new Map();
78
- for (const task of allTasks) {
79
- const existing = taskMap.get(task.id);
80
- if (!existing || task.updatedAt > existing.updatedAt) {
81
- taskMap.set(task.id, task);
82
- }
83
- }
84
- this.tasksCache = taskMap;
85
- this.cacheLoaded = true;
86
- }
87
- catch (error) {
88
- // Silent failure - don't break user workflow
89
- console.error('[TaskRepository] Failed to load tasks:', error);
90
- this.cacheLoaded = true;
91
- }
92
- }
93
- /**
94
- * Create a new task
95
- */
96
- async create(task) {
97
- // Ensure cache is loaded
98
- this.loadTasks();
99
- // Set timestamps if not provided
100
- const now = Date.now();
101
- const taskToCreate = {
102
- ...task,
103
- createdAt: task.createdAt || now,
104
- updatedAt: task.updatedAt || now,
105
- };
106
- // Add to cache
107
- this.tasksCache.set(taskToCreate.id, taskToCreate);
108
- // Append to JSONL file (append-only, immutable history)
109
- try {
110
- appendFileSync(this.tasksPath, JSON.stringify(taskToCreate) + '\n', 'utf-8');
111
- }
112
- catch (error) {
113
- // Silent failure - remove from cache if write failed
114
- this.tasksCache.delete(taskToCreate.id);
115
- console.error('[TaskRepository] Failed to create task:', error);
116
- throw error;
117
- }
118
- }
119
- /**
120
- * Get task by ID (returns latest version if multiple exist)
121
- */
122
- async getById(id) {
123
- this.loadTasks();
124
- // Load all tasks and find the latest version of this ID
125
- const allTasks = Array.from(this.tasksCache.values());
126
- const tasksWithId = allTasks.filter((task) => task.id === id);
127
- if (tasksWithId.length === 0) {
128
- return null;
129
- }
130
- // Return the task with the latest updatedAt timestamp
131
- return tasksWithId.reduce((latest, current) => {
132
- return current.updatedAt > latest.updatedAt ? current : latest;
133
- });
134
- }
135
- /**
136
- * Get tasks by status
137
- */
138
- async getByStatus(status) {
139
- this.loadTasks();
140
- const tasks = Array.from(this.tasksCache.values());
141
- return tasks.filter((task) => task.status === status);
142
- }
143
- /**
144
- * Get tasks by mode
145
- */
146
- async getByMode(mode) {
147
- this.loadTasks();
148
- const tasks = Array.from(this.tasksCache.values());
149
- return tasks.filter((task) => task.mode === mode);
150
- }
151
- /**
152
- * Get recent tasks (latest updated first)
153
- */
154
- async getRecent(limit = 10) {
155
- this.loadTasks();
156
- const tasks = Array.from(this.tasksCache.values());
157
- return tasks.sort((a, b) => b.updatedAt - a.updatedAt).slice(0, limit);
158
- }
159
- /**
160
- * Get all tasks (latest version of each)
161
- */
162
- async getAll() {
163
- this.loadTasks();
164
- return Array.from(this.tasksCache.values());
165
- }
166
- /**
167
- * Update existing task
168
- * Creates a new entry in JSONL (append-only)
169
- */
170
- async update(task) {
171
- // Ensure cache is loaded
172
- this.loadTasks();
173
- // Update timestamp
174
- const updatedTask = {
175
- ...task,
176
- updatedAt: Date.now(),
177
- };
178
- // Update cache
179
- this.tasksCache.set(updatedTask.id, updatedTask);
180
- // Append updated version to JSONL (append-only, immutable history)
181
- try {
182
- appendFileSync(this.tasksPath, JSON.stringify(updatedTask) + '\n', 'utf-8');
183
- }
184
- catch (error) {
185
- // Revert cache if write failed
186
- const original = await this.getById(task.id);
187
- if (original) {
188
- this.tasksCache.set(task.id, original);
189
- }
190
- console.error('[TaskRepository] Failed to update task:', error);
191
- throw error;
192
- }
193
- }
194
- }
195
- // Singleton instance (lazy initialization with codebase detection)
196
- let taskRepositoryInstance = null;
197
- /**
198
- * Get task repository instance
199
- */
200
- export function getTaskRepository(customPath) {
201
- if (!taskRepositoryInstance || customPath) {
202
- taskRepositoryInstance = new JsonlTaskRepository(customPath);
203
- }
204
- return taskRepositoryInstance;
205
- }
206
- //# sourceMappingURL=task-repository.js.map