@cleocode/contracts 2026.3.38 → 2026.3.40

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/src/task-sync.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Task synchronization contracts for provider-agnostic task reconciliation.
3
3
  *
4
- * Replaces the legacy Claude Code-specific TodoWrite integration with a
5
- * provider-agnostic system. Any provider adapter can implement
6
- * AdapterTaskSyncProvider to sync its external task system with CLEO as SSoT.
7
- *
8
- * @task T5800
4
+ * Defines the interface for syncing external issue/task systems (Linear, Jira,
5
+ * GitHub Issues, GitLab, etc.) with CLEO as SSoT. Provider adapters normalize
6
+ * their native formats into ExternalTask[], and the reconciliation engine
7
+ * handles diffing, creating, updating, and linking.
9
8
  */
10
9
 
11
10
  // ---------------------------------------------------------------------------
@@ -22,37 +21,63 @@ export type ExternalTaskStatus = 'pending' | 'active' | 'completed' | 'removed';
22
21
  export interface ExternalTask {
23
22
  /** Provider-assigned identifier for this task (opaque to core). */
24
23
  externalId: string;
25
- /** Mapped CLEO task ID, or null if the task is new / unmatched. */
26
- cleoTaskId: string | null;
27
24
  /** Human-readable title. */
28
25
  title: string;
29
26
  /** Normalized status. */
30
27
  status: ExternalTaskStatus;
31
28
  /** Optional description text. */
32
29
  description?: string;
30
+ /** Optional priority mapping (provider decides how to map). */
31
+ priority?: 'critical' | 'high' | 'medium' | 'low';
32
+ /** Optional task type mapping. */
33
+ type?: 'epic' | 'task' | 'subtask';
33
34
  /** Optional labels/tags from the provider. */
34
35
  labels?: string[];
36
+ /** Optional URL to the external task (for linking). */
37
+ url?: string;
38
+ /** Optional parent external ID (for hierarchy). */
39
+ parentExternalId?: string;
35
40
  /** Arbitrary provider-specific metadata (opaque to core). */
36
41
  providerMeta?: Record<string, unknown>;
37
42
  }
38
43
 
39
44
  // ---------------------------------------------------------------------------
40
- // Sync session state
45
+ // External task link (DB-backed tracking)
41
46
  // ---------------------------------------------------------------------------
42
47
 
48
+ /** How an external task link was established. */
49
+ export type ExternalLinkType = 'created' | 'matched' | 'manual';
50
+
51
+ /** Direction of the sync that established the link. */
52
+ export type SyncDirection = 'inbound' | 'outbound' | 'bidirectional';
53
+
43
54
  /**
44
- * Persistent state for a sync session between CLEO and a provider.
45
- * Stored per-provider under `.cleo/sync/<providerId>-session.json`.
55
+ * A link between a CLEO task and an external provider task.
56
+ * Stored in the external_task_links table in tasks.db.
46
57
  */
