@proletariat/cli 0.3.95 → 0.3.96
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/config/index.js +1 -1
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/db/repair.js +160 -35
- package/dist/commands/db/repair.js.map +1 -1
- package/dist/commands/gc.d.ts +13 -0
- package/dist/commands/gc.js +178 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/pr/merge.js +1 -1
- package/dist/commands/pr/merge.js.map +1 -1
- package/dist/commands/session/attach.d.ts +3 -3
- package/dist/commands/session/attach.js +37 -79
- package/dist/commands/session/attach.js.map +1 -1
- package/dist/commands/session/exec.js +1 -1
- package/dist/commands/session/exec.js.map +1 -1
- package/dist/commands/session/health.js +1 -1
- package/dist/commands/session/health.js.map +1 -1
- package/dist/commands/session/inspect.js +1 -1
- package/dist/commands/session/inspect.js.map +1 -1
- package/dist/commands/session/list.d.ts +1 -0
- package/dist/commands/session/list.js +111 -78
- package/dist/commands/session/list.js.map +1 -1
- package/dist/commands/session/peek.js +1 -1
- package/dist/commands/session/peek.js.map +1 -1
- package/dist/commands/session/poke.js +1 -1
- package/dist/commands/session/poke.js.map +1 -1
- package/dist/commands/session/prune.js +50 -11
- package/dist/commands/session/prune.js.map +1 -1
- package/dist/commands/session/restart.js +1 -1
- package/dist/commands/session/restart.js.map +1 -1
- package/dist/commands/{action → sync}/index.d.ts +2 -6
- package/dist/commands/sync/index.js +68 -0
- package/dist/commands/sync/index.js.map +1 -0
- package/dist/commands/sync/pause.d.ts +10 -0
- package/dist/commands/sync/pause.js +35 -0
- package/dist/commands/sync/pause.js.map +1 -0
- package/dist/commands/sync/queue.d.ts +10 -0
- package/dist/commands/sync/queue.js +106 -0
- package/dist/commands/sync/queue.js.map +1 -0
- package/dist/commands/sync/resume.d.ts +10 -0
- package/dist/commands/sync/resume.js +34 -0
- package/dist/commands/sync/resume.js.map +1 -0
- package/dist/commands/sync/start.d.ts +11 -0
- package/dist/commands/sync/start.js +73 -0
- package/dist/commands/sync/start.js.map +1 -0
- package/dist/commands/sync/status.d.ts +10 -0
- package/dist/commands/sync/status.js +40 -0
- package/dist/commands/sync/status.js.map +1 -0
- package/dist/commands/sync/stop.d.ts +10 -0
- package/dist/commands/sync/stop.js +39 -0
- package/dist/commands/sync/stop.js.map +1 -0
- package/dist/commands/ticket/create.js +1 -1
- package/dist/commands/ticket/create.js.map +1 -1
- package/dist/commands/ticket/edit.js +1 -1
- package/dist/commands/ticket/edit.js.map +1 -1
- package/dist/commands/ticket/list.js +1 -1
- package/dist/commands/ticket/list.js.map +1 -1
- package/dist/commands/ticket/update.js +1 -1
- package/dist/commands/ticket/update.js.map +1 -1
- package/dist/commands/work/complete.js +1 -1
- package/dist/commands/work/complete.js.map +1 -1
- package/dist/commands/work/ready.js +1 -1
- package/dist/commands/work/ready.js.map +1 -1
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/resolve.js.map +1 -1
- package/dist/commands/work/ship.js +1 -1
- package/dist/commands/work/ship.js.map +1 -1
- package/dist/commands/work/start.js +13 -84
- package/dist/commands/work/start.js.map +1 -1
- package/dist/lib/dashboard/data.js +1 -1
- package/dist/lib/dashboard/data.js.map +1 -1
- package/dist/lib/database/db-safety.d.ts +22 -0
- package/dist/lib/database/db-safety.js +91 -4
- package/dist/lib/database/db-safety.js.map +1 -1
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +1 -1
- package/dist/lib/database/index.js.map +1 -1
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.d.ts +13 -0
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.js +85 -0
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.js.map +1 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.d.ts +11 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.js +40 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.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/devcontainer.js +1 -1
- package/dist/lib/execution/devcontainer.js.map +1 -1
- package/dist/lib/execution/runners/docker-management.d.ts +9 -0
- package/dist/lib/execution/runners/docker-management.js +14 -3
- package/dist/lib/execution/runners/docker-management.js.map +1 -1
- package/dist/lib/execution/runners/prompt-builder.js +15 -3
- package/dist/lib/execution/runners/prompt-builder.js.map +1 -1
- package/dist/lib/execution/runners/shared.d.ts +1 -1
- package/dist/lib/execution/runners/shared.js +1 -1
- package/dist/lib/execution/runners/shared.js.map +1 -1
- package/dist/lib/execution/session-utils.d.ts +16 -0
- package/dist/lib/execution/session-utils.js +42 -0
- package/dist/lib/execution/session-utils.js.map +1 -1
- package/dist/lib/execution/spawner.js +2 -1
- package/dist/lib/execution/spawner.js.map +1 -1
- package/dist/lib/execution/storage.js +2 -1
- package/dist/lib/execution/storage.js.map +1 -1
- package/dist/lib/external-issues/utils.d.ts +25 -0
- package/dist/lib/external-issues/utils.js +32 -0
- package/dist/lib/external-issues/utils.js.map +1 -0
- package/dist/lib/gc/index.d.ts +126 -0
- package/dist/lib/gc/index.js +410 -0
- package/dist/lib/gc/index.js.map +1 -0
- package/dist/lib/mcp/tools/action.js +1 -1
- package/dist/lib/mcp/tools/action.js.map +1 -1
- package/dist/lib/mcp/tools/ticket.js +1 -1
- package/dist/lib/mcp/tools/ticket.js.map +1 -1
- package/dist/lib/orchestrate/actions.js +30 -0
- package/dist/lib/orchestrate/actions.js.map +1 -1
- package/dist/lib/orchestrate/poller.js +3 -3
- package/dist/lib/orchestrate/poller.js.map +1 -1
- package/dist/lib/orchestrate/presets.js +2 -1
- package/dist/lib/orchestrate/presets.js.map +1 -1
- package/dist/lib/orchestrate/types.d.ts +1 -1
- package/dist/lib/orchestrate/types.js +1 -0
- package/dist/lib/orchestrate/types.js.map +1 -1
- package/dist/lib/pmo/index.js +1 -1
- package/dist/lib/pmo/index.js.map +1 -1
- package/dist/lib/pmo/markdown.js +1 -1
- package/dist/lib/pmo/markdown.js.map +1 -1
- package/dist/lib/pmo/schema.d.ts +3 -1
- package/dist/lib/pmo/schema.js +26 -2
- package/dist/lib/pmo/schema.js.map +1 -1
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/actions.js.map +1 -1
- package/dist/lib/pmo/storage/base.js +37 -15
- package/dist/lib/pmo/storage/base.js.map +1 -1
- package/dist/lib/pmo/storage/projects.js +2 -1
- package/dist/lib/pmo/storage/projects.js.map +1 -1
- package/dist/lib/pmo/storage/statuses.js +1 -1
- package/dist/lib/pmo/storage/statuses.js.map +1 -1
- package/dist/lib/pmo/storage/subtasks.js +1 -1
- package/dist/lib/pmo/storage/subtasks.js.map +1 -1
- package/dist/lib/pmo/storage/templates.js +1 -1
- package/dist/lib/pmo/storage/templates.js.map +1 -1
- package/dist/lib/pmo/storage/tickets.js +2 -1
- package/dist/lib/pmo/storage/tickets.js.map +1 -1
- package/dist/lib/pmo/storage/workflow-rules.js +1 -1
- package/dist/lib/pmo/storage/workflow-rules.js.map +1 -1
- package/dist/lib/pmo/utils.d.ts +6 -189
- package/dist/lib/pmo/utils.js +6 -306
- package/dist/lib/pmo/utils.js.map +1 -1
- package/dist/lib/session/heartbeat.js +1 -1
- package/dist/lib/session/heartbeat.js.map +1 -1
- package/dist/lib/sync/daemon-process.d.ts +9 -0
- package/dist/lib/sync/daemon-process.js +184 -0
- package/dist/lib/sync/daemon-process.js.map +1 -0
- package/dist/lib/sync/daemon.d.ts +39 -0
- package/dist/lib/sync/daemon.js +91 -0
- package/dist/lib/sync/daemon.js.map +1 -0
- package/dist/lib/sync/engine.d.ts +38 -0
- package/dist/lib/sync/engine.js +145 -0
- package/dist/lib/sync/engine.js.map +1 -0
- package/dist/lib/sync/merge-queue.d.ts +116 -0
- package/dist/lib/sync/merge-queue.js +321 -0
- package/dist/lib/sync/merge-queue.js.map +1 -0
- package/dist/lib/sync/reconciler.d.ts +44 -0
- package/dist/lib/sync/reconciler.js +88 -0
- package/dist/lib/sync/reconciler.js.map +1 -0
- package/dist/lib/utils/text.d.ts +44 -0
- package/dist/lib/utils/text.js +72 -0
- package/dist/lib/utils/text.js.map +1 -0
- package/dist/lib/work-lifecycle/post-execution.js +1 -1
- package/dist/lib/work-lifecycle/post-execution.js.map +1 -1
- package/dist/lib/work-lifecycle/settings.d.ts +138 -0
- package/dist/lib/work-lifecycle/settings.js +213 -0
- package/dist/lib/work-lifecycle/settings.js.map +1 -0
- package/oclif.manifest.json +1456 -1707
- package/package.json +1 -1
- package/dist/commands/action/create.d.ts +0 -26
- package/dist/commands/action/create.js +0 -245
- package/dist/commands/action/create.js.map +0 -1
- package/dist/commands/action/delete.d.ts +0 -18
- package/dist/commands/action/delete.js +0 -78
- package/dist/commands/action/delete.js.map +0 -1
- package/dist/commands/action/index.js +0 -103
- package/dist/commands/action/index.js.map +0 -1
- package/dist/commands/action/list.d.ts +0 -15
- package/dist/commands/action/list.js +0 -90
- package/dist/commands/action/list.js.map +0 -1
- package/dist/commands/action/run.d.ts +0 -20
- package/dist/commands/action/run.js +0 -188
- package/dist/commands/action/run.js.map +0 -1
- package/dist/commands/action/show.d.ts +0 -17
- package/dist/commands/action/show.js +0 -78
- package/dist/commands/action/show.js.map +0 -1
- package/dist/commands/action/update.d.ts +0 -27
- package/dist/commands/action/update.js +0 -288
- package/dist/commands/action/update.js.map +0 -1
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge Queue
|
|
3
|
+
*
|
|
4
|
+
* Sequential rebase-test-merge pipeline for parallel agent PRs.
|
|
5
|
+
*
|
|
6
|
+
* With strict branch protection (PR must be up-to-date with main), parallel
|
|
7
|
+
* agent PRs create a rebase treadmill. The merge queue processes green PRs
|
|
8
|
+
* one at a time: rebase on main → wait for CI → merge if green → eject if red.
|
|
9
|
+
*
|
|
10
|
+
* State machine per cycle:
|
|
11
|
+
* 1. If paused → skip
|
|
12
|
+
* 2. If a PR is currently being processed (rebased, waiting for CI):
|
|
13
|
+
* - CI green → merge, rebase siblings
|
|
14
|
+
* - CI failed → eject (label + comment)
|
|
15
|
+
* - CI pending → wait
|
|
16
|
+
* 3. If no current PR:
|
|
17
|
+
* - Build queue: open, non-draft PRs with green CI, ordered by priority then age
|
|
18
|
+
* - Pick first → rebase → set as current
|
|
19
|
+
* - If rebase fails (conflicts) → eject, try next
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
import { listOpenPRs, getPRChecks, getPRByNumber, mergePR, } from '../pr/index.js';
|
|
24
|
+
import { rebaseSiblingPRs } from '../shipping/rebase.js';
|
|
25
|
+
import { GitHubProvider } from '../shipping/github.js';
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Constants
|
|
28
|
+
// =============================================================================
|
|
29
|
+
const MERGE_QUEUE_STATE_FILE = 'merge-queue.json';
|
|
30
|
+
const MAX_EJECTED_HISTORY = 10;
|
|
31
|
+
const EJECTED_LABEL = 'merge-queue-ejected';
|
|
32
|
+
const EJECTED_COMMENT_PREFIX = 'Merge queue ejected this PR:';
|
|
33
|
+
const DEFAULT_PRIORITY = 3; // P3 — lowest
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// State Management
|
|
36
|
+
// =============================================================================
|
|
37
|
+
export function getMergeQueueStatePath(hqPath) {
|
|
38
|
+
return path.join(hqPath, '.proletariat', MERGE_QUEUE_STATE_FILE);
|
|
39
|
+
}
|
|
40
|
+
export function getDefaultState() {
|
|
41
|
+
return {
|
|
42
|
+
paused: false,
|
|
43
|
+
pausedAt: null,
|
|
44
|
+
currentPR: null,
|
|
45
|
+
lastMergedPR: null,
|
|
46
|
+
lastCycleAt: null,
|
|
47
|
+
ejectedPRs: [],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function getMergeQueueState(hqPath) {
|
|
51
|
+
const statePath = getMergeQueueStatePath(hqPath);
|
|
52
|
+
try {
|
|
53
|
+
const content = fs.readFileSync(statePath, 'utf-8');
|
|
54
|
+
return { ...getDefaultState(), ...JSON.parse(content) };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return getDefaultState();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function saveMergeQueueState(hqPath, state) {
|
|
61
|
+
const statePath = getMergeQueueStatePath(hqPath);
|
|
62
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
63
|
+
}
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Pause / Resume
|
|
66
|
+
// =============================================================================
|
|
67
|
+
export function isMergeQueuePaused(hqPath) {
|
|
68
|
+
return getMergeQueueState(hqPath).paused;
|
|
69
|
+
}
|
|
70
|
+
export function pauseMergeQueue(hqPath) {
|
|
71
|
+
const state = getMergeQueueState(hqPath);
|
|
72
|
+
state.paused = true;
|
|
73
|
+
state.pausedAt = new Date().toISOString();
|
|
74
|
+
saveMergeQueueState(hqPath, state);
|
|
75
|
+
return state;
|
|
76
|
+
}
|
|
77
|
+
export function resumeMergeQueue(hqPath) {
|
|
78
|
+
const state = getMergeQueueState(hqPath);
|
|
79
|
+
state.paused = false;
|
|
80
|
+
state.pausedAt = null;
|
|
81
|
+
saveMergeQueueState(hqPath, state);
|
|
82
|
+
return state;
|
|
83
|
+
}
|
|
84
|
+
// =============================================================================
|
|
85
|
+
// Queue Building
|
|
86
|
+
// =============================================================================
|
|
87
|
+
/**
|
|
88
|
+
* Build the merge queue: open, non-draft PRs with all CI checks green,
|
|
89
|
+
* ordered by priority (P0 first) then by creation date (oldest first).
|
|
90
|
+
*/
|
|
91
|
+
export function buildMergeQueue(options, deps = { listOpenPRs, getPRChecks }) {
|
|
92
|
+
const { cwd, branchPriorities } = options;
|
|
93
|
+
const openPRs = deps.listOpenPRs(cwd);
|
|
94
|
+
const entries = [];
|
|
95
|
+
for (const pr of openPRs) {
|
|
96
|
+
// Skip drafts
|
|
97
|
+
if (pr.isDraft)
|
|
98
|
+
continue;
|
|
99
|
+
// Check CI
|
|
100
|
+
const checks = deps.getPRChecks(pr.number, cwd);
|
|
101
|
+
if (checks.length === 0)
|
|
102
|
+
continue; // No checks = not ready
|
|
103
|
+
if (!allChecksGreen(checks))
|
|
104
|
+
continue;
|
|
105
|
+
// Resolve priority from branch
|
|
106
|
+
const priority = branchPriorities?.get(pr.headBranch) ?? DEFAULT_PRIORITY;
|
|
107
|
+
const ticketId = extractTicketIdFromBranch(pr.headBranch);
|
|
108
|
+
entries.push({ pr, ticketId, priority });
|
|
109
|
+
}
|
|
110
|
+
// Sort: lower priority number first (P0 < P1 < P2 < P3), then oldest first
|
|
111
|
+
entries.sort((a, b) => {
|
|
112
|
+
if (a.priority !== b.priority)
|
|
113
|
+
return a.priority - b.priority;
|
|
114
|
+
return new Date(a.pr.createdAt).getTime() - new Date(b.pr.createdAt).getTime();
|
|
115
|
+
});
|
|
116
|
+
return entries;
|
|
117
|
+
}
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// Main Cycle
|
|
120
|
+
// =============================================================================
|
|
121
|
+
const _defaultProvider = new GitHubProvider();
|
|
122
|
+
const defaultDeps = {
|
|
123
|
+
listOpenPRs,
|
|
124
|
+
getPRChecks,
|
|
125
|
+
getPRByNumber,
|
|
126
|
+
mergePR,
|
|
127
|
+
rebaseSiblingPRs,
|
|
128
|
+
updatePRBranch: (prNumber, cwd) => _defaultProvider.updatePRBranch(prNumber, cwd),
|
|
129
|
+
addLabel: (prNumber, label, cwd) => _defaultProvider.addLabel(prNumber, label, cwd),
|
|
130
|
+
addComment: (prNumber, body, cwd) => _defaultProvider.addComment(prNumber, body, cwd),
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Run a single merge queue cycle.
|
|
134
|
+
*
|
|
135
|
+
* Called by the daemon on each interval. Handles the state machine:
|
|
136
|
+
* - If paused, returns immediately
|
|
137
|
+
* - If a PR is in progress (rebased, waiting CI), checks status
|
|
138
|
+
* - If no PR in progress, picks next from queue and rebases
|
|
139
|
+
*/
|
|
140
|
+
export function runMergeQueueCycle(options, deps = defaultDeps) {
|
|
141
|
+
const { hqPath, cwd, log, mergeMethod = 'squash', deleteBranch = true, branchPriorities, } = options;
|
|
142
|
+
const state = getMergeQueueState(hqPath);
|
|
143
|
+
state.lastCycleAt = new Date().toISOString();
|
|
144
|
+
// Step 1: Check if paused
|
|
145
|
+
if (state.paused) {
|
|
146
|
+
saveMergeQueueState(hqPath, state);
|
|
147
|
+
log?.('Merge queue is paused');
|
|
148
|
+
return { action: 'paused', queueSize: 0 };
|
|
149
|
+
}
|
|
150
|
+
// Step 2: If a PR is currently being processed, check its status
|
|
151
|
+
if (state.currentPR) {
|
|
152
|
+
const result = processCurrentPR(state, { cwd, log, mergeMethod, deleteBranch }, deps);
|
|
153
|
+
saveMergeQueueState(hqPath, state);
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
// Step 3: No current PR — build queue and pick next
|
|
157
|
+
const queue = buildMergeQueue({ cwd, branchPriorities }, deps);
|
|
158
|
+
log?.(`Merge queue: ${queue.length} eligible PR(s)`);
|
|
159
|
+
if (queue.length === 0) {
|
|
160
|
+
saveMergeQueueState(hqPath, state);
|
|
161
|
+
return { action: 'none', queueSize: 0 };
|
|
162
|
+
}
|
|
163
|
+
// Try to rebase the top PR — if conflicts, eject and try next
|
|
164
|
+
for (const entry of queue) {
|
|
165
|
+
const rebaseResult = deps.updatePRBranch(entry.pr.number, cwd);
|
|
166
|
+
if (rebaseResult.success) {
|
|
167
|
+
state.currentPR = {
|
|
168
|
+
prNumber: entry.pr.number,
|
|
169
|
+
headBranch: entry.pr.headBranch,
|
|
170
|
+
baseBranch: entry.pr.baseBranch,
|
|
171
|
+
ticketId: entry.ticketId,
|
|
172
|
+
priority: entry.priority,
|
|
173
|
+
rebasedAt: new Date().toISOString(),
|
|
174
|
+
};
|
|
175
|
+
log?.(`Rebased PR #${entry.pr.number} (${entry.pr.headBranch}) — waiting for CI`);
|
|
176
|
+
saveMergeQueueState(hqPath, state);
|
|
177
|
+
return { action: 'rebase_started', prNumber: entry.pr.number, queueSize: queue.length };
|
|
178
|
+
}
|
|
179
|
+
// Rebase failed — eject this PR
|
|
180
|
+
const reason = rebaseResult.hasConflicts
|
|
181
|
+
? 'Merge conflicts during rebase'
|
|
182
|
+
: `Rebase failed: ${rebaseResult.error ?? 'unknown error'}`;
|
|
183
|
+
ejectPR(state, entry.pr.number, entry.pr.headBranch, reason, cwd, deps);
|
|
184
|
+
log?.(`Ejected PR #${entry.pr.number}: ${reason}`);
|
|
185
|
+
}
|
|
186
|
+
// All PRs in queue had conflicts
|
|
187
|
+
saveMergeQueueState(hqPath, state);
|
|
188
|
+
return { action: 'none', reason: 'All eligible PRs have conflicts', queueSize: queue.length };
|
|
189
|
+
}
|
|
190
|
+
// =============================================================================
|
|
191
|
+
// Process Current PR
|
|
192
|
+
// =============================================================================
|
|
193
|
+
function processCurrentPR(state, options, deps) {
|
|
194
|
+
const { cwd, log, mergeMethod, deleteBranch } = options;
|
|
195
|
+
const current = state.currentPR;
|
|
196
|
+
const queueSize = 0; // We don't rebuild the queue when checking current
|
|
197
|
+
// Verify PR is still open
|
|
198
|
+
const prInfo = deps.getPRByNumber(current.prNumber, cwd);
|
|
199
|
+
if (!prInfo || prInfo.state !== 'OPEN') {
|
|
200
|
+
const reason = prInfo?.state === 'MERGED'
|
|
201
|
+
? 'PR was merged externally'
|
|
202
|
+
: 'PR is no longer open';
|
|
203
|
+
log?.(`Current PR #${current.prNumber}: ${reason} — clearing`);
|
|
204
|
+
state.currentPR = null;
|
|
205
|
+
if (prInfo?.state === 'MERGED') {
|
|
206
|
+
state.lastMergedPR = {
|
|
207
|
+
prNumber: current.prNumber,
|
|
208
|
+
headBranch: current.headBranch,
|
|
209
|
+
mergedAt: new Date().toISOString(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return { action: 'none', prNumber: current.prNumber, reason, queueSize };
|
|
213
|
+
}
|
|
214
|
+
// Check CI status
|
|
215
|
+
const checks = deps.getPRChecks(current.prNumber, cwd);
|
|
216
|
+
// No checks yet — still waiting
|
|
217
|
+
if (checks.length === 0) {
|
|
218
|
+
log?.(`PR #${current.prNumber}: no CI checks yet — waiting`);
|
|
219
|
+
return { action: 'waiting_ci', prNumber: current.prNumber, queueSize };
|
|
220
|
+
}
|
|
221
|
+
const failed = checks.filter(c => c.conclusion === 'FAILURE');
|
|
222
|
+
const pending = checks.filter(c => !c.conclusion || c.status === 'IN_PROGRESS' || c.status === 'QUEUED');
|
|
223
|
+
// CI still pending
|
|
224
|
+
if (pending.length > 0) {
|
|
225
|
+
log?.(`PR #${current.prNumber}: CI pending (${pending.length} check(s)) — waiting`);
|
|
226
|
+
return { action: 'waiting_ci', prNumber: current.prNumber, queueSize };
|
|
227
|
+
}
|
|
228
|
+
// CI failed — eject
|
|
229
|
+
if (failed.length > 0) {
|
|
230
|
+
const failedNames = failed.map(c => c.name).join(', ');
|
|
231
|
+
const reason = `CI failed after rebase: ${failedNames}`;
|
|
232
|
+
ejectPR(state, current.prNumber, current.headBranch, reason, cwd, deps);
|
|
233
|
+
state.currentPR = null;
|
|
234
|
+
log?.(`Ejected PR #${current.prNumber}: ${reason}`);
|
|
235
|
+
return { action: 'ejected', prNumber: current.prNumber, reason, queueSize };
|
|
236
|
+
}
|
|
237
|
+
// All CI green — merge!
|
|
238
|
+
log?.(`PR #${current.prNumber}: CI green — merging (${mergeMethod})`);
|
|
239
|
+
const mergeResult = deps.mergePR(current.prNumber, {
|
|
240
|
+
method: mergeMethod,
|
|
241
|
+
deleteBranch,
|
|
242
|
+
cwd,
|
|
243
|
+
});
|
|
244
|
+
if (!mergeResult.success) {
|
|
245
|
+
// Check if it was merged by someone else
|
|
246
|
+
const recheck = deps.getPRByNumber(current.prNumber, cwd);
|
|
247
|
+
if (recheck?.state === 'MERGED') {
|
|
248
|
+
log?.(`PR #${current.prNumber}: was merged externally`);
|
|
249
|
+
state.currentPR = null;
|
|
250
|
+
state.lastMergedPR = {
|
|
251
|
+
prNumber: current.prNumber,
|
|
252
|
+
headBranch: current.headBranch,
|
|
253
|
+
mergedAt: new Date().toISOString(),
|
|
254
|
+
};
|
|
255
|
+
return { action: 'merged', prNumber: current.prNumber, reason: 'Merged externally', queueSize };
|
|
256
|
+
}
|
|
257
|
+
const reason = `Merge failed: ${mergeResult.error}`;
|
|
258
|
+
ejectPR(state, current.prNumber, current.headBranch, reason, cwd, deps);
|
|
259
|
+
state.currentPR = null;
|
|
260
|
+
log?.(`Ejected PR #${current.prNumber}: ${reason}`);
|
|
261
|
+
return { action: 'ejected', prNumber: current.prNumber, reason, queueSize };
|
|
262
|
+
}
|
|
263
|
+
// Merge succeeded!
|
|
264
|
+
log?.(`Merged PR #${current.prNumber} (${current.headBranch})`);
|
|
265
|
+
state.currentPR = null;
|
|
266
|
+
state.lastMergedPR = {
|
|
267
|
+
prNumber: current.prNumber,
|
|
268
|
+
headBranch: current.headBranch,
|
|
269
|
+
mergedAt: new Date().toISOString(),
|
|
270
|
+
};
|
|
271
|
+
// Rebase sibling PRs
|
|
272
|
+
log?.('Rebasing sibling PRs...');
|
|
273
|
+
const siblingResult = deps.rebaseSiblingPRs({
|
|
274
|
+
excludePRNumber: current.prNumber,
|
|
275
|
+
cwd,
|
|
276
|
+
onProgress: log,
|
|
277
|
+
labelConflicts: true,
|
|
278
|
+
commentOnConflicts: true,
|
|
279
|
+
});
|
|
280
|
+
log?.(`Siblings: ${siblingResult.succeeded.length} rebased, ${siblingResult.failed.length} failed, ${siblingResult.skipped.length} skipped`);
|
|
281
|
+
return { action: 'merged', prNumber: current.prNumber, queueSize };
|
|
282
|
+
}
|
|
283
|
+
// =============================================================================
|
|
284
|
+
// Eject PR
|
|
285
|
+
// =============================================================================
|
|
286
|
+
function ejectPR(state, prNumber, headBranch, reason, cwd, deps) {
|
|
287
|
+
// Record ejection
|
|
288
|
+
state.ejectedPRs.unshift({
|
|
289
|
+
prNumber,
|
|
290
|
+
headBranch,
|
|
291
|
+
reason,
|
|
292
|
+
ejectedAt: new Date().toISOString(),
|
|
293
|
+
});
|
|
294
|
+
// Keep only the last N ejected PRs
|
|
295
|
+
if (state.ejectedPRs.length > MAX_EJECTED_HISTORY) {
|
|
296
|
+
state.ejectedPRs = state.ejectedPRs.slice(0, MAX_EJECTED_HISTORY);
|
|
297
|
+
}
|
|
298
|
+
// Label and comment on the PR (best effort)
|
|
299
|
+
try {
|
|
300
|
+
deps.addLabel(prNumber, EJECTED_LABEL, cwd);
|
|
301
|
+
deps.addComment(prNumber, `${EJECTED_COMMENT_PREFIX} ${reason}`, cwd);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Best effort — don't fail the cycle
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// =============================================================================
|
|
308
|
+
// Helpers
|
|
309
|
+
// =============================================================================
|
|
310
|
+
function allChecksGreen(checks) {
|
|
311
|
+
return checks.every(c => c.conclusion === 'SUCCESS' || c.conclusion === 'NEUTRAL' || c.conclusion === 'SKIPPED');
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Extract a ticket ID from a branch name.
|
|
315
|
+
* Supports patterns like: PRLT-1173/feat/... or TKT-007/...
|
|
316
|
+
*/
|
|
317
|
+
function extractTicketIdFromBranch(branch) {
|
|
318
|
+
const match = branch.match(/^([A-Z]+-\d+)\//);
|
|
319
|
+
return match?.[1] ?? null;
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=merge-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-queue.js","sourceRoot":"","sources":["../../../src/lib/sync/merge-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board Sync Reconciler
|
|
3
|
+
*
|
|
4
|
+
* Core reconciliation logic that detects drift between GitHub PR state
|
|
5
|
+
* and ticket provider state, then produces corrective actions.
|
|
6
|
+
*
|
|
7
|
+
* Provider-agnostic: works with any ticket provider (Linear, PMO, etc.)
|
|
8
|
+
* and any git host that exposes PR info.
|
|
9
|
+
*
|
|
10
|
+
* Reconciliation rules:
|
|
11
|
+
* 1. Merged PR + ticket not Done → move to Done
|
|
12
|
+
* 2. Green CI + ticket In Progress → move to Review
|
|
13
|
+
* 3. Ticket In Progress + no active agent → flag as stale
|
|
14
|
+
* 4. Ticket In Review + PR closed (not merged) → move to Backlog
|
|
15
|
+
*/
|
|
16
|
+
import type { PRInfo, PRCheck } from '../pr/index.js';
|
|
17
|
+
import type { Ticket } from '../pmo/types.js';
|
|
18
|
+
export type ReconcileActionType = 'move_to_done' | 'move_to_review' | 'flag_stale' | 'move_to_backlog';
|
|
19
|
+
export interface ReconcileAction {
|
|
20
|
+
type: ReconcileActionType;
|
|
21
|
+
ticketId: string;
|
|
22
|
+
ticketTitle: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
/** Target status name to move to (for move actions) */
|
|
25
|
+
targetStatus?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ReconcileContext {
|
|
28
|
+
ticket: Ticket;
|
|
29
|
+
pr: PRInfo | null;
|
|
30
|
+
checks: PRCheck[];
|
|
31
|
+
hasActiveExecution: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface ReconcileResult {
|
|
34
|
+
actions: ReconcileAction[];
|
|
35
|
+
checked: number;
|
|
36
|
+
errors: Array<{
|
|
37
|
+
ticketId: string;
|
|
38
|
+
error: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Determine reconciliation actions for a single ticket.
|
|
43
|
+
*/
|
|
44
|
+
export declare function reconcileTicket(ctx: ReconcileContext): ReconcileAction | null;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board Sync Reconciler
|
|
3
|
+
*
|
|
4
|
+
* Core reconciliation logic that detects drift between GitHub PR state
|
|
5
|
+
* and ticket provider state, then produces corrective actions.
|
|
6
|
+
*
|
|
7
|
+
* Provider-agnostic: works with any ticket provider (Linear, PMO, etc.)
|
|
8
|
+
* and any git host that exposes PR info.
|
|
9
|
+
*
|
|
10
|
+
* Reconciliation rules:
|
|
11
|
+
* 1. Merged PR + ticket not Done → move to Done
|
|
12
|
+
* 2. Green CI + ticket In Progress → move to Review
|
|
13
|
+
* 3. Ticket In Progress + no active agent → flag as stale
|
|
14
|
+
* 4. Ticket In Review + PR closed (not merged) → move to Backlog
|
|
15
|
+
*/
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Reconciler
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Determine reconciliation actions for a single ticket.
|
|
21
|
+
*/
|
|
22
|
+
export function reconcileTicket(ctx) {
|
|
23
|
+
const { ticket, pr, checks, hasActiveExecution } = ctx;
|
|
24
|
+
const category = ticket.statusCategory;
|
|
25
|
+
// Rule 1: Merged PR + ticket not Done → move to Done
|
|
26
|
+
if (pr?.state === 'MERGED' && category !== 'completed' && category !== 'canceled') {
|
|
27
|
+
return {
|
|
28
|
+
type: 'move_to_done',
|
|
29
|
+
ticketId: ticket.id,
|
|
30
|
+
ticketTitle: ticket.title,
|
|
31
|
+
reason: `PR #${pr.number} is merged but ticket is still in ${ticket.statusName ?? category}`,
|
|
32
|
+
targetStatus: 'Done',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Rule 4: Ticket in review + PR closed (not merged) → move to Backlog
|
|
36
|
+
// Check this before rule 2 since a closed PR should take precedence
|
|
37
|
+
if (pr?.state === 'CLOSED' && category === 'started' && isReviewStatus(ticket)) {
|
|
38
|
+
return {
|
|
39
|
+
type: 'move_to_backlog',
|
|
40
|
+
ticketId: ticket.id,
|
|
41
|
+
ticketTitle: ticket.title,
|
|
42
|
+
reason: `PR #${pr.number} was closed without merging`,
|
|
43
|
+
targetStatus: 'Backlog',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Rule 2: Green CI + ticket In Progress → move to Review
|
|
47
|
+
if (pr?.state === 'OPEN' &&
|
|
48
|
+
!pr.isDraft &&
|
|
49
|
+
category === 'started' &&
|
|
50
|
+
!isReviewStatus(ticket) &&
|
|
51
|
+
checks.length > 0 &&
|
|
52
|
+
allChecksGreen(checks)) {
|
|
53
|
+
return {
|
|
54
|
+
type: 'move_to_review',
|
|
55
|
+
ticketId: ticket.id,
|
|
56
|
+
ticketTitle: ticket.title,
|
|
57
|
+
reason: `PR #${pr.number} has all CI checks passing`,
|
|
58
|
+
targetStatus: 'Review',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Rule 3: Ticket In Progress + no active agent + no open PR → flag as stale
|
|
62
|
+
if (category === 'started' &&
|
|
63
|
+
!isReviewStatus(ticket) &&
|
|
64
|
+
!hasActiveExecution &&
|
|
65
|
+
(!pr || pr.state === 'CLOSED')) {
|
|
66
|
+
return {
|
|
67
|
+
type: 'flag_stale',
|
|
68
|
+
ticketId: ticket.id,
|
|
69
|
+
ticketTitle: ticket.title,
|
|
70
|
+
reason: 'No active agent and no open PR',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if all CI checks have passed.
|
|
77
|
+
*/
|
|
78
|
+
function allChecksGreen(checks) {
|
|
79
|
+
return checks.every(c => c.conclusion === 'SUCCESS' || c.conclusion === 'NEUTRAL' || c.conclusion === 'SKIPPED');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if a ticket is in a review-like status.
|
|
83
|
+
*/
|
|
84
|
+
function isReviewStatus(ticket) {
|
|
85
|
+
const name = (ticket.statusName ?? '').toLowerCase();
|
|
86
|
+
return name.includes('review') || name.includes('in review');
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=reconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciler.js","sourceRoot":"","sources":["../../../src/lib/sync/reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAqCH,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAqB;IACnD,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,GAAG,GAAG,CAAA;IACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAA;IAEtC,qDAAqD;IACrD,IAAI,EAAE,EAAE,KAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAClF,OAAO;YACL,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,qCAAqC,MAAM,CAAC,UAAU,IAAI,QAAQ,EAAE;YAC5F,YAAY,EAAE,MAAM;SACrB,CAAA;IACH,CAAC;IAED,sEAAsE;IACtE,oEAAoE;IACpE,IAAI,EAAE,EAAE,KAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/E,OAAO;YACL,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,6BAA6B;YACrD,YAAY,EAAE,SAAS;SACxB,CAAA;IACH,CAAC;IAED,yDAAyD;IACzD,IACE,EAAE,EAAE,KAAK,KAAK,MAAM;QACpB,CAAC,EAAE,CAAC,OAAO;QACX,QAAQ,KAAK,SAAS;QACtB,CAAC,cAAc,CAAC,MAAM,CAAC;QACvB,MAAM,CAAC,MAAM,GAAG,CAAC;QACjB,cAAc,CAAC,MAAM,CAAC,EACtB,CAAC;QACD,OAAO;YACL,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,4BAA4B;YACpD,YAAY,EAAE,QAAQ;SACvB,CAAA;IACH,CAAC;IAED,4EAA4E;IAC5E,IACE,QAAQ,KAAK,SAAS;QACtB,CAAC,cAAc,CAAC,MAAM,CAAC;QACvB,CAAC,kBAAkB;QACnB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,KAAK,QAAQ,CAAC,EAC9B,CAAC;QACD,OAAO;YACL,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,gCAAgC;SACzC,CAAA;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,MAAiB;IACvC,OAAO,MAAM,CAAC,KAAK,CACjB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,CAC5F,CAAA;AACH,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,MAAc;IACpC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAC9D,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text and general-purpose utility functions.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert a string to a URL-safe slug
|
|
6
|
+
*/
|
|
7
|
+
export declare function slugify(text: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Format a date as ISO string (date only)
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatDate(date: Date): string;
|
|
12
|
+
/**
|
|
13
|
+
* Format a date as ISO timestamp
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatTimestamp(date: Date): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse an ISO date string
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseDate(str: string): Date;
|
|
20
|
+
/**
|
|
21
|
+
* Parsed entity ID components
|
|
22
|
+
*/
|
|
23
|
+
export interface ParsedEntityId {
|
|
24
|
+
entityType: string;
|
|
25
|
+
number: number;
|
|
26
|
+
raw: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse an entity ID into its components.
|
|
30
|
+
*
|
|
31
|
+
* Format: TKT-001 → { entityType: 'TKT', number: 1 }
|
|
32
|
+
*
|
|
33
|
+
* @param id - Entity ID to parse
|
|
34
|
+
* @returns Parsed components, or null if invalid format
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseEntityId(id: string): ParsedEntityId | null;
|
|
37
|
+
/**
|
|
38
|
+
* Deep clone an object
|
|
39
|
+
*/
|
|
40
|
+
export declare function deepClone<T>(obj: T): T;
|
|
41
|
+
/**
|
|
42
|
+
* Check if two arrays have the same elements (order-independent)
|
|
43
|
+
*/
|
|
44
|
+
export declare function arraysEqual<T>(a: T[], b: T[]): boolean;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text and general-purpose utility functions.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert a string to a URL-safe slug
|
|
6
|
+
*/
|
|
7
|
+
export function slugify(text) {
|
|
8
|
+
return text
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.trim()
|
|
11
|
+
.replace(/[^\w\s-]/g, '') // Remove non-word chars (except spaces and hyphens)
|
|
12
|
+
.replace(/[\s_]+/g, '-') // Replace spaces and underscores with hyphens
|
|
13
|
+
.replace(/-+/g, '-') // Replace multiple hyphens with single hyphen
|
|
14
|
+
.replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens
|
|
15
|
+
.substring(0, 100); // Limit length
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Format a date as ISO string (date only)
|
|
19
|
+
*/
|
|
20
|
+
export function formatDate(date) {
|
|
21
|
+
return date.toISOString().split('T')[0];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format a date as ISO timestamp
|
|
25
|
+
*/
|
|
26
|
+
export function formatTimestamp(date) {
|
|
27
|
+
return date.toISOString();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parse an ISO date string
|
|
31
|
+
*/
|
|
32
|
+
export function parseDate(str) {
|
|
33
|
+
return new Date(str);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse an entity ID into its components.
|
|
37
|
+
*
|
|
38
|
+
* Format: TKT-001 → { entityType: 'TKT', number: 1 }
|
|
39
|
+
*
|
|
40
|
+
* @param id - Entity ID to parse
|
|
41
|
+
* @returns Parsed components, or null if invalid format
|
|
42
|
+
*/
|
|
43
|
+
export function parseEntityId(id) {
|
|
44
|
+
if (!id)
|
|
45
|
+
return null;
|
|
46
|
+
const match = id.match(/^([A-Z]+)-(\d+)$/);
|
|
47
|
+
if (match) {
|
|
48
|
+
return {
|
|
49
|
+
entityType: match[1],
|
|
50
|
+
number: parseInt(match[2], 10),
|
|
51
|
+
raw: id,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Deep clone an object
|
|
58
|
+
*/
|
|
59
|
+
export function deepClone(obj) {
|
|
60
|
+
return JSON.parse(JSON.stringify(obj));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if two arrays have the same elements (order-independent)
|
|
64
|
+
*/
|
|
65
|
+
export function arraysEqual(a, b) {
|
|
66
|
+
if (a.length !== b.length)
|
|
67
|
+
return false;
|
|
68
|
+
const sortedA = [...a].sort();
|
|
69
|
+
const sortedB = [...b].sort();
|
|
70
|
+
return sortedA.every((val, idx) => val === sortedB[idx]);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/lib/utils/text.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,IAAI,EAAE;SACN,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,oDAAoD;SAC7E,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAG,8CAA8C;SACxE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAO,8CAA8C;SACxE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAG,kCAAkC;SAC5D,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAS,eAAe;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAA;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;AACtB,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAErB,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC3C,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;YACpB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAE,EAAE;SACR,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAI,GAAM;IACjC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAI,CAAM,EAAE,CAAM;IAC3C,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACvC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7B,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7B,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;AAC1D,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* (Linear, Jira, etc.) — not through the local PMO as a cache layer.
|
|
14
14
|
* The local PMO is just the default provider for users without integrations.
|
|
15
15
|
*/
|
|
16
|
-
import { getWorkColumnSetting, findColumnByName, getReviewGateSetting } from '
|
|
16
|
+
import { getWorkColumnSetting, findColumnByName, getReviewGateSetting } from './settings.js';
|
|
17
17
|
import { resolveTicketProvider } from '../providers/resolver.js';
|
|
18
18
|
import { tryValidateCommits } from '../execution/commit-validation.js';
|
|
19
19
|
import { moveWithProvider } from '../providers/state-resolution.js';
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"post-execution.js","sourceRoot":"","sources":["../../../src/lib/work-lifecycle/post-execution.ts"],"names":[],"mappings":"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"}
|