@proletariat/cli 0.3.96 → 0.3.98
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/commands/gc.d.ts +1 -0
- package/dist/commands/gc.js +31 -1
- package/dist/commands/gc.js.map +1 -1
- package/dist/commands/linear/connect.d.ts +5 -0
- package/dist/commands/linear/connect.js +84 -0
- package/dist/commands/linear/connect.js.map +1 -1
- package/dist/commands/orchestrate/index.js +18 -10
- package/dist/commands/orchestrate/index.js.map +1 -1
- package/dist/commands/qa/index.js +1 -1
- package/dist/commands/session/watch.d.ts +1 -0
- package/dist/commands/session/watch.js +46 -2
- package/dist/commands/session/watch.js.map +1 -1
- package/dist/commands/watch/index.d.ts +28 -0
- package/dist/commands/watch/index.js +172 -0
- package/dist/commands/watch/index.js.map +1 -0
- package/dist/commands/work/complete.d.ts +1 -0
- package/dist/commands/work/complete.js +38 -31
- package/dist/commands/work/complete.js.map +1 -1
- package/dist/commands/{ticket/index.d.ts → work/drop.d.ts} +5 -4
- package/dist/commands/work/drop.js +215 -0
- package/dist/commands/work/drop.js.map +1 -0
- package/dist/commands/work/linear.js +1 -1
- package/dist/commands/work/linear.js.map +1 -1
- package/dist/commands/work/ready.d.ts +1 -0
- package/dist/commands/work/ready.js +46 -30
- package/dist/commands/work/ready.js.map +1 -1
- package/dist/commands/work/ship.d.ts +1 -0
- package/dist/commands/work/ship.js +56 -40
- package/dist/commands/work/ship.js.map +1 -1
- package/dist/commands/work/start.d.ts +2 -0
- package/dist/commands/work/start.js +238 -83
- package/dist/commands/work/start.js.map +1 -1
- package/dist/commands/work/stop.d.ts +1 -0
- package/dist/commands/work/stop.js +40 -0
- package/dist/commands/work/stop.js.map +1 -1
- package/dist/lib/agents/commands.js +7 -5
- package/dist/lib/agents/commands.js.map +1 -1
- package/dist/lib/asana/client.d.ts +4 -1
- package/dist/lib/asana/client.js +15 -0
- package/dist/lib/asana/client.js.map +1 -1
- package/dist/lib/asana/index.d.ts +1 -1
- package/dist/lib/asana/types.d.ts +4 -0
- package/dist/lib/database/credential-store.js +1 -0
- package/dist/lib/database/credential-store.js.map +1 -1
- package/dist/lib/database/drizzle-schema.d.ts +17 -0
- package/dist/lib/database/drizzle-schema.js +1 -0
- package/dist/lib/database/drizzle-schema.js.map +1 -1
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.d.ts +9 -0
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.js +23 -0
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.js.map +1 -0
- package/dist/lib/database/migrations/0020_transition_map.d.ts +2 -0
- package/dist/lib/database/migrations/0020_transition_map.js +27 -0
- package/dist/lib/database/migrations/0020_transition_map.js.map +1 -0
- package/dist/lib/database/migrations/index.js +4 -0
- package/dist/lib/database/migrations/index.js.map +1 -1
- package/dist/lib/execution/config.d.ts +10 -0
- package/dist/lib/execution/config.js +24 -0
- package/dist/lib/execution/config.js.map +1 -1
- package/dist/lib/execution/preflight.d.ts +51 -0
- package/dist/lib/execution/preflight.js +278 -0
- package/dist/lib/execution/preflight.js.map +1 -0
- package/dist/lib/execution/runners/prompt-builder.d.ts +6 -0
- package/dist/lib/execution/runners/prompt-builder.js +38 -7
- package/dist/lib/execution/runners/prompt-builder.js.map +1 -1
- package/dist/lib/execution/session-utils.d.ts +23 -0
- package/dist/lib/execution/session-utils.js +69 -0
- package/dist/lib/execution/session-utils.js.map +1 -1
- package/dist/lib/execution/spawner.d.ts +11 -1
- package/dist/lib/execution/spawner.js +44 -16
- package/dist/lib/execution/spawner.js.map +1 -1
- package/dist/lib/execution/storage.d.ts +6 -0
- package/dist/lib/execution/storage.js +18 -0
- package/dist/lib/execution/storage.js.map +1 -1
- package/dist/lib/execution/ticket-refs.d.ts +71 -0
- package/dist/lib/execution/ticket-refs.js +125 -0
- package/dist/lib/execution/ticket-refs.js.map +1 -0
- package/dist/lib/execution/types.d.ts +7 -2
- package/dist/lib/execution/types.js +5 -3
- package/dist/lib/execution/types.js.map +1 -1
- package/dist/lib/external-issues/index.d.ts +1 -0
- package/dist/lib/external-issues/index.js +2 -0
- package/dist/lib/external-issues/index.js.map +1 -1
- package/dist/lib/external-issues/linear.js +1 -1
- package/dist/lib/external-issues/linear.js.map +1 -1
- package/dist/lib/external-issues/ticket-builder.d.ts +21 -0
- package/dist/lib/external-issues/ticket-builder.js +43 -0
- package/dist/lib/external-issues/ticket-builder.js.map +1 -0
- package/dist/lib/external-issues/work-start.js +1 -1
- package/dist/lib/external-issues/work-start.js.map +1 -1
- package/dist/lib/gc/index.d.ts +67 -6
- package/dist/lib/gc/index.js +293 -15
- package/dist/lib/gc/index.js.map +1 -1
- package/dist/lib/github/client.d.ts +84 -0
- package/dist/lib/github/client.js +123 -0
- package/dist/lib/github/client.js.map +1 -0
- package/dist/lib/github/config.d.ts +42 -0
- package/dist/lib/github/config.js +115 -0
- package/dist/lib/github/config.js.map +1 -0
- package/dist/lib/github/types.d.ts +71 -0
- package/dist/lib/github/types.js +50 -0
- package/dist/lib/github/types.js.map +1 -0
- package/dist/lib/jira/client.d.ts +113 -0
- package/dist/lib/jira/client.js +208 -0
- package/dist/lib/jira/client.js.map +1 -0
- package/dist/lib/jira/config.d.ts +9 -0
- package/dist/lib/jira/config.js +30 -0
- package/dist/lib/jira/config.js.map +1 -1
- package/dist/lib/jira/index.d.ts +6 -2
- package/dist/lib/jira/index.js +4 -2
- package/dist/lib/jira/index.js.map +1 -1
- package/dist/lib/jira/types.d.ts +118 -0
- package/dist/lib/jira/types.js +45 -0
- package/dist/lib/jira/types.js.map +1 -0
- package/dist/lib/linear/config.d.ts +10 -0
- package/dist/lib/linear/config.js +33 -0
- package/dist/lib/linear/config.js.map +1 -1
- package/dist/lib/mcp/tools/index.d.ts +0 -2
- package/dist/lib/mcp/tools/index.js +0 -2
- package/dist/lib/mcp/tools/index.js.map +1 -1
- package/dist/lib/orchestrate/index.d.ts +2 -0
- package/dist/lib/orchestrate/index.js +1 -0
- package/dist/lib/orchestrate/index.js.map +1 -1
- package/dist/lib/orchestrate/simple-poller.d.ts +57 -0
- package/dist/lib/orchestrate/simple-poller.js +324 -0
- package/dist/lib/orchestrate/simple-poller.js.map +1 -0
- package/dist/lib/pmo/storage/index.js +16 -5
- package/dist/lib/pmo/storage/index.js.map +1 -1
- package/dist/lib/prompt-json.d.ts +31 -0
- package/dist/lib/prompt-json.js.map +1 -1
- package/dist/lib/providers/asana-provider.d.ts +27 -0
- package/dist/lib/providers/asana-provider.js +426 -0
- package/dist/lib/providers/asana-provider.js.map +1 -0
- package/dist/lib/providers/auto-mapper.d.ts +45 -0
- package/dist/lib/providers/auto-mapper.js +138 -0
- package/dist/lib/providers/auto-mapper.js.map +1 -0
- package/dist/lib/providers/github-provider.d.ts +34 -0
- package/dist/lib/providers/github-provider.js +418 -0
- package/dist/lib/providers/github-provider.js.map +1 -0
- package/dist/lib/providers/index.d.ts +3 -0
- package/dist/lib/providers/index.js +3 -0
- package/dist/lib/providers/index.js.map +1 -1
- package/dist/lib/providers/jira-provider.d.ts +31 -0
- package/dist/lib/providers/jira-provider.js +383 -0
- package/dist/lib/providers/jira-provider.js.map +1 -0
- package/dist/lib/providers/linear-provider.js +6 -7
- package/dist/lib/providers/linear-provider.js.map +1 -1
- package/dist/lib/providers/resolver.js +54 -0
- package/dist/lib/providers/resolver.js.map +1 -1
- package/dist/lib/providers/state-intents.d.ts +20 -0
- package/dist/lib/providers/state-intents.js +61 -7
- package/dist/lib/providers/state-intents.js.map +1 -1
- package/dist/lib/providers/state-resolution.d.ts +15 -11
- package/dist/lib/providers/state-resolution.js +54 -48
- package/dist/lib/providers/state-resolution.js.map +1 -1
- package/dist/lib/providers/transition-map.d.ts +59 -0
- package/dist/lib/providers/transition-map.js +113 -0
- package/dist/lib/providers/transition-map.js.map +1 -0
- package/dist/lib/providers/types.d.ts +1 -1
- package/dist/lib/session/index.d.ts +3 -1
- package/dist/lib/session/index.js +3 -1
- package/dist/lib/session/index.js.map +1 -1
- package/dist/lib/session/tmux-watchdog.d.ts +157 -0
- package/dist/lib/session/tmux-watchdog.js +424 -0
- package/dist/lib/session/tmux-watchdog.js.map +1 -0
- package/dist/lib/session/watcher.d.ts +22 -4
- package/dist/lib/session/watcher.js +66 -8
- package/dist/lib/session/watcher.js.map +1 -1
- package/dist/lib/work-lifecycle/post-execution.js +26 -1
- package/dist/lib/work-lifecycle/post-execution.js.map +1 -1
- package/dist/lib/work-lifecycle/transition.d.ts +73 -0
- package/dist/lib/work-lifecycle/transition.js +138 -0
- package/dist/lib/work-lifecycle/transition.js.map +1 -0
- package/dist/lib/work-source/config.d.ts +1 -1
- package/dist/lib/work-source/config.js +11 -1
- package/dist/lib/work-source/config.js.map +1 -1
- package/oclif.manifest.json +936 -1628
- package/package.json +1 -1
- package/dist/commands/ticket/create.d.ts +0 -44
- package/dist/commands/ticket/create.js +0 -760
- package/dist/commands/ticket/create.js.map +0 -1
- package/dist/commands/ticket/delete.d.ts +0 -17
- package/dist/commands/ticket/delete.js +0 -204
- package/dist/commands/ticket/delete.js.map +0 -1
- package/dist/commands/ticket/edit.d.ts +0 -28
- package/dist/commands/ticket/edit.js +0 -402
- package/dist/commands/ticket/edit.js.map +0 -1
- package/dist/commands/ticket/index.js +0 -74
- package/dist/commands/ticket/index.js.map +0 -1
- package/dist/commands/ticket/list.d.ts +0 -33
- package/dist/commands/ticket/list.js +0 -519
- package/dist/commands/ticket/list.js.map +0 -1
- package/dist/commands/ticket/move.d.ts +0 -27
- package/dist/commands/ticket/move.js +0 -413
- package/dist/commands/ticket/move.js.map +0 -1
- package/dist/commands/ticket/show.d.ts +0 -14
- package/dist/commands/ticket/show.js +0 -110
- package/dist/commands/ticket/show.js.map +0 -1
- package/dist/commands/ticket/update.d.ts +0 -28
- package/dist/commands/ticket/update.js +0 -458
- package/dist/commands/ticket/update.js.map +0 -1
- package/dist/lib/mcp/tools/action.d.ts +0 -6
- package/dist/lib/mcp/tools/action.js +0 -123
- package/dist/lib/mcp/tools/action.js.map +0 -1
- package/dist/lib/mcp/tools/ticket.d.ts +0 -6
- package/dist/lib/mcp/tools/ticket.js +0 -464
- package/dist/lib/mcp/tools/ticket.js.map +0 -1
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asana Ticket Provider
|
|
3
|
+
*
|
|
4
|
+
* Writes ticket operations directly to Asana via REST API,
|
|
5
|
+
* then updates local PMO to keep it in sync.
|
|
6
|
+
*
|
|
7
|
+
* Asana is the source of truth, PMO is best-effort mirror.
|
|
8
|
+
* Board sections map to kanban columns / prlt intents.
|
|
9
|
+
*/
|
|
10
|
+
import { AsanaClient } from '../asana/client.js';
|
|
11
|
+
import { AsanaMapper } from '../asana/mapper.js';
|
|
12
|
+
import { getAsanaAccessToken, loadAsanaConfig } from '../asana/config.js';
|
|
13
|
+
export class AsanaTicketProvider {
|
|
14
|
+
db;
|
|
15
|
+
storage;
|
|
16
|
+
projectId;
|
|
17
|
+
name = 'asana';
|
|
18
|
+
constructor(db, storage, projectId) {
|
|
19
|
+
this.db = db;
|
|
20
|
+
this.storage = storage;
|
|
21
|
+
this.projectId = projectId;
|
|
22
|
+
}
|
|
23
|
+
getAccessTokenOrFail() {
|
|
24
|
+
const token = getAsanaAccessToken(this.db);
|
|
25
|
+
if (!token)
|
|
26
|
+
throw new Error('Asana access token not configured');
|
|
27
|
+
return token;
|
|
28
|
+
}
|
|
29
|
+
async moveTicket(ticketId, newState) {
|
|
30
|
+
let token;
|
|
31
|
+
try {
|
|
32
|
+
token = this.getAccessTokenOrFail();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { success: false, provider: 'asana', error: 'Asana access token not configured' };
|
|
36
|
+
}
|
|
37
|
+
// Look up Asana task GID from mapper
|
|
38
|
+
const mapper = new AsanaMapper(this.db);
|
|
39
|
+
const mapping = mapper.getByTicketId(ticketId);
|
|
40
|
+
if (!mapping) {
|
|
41
|
+
return { success: false, provider: 'asana', error: `No Asana mapping for ticket ${ticketId}` };
|
|
42
|
+
}
|
|
43
|
+
const client = new AsanaClient(token);
|
|
44
|
+
// Get the task to find its project membership
|
|
45
|
+
const task = await client.getTask(mapping.asanaTaskGid);
|
|
46
|
+
if (!task) {
|
|
47
|
+
return { success: false, provider: 'asana', error: `Asana task ${mapping.asanaTaskGid} not found` };
|
|
48
|
+
}
|
|
49
|
+
// Get the project GID from the mapping or task memberships
|
|
50
|
+
const projectGid = mapping.asanaProjectGid || task.memberships?.[0]?.project?.gid;
|
|
51
|
+
if (!projectGid) {
|
|
52
|
+
return { success: false, provider: 'asana', error: 'Cannot determine Asana project for section lookup' };
|
|
53
|
+
}
|
|
54
|
+
// Get project sections and find the matching one for the target state
|
|
55
|
+
let sections;
|
|
56
|
+
try {
|
|
57
|
+
sections = await client.listSections(projectGid);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
provider: 'asana',
|
|
63
|
+
error: `Failed to list Asana sections: ${error instanceof Error ? error.message : String(error)}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const targetSection = findMatchingSection(sections, newState);
|
|
67
|
+
if (!targetSection) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
provider: 'asana',
|
|
71
|
+
error: `No matching Asana section for state "${newState}". Available sections: ${sections.map(s => s.name).join(', ')}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Move the task to the target section
|
|
75
|
+
try {
|
|
76
|
+
await client.addTaskToSection(targetSection.gid, mapping.asanaTaskGid);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
provider: 'asana',
|
|
82
|
+
error: `Failed to move Asana task to section: ${error instanceof Error ? error.message : String(error)}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// If the target state looks like a "done" state, mark the task as completed
|
|
86
|
+
if (isCompletedState(newState)) {
|
|
87
|
+
try {
|
|
88
|
+
await client.updateTask(mapping.asanaTaskGid, { name: task.name, completed: true });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Non-fatal: section move is the primary action
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Update local PMO mirror (best-effort)
|
|
95
|
+
try {
|
|
96
|
+
await this.storage.moveTicket(this.projectId, ticketId, newState);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Non-fatal: Asana is the source of truth
|
|
100
|
+
}
|
|
101
|
+
// Update sync timestamp (best-effort)
|
|
102
|
+
try {
|
|
103
|
+
mapper.updateSyncTimestamp(ticketId);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Non-fatal
|
|
107
|
+
}
|
|
108
|
+
return { success: true, provider: 'asana' };
|
|
109
|
+
}
|
|
110
|
+
async deleteTicket(ticketId) {
|
|
111
|
+
let token;
|
|
112
|
+
try {
|
|
113
|
+
token = this.getAccessTokenOrFail();
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return { success: false, provider: 'asana', error: 'Asana access token not configured' };
|
|
117
|
+
}
|
|
118
|
+
// Look up Asana task GID from mapper
|
|
119
|
+
const mapper = new AsanaMapper(this.db);
|
|
120
|
+
const mapping = mapper.getByTicketId(ticketId);
|
|
121
|
+
if (mapping) {
|
|
122
|
+
const client = new AsanaClient(token);
|
|
123
|
+
try {
|
|
124
|
+
await client.deleteTask(mapping.asanaTaskGid);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
provider: 'asana',
|
|
130
|
+
error: `Failed to delete Asana task: ${error instanceof Error ? error.message : String(error)}`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Delete the local PMO mirror
|
|
135
|
+
try {
|
|
136
|
+
await this.storage.deleteTicket(ticketId);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Non-fatal if Asana delete succeeded
|
|
140
|
+
}
|
|
141
|
+
return { success: true, provider: 'asana' };
|
|
142
|
+
}
|
|
143
|
+
async listTickets(_projectId, filter) {
|
|
144
|
+
let token;
|
|
145
|
+
try {
|
|
146
|
+
token = this.getAccessTokenOrFail();
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return { success: false, provider: 'asana', tickets: [], error: 'Asana access token not configured' };
|
|
150
|
+
}
|
|
151
|
+
const asanaConfig = loadAsanaConfig(this.db);
|
|
152
|
+
const projectGid = asanaConfig?.projectGid || process.env.PRLT_ASANA_PROJECT_GID;
|
|
153
|
+
if (!projectGid) {
|
|
154
|
+
return { success: false, provider: 'asana', tickets: [], error: 'Asana project GID is required. Run "prlt asana connect" or set PRLT_ASANA_PROJECT_GID.' };
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const client = new AsanaClient(token);
|
|
158
|
+
const tasks = await client.listTasks(projectGid);
|
|
159
|
+
let tickets = tasks.map(task => asanaTaskToTicket(task));
|
|
160
|
+
// Apply client-side filters
|
|
161
|
+
if (filter?.priority) {
|
|
162
|
+
tickets = tickets.filter(t => t.priority === filter.priority);
|
|
163
|
+
}
|
|
164
|
+
if (filter?.column) {
|
|
165
|
+
tickets = tickets.filter(t => t.statusName === filter.column);
|
|
166
|
+
}
|
|
167
|
+
if (filter?.category) {
|
|
168
|
+
tickets = tickets.filter(t => t.category === filter.category);
|
|
169
|
+
}
|
|
170
|
+
if (filter?.search) {
|
|
171
|
+
const term = filter.search.toLowerCase();
|
|
172
|
+
tickets = tickets.filter(t => t.title.toLowerCase().includes(term) ||
|
|
173
|
+
(t.description || '').toLowerCase().includes(term));
|
|
174
|
+
}
|
|
175
|
+
if (filter?.label) {
|
|
176
|
+
const label = filter.label.toLowerCase();
|
|
177
|
+
tickets = tickets.filter(t => t.labels.some(l => l.toLowerCase() === label));
|
|
178
|
+
}
|
|
179
|
+
return { success: true, provider: 'asana', tickets };
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
provider: 'asana',
|
|
185
|
+
tickets: [],
|
|
186
|
+
error: error instanceof Error ? error.message : String(error),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async createTicket(projectId, input) {
|
|
191
|
+
let token;
|
|
192
|
+
try {
|
|
193
|
+
token = this.getAccessTokenOrFail();
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return { success: false, provider: 'asana', error: 'Asana access token not configured' };
|
|
197
|
+
}
|
|
198
|
+
const asanaConfig = loadAsanaConfig(this.db);
|
|
199
|
+
const asanaProjectGid = asanaConfig?.projectGid || process.env.PRLT_ASANA_PROJECT_GID;
|
|
200
|
+
if (!asanaProjectGid) {
|
|
201
|
+
return { success: false, provider: 'asana', error: 'Asana project GID is required. Run "prlt asana connect" or set PRLT_ASANA_PROJECT_GID.' };
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const client = new AsanaClient(token);
|
|
205
|
+
// Create the task in Asana
|
|
206
|
+
const task = await client.createTask({
|
|
207
|
+
name: input.title,
|
|
208
|
+
notes: input.description || undefined,
|
|
209
|
+
projects: [asanaProjectGid],
|
|
210
|
+
});
|
|
211
|
+
// Create local PMO mirror ticket
|
|
212
|
+
const mirrorDescription = [
|
|
213
|
+
input.description || '',
|
|
214
|
+
'',
|
|
215
|
+
'---',
|
|
216
|
+
`_Created in Asana: [${task.name}](https://app.asana.com/0/0/${task.gid})_`,
|
|
217
|
+
].join('\n').trim();
|
|
218
|
+
const pmoTicket = await this.storage.createTicket(projectId, {
|
|
219
|
+
...input,
|
|
220
|
+
title: task.name,
|
|
221
|
+
description: mirrorDescription,
|
|
222
|
+
metadata: {
|
|
223
|
+
...input.metadata,
|
|
224
|
+
'external_source': 'asana',
|
|
225
|
+
'external_id': task.gid,
|
|
226
|
+
'external_key': task.gid,
|
|
227
|
+
'external_url': task.permalink_url || `https://app.asana.com/0/0/${task.gid}`,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
// Create mapping record for sync operations
|
|
231
|
+
const mapper = new AsanaMapper(this.db);
|
|
232
|
+
mapper.createOrUpdateMapping(pmoTicket.id, task.gid, asanaProjectGid);
|
|
233
|
+
return { success: true, provider: 'asana', ticket: pmoTicket };
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
provider: 'asana',
|
|
239
|
+
error: error instanceof Error ? error.message : String(error),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async getTicket(ticketId) {
|
|
244
|
+
// Use local PMO mirror to avoid unnecessary API calls
|
|
245
|
+
try {
|
|
246
|
+
const ticket = await this.storage.getTicket(ticketId);
|
|
247
|
+
return { success: true, provider: 'asana', ticket };
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
return {
|
|
251
|
+
success: false,
|
|
252
|
+
provider: 'asana',
|
|
253
|
+
error: error instanceof Error ? error.message : String(error),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async updateTicket(ticketId, input) {
|
|
258
|
+
let token;
|
|
259
|
+
try {
|
|
260
|
+
token = this.getAccessTokenOrFail();
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return { success: false, provider: 'asana', error: 'Asana access token not configured' };
|
|
264
|
+
}
|
|
265
|
+
// Look up Asana task GID from mapper
|
|
266
|
+
const mapper = new AsanaMapper(this.db);
|
|
267
|
+
const mapping = mapper.getByTicketId(ticketId);
|
|
268
|
+
if (mapping) {
|
|
269
|
+
// Build Asana update payload from input fields
|
|
270
|
+
const asanaInput = {};
|
|
271
|
+
if (input.title !== undefined)
|
|
272
|
+
asanaInput.name = input.title;
|
|
273
|
+
if (input.description !== undefined)
|
|
274
|
+
asanaInput.notes = input.description ?? undefined;
|
|
275
|
+
// Only call Asana API if there are Asana-relevant fields
|
|
276
|
+
if (Object.keys(asanaInput).length > 0) {
|
|
277
|
+
const client = new AsanaClient(token);
|
|
278
|
+
try {
|
|
279
|
+
await client.updateTask(mapping.asanaTaskGid, asanaInput);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
provider: 'asana',
|
|
285
|
+
error: `Failed to update Asana task: ${error instanceof Error ? error.message : String(error)}`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Update sync timestamp (best-effort)
|
|
290
|
+
try {
|
|
291
|
+
mapper.updateSyncTimestamp(ticketId);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// Non-fatal
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Also update local PMO mirror
|
|
298
|
+
try {
|
|
299
|
+
const ticket = await this.storage.updateTicket(ticketId, input);
|
|
300
|
+
return { success: true, provider: 'asana', ticket };
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
return {
|
|
304
|
+
success: false,
|
|
305
|
+
provider: 'asana',
|
|
306
|
+
error: error instanceof Error ? error.message : String(error),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async assignTicket(ticketId, assignee) {
|
|
311
|
+
let token;
|
|
312
|
+
try {
|
|
313
|
+
token = this.getAccessTokenOrFail();
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
return { success: false, provider: 'asana', error: 'Asana access token not configured' };
|
|
317
|
+
}
|
|
318
|
+
// Look up Asana task GID from mapper
|
|
319
|
+
const mapper = new AsanaMapper(this.db);
|
|
320
|
+
const mapping = mapper.getByTicketId(ticketId);
|
|
321
|
+
if (mapping) {
|
|
322
|
+
// Asana assignment requires user GID. Best-effort — search by name if possible.
|
|
323
|
+
// For now, skip the Asana-side assignment (same pattern as Trello).
|
|
324
|
+
// The local PMO mirror is always updated.
|
|
325
|
+
}
|
|
326
|
+
// Update local PMO mirror
|
|
327
|
+
try {
|
|
328
|
+
await this.storage.updateTicket(ticketId, { assignee });
|
|
329
|
+
return { success: true, provider: 'asana' };
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
provider: 'asana',
|
|
335
|
+
error: error instanceof Error ? error.message : String(error),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Convert an Asana task to a normalized PMO Ticket.
|
|
342
|
+
*/
|
|
343
|
+
function asanaTaskToTicket(task) {
|
|
344
|
+
const sectionName = task.memberships?.[0]?.section?.name;
|
|
345
|
+
const statusName = task.completed ? 'Completed' : (sectionName || 'Open');
|
|
346
|
+
const statusCategory = task.completed ? 'completed' : deriveStatusCategory(sectionName);
|
|
347
|
+
const projectName = task.memberships?.[0]?.project?.name;
|
|
348
|
+
const projectGid = task.memberships?.[0]?.project?.gid;
|
|
349
|
+
return {
|
|
350
|
+
id: task.gid,
|
|
351
|
+
title: task.name,
|
|
352
|
+
description: task.notes || undefined,
|
|
353
|
+
projectId: projectGid || '',
|
|
354
|
+
projectName: projectName || 'Asana',
|
|
355
|
+
statusId: sectionName || (task.completed ? 'completed' : 'open'),
|
|
356
|
+
statusName,
|
|
357
|
+
statusCategory: statusCategory,
|
|
358
|
+
owner: task.assignee?.name || undefined,
|
|
359
|
+
assignee: task.assignee?.name || undefined,
|
|
360
|
+
subtasks: [],
|
|
361
|
+
labels: (task.tags ?? []).map(t => t.name),
|
|
362
|
+
metadata: {
|
|
363
|
+
external_source: 'asana',
|
|
364
|
+
external_key: task.gid,
|
|
365
|
+
external_id: task.gid,
|
|
366
|
+
external_url: task.permalink_url || `https://app.asana.com/0/0/${task.gid}`,
|
|
367
|
+
},
|
|
368
|
+
createdAt: new Date(),
|
|
369
|
+
updatedAt: new Date(),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Derive a PMO status category from an Asana section name.
|
|
374
|
+
* Uses heuristic matching against common section naming patterns.
|
|
375
|
+
*/
|
|
376
|
+
function deriveStatusCategory(sectionName) {
|
|
377
|
+
if (!sectionName)
|
|
378
|
+
return 'unstarted';
|
|
379
|
+
const lower = sectionName.toLowerCase();
|
|
380
|
+
// Completed states
|
|
381
|
+
if (lower.includes('done') || lower.includes('complete') || lower.includes('shipped') || lower.includes('closed')) {
|
|
382
|
+
return 'completed';
|
|
383
|
+
}
|
|
384
|
+
// Canceled states
|
|
385
|
+
if (lower.includes('cancel') || lower.includes('won\'t do') || lower.includes('wont do')) {
|
|
386
|
+
return 'canceled';
|
|
387
|
+
}
|
|
388
|
+
// Started states
|
|
389
|
+
if (lower.includes('progress') || lower.includes('doing') || lower.includes('active') || lower.includes('review') || lower.includes('testing')) {
|
|
390
|
+
return 'started';
|
|
391
|
+
}
|
|
392
|
+
// Backlog / unstarted
|
|
393
|
+
if (lower.includes('backlog') || lower.includes('todo') || lower.includes('to do') || lower.includes('icebox') || lower.includes('later')) {
|
|
394
|
+
return 'unstarted';
|
|
395
|
+
}
|
|
396
|
+
// Default to started for unknown section names
|
|
397
|
+
return 'started';
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Find the best matching Asana section for a target state name.
|
|
401
|
+
* Uses case-insensitive exact match first, then substring match.
|
|
402
|
+
*/
|
|
403
|
+
function findMatchingSection(sections, targetState) {
|
|
404
|
+
const lower = targetState.toLowerCase();
|
|
405
|
+
// 1. Exact match (case-insensitive)
|
|
406
|
+
const exact = sections.find(s => s.name.toLowerCase() === lower);
|
|
407
|
+
if (exact)
|
|
408
|
+
return exact;
|
|
409
|
+
// 2. Section name contains the target state
|
|
410
|
+
const contains = sections.find(s => s.name.toLowerCase().includes(lower));
|
|
411
|
+
if (contains)
|
|
412
|
+
return contains;
|
|
413
|
+
// 3. Target state contains the section name
|
|
414
|
+
const reverseContains = sections.find(s => lower.includes(s.name.toLowerCase()));
|
|
415
|
+
if (reverseContains)
|
|
416
|
+
return reverseContains;
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Check if a state name represents a completed/done state.
|
|
421
|
+
*/
|
|
422
|
+
function isCompletedState(stateName) {
|
|
423
|
+
const lower = stateName.toLowerCase();
|
|
424
|
+
return lower.includes('done') || lower.includes('complete') || lower.includes('shipped') || lower.includes('closed');
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=asana-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asana-provider.js","sourceRoot":"","sources":["../../../src/lib/providers/asana-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Mapper for Transition Intents
|
|
3
|
+
*
|
|
4
|
+
* Auto-guesses intent-to-state mappings when connecting a board.
|
|
5
|
+
* Uses provider state types first, then name heuristics.
|
|
6
|
+
*
|
|
7
|
+
* Each provider can have different state type vocabularies:
|
|
8
|
+
* - Linear: triage, backlog, unstarted, started, completed, canceled
|
|
9
|
+
* - Jira: new, indeterminate, done, category-based
|
|
10
|
+
* - Trello: no types (name heuristics only)
|
|
11
|
+
*/
|
|
12
|
+
import type { TransitionIntent } from './state-intents.js';
|
|
13
|
+
export interface BoardState {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
position?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface IntentMapping {
|
|
20
|
+
intent: TransitionIntent;
|
|
21
|
+
stateName: string;
|
|
22
|
+
stateId: string;
|
|
23
|
+
confidence: 'type' | 'name' | 'none';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Auto-guess transition intent mappings from a list of board states.
|
|
27
|
+
*
|
|
28
|
+
* Strategy:
|
|
29
|
+
* 1. For each intent, check if any state has a matching type (provider-specific)
|
|
30
|
+
* 2. If no type match, fall back to name heuristics from DEFAULT_INTENTS aliases
|
|
31
|
+
* 3. States can only be mapped to one intent (first match wins by intent priority)
|
|
32
|
+
*
|
|
33
|
+
* @param states - Available board states from the provider
|
|
34
|
+
* @param providerType - Provider type for type-based mapping ('linear', 'jira', etc.)
|
|
35
|
+
* @returns Array of intent mappings, one per matched intent
|
|
36
|
+
*/
|
|
37
|
+
export declare function autoMapIntents(states: BoardState[], providerType?: 'linear' | 'jira' | 'trello' | 'asana' | 'shortcut' | 'clickup' | 'github' | 'pmo'): IntentMapping[];
|
|
38
|
+
/**
|
|
39
|
+
* Format intent mappings for display to the user.
|
|
40
|
+
*
|
|
41
|
+
* @param mappings - The auto-guessed mappings
|
|
42
|
+
* @param allStates - All available board states
|
|
43
|
+
* @returns Array of display lines
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatMappingTable(mappings: IntentMapping[], allStates: BoardState[]): string[];
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Mapper for Transition Intents
|
|
3
|
+
*
|
|
4
|
+
* Auto-guesses intent-to-state mappings when connecting a board.
|
|
5
|
+
* Uses provider state types first, then name heuristics.
|
|
6
|
+
*
|
|
7
|
+
* Each provider can have different state type vocabularies:
|
|
8
|
+
* - Linear: triage, backlog, unstarted, started, completed, canceled
|
|
9
|
+
* - Jira: new, indeterminate, done, category-based
|
|
10
|
+
* - Trello: no types (name heuristics only)
|
|
11
|
+
*/
|
|
12
|
+
import { matchIntentByAliases, getDefaultIntent } from './state-intents.js';
|
|
13
|
+
/**
|
|
14
|
+
* Map from Linear state types to transition intents.
|
|
15
|
+
* Linear has no native "review" type, so that's always resolved by name heuristics.
|
|
16
|
+
*/
|
|
17
|
+
const LINEAR_TYPE_TO_INTENT = {
|
|
18
|
+
started: 'started',
|
|
19
|
+
completed: 'completed',
|
|
20
|
+
canceled: 'dropped',
|
|
21
|
+
cancelled: 'dropped',
|
|
22
|
+
backlog: 'paused',
|
|
23
|
+
unstarted: 'ready',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Map from Jira status category keys to transition intents.
|
|
27
|
+
* Jira has 3 categories: new, indeterminate, done.
|
|
28
|
+
* "needs_review" has no Jira category — resolved by name heuristics.
|
|
29
|
+
*/
|
|
30
|
+
const JIRA_CATEGORY_TO_INTENT = {
|
|
31
|
+
new: 'ready',
|
|
32
|
+
indeterminate: 'started',
|
|
33
|
+
done: 'completed',
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Auto-guess transition intent mappings from a list of board states.
|
|
37
|
+
*
|
|
38
|
+
* Strategy:
|
|
39
|
+
* 1. For each intent, check if any state has a matching type (provider-specific)
|
|
40
|
+
* 2. If no type match, fall back to name heuristics from DEFAULT_INTENTS aliases
|
|
41
|
+
* 3. States can only be mapped to one intent (first match wins by intent priority)
|
|
42
|
+
*
|
|
43
|
+
* @param states - Available board states from the provider
|
|
44
|
+
* @param providerType - Provider type for type-based mapping ('linear', 'jira', etc.)
|
|
45
|
+
* @returns Array of intent mappings, one per matched intent
|
|
46
|
+
*/
|
|
47
|
+
export function autoMapIntents(states, providerType = 'pmo') {
|
|
48
|
+
const mappings = [];
|
|
49
|
+
const usedStateIds = new Set();
|
|
50
|
+
// Priority order for intent resolution
|
|
51
|
+
const intentOrder = [
|
|
52
|
+
'started',
|
|
53
|
+
'needs_review',
|
|
54
|
+
'completed',
|
|
55
|
+
'paused',
|
|
56
|
+
'ready',
|
|
57
|
+
'dropped',
|
|
58
|
+
];
|
|
59
|
+
for (const intent of intentOrder) {
|
|
60
|
+
// 1. Try type-based mapping (provider-specific)
|
|
61
|
+
if (providerType === 'linear') {
|
|
62
|
+
const typeMatch = states.find(s => s.type && LINEAR_TYPE_TO_INTENT[s.type] === intent && !usedStateIds.has(s.id));
|
|
63
|
+
if (typeMatch) {
|
|
64
|
+
mappings.push({
|
|
65
|
+
intent,
|
|
66
|
+
stateName: typeMatch.name,
|
|
67
|
+
stateId: typeMatch.id,
|
|
68
|
+
confidence: 'type',
|
|
69
|
+
});
|
|
70
|
+
usedStateIds.add(typeMatch.id);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (providerType === 'jira') {
|
|
75
|
+
const typeMatch = states.find(s => s.type && JIRA_CATEGORY_TO_INTENT[s.type] === intent && !usedStateIds.has(s.id));
|
|
76
|
+
if (typeMatch) {
|
|
77
|
+
mappings.push({
|
|
78
|
+
intent,
|
|
79
|
+
stateName: typeMatch.name,
|
|
80
|
+
stateId: typeMatch.id,
|
|
81
|
+
confidence: 'type',
|
|
82
|
+
});
|
|
83
|
+
usedStateIds.add(typeMatch.id);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// 2. Fall back to name heuristics from DEFAULT_INTENTS
|
|
88
|
+
const intentDef = getDefaultIntent(intent);
|
|
89
|
+
if (intentDef) {
|
|
90
|
+
const availableStates = states.filter(s => !usedStateIds.has(s.id));
|
|
91
|
+
const nameMatch = matchIntentByAliases(availableStates.map(s => ({ id: s.id, name: s.name })), intentDef);
|
|
92
|
+
if (nameMatch) {
|
|
93
|
+
mappings.push({
|
|
94
|
+
intent,
|
|
95
|
+
stateName: nameMatch.name,
|
|
96
|
+
stateId: nameMatch.id,
|
|
97
|
+
confidence: 'name',
|
|
98
|
+
});
|
|
99
|
+
usedStateIds.add(nameMatch.id);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return mappings;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Format intent mappings for display to the user.
|
|
108
|
+
*
|
|
109
|
+
* @param mappings - The auto-guessed mappings
|
|
110
|
+
* @param allStates - All available board states
|
|
111
|
+
* @returns Array of display lines
|
|
112
|
+
*/
|
|
113
|
+
export function formatMappingTable(mappings, allStates) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
const maxStateLen = Math.max(...allStates.map(s => s.name.length), 10);
|
|
116
|
+
const maxIntentLen = Math.max(...mappings.map(m => m.intent.length), 10);
|
|
117
|
+
// Header
|
|
118
|
+
lines.push(`${'Board State'.padEnd(maxStateLen + 2)}${'Intent'.padEnd(maxIntentLen + 2)}Work Command`);
|
|
119
|
+
lines.push(`${'─'.repeat(maxStateLen + 2)}${'─'.repeat(maxIntentLen + 2)}${'─'.repeat(20)}`);
|
|
120
|
+
const intentToCommand = {
|
|
121
|
+
started: 'work start',
|
|
122
|
+
needs_review: 'work ready',
|
|
123
|
+
completed: 'work ship',
|
|
124
|
+
paused: 'work stop',
|
|
125
|
+
ready: 'work groom',
|
|
126
|
+
dropped: 'work drop',
|
|
127
|
+
};
|
|
128
|
+
// Map states to their intents
|
|
129
|
+
const stateToMapping = new Map(mappings.map(m => [m.stateId, m]));
|
|
130
|
+
for (const state of allStates) {
|
|
131
|
+
const mapping = stateToMapping.get(state.id);
|
|
132
|
+
const intentStr = mapping ? mapping.intent : '(unmapped)';
|
|
133
|
+
const commandStr = mapping ? intentToCommand[mapping.intent] || '' : '';
|
|
134
|
+
lines.push(`${state.name.padEnd(maxStateLen + 2)}${intentStr.padEnd(maxIntentLen + 2)}${commandStr}`);
|
|
135
|
+
}
|
|
136
|
+
return lines;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=auto-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-mapper.js","sourceRoot":"","sources":["../../../src/lib/providers/auto-mapper.ts"],"names":[],"mappings":"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"}
|