@cleocode/adapters 2.0.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/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1927 -0
- package/dist/index.js.map +7 -0
- package/dist/providers/claude-code/adapter.d.ts +75 -0
- package/dist/providers/claude-code/adapter.d.ts.map +1 -0
- package/dist/providers/claude-code/adapter.js +154 -0
- package/dist/providers/claude-code/adapter.js.map +1 -0
- package/dist/providers/claude-code/context-monitor.d.ts +24 -0
- package/dist/providers/claude-code/context-monitor.d.ts.map +1 -0
- package/dist/providers/claude-code/context-monitor.js +148 -0
- package/dist/providers/claude-code/context-monitor.js.map +1 -0
- package/dist/providers/claude-code/hooks.d.ts +59 -0
- package/dist/providers/claude-code/hooks.d.ts.map +1 -0
- package/dist/providers/claude-code/hooks.js +77 -0
- package/dist/providers/claude-code/hooks.js.map +1 -0
- package/dist/providers/claude-code/index.d.ts +24 -0
- package/dist/providers/claude-code/index.d.ts.map +1 -0
- package/dist/providers/claude-code/index.js +26 -0
- package/dist/providers/claude-code/index.js.map +1 -0
- package/dist/providers/claude-code/install.d.ts +75 -0
- package/dist/providers/claude-code/install.d.ts.map +1 -0
- package/dist/providers/claude-code/install.js +237 -0
- package/dist/providers/claude-code/install.js.map +1 -0
- package/dist/providers/claude-code/paths.d.ts +24 -0
- package/dist/providers/claude-code/paths.d.ts.map +1 -0
- package/dist/providers/claude-code/paths.js +33 -0
- package/dist/providers/claude-code/paths.js.map +1 -0
- package/dist/providers/claude-code/spawn.d.ts +60 -0
- package/dist/providers/claude-code/spawn.d.ts.map +1 -0
- package/dist/providers/claude-code/spawn.js +160 -0
- package/dist/providers/claude-code/spawn.js.map +1 -0
- package/dist/providers/claude-code/statusline.d.ts +24 -0
- package/dist/providers/claude-code/statusline.d.ts.map +1 -0
- package/dist/providers/claude-code/statusline.js +85 -0
- package/dist/providers/claude-code/statusline.js.map +1 -0
- package/dist/providers/claude-code/task-sync.d.ts +27 -0
- package/dist/providers/claude-code/task-sync.d.ts.map +1 -0
- package/dist/providers/claude-code/task-sync.js +124 -0
- package/dist/providers/claude-code/task-sync.js.map +1 -0
- package/dist/providers/claude-code/transport.d.ts +14 -0
- package/dist/providers/claude-code/transport.d.ts.map +1 -0
- package/dist/providers/claude-code/transport.js +18 -0
- package/dist/providers/claude-code/transport.js.map +1 -0
- package/dist/providers/cursor/adapter.d.ts +62 -0
- package/dist/providers/cursor/adapter.d.ts.map +1 -0
- package/dist/providers/cursor/adapter.js +124 -0
- package/dist/providers/cursor/adapter.js.map +1 -0
- package/dist/providers/cursor/hooks.d.ts +48 -0
- package/dist/providers/cursor/hooks.d.ts.map +1 -0
- package/dist/providers/cursor/hooks.js +55 -0
- package/dist/providers/cursor/hooks.js.map +1 -0
- package/dist/providers/cursor/index.d.ts +19 -0
- package/dist/providers/cursor/index.d.ts.map +1 -0
- package/dist/providers/cursor/index.js +21 -0
- package/dist/providers/cursor/index.js.map +1 -0
- package/dist/providers/cursor/install.d.ts +94 -0
- package/dist/providers/cursor/install.d.ts.map +1 -0
- package/dist/providers/cursor/install.js +241 -0
- package/dist/providers/cursor/install.js.map +1 -0
- package/dist/providers/cursor/spawn.d.ts +50 -0
- package/dist/providers/cursor/spawn.d.ts.map +1 -0
- package/dist/providers/cursor/spawn.js +59 -0
- package/dist/providers/cursor/spawn.js.map +1 -0
- package/dist/providers/opencode/adapter.d.ts +67 -0
- package/dist/providers/opencode/adapter.d.ts.map +1 -0
- package/dist/providers/opencode/adapter.js +144 -0
- package/dist/providers/opencode/adapter.js.map +1 -0
- package/dist/providers/opencode/hooks.d.ts +66 -0
- package/dist/providers/opencode/hooks.d.ts.map +1 -0
- package/dist/providers/opencode/hooks.js +89 -0
- package/dist/providers/opencode/hooks.js.map +1 -0
- package/dist/providers/opencode/index.d.ts +20 -0
- package/dist/providers/opencode/index.d.ts.map +1 -0
- package/dist/providers/opencode/index.js +22 -0
- package/dist/providers/opencode/index.js.map +1 -0
- package/dist/providers/opencode/install.d.ts +65 -0
- package/dist/providers/opencode/install.d.ts.map +1 -0
- package/dist/providers/opencode/install.js +183 -0
- package/dist/providers/opencode/install.js.map +1 -0
- package/dist/providers/opencode/spawn.d.ts +72 -0
- package/dist/providers/opencode/spawn.d.ts.map +1 -0
- package/dist/providers/opencode/spawn.js +219 -0
- package/dist/providers/opencode/spawn.js.map +1 -0
- package/dist/registry.d.ts +36 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +55 -0
- package/dist/registry.js.map +1 -0
- package/package.json +32 -0
- package/src/index.d.ts +27 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +28 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +37 -0
- package/src/providers/claude-code/__tests__/adapter.test.d.ts +7 -0
- package/src/providers/claude-code/__tests__/adapter.test.d.ts.map +1 -0
- package/src/providers/claude-code/__tests__/adapter.test.js +249 -0
- package/src/providers/claude-code/__tests__/adapter.test.js.map +1 -0
- package/src/providers/claude-code/__tests__/adapter.test.ts +291 -0
- package/src/providers/claude-code/adapter.d.ts +75 -0
- package/src/providers/claude-code/adapter.d.ts.map +1 -0
- package/src/providers/claude-code/adapter.js +154 -0
- package/src/providers/claude-code/adapter.js.map +1 -0
- package/src/providers/claude-code/adapter.ts +175 -0
- package/src/providers/claude-code/context-monitor.d.ts +24 -0
- package/src/providers/claude-code/context-monitor.d.ts.map +1 -0
- package/src/providers/claude-code/context-monitor.js +148 -0
- package/src/providers/claude-code/context-monitor.js.map +1 -0
- package/src/providers/claude-code/context-monitor.ts +175 -0
- package/src/providers/claude-code/hooks.d.ts +59 -0
- package/src/providers/claude-code/hooks.d.ts.map +1 -0
- package/src/providers/claude-code/hooks.js +77 -0
- package/src/providers/claude-code/hooks.js.map +1 -0
- package/src/providers/claude-code/hooks.ts +85 -0
- package/src/providers/claude-code/index.d.ts +24 -0
- package/src/providers/claude-code/index.d.ts.map +1 -0
- package/src/providers/claude-code/index.js +26 -0
- package/src/providers/claude-code/index.js.map +1 -0
- package/src/providers/claude-code/index.ts +33 -0
- package/src/providers/claude-code/install.d.ts +75 -0
- package/src/providers/claude-code/install.d.ts.map +1 -0
- package/src/providers/claude-code/install.js +237 -0
- package/src/providers/claude-code/install.js.map +1 -0
- package/src/providers/claude-code/install.ts +267 -0
- package/src/providers/claude-code/manifest.json +26 -0
- package/src/providers/claude-code/paths.d.ts +24 -0
- package/src/providers/claude-code/paths.d.ts.map +1 -0
- package/src/providers/claude-code/paths.js +33 -0
- package/src/providers/claude-code/paths.js.map +1 -0
- package/src/providers/claude-code/paths.ts +38 -0
- package/src/providers/claude-code/spawn.d.ts +60 -0
- package/src/providers/claude-code/spawn.d.ts.map +1 -0
- package/src/providers/claude-code/spawn.js +160 -0
- package/src/providers/claude-code/spawn.js.map +1 -0
- package/src/providers/claude-code/spawn.ts +178 -0
- package/src/providers/claude-code/statusline.d.ts +24 -0
- package/src/providers/claude-code/statusline.d.ts.map +1 -0
- package/src/providers/claude-code/statusline.js +85 -0
- package/src/providers/claude-code/statusline.js.map +1 -0
- package/src/providers/claude-code/statusline.ts +99 -0
- package/src/providers/claude-code/task-sync.d.ts +27 -0
- package/src/providers/claude-code/task-sync.d.ts.map +1 -0
- package/src/providers/claude-code/task-sync.js +124 -0
- package/src/providers/claude-code/task-sync.js.map +1 -0
- package/src/providers/claude-code/task-sync.ts +158 -0
- package/src/providers/claude-code/transport.d.ts +14 -0
- package/src/providers/claude-code/transport.d.ts.map +1 -0
- package/src/providers/claude-code/transport.js +18 -0
- package/src/providers/claude-code/transport.js.map +1 -0
- package/src/providers/claude-code/transport.ts +21 -0
- package/src/providers/cursor/__tests__/adapter.test.d.ts +7 -0
- package/src/providers/cursor/__tests__/adapter.test.d.ts.map +1 -0
- package/src/providers/cursor/__tests__/adapter.test.js +246 -0
- package/src/providers/cursor/__tests__/adapter.test.js.map +1 -0
- package/src/providers/cursor/__tests__/adapter.test.ts +291 -0
- package/src/providers/cursor/adapter.d.ts +62 -0
- package/src/providers/cursor/adapter.d.ts.map +1 -0
- package/src/providers/cursor/adapter.js +124 -0
- package/src/providers/cursor/adapter.js.map +1 -0
- package/src/providers/cursor/adapter.ts +145 -0
- package/src/providers/cursor/hooks.d.ts +48 -0
- package/src/providers/cursor/hooks.d.ts.map +1 -0
- package/src/providers/cursor/hooks.js +55 -0
- package/src/providers/cursor/hooks.js.map +1 -0
- package/src/providers/cursor/hooks.ts +61 -0
- package/src/providers/cursor/index.d.ts +19 -0
- package/src/providers/cursor/index.d.ts.map +1 -0
- package/src/providers/cursor/index.js +21 -0
- package/src/providers/cursor/index.js.map +1 -0
- package/src/providers/cursor/index.ts +24 -0
- package/src/providers/cursor/install.d.ts +94 -0
- package/src/providers/cursor/install.d.ts.map +1 -0
- package/src/providers/cursor/install.js +241 -0
- package/src/providers/cursor/install.js.map +1 -0
- package/src/providers/cursor/install.ts +271 -0
- package/src/providers/cursor/manifest.json +26 -0
- package/src/providers/cursor/spawn.d.ts +50 -0
- package/src/providers/cursor/spawn.d.ts.map +1 -0
- package/src/providers/cursor/spawn.js +59 -0
- package/src/providers/cursor/spawn.js.map +1 -0
- package/src/providers/cursor/spawn.ts +66 -0
- package/src/providers/opencode/__tests__/adapter.test.d.ts +7 -0
- package/src/providers/opencode/__tests__/adapter.test.d.ts.map +1 -0
- package/src/providers/opencode/__tests__/adapter.test.js +263 -0
- package/src/providers/opencode/__tests__/adapter.test.js.map +1 -0
- package/src/providers/opencode/__tests__/adapter.test.ts +309 -0
- package/src/providers/opencode/adapter.d.ts +67 -0
- package/src/providers/opencode/adapter.d.ts.map +1 -0
- package/src/providers/opencode/adapter.js +144 -0
- package/src/providers/opencode/adapter.js.map +1 -0
- package/src/providers/opencode/adapter.ts +165 -0
- package/src/providers/opencode/hooks.d.ts +66 -0
- package/src/providers/opencode/hooks.d.ts.map +1 -0
- package/src/providers/opencode/hooks.js +89 -0
- package/src/providers/opencode/hooks.js.map +1 -0
- package/src/providers/opencode/hooks.ts +97 -0
- package/src/providers/opencode/index.d.ts +20 -0
- package/src/providers/opencode/index.d.ts.map +1 -0
- package/src/providers/opencode/index.js +22 -0
- package/src/providers/opencode/index.js.map +1 -0
- package/src/providers/opencode/index.ts +25 -0
- package/src/providers/opencode/install.d.ts +65 -0
- package/src/providers/opencode/install.d.ts.map +1 -0
- package/src/providers/opencode/install.js +183 -0
- package/src/providers/opencode/install.js.map +1 -0
- package/src/providers/opencode/install.ts +206 -0
- package/src/providers/opencode/manifest.json +26 -0
- package/src/providers/opencode/spawn.d.ts +72 -0
- package/src/providers/opencode/spawn.d.ts.map +1 -0
- package/src/providers/opencode/spawn.js +219 -0
- package/src/providers/opencode/spawn.js.map +1 -0
- package/src/providers/opencode/spawn.ts +253 -0
- package/src/registry.d.ts +36 -0
- package/src/registry.d.ts.map +1 -0
- package/src/registry.js +55 -0
- package/src/registry.js.map +1 -0
- package/src/registry.ts +81 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code TaskSyncProvider — bridges Claude's TodoWrite format
|
|
3
|
+
* to the provider-agnostic reconciliation system.
|
|
4
|
+
*
|
|
5
|
+
* All Claude Code / TodoWrite-specific parsing lives here.
|
|
6
|
+
* The core reconciliation engine never sees TodoWrite formats.
|
|
7
|
+
*
|
|
8
|
+
* @task T5800
|
|
9
|
+
*/
|
|
10
|
+
import { readFile, rm, stat } from 'node:fs/promises';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Parsing helpers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/**
|
|
16
|
+
* Parse a CLEO task ID from TodoWrite content prefix: "[T001] ..." -> "T001".
|
|
17
|
+
*/
|
|
18
|
+
function parseTaskId(content) {
|
|
19
|
+
const match = content.match(/^\[T(\d+)\]/);
|
|
20
|
+
return match ? `T${match[1]}` : null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Strip ID and status prefixes from content to extract the clean title.
|
|
24
|
+
*/
|
|
25
|
+
function stripPrefixes(content) {
|
|
26
|
+
return content
|
|
27
|
+
.replace(/^\[T\d+\]\s*/, '')
|
|
28
|
+
.replace(/^\[!\]\s*/, '')
|
|
29
|
+
.replace(/^\[BLOCKED\]\s*/, '');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Map TodoWrite status to normalized ExternalTaskStatus.
|
|
33
|
+
*/
|
|
34
|
+
function mapStatus(twStatus) {
|
|
35
|
+
switch (twStatus) {
|
|
36
|
+
case 'completed':
|
|
37
|
+
return 'completed';
|
|
38
|
+
case 'in_progress':
|
|
39
|
+
return 'active';
|
|
40
|
+
case 'pending':
|
|
41
|
+
return 'pending';
|
|
42
|
+
default:
|
|
43
|
+
return 'pending';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the TodoWrite state file path.
|
|
48
|
+
* Claude Code writes its TodoWrite state to a known location.
|
|
49
|
+
*/
|
|
50
|
+
function getTodoWriteFilePath(projectDir) {
|
|
51
|
+
return join(projectDir, '.cleo', 'sync', 'todowrite-state.json');
|
|
52
|
+
}
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Provider implementation
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
/**
|
|
57
|
+
* Claude Code TaskSyncProvider.
|
|
58
|
+
*
|
|
59
|
+
* Reads Claude's TodoWrite JSON state, parses [T001]-prefixed task IDs
|
|
60
|
+
* and status, and returns normalized ExternalTask[].
|
|
61
|
+
*
|
|
62
|
+
* Optional: accepts a custom file path for testing.
|
|
63
|
+
*/
|
|
64
|
+
export class ClaudeCodeTaskSyncProvider {
|
|
65
|
+
customFilePath;
|
|
66
|
+
constructor(options) {
|
|
67
|
+
this.customFilePath = options?.filePath;
|
|
68
|
+
}
|
|
69
|
+
async getExternalTasks(projectDir) {
|
|
70
|
+
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
71
|
+
// Check file exists
|
|
72
|
+
try {
|
|
73
|
+
await stat(filePath);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// No TodoWrite state — return empty (no tasks to sync)
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
// Parse the TodoWrite JSON
|
|
80
|
+
const raw = await readFile(filePath, 'utf-8');
|
|
81
|
+
let state;
|
|
82
|
+
try {
|
|
83
|
+
state = JSON.parse(raw);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return []; // Malformed JSON — treat as empty
|
|
87
|
+
}
|
|
88
|
+
if (!state.todos || !Array.isArray(state.todos)) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const tasks = [];
|
|
92
|
+
let syntheticIndex = 0;
|
|
93
|
+
for (const item of state.todos) {
|
|
94
|
+
const cleoTaskId = parseTaskId(item.content);
|
|
95
|
+
const title = cleoTaskId
|
|
96
|
+
? stripPrefixes(item.content).trim()
|
|
97
|
+
: item.content.trim();
|
|
98
|
+
if (!title)
|
|
99
|
+
continue;
|
|
100
|
+
tasks.push({
|
|
101
|
+
externalId: cleoTaskId ?? `tw-new-${syntheticIndex++}`,
|
|
102
|
+
cleoTaskId,
|
|
103
|
+
title,
|
|
104
|
+
status: mapStatus(item.status),
|
|
105
|
+
providerMeta: {
|
|
106
|
+
source: 'todowrite',
|
|
107
|
+
activeForm: item.activeForm,
|
|
108
|
+
rawContent: item.content,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return tasks;
|
|
113
|
+
}
|
|
114
|
+
async cleanup(projectDir) {
|
|
115
|
+
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
116
|
+
try {
|
|
117
|
+
await rm(filePath);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// File may not exist — that's fine
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=task-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-sync.js","sourceRoot":"","sources":["task-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code TaskSyncProvider — bridges Claude's TodoWrite format
|
|
3
|
+
* to the provider-agnostic reconciliation system.
|
|
4
|
+
*
|
|
5
|
+
* All Claude Code / TodoWrite-specific parsing lives here.
|
|
6
|
+
* The core reconciliation engine never sees TodoWrite formats.
|
|
7
|
+
*
|
|
8
|
+
* @task T5800
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFile, rm, stat } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
AdapterTaskSyncProvider,
|
|
16
|
+
ExternalTask,
|
|
17
|
+
ExternalTaskStatus,
|
|
18
|
+
} from '@cleocode/contracts';
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// TodoWrite native types (Claude-specific, never exposed beyond this file)
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
interface TodoWriteItem {
|
|
25
|
+
content: string;
|
|
26
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
27
|
+
activeForm?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface TodoWriteState {
|
|
31
|
+
todos: TodoWriteItem[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Parsing helpers
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Parse a CLEO task ID from TodoWrite content prefix: "[T001] ..." -> "T001".
|
|
40
|
+
*/
|
|
41
|
+
function parseTaskId(content: string): string | null {
|
|
42
|
+
const match = content.match(/^\[T(\d+)\]/);
|
|
43
|
+
return match ? `T${match[1]}` : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Strip ID and status prefixes from content to extract the clean title.
|
|
48
|
+
*/
|
|
49
|
+
function stripPrefixes(content: string): string {
|
|
50
|
+
return content
|
|
51
|
+
.replace(/^\[T\d+\]\s*/, '')
|
|
52
|
+
.replace(/^\[!\]\s*/, '')
|
|
53
|
+
.replace(/^\[BLOCKED\]\s*/, '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Map TodoWrite status to normalized ExternalTaskStatus.
|
|
58
|
+
*/
|
|
59
|
+
function mapStatus(twStatus: TodoWriteItem['status']): ExternalTaskStatus {
|
|
60
|
+
switch (twStatus) {
|
|
61
|
+
case 'completed':
|
|
62
|
+
return 'completed';
|
|
63
|
+
case 'in_progress':
|
|
64
|
+
return 'active';
|
|
65
|
+
case 'pending':
|
|
66
|
+
return 'pending';
|
|
67
|
+
default:
|
|
68
|
+
return 'pending';
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the TodoWrite state file path.
|
|
74
|
+
* Claude Code writes its TodoWrite state to a known location.
|
|
75
|
+
*/
|
|
76
|
+
function getTodoWriteFilePath(projectDir: string): string {
|
|
77
|
+
return join(projectDir, '.cleo', 'sync', 'todowrite-state.json');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Provider implementation
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Claude Code TaskSyncProvider.
|
|
86
|
+
*
|
|
87
|
+
* Reads Claude's TodoWrite JSON state, parses [T001]-prefixed task IDs
|
|
88
|
+
* and status, and returns normalized ExternalTask[].
|
|
89
|
+
*
|
|
90
|
+
* Optional: accepts a custom file path for testing.
|
|
91
|
+
*/
|
|
92
|
+
export class ClaudeCodeTaskSyncProvider implements AdapterTaskSyncProvider {
|
|
93
|
+
private readonly customFilePath?: string;
|
|
94
|
+
|
|
95
|
+
constructor(options?: { filePath?: string }) {
|
|
96
|
+
this.customFilePath = options?.filePath;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async getExternalTasks(projectDir: string): Promise<ExternalTask[]> {
|
|
100
|
+
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
101
|
+
|
|
102
|
+
// Check file exists
|
|
103
|
+
try {
|
|
104
|
+
await stat(filePath);
|
|
105
|
+
} catch {
|
|
106
|
+
// No TodoWrite state — return empty (no tasks to sync)
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Parse the TodoWrite JSON
|
|
111
|
+
const raw = await readFile(filePath, 'utf-8');
|
|
112
|
+
let state: TodoWriteState;
|
|
113
|
+
try {
|
|
114
|
+
state = JSON.parse(raw) as TodoWriteState;
|
|
115
|
+
} catch {
|
|
116
|
+
return []; // Malformed JSON — treat as empty
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!state.todos || !Array.isArray(state.todos)) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const tasks: ExternalTask[] = [];
|
|
124
|
+
let syntheticIndex = 0;
|
|
125
|
+
|
|
126
|
+
for (const item of state.todos) {
|
|
127
|
+
const cleoTaskId = parseTaskId(item.content);
|
|
128
|
+
const title = cleoTaskId
|
|
129
|
+
? stripPrefixes(item.content).trim()
|
|
130
|
+
: item.content.trim();
|
|
131
|
+
|
|
132
|
+
if (!title) continue;
|
|
133
|
+
|
|
134
|
+
tasks.push({
|
|
135
|
+
externalId: cleoTaskId ?? `tw-new-${syntheticIndex++}`,
|
|
136
|
+
cleoTaskId,
|
|
137
|
+
title,
|
|
138
|
+
status: mapStatus(item.status),
|
|
139
|
+
providerMeta: {
|
|
140
|
+
source: 'todowrite',
|
|
141
|
+
activeForm: item.activeForm,
|
|
142
|
+
rawContent: item.content,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return tasks;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async cleanup(projectDir: string): Promise<void> {
|
|
151
|
+
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
152
|
+
try {
|
|
153
|
+
await rm(filePath);
|
|
154
|
+
} catch {
|
|
155
|
+
// File may not exist — that's fine
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport provider for the Claude Code adapter.
|
|
3
|
+
*
|
|
4
|
+
* Implements AdapterTransportProvider to supply Claude Code's
|
|
5
|
+
* native inter-agent transport mechanism.
|
|
6
|
+
*
|
|
7
|
+
* @task T5240
|
|
8
|
+
*/
|
|
9
|
+
import type { AdapterTransportProvider } from '@cleocode/contracts';
|
|
10
|
+
export declare class ClaudeCodeTransportProvider implements AdapterTransportProvider {
|
|
11
|
+
readonly transportName = "claude-code";
|
|
12
|
+
createTransport(): unknown;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,qBAAa,2BAA4B,YAAW,wBAAwB;IAC1E,QAAQ,CAAC,aAAa,iBAAiB;IAEvC,eAAe,IAAI,OAAO;CAM3B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport provider for the Claude Code adapter.
|
|
3
|
+
*
|
|
4
|
+
* Implements AdapterTransportProvider to supply Claude Code's
|
|
5
|
+
* native inter-agent transport mechanism.
|
|
6
|
+
*
|
|
7
|
+
* @task T5240
|
|
8
|
+
*/
|
|
9
|
+
export class ClaudeCodeTransportProvider {
|
|
10
|
+
transportName = 'claude-code';
|
|
11
|
+
createTransport() {
|
|
12
|
+
// Returns null — actual transport creation is handled by the signaldock factory
|
|
13
|
+
// which checks for this adapter's transport capability.
|
|
14
|
+
// Full wiring will be completed in Phase 5.
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,OAAO,2BAA2B;IAC7B,aAAa,GAAG,aAAa,CAAC;IAEvC,eAAe;QACb,gFAAgF;QAChF,wDAAwD;QACxD,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport provider for the Claude Code adapter.
|
|
3
|
+
*
|
|
4
|
+
* Implements AdapterTransportProvider to supply Claude Code's
|
|
5
|
+
* native inter-agent transport mechanism.
|
|
6
|
+
*
|
|
7
|
+
* @task T5240
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AdapterTransportProvider } from '@cleocode/contracts';
|
|
11
|
+
|
|
12
|
+
export class ClaudeCodeTransportProvider implements AdapterTransportProvider {
|
|
13
|
+
readonly transportName = 'claude-code';
|
|
14
|
+
|
|
15
|
+
createTransport(): unknown {
|
|
16
|
+
// Returns null — actual transport creation is handled by the signaldock factory
|
|
17
|
+
// which checks for this adapter's transport capability.
|
|
18
|
+
// Full wiring will be completed in Phase 5.
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.test.d.ts","sourceRoot":"","sources":["adapter.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the Cursor adapter package.
|
|
3
|
+
*
|
|
4
|
+
* @task T5240
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
7
|
+
import { CursorAdapter } from '../adapter.js';
|
|
8
|
+
import { CursorHookProvider } from '../hooks.js';
|
|
9
|
+
import { CursorSpawnProvider } from '../spawn.js'; // spawn.ts still exists for direct use
|
|
10
|
+
import { CursorInstallProvider } from '../install.js';
|
|
11
|
+
vi.mock('node:fs', async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal();
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
existsSync: vi.fn((path) => {
|
|
16
|
+
if (typeof path === 'string' && path.includes('.cursor'))
|
|
17
|
+
return true;
|
|
18
|
+
if (typeof path === 'string' && path.includes('.cursorrules'))
|
|
19
|
+
return false;
|
|
20
|
+
return false;
|
|
21
|
+
}),
|
|
22
|
+
readFileSync: vi.fn((path) => {
|
|
23
|
+
if (typeof path === 'string' && path.includes('mcp.json')) {
|
|
24
|
+
return JSON.stringify({ mcpServers: { cleo: { command: 'node', args: ['mcp.js'] } } });
|
|
25
|
+
}
|
|
26
|
+
return '{}';
|
|
27
|
+
}),
|
|
28
|
+
writeFileSync: vi.fn(),
|
|
29
|
+
mkdirSync: vi.fn(),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
describe('CursorAdapter', () => {
|
|
33
|
+
let adapter;
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
adapter = new CursorAdapter();
|
|
36
|
+
});
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
if (adapter.isInitialized()) {
|
|
39
|
+
await adapter.dispose();
|
|
40
|
+
}
|
|
41
|
+
vi.restoreAllMocks();
|
|
42
|
+
});
|
|
43
|
+
describe('identity', () => {
|
|
44
|
+
it('has correct id', () => {
|
|
45
|
+
expect(adapter.id).toBe('cursor');
|
|
46
|
+
});
|
|
47
|
+
it('has correct name', () => {
|
|
48
|
+
expect(adapter.name).toBe('Cursor');
|
|
49
|
+
});
|
|
50
|
+
it('has correct version', () => {
|
|
51
|
+
expect(adapter.version).toBe('1.0.0');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('capabilities', () => {
|
|
55
|
+
it('does not support hooks', () => {
|
|
56
|
+
expect(adapter.capabilities.supportsHooks).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('has no supported hook events', () => {
|
|
59
|
+
expect(adapter.capabilities.supportedHookEvents).toHaveLength(0);
|
|
60
|
+
});
|
|
61
|
+
it('does not support spawn', () => {
|
|
62
|
+
expect(adapter.capabilities.supportsSpawn).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it('supports install', () => {
|
|
65
|
+
expect(adapter.capabilities.supportsInstall).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('supports MCP', () => {
|
|
68
|
+
expect(adapter.capabilities.supportsMcp).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
it('supports instruction files with MDC pattern', () => {
|
|
71
|
+
expect(adapter.capabilities.supportsInstructionFiles).toBe(true);
|
|
72
|
+
expect(adapter.capabilities.instructionFilePattern).toBe('.cursor/rules/*.mdc');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('sub-providers', () => {
|
|
76
|
+
it('provides a hook provider (stub)', () => {
|
|
77
|
+
expect(adapter.hooks).toBeInstanceOf(CursorHookProvider);
|
|
78
|
+
});
|
|
79
|
+
it('provides an install provider', () => {
|
|
80
|
+
expect(adapter.install).toBeInstanceOf(CursorInstallProvider);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('initialize', () => {
|
|
84
|
+
it('sets initialized state', async () => {
|
|
85
|
+
expect(adapter.isInitialized()).toBe(false);
|
|
86
|
+
await adapter.initialize('/tmp/test-project');
|
|
87
|
+
expect(adapter.isInitialized()).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
it('stores project directory', async () => {
|
|
90
|
+
await adapter.initialize('/tmp/test-project');
|
|
91
|
+
expect(adapter.getProjectDir()).toBe('/tmp/test-project');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('dispose', () => {
|
|
95
|
+
it('resets initialized state', async () => {
|
|
96
|
+
await adapter.initialize('/tmp/test-project');
|
|
97
|
+
await adapter.dispose();
|
|
98
|
+
expect(adapter.isInitialized()).toBe(false);
|
|
99
|
+
expect(adapter.getProjectDir()).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('healthCheck', () => {
|
|
103
|
+
it('returns unhealthy when not initialized', async () => {
|
|
104
|
+
const status = await adapter.healthCheck();
|
|
105
|
+
expect(status.healthy).toBe(false);
|
|
106
|
+
expect(status.provider).toBe('cursor');
|
|
107
|
+
expect(status.details?.error).toBe('Adapter not initialized');
|
|
108
|
+
});
|
|
109
|
+
it('returns health status with provider id', async () => {
|
|
110
|
+
await adapter.initialize('/tmp/test-project');
|
|
111
|
+
const status = await adapter.healthCheck();
|
|
112
|
+
expect(status.provider).toBe('cursor');
|
|
113
|
+
expect(typeof status.healthy).toBe('boolean');
|
|
114
|
+
});
|
|
115
|
+
it('checks for .cursor directory existence', async () => {
|
|
116
|
+
await adapter.initialize('/tmp/test-project');
|
|
117
|
+
const status = await adapter.healthCheck();
|
|
118
|
+
expect(status.details?.configDirExists).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
it('checks for CURSOR_EDITOR env var', async () => {
|
|
121
|
+
await adapter.initialize('/tmp/test-project');
|
|
122
|
+
const status = await adapter.healthCheck();
|
|
123
|
+
expect(status.details?.editorEnvSet).toBeDefined();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
describe('CursorHookProvider', () => {
|
|
128
|
+
let hooks;
|
|
129
|
+
beforeEach(() => {
|
|
130
|
+
hooks = new CursorHookProvider();
|
|
131
|
+
});
|
|
132
|
+
describe('mapProviderEvent', () => {
|
|
133
|
+
it('returns null for any event (no hook support)', () => {
|
|
134
|
+
expect(hooks.mapProviderEvent('session.start')).toBeNull();
|
|
135
|
+
expect(hooks.mapProviderEvent('tool.complete')).toBeNull();
|
|
136
|
+
expect(hooks.mapProviderEvent('any-event')).toBeNull();
|
|
137
|
+
expect(hooks.mapProviderEvent('')).toBeNull();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('registerNativeHooks', () => {
|
|
141
|
+
it('completes without error and marks as registered', async () => {
|
|
142
|
+
expect(hooks.isRegistered()).toBe(false);
|
|
143
|
+
await hooks.registerNativeHooks('/tmp/project');
|
|
144
|
+
expect(hooks.isRegistered()).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe('unregisterNativeHooks', () => {
|
|
148
|
+
it('completes without error and marks as unregistered', async () => {
|
|
149
|
+
await hooks.registerNativeHooks('/tmp/project');
|
|
150
|
+
await hooks.unregisterNativeHooks();
|
|
151
|
+
expect(hooks.isRegistered()).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe('CursorSpawnProvider', () => {
|
|
156
|
+
let spawnProvider;
|
|
157
|
+
beforeEach(() => {
|
|
158
|
+
spawnProvider = new CursorSpawnProvider();
|
|
159
|
+
});
|
|
160
|
+
describe('canSpawn', () => {
|
|
161
|
+
it('returns false (spawn not supported)', async () => {
|
|
162
|
+
const result = await spawnProvider.canSpawn();
|
|
163
|
+
expect(result).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe('spawn', () => {
|
|
167
|
+
it('throws an error explaining spawn is not supported', async () => {
|
|
168
|
+
await expect(spawnProvider.spawn({
|
|
169
|
+
taskId: 'T1234',
|
|
170
|
+
prompt: 'test prompt',
|
|
171
|
+
})).rejects.toThrow('Cursor does not support subagent spawning');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe('listRunning', () => {
|
|
175
|
+
it('returns empty array', async () => {
|
|
176
|
+
const running = await spawnProvider.listRunning();
|
|
177
|
+
expect(running).toEqual([]);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe('terminate', () => {
|
|
181
|
+
it('handles any instance id gracefully (no-op)', async () => {
|
|
182
|
+
await expect(spawnProvider.terminate('any-id')).resolves.toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('CursorInstallProvider', () => {
|
|
187
|
+
let installProvider;
|
|
188
|
+
beforeEach(() => {
|
|
189
|
+
installProvider = new CursorInstallProvider();
|
|
190
|
+
});
|
|
191
|
+
describe('isInstalled', () => {
|
|
192
|
+
it('returns a boolean', async () => {
|
|
193
|
+
const result = await installProvider.isInstalled();
|
|
194
|
+
expect(typeof result).toBe('boolean');
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('install', () => {
|
|
198
|
+
it('returns a success result', async () => {
|
|
199
|
+
const result = await installProvider.install({
|
|
200
|
+
projectDir: '/tmp/test-project',
|
|
201
|
+
});
|
|
202
|
+
expect(result.success).toBe(true);
|
|
203
|
+
expect(result.installedAt).toBeTruthy();
|
|
204
|
+
expect(typeof result.instructionFileUpdated).toBe('boolean');
|
|
205
|
+
expect(typeof result.mcpRegistered).toBe('boolean');
|
|
206
|
+
});
|
|
207
|
+
it('registers MCP when mcpServerPath provided', async () => {
|
|
208
|
+
const result = await installProvider.install({
|
|
209
|
+
projectDir: '/tmp/test-project',
|
|
210
|
+
mcpServerPath: '/path/to/mcp-server.js',
|
|
211
|
+
});
|
|
212
|
+
expect(result.mcpRegistered).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
it('includes instruction files in details', async () => {
|
|
215
|
+
const result = await installProvider.install({
|
|
216
|
+
projectDir: '/tmp/test-project',
|
|
217
|
+
});
|
|
218
|
+
const files = result.details?.instructionFiles;
|
|
219
|
+
expect(Array.isArray(files)).toBe(true);
|
|
220
|
+
expect(files.some((f) => f.includes('cleo.mdc'))).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('uninstall', () => {
|
|
224
|
+
it('handles uninstall when not installed', async () => {
|
|
225
|
+
await expect(installProvider.uninstall()).resolves.toBeUndefined();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
describe('ensureInstructionReferences', () => {
|
|
229
|
+
it('completes without error', async () => {
|
|
230
|
+
await expect(installProvider.ensureInstructionReferences('/tmp/test-project')).resolves.toBeUndefined();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
describe('barrel exports', () => {
|
|
235
|
+
it('exports createAdapter factory function', async () => {
|
|
236
|
+
const module = await import('../index.js');
|
|
237
|
+
expect(typeof module.createAdapter).toBe('function');
|
|
238
|
+
const adapter = module.createAdapter();
|
|
239
|
+
expect(adapter).toBeInstanceOf(CursorAdapter);
|
|
240
|
+
});
|
|
241
|
+
it('exports CursorAdapter as default', async () => {
|
|
242
|
+
const module = await import('../index.js');
|
|
243
|
+
expect(module.default).toBe(CursorAdapter);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
//# sourceMappingURL=adapter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.test.js","sourceRoot":"","sources":["adapter.test.ts"],"names":[],"mappings":"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"}
|