@proletariat/cli 0.3.90 → 0.3.92
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/work/index.js +4 -0
- package/dist/commands/work/index.js.map +1 -1
- package/dist/commands/work/ship.d.ts +43 -0
- package/dist/commands/work/ship.js +587 -0
- package/dist/commands/work/ship.js.map +1 -0
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +11 -1
- package/dist/commands/work/start.js.map +1 -1
- package/dist/lib/execution/context.d.ts +20 -0
- package/dist/lib/execution/context.js +88 -0
- package/dist/lib/execution/context.js.map +1 -1
- package/dist/lib/execution/devcontainer.d.ts +6 -0
- package/dist/lib/execution/devcontainer.js +48 -1
- package/dist/lib/execution/devcontainer.js.map +1 -1
- package/dist/lib/execution/runners/devcontainer.js +11 -0
- package/dist/lib/execution/runners/devcontainer.js.map +1 -1
- package/dist/lib/execution/runners/docker-management.js +1 -1
- package/dist/lib/execution/runners/docker-management.js.map +1 -1
- package/dist/lib/execution/runners/orchestrator.js +6 -3
- package/dist/lib/execution/runners/orchestrator.js.map +1 -1
- package/dist/lib/execution/runners/prompt-builder.js +31 -0
- package/dist/lib/execution/runners/prompt-builder.js.map +1 -1
- package/dist/lib/execution/runners/shared.d.ts +2 -2
- package/dist/lib/execution/runners/shared.js +2 -2
- package/dist/lib/execution/runners/shared.js.map +1 -1
- package/dist/lib/execution/types.d.ts +23 -0
- package/dist/lib/execution/types.js.map +1 -1
- package/dist/lib/providers/index.d.ts +2 -0
- package/dist/lib/providers/index.js +2 -0
- package/dist/lib/providers/index.js.map +1 -1
- package/dist/lib/providers/state-intents.d.ts +44 -0
- package/dist/lib/providers/state-intents.js +101 -0
- package/dist/lib/providers/state-intents.js.map +1 -0
- package/dist/lib/providers/state-resolution.d.ts +137 -0
- package/dist/lib/providers/state-resolution.js +302 -0
- package/dist/lib/providers/state-resolution.js.map +1 -0
- package/dist/lib/work-lifecycle/post-execution.js +47 -28
- package/dist/lib/work-lifecycle/post-execution.js.map +1 -1
- package/oclif.manifest.json +2317 -2203
- package/package.json +1 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Resolution Engine
|
|
3
|
+
*
|
|
4
|
+
* Resolves semantic intents (e.g., 'review', 'active', 'done') to actual
|
|
5
|
+
* PM tool states at runtime. Never caches state IDs across calls.
|
|
6
|
+
*
|
|
7
|
+
* Resolution flow:
|
|
8
|
+
* 1. Always fetch fresh states from the PM provider
|
|
9
|
+
* 2. Check user config — `state-map.{intent}` overrides exact-match against fetched states
|
|
10
|
+
* 3. Match against built-in semantic intent aliases
|
|
11
|
+
* 4. No config + no alias match → LLM resolves (pass available states to LLM)
|
|
12
|
+
* 5. No match → skip (don't move, log warning)
|
|
13
|
+
*
|
|
14
|
+
* The same move() function works across Linear, Trello, ClickUp, Jira, etc. —
|
|
15
|
+
* each provider implements fetchStates() differently but returns the same shape.
|
|
16
|
+
* Resolution logic is provider-agnostic.
|
|
17
|
+
*/
|
|
18
|
+
import { SettingsStore } from '../database/settings-store.js';
|
|
19
|
+
import { matchIntentByAliases, getDefaultIntent } from './state-intents.js';
|
|
20
|
+
/**
|
|
21
|
+
* Config key prefix for state-map overrides.
|
|
22
|
+
* e.g., `state-map.review` → "Awaiting Client Feedback"
|
|
23
|
+
*/
|
|
24
|
+
const STATE_MAP_PREFIX = 'state-map.';
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// LLM Resolution
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Use the LLM to resolve which available state best matches a semantic intent.
|
|
30
|
+
*
|
|
31
|
+
* Sends the list of available states and the intent to the Anthropic API.
|
|
32
|
+
* Returns the matching state ID, or null if no match.
|
|
33
|
+
*
|
|
34
|
+
* Requires ANTHROPIC_API_KEY to be set.
|
|
35
|
+
*/
|
|
36
|
+
export async function llmResolveState(states, intent) {
|
|
37
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
38
|
+
if (!apiKey) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const stateList = states.map(s => `- "${s.name}" (id: ${s.id})`).join('\n');
|
|
42
|
+
const prompt = `You are a state resolution assistant. Given a list of available workflow states from a project management tool and a semantic intent, pick the state that best matches the intent.
|
|
43
|
+
|
|
44
|
+
Available states:
|
|
45
|
+
${stateList}
|
|
46
|
+
|
|
47
|
+
Semantic intent: "${intent}"
|
|
48
|
+
${getDefaultIntent(intent) ? `Intent description: ${getDefaultIntent(intent).description}` : ''}
|
|
49
|
+
|
|
50
|
+
Respond with ONLY the exact state ID that best matches this intent. If no state matches, respond with "NONE".`;
|
|
51
|
+
try {
|
|
52
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
'x-api-key': apiKey,
|
|
57
|
+
'anthropic-version': '2023-06-01',
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
model: 'claude-haiku-4-5-20251001',
|
|
61
|
+
max_tokens: 100,
|
|
62
|
+
messages: [
|
|
63
|
+
{
|
|
64
|
+
role: 'user',
|
|
65
|
+
content: prompt,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const data = (await response.json());
|
|
74
|
+
const text = data.content?.[0]?.text?.trim();
|
|
75
|
+
if (!text || text === 'NONE') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
// The LLM should return a state ID — find the matching state
|
|
79
|
+
const match = states.find(s => s.id === text);
|
|
80
|
+
if (match)
|
|
81
|
+
return match;
|
|
82
|
+
// Fallback: LLM might have returned a state name instead of ID
|
|
83
|
+
const nameMatch = states.find(s => s.name.toLowerCase() === text.toLowerCase());
|
|
84
|
+
if (nameMatch)
|
|
85
|
+
return nameMatch;
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// LLM call failed — non-fatal, fall through to skip
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Config Resolution
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
/**
|
|
97
|
+
* Check user config for a state-map override for the given intent.
|
|
98
|
+
* Config stores state NAMES, not IDs.
|
|
99
|
+
*
|
|
100
|
+
* @param db - Database instance for settings lookup
|
|
101
|
+
* @param intent - Semantic intent name (e.g., 'review')
|
|
102
|
+
* @returns The configured state name, or null if not set
|
|
103
|
+
*/
|
|
104
|
+
export function getStateMapConfig(db, intent) {
|
|
105
|
+
try {
|
|
106
|
+
const settings = new SettingsStore(db);
|
|
107
|
+
return settings.get(`${STATE_MAP_PREFIX}${intent}`);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Set a state-map config override for an intent.
|
|
115
|
+
*
|
|
116
|
+
* @param db - Database instance
|
|
117
|
+
* @param intent - Semantic intent name
|
|
118
|
+
* @param stateName - The state name to map to
|
|
119
|
+
*/
|
|
120
|
+
export function setStateMapConfig(db, intent, stateName) {
|
|
121
|
+
const settings = new SettingsStore(db);
|
|
122
|
+
settings.set(`${STATE_MAP_PREFIX}${intent}`, stateName);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Remove a state-map config override for an intent.
|
|
126
|
+
*/
|
|
127
|
+
export function deleteStateMapConfig(db, intent) {
|
|
128
|
+
const settings = new SettingsStore(db);
|
|
129
|
+
settings.delete(`${STATE_MAP_PREFIX}${intent}`);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List all state-map config overrides.
|
|
133
|
+
*/
|
|
134
|
+
export function listStateMapConfigs(db) {
|
|
135
|
+
try {
|
|
136
|
+
const settings = new SettingsStore(db);
|
|
137
|
+
const entries = settings.getByPrefix(STATE_MAP_PREFIX);
|
|
138
|
+
return entries.map(e => ({
|
|
139
|
+
intent: e.key.slice(STATE_MAP_PREFIX.length),
|
|
140
|
+
stateName: e.value,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// State Fetching — Provider Adapters
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
/**
|
|
151
|
+
* Create a PMProvider adapter from the existing TicketProvider + ProviderStorage.
|
|
152
|
+
*
|
|
153
|
+
* Fetches fresh states from the project's board via storage, and delegates
|
|
154
|
+
* moveTicket to the TicketProvider (which routes to Linear/Jira/PMO).
|
|
155
|
+
*/
|
|
156
|
+
export function createPMProviderAdapter(provider, storage, projectId) {
|
|
157
|
+
return {
|
|
158
|
+
async fetchStates(_ticketId) {
|
|
159
|
+
const board = await storage.getProjectBoard(projectId);
|
|
160
|
+
if (!board)
|
|
161
|
+
return [];
|
|
162
|
+
return board.columns.map((col, idx) => ({
|
|
163
|
+
id: col.name, // For PMO, the state ID is the column name
|
|
164
|
+
name: col.name,
|
|
165
|
+
}));
|
|
166
|
+
},
|
|
167
|
+
async moveTicket(ticketId, stateId) {
|
|
168
|
+
const result = await provider.moveTicket(ticketId, stateId);
|
|
169
|
+
return { success: result.success, error: result.error };
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Move a ticket to a state matching a semantic intent.
|
|
175
|
+
*
|
|
176
|
+
* Resolution order:
|
|
177
|
+
* 1. Fetch fresh states from the provider (never cache)
|
|
178
|
+
* 2. Check user config for `state-map.{intent}` override → exact match
|
|
179
|
+
* 3. Match against built-in semantic intent aliases
|
|
180
|
+
* 4. LLM fallback — ask Claude which state matches the intent
|
|
181
|
+
* 5. No match → skip, return warning
|
|
182
|
+
*
|
|
183
|
+
* @param pmProvider - The PM provider to fetch states from and move tickets in
|
|
184
|
+
* @param ticketId - The ticket to move
|
|
185
|
+
* @param intent - The semantic intent (e.g., 'review', 'active', 'done', 'blocked')
|
|
186
|
+
* @param dbOrOptions - Database instance or options object
|
|
187
|
+
* @returns Resolution result with success/failure and metadata
|
|
188
|
+
*/
|
|
189
|
+
export async function move(pmProvider, ticketId, intent, dbOrOptions) {
|
|
190
|
+
// Normalize arguments: support both `move(p, id, intent, db)` and `move(p, id, intent, { db, currentState })`
|
|
191
|
+
let db;
|
|
192
|
+
let currentState;
|
|
193
|
+
if (dbOrOptions && typeof dbOrOptions === 'object' && 'prepare' in dbOrOptions) {
|
|
194
|
+
// It's a Database instance (has .prepare method)
|
|
195
|
+
db = dbOrOptions;
|
|
196
|
+
}
|
|
197
|
+
else if (dbOrOptions && typeof dbOrOptions === 'object') {
|
|
198
|
+
const opts = dbOrOptions;
|
|
199
|
+
db = opts.db;
|
|
200
|
+
currentState = opts.currentState;
|
|
201
|
+
}
|
|
202
|
+
// 1. Always fetch fresh states
|
|
203
|
+
let states;
|
|
204
|
+
try {
|
|
205
|
+
states = await pmProvider.fetchStates(ticketId);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return {
|
|
209
|
+
success: false,
|
|
210
|
+
error: `Failed to fetch states: ${error instanceof Error ? error.message : String(error)}`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (states.length === 0) {
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
error: 'No states available from provider',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Helper: check if ticket is already in the resolved state (case-insensitive)
|
|
220
|
+
const isAlreadyInState = (stateName) => {
|
|
221
|
+
if (!currentState)
|
|
222
|
+
return false;
|
|
223
|
+
return currentState.toLowerCase() === stateName.toLowerCase();
|
|
224
|
+
};
|
|
225
|
+
// 2. Check user config override
|
|
226
|
+
if (db) {
|
|
227
|
+
const configOverride = getStateMapConfig(db, intent);
|
|
228
|
+
if (configOverride) {
|
|
229
|
+
const match = states.find(s => s.name.toLowerCase() === configOverride.toLowerCase());
|
|
230
|
+
if (match) {
|
|
231
|
+
if (isAlreadyInState(match.name)) {
|
|
232
|
+
return { success: false, resolvedVia: 'config', stateName: match.name, stateId: match.id };
|
|
233
|
+
}
|
|
234
|
+
const result = await pmProvider.moveTicket(ticketId, match.id);
|
|
235
|
+
return {
|
|
236
|
+
success: result.success,
|
|
237
|
+
resolvedVia: 'config',
|
|
238
|
+
stateName: match.name,
|
|
239
|
+
stateId: match.id,
|
|
240
|
+
error: result.error,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// Config is set but no matching state — fall through to alias/LLM
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// 3. Match against built-in semantic intent aliases
|
|
247
|
+
const intentDef = getDefaultIntent(intent);
|
|
248
|
+
if (intentDef) {
|
|
249
|
+
const aliasMatch = matchIntentByAliases(states, intentDef);
|
|
250
|
+
if (aliasMatch) {
|
|
251
|
+
if (isAlreadyInState(aliasMatch.name)) {
|
|
252
|
+
return { success: false, resolvedVia: 'alias', stateName: aliasMatch.name, stateId: aliasMatch.id };
|
|
253
|
+
}
|
|
254
|
+
const result = await pmProvider.moveTicket(ticketId, aliasMatch.id);
|
|
255
|
+
return {
|
|
256
|
+
success: result.success,
|
|
257
|
+
resolvedVia: 'alias',
|
|
258
|
+
stateName: aliasMatch.name,
|
|
259
|
+
stateId: aliasMatch.id,
|
|
260
|
+
error: result.error,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// 4. LLM fallback
|
|
265
|
+
const llmMatch = await llmResolveState(states, intent);
|
|
266
|
+
if (llmMatch) {
|
|
267
|
+
if (isAlreadyInState(llmMatch.name)) {
|
|
268
|
+
return { success: false, resolvedVia: 'llm', stateName: llmMatch.name, stateId: llmMatch.id };
|
|
269
|
+
}
|
|
270
|
+
const result = await pmProvider.moveTicket(ticketId, llmMatch.id);
|
|
271
|
+
return {
|
|
272
|
+
success: result.success,
|
|
273
|
+
resolvedVia: 'llm',
|
|
274
|
+
stateName: llmMatch.name,
|
|
275
|
+
stateId: llmMatch.id,
|
|
276
|
+
error: result.error,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// 5. No match — skip
|
|
280
|
+
const warning = `No state match for intent '${intent}', skipping move`;
|
|
281
|
+
console.warn(warning);
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
resolvedVia: 'skipped',
|
|
285
|
+
warning,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
// Convenience: moveWithProvider()
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
/**
|
|
292
|
+
* High-level convenience function that wraps move() with the existing
|
|
293
|
+
* TicketProvider + ProviderStorage infrastructure.
|
|
294
|
+
*
|
|
295
|
+
* Use this from commands and lifecycle hooks that already have a resolved
|
|
296
|
+
* TicketProvider and ProviderStorage.
|
|
297
|
+
*/
|
|
298
|
+
export async function moveWithProvider(provider, storage, projectId, ticketId, intent, db, currentState) {
|
|
299
|
+
const pmProvider = createPMProviderAdapter(provider, storage, projectId);
|
|
300
|
+
return move(pmProvider, ticketId, intent, { db, currentState });
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=state-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-resolution.js","sourceRoot":"","sources":["../../../src/lib/providers/state-resolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { getWorkColumnSetting, findColumnByName, getReviewGateSetting } from '../pmo/utils.js';
|
|
17
17
|
import { resolveTicketProvider } from '../providers/resolver.js';
|
|
18
18
|
import { tryValidateCommits } from '../execution/commit-validation.js';
|
|
19
|
+
import { moveWithProvider } from '../providers/state-resolution.js';
|
|
19
20
|
/**
|
|
20
21
|
* Check if a completed execution should trigger an automatic state transition.
|
|
21
22
|
*
|
|
@@ -82,40 +83,58 @@ export async function handlePostExecutionTransition(context, storage, db) {
|
|
|
82
83
|
// If we can't validate, allow the transition to proceed.
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
|
-
// Determine
|
|
86
|
-
// - auto:
|
|
87
|
-
// - post:
|
|
88
|
-
|
|
89
|
-
const targetColumnType = reviewGate === 'auto' ? 'done' : 'review';
|
|
90
|
-
const targetColumnName = getWorkColumnSetting(db, targetColumnType);
|
|
91
|
-
// Get board columns to find the target column
|
|
92
|
-
const board = await storage.getProjectBoard(ticket.projectId);
|
|
93
|
-
if (!board) {
|
|
94
|
-
return { transitioned: false, reviewGate };
|
|
95
|
-
}
|
|
96
|
-
const columnNames = board.columns.map(col => col.name);
|
|
97
|
-
const targetColumn = findColumnByName(columnNames, targetColumnName);
|
|
98
|
-
if (!targetColumn) {
|
|
99
|
-
return { transitioned: false, reviewGate };
|
|
100
|
-
}
|
|
101
|
-
// Already in target state — skip
|
|
102
|
-
if (ticket.statusName === targetColumn) {
|
|
103
|
-
return { transitioned: false, reviewGate };
|
|
104
|
-
}
|
|
86
|
+
// Determine semantic intent based on review gate mode:
|
|
87
|
+
// - auto: intent is 'done' (no human review needed)
|
|
88
|
+
// - post/required: intent is 'review' (human reviews)
|
|
89
|
+
const intent = reviewGate === 'auto' ? 'done' : 'review';
|
|
105
90
|
// Resolve the appropriate provider for this ticket
|
|
106
91
|
// Cast to ProviderStorage — at runtime the actual object is SQLiteStorage
|
|
107
92
|
// which implements the full interface. For post-execution, only moveTicket is used.
|
|
108
93
|
const provider = resolveTicketProvider(context.ticketId, ticket.projectId, db, storage, ticket.metadata);
|
|
109
|
-
//
|
|
94
|
+
// Use state resolution engine to resolve intent → actual state and move
|
|
110
95
|
const previousState = ticket.statusName;
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
96
|
+
const resolution = await moveWithProvider(provider, storage, ticket.projectId, context.ticketId, intent, db, ticket.statusName);
|
|
97
|
+
if (!resolution.success) {
|
|
98
|
+
// If skipped (no match), fall back to legacy column matching
|
|
99
|
+
if (resolution.resolvedVia === 'skipped') {
|
|
100
|
+
const targetColumnType = reviewGate === 'auto' ? 'done' : 'review';
|
|
101
|
+
const targetColumnName = getWorkColumnSetting(db, targetColumnType);
|
|
102
|
+
const board = await storage.getProjectBoard(ticket.projectId);
|
|
103
|
+
if (!board) {
|
|
104
|
+
return { transitioned: false, reviewGate };
|
|
105
|
+
}
|
|
106
|
+
const columnNames = board.columns.map(col => col.name);
|
|
107
|
+
const targetColumn = findColumnByName(columnNames, targetColumnName);
|
|
108
|
+
if (!targetColumn || ticket.statusName === targetColumn) {
|
|
109
|
+
return { transitioned: false, reviewGate };
|
|
110
|
+
}
|
|
111
|
+
const moveResult = await provider.moveTicket(context.ticketId, targetColumn);
|
|
112
|
+
if (!moveResult.success) {
|
|
113
|
+
return {
|
|
114
|
+
transitioned: false,
|
|
115
|
+
fromState: previousState,
|
|
116
|
+
toState: targetColumn,
|
|
117
|
+
provider: moveResult.provider,
|
|
118
|
+
providerError: moveResult.error,
|
|
119
|
+
validation,
|
|
120
|
+
reviewGate,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
transitioned: true,
|
|
125
|
+
fromState: previousState,
|
|
126
|
+
toState: targetColumn,
|
|
127
|
+
provider: moveResult.provider,
|
|
128
|
+
validation,
|
|
129
|
+
reviewGate,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
113
132
|
return {
|
|
114
133
|
transitioned: false,
|
|
115
134
|
fromState: previousState,
|
|
116
|
-
toState:
|
|
117
|
-
provider:
|
|
118
|
-
providerError:
|
|
135
|
+
toState: resolution.stateName,
|
|
136
|
+
provider: provider.name,
|
|
137
|
+
providerError: resolution.error || resolution.warning,
|
|
119
138
|
validation,
|
|
120
139
|
reviewGate,
|
|
121
140
|
};
|
|
@@ -123,8 +142,8 @@ export async function handlePostExecutionTransition(context, storage, db) {
|
|
|
123
142
|
return {
|
|
124
143
|
transitioned: true,
|
|
125
144
|
fromState: previousState,
|
|
126
|
-
toState:
|
|
127
|
-
provider:
|
|
145
|
+
toState: resolution.stateName,
|
|
146
|
+
provider: provider.name,
|
|
128
147
|
validation,
|
|
129
148
|
reviewGate,
|
|
130
149
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-execution.js","sourceRoot":"","sources":["../../../src/lib/work-lifecycle/post-execution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAEhE,OAAO,EAAE,kBAAkB,EAA+B,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"post-execution.js","sourceRoot":"","sources":["../../../src/lib/work-lifecycle/post-execution.ts"],"names":[],"mappings":"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"}
|