47
- export interface SyncSessionState {
48
- /** CLEO task IDs that were injected into the provider's task list. */
49
- injectedTaskIds: string[];
50
- /** Optional phase context when tasks were injected. */
51
- injectedPhase?: string;
52
- /** Per-task metadata at injection time. */
53
- taskMetadata?: Record<string, { phase?: string }>;
54
- /** ISO timestamp of the last successful reconciliation. */
55
- lastSyncAt?: string;
58
+ export interface ExternalTaskLink {
59
+ /** Link ID (UUID). */
60
+ id: string;
61
+ /** CLEO task ID. */
62
+ taskId: string;
63
+ /** Provider identifier (e.g. 'linear', 'jira', 'github'). */
64
+ providerId: string;
65
+ /** Provider-assigned external task ID. */
66
+ externalId: string;
67
+ /** URL to the external task. */
68
+ externalUrl?: string | null;
69
+ /** Title at time of last sync. */
70
+ externalTitle?: string | null;
71
+ /** How this link was established. */
72
+ linkType: ExternalLinkType;
73
+ /** Sync direction. */
74
+ syncDirection: SyncDirection;
75
+ /** Provider-specific metadata (JSON). */
76
+ metadata?: Record<string, unknown>;
77
+ /** When the link was first established. */
78
+ linkedAt: string;
79
+ /** When the external task was last synchronized. */
80
+ lastSyncAt?: string | null;
56
81
  }
57
82
 
58
83
  // ---------------------------------------------------------------------------
@@ -75,7 +100,7 @@ export type ConflictPolicy = 'cleo-wins' | 'provider-wins' | 'latest-wins' | 're
75
100
 
76
101
  /** Options for the reconciliation engine. */
77
102
  export interface ReconcileOptions {
78
- /** Provider ID (e.g. 'claude-code', 'cursor'). */
103
+ /** Provider ID (e.g. 'linear', 'jira', 'github'). */
79
104
  providerId: string;
80
105
  /** Working directory (project root). */
81
106
  cwd?: string;
@@ -90,7 +115,13 @@ export interface ReconcileOptions {
90
115
  }
91
116
 
92
117
  /** The type of action the reconciliation engine will take. */
93
- export type ReconcileActionType = 'complete' | 'activate' | 'create' | 'remove' | 'skip' | 'conflict';
118
+ export type ReconcileActionType =
119
+ | 'create'
120
+ | 'update'
121
+ | 'complete'
122
+ | 'activate'
123
+ | 'skip'
124
+ | 'conflict';
94
125
 
95
126
  /** A single reconciliation action (planned or applied). */
96
127
  export interface ReconcileAction {
@@ -98,12 +129,14 @@ export interface ReconcileAction {
98
129
  type: ReconcileActionType;
99
130
  /** The CLEO task ID affected (null for creates before they happen). */
100
131
  cleoTaskId: string | null;
101
- /** The external task that triggered this action. */
132
+ /** The external task ID that triggered this action. */
102
133
  externalId: string;
103
134
  /** Human-readable description of the action. */
104
135
  summary: string;
105
136
  /** Whether this action was actually applied. */
106
137
  applied: boolean;
138
+ /** The link ID if a link was created or updated. */
139
+ linkId?: string;
107
140
  /** Error message if the action failed during apply. */
108
141
  error?: string;
109
142
  }
@@ -118,16 +151,17 @@ export interface ReconcileResult {
118
151
  actions: ReconcileAction[];
119
152
  /** Summary counts. */
120
153
  summary: {
154
+ created: number;
155
+ updated: number;
121
156
  completed: number;
122
157
  activated: number;
123
- created: number;
124
- removed: number;
125
158
  skipped: number;
126
159
  conflicts: number;
160
+ total: number;
127
161
  applied: number;
128
162
  };
129
- /** Whether sync session state was cleared after apply. */
130
- sessionCleared: boolean;
163
+ /** Links created or updated during this reconciliation. */
164
+ linksAffected: number;
131
165
  }
132
166
 
133
167
  // ---------------------------------------------------------------------------
@@ -138,9 +172,29 @@ export interface ReconcileResult {
138
172
  * Interface that provider adapters implement to expose their external
139
173
  * task system to the reconciliation engine.
140
174
  *
141
- * Provider-specific parsing lives here — core never sees native formats.
175
+ * Provider-specific parsing lives in the adapter — core never sees native formats.
176
+ * Consumers implement this interface to integrate their issue tracker with CLEO.
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * class LinearAdapter implements ExternalTaskProvider {
181
+ * async getExternalTasks(projectDir: string): Promise<ExternalTask[]> {
182
+ * const issues = await linearClient.issues({ projectId: '...' });
183
+ * return issues.map(issue => ({
184
+ * externalId: issue.id,
185
+ * title: issue.title,
186
+ * status: mapLinearStatus(issue.state),
187
+ * description: issue.description,
188
+ * priority: mapLinearPriority(issue.priority),
189
+ * labels: issue.labels.map(l => l.name),
190
+ * url: issue.url,
191
+ * providerMeta: { linearId: issue.identifier },
192
+ * }));
193
+ * }
194
+ * }
195
+ * ```
142
196
  */
143
- export interface AdapterTaskSyncProvider {
197
+ export interface ExternalTaskProvider {
144
198
  /**
145
199
  * Read the provider's current task state and return normalized ExternalTasks.
146
200
  *
@@ -150,18 +204,14 @@ export interface AdapterTaskSyncProvider {
150
204
  getExternalTasks(projectDir: string): Promise<ExternalTask[]>;
151
205
 
152
206
  /**
153
- * Optionally push CLEO task state back to the provider.
207
+ * Optionally push CLEO task state back to the provider (outbound sync).
154
208
  * Not all providers support bidirectional sync.
155
209
  *
156
210
  * @param tasks - Current CLEO tasks to push.
157
211
  * @param projectDir - Project root directory.
158
212
  */
159
- pushTaskState?(tasks: ReadonlyArray<{ id: string; title: string; status: string }>, projectDir: string): Promise<void>;
160
-
161
- /**
162
- * Clean up provider-specific sync artifacts (e.g. state files).
163
- *
164
- * @param projectDir - Project root directory.
165
- */
166
- cleanup?(projectDir: string): Promise<void>;
213
+ pushTaskState?(
214
+ tasks: ReadonlyArray<{ id: string; title: string; status: string }>,
215
+ projectDir: string,
216
+ ): Promise<void>;
167
217
  }
package/src/task.ts CHANGED
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  import type { TaskStatus } from './status-registry.js';
25
+
25
26
  export type { TaskStatus };
26
27
 
27
28
  /** Task priority levels. */
@@ -1,53 +0,0 @@
1
- /**
2
- * TodoWrite types for Claude TodoWrite state merge operations.
3
- *
4
- * @task T4551
5
- */
6
- /** TodoWrite item status as exported by Claude. */
7
- export type TodoWriteItemStatus = 'pending' | 'in_progress' | 'completed';
8
- /** TodoWrite item as exported by Claude. */
9
- export interface TodoWriteItem {
10
- content: string;
11
- status: TodoWriteItemStatus;
12
- activeForm?: string;
13
- }
14
- /** TodoWrite state file format. */
15
- export interface TodoWriteState {
16
- todos: TodoWriteItem[];
17
- }
18
- /** Sync session state for TodoWrite integration. */
19
- export interface TodoWriteSyncSessionState {
20
- injected_tasks: string[];
21
- injectedPhase?: string;
22
- task_metadata?: Record<string, {
23
- phase?: string;
24
- }>;
25
- }
26
- /** Detected changes from TodoWrite state analysis. */
27
- export interface TodoWriteChangeSet {
28
- completed: string[];
29
- progressed: string[];
30
- newTasks: string[];
31
- removed: string[];
32
- }
33
- /** Action type for a TodoWrite merge change. */
34
- export type TodoWriteChangeAction = 'complete' | 'create' | 'update';
35
- /** A single change applied during TodoWrite merge. */
36
- export interface TodoWriteChange {
37
- taskId: string;
38
- action: TodoWriteChangeAction;
39
- details?: string;
40
- }
41
- /** Result of a TodoWrite merge operation. */
42
- export interface TodoWriteMergeResult {
43
- dryRun: boolean;
44
- changes: {
45
- completed: number;
46
- progressed: number;
47
- new: number;
48
- removed: number;
49
- applied: number;
50
- };
51
- sessionCleared?: boolean;
52
- }
53
- //# sourceMappingURL=todowrite.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"todowrite.d.ts","sourceRoot":"","sources":["../src/todowrite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mDAAmD;AACnD,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAE1E,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,oDAAoD;AACpD,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,gDAAgD;AAChD,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErE,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
package/dist/todowrite.js DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * TodoWrite types for Claude TodoWrite state merge operations.
3
- *
4
- * @task T4551
5
- */
6
- export {};
7
- //# sourceMappingURL=todowrite.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"todowrite.js","sourceRoot":"","sources":["../src/todowrite.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/src/todowrite.ts DELETED
@@ -1,58 +0,0 @@
1
- /**
2
- * TodoWrite types for Claude TodoWrite state merge operations.
3
- *
4
- * @task T4551
5
- */
6
-
7
- /** TodoWrite item status as exported by Claude. */
8
- export type TodoWriteItemStatus = 'pending' | 'in_progress' | 'completed';
9
-
10
- /** TodoWrite item as exported by Claude. */
11
- export interface TodoWriteItem {
12
- content: string;
13
- status: TodoWriteItemStatus;
14
- activeForm?: string;
15
- }
16
-
17
- /** TodoWrite state file format. */
18
- export interface TodoWriteState {
19
- todos: TodoWriteItem[];
20
- }
21
-
22
- /** Sync session state for TodoWrite integration. */
23
- export interface TodoWriteSyncSessionState {
24
- injected_tasks: string[];
25
- injectedPhase?: string;
26
- task_metadata?: Record<string, { phase?: string }>;
27
- }
28
-
29
- /** Detected changes from TodoWrite state analysis. */
30
- export interface TodoWriteChangeSet {
31
- completed: string[];
32
- progressed: string[];
33
- newTasks: string[];
34
- removed: string[];
35
- }
36
-
37
- /** Action type for a TodoWrite merge change. */
38
- export type TodoWriteChangeAction = 'complete' | 'create' | 'update';
39
-
40
- /** A single change applied during TodoWrite merge. */
41
- export interface TodoWriteChange {
42
- taskId: string;
43
- action: TodoWriteChangeAction;
44
- details?: string;
45
- }
46
-
47
- /** Result of a TodoWrite merge operation. */
48
- export interface TodoWriteMergeResult {
49
- dryRun: boolean;
50
- changes: {
51
- completed: number;
52
- progressed: number;
53
- new: number;
54
- removed: number;
55
- applied: number;
56
- };
57
- sessionCleared?: boolean;
58
- }