pm-github 2026.7.11 → 2026.7.13
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/CHANGELOG.md +21 -0
- package/README.md +54 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +821 -8
- package/dist/index.js.map +1 -1
- package/dist/projects.d.ts +142 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +445 -0
- package/dist/projects.js.map +1 -0
- package/manifest.json +2 -2
- package/package.json +1 -1
package/dist/projects.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
// pm-github — GitHub Projects v2 support (pure logic layer).
|
|
2
|
+
//
|
|
3
|
+
// GitHub Projects v2 is a GraphQL-only API, structurally different from the REST
|
|
4
|
+
// Issues API the rest of pm-github speaks. This module holds the *pure*,
|
|
5
|
+
// side-effect-free half of the integration — reference parsing, provenance-tag
|
|
6
|
+
// helpers, status mapping, and plan builders — so it can be unit-tested without
|
|
7
|
+
// any network I/O. The GraphQL client and command handlers live in index.ts
|
|
8
|
+
// where the shared request/backoff infrastructure already exists.
|
|
9
|
+
//
|
|
10
|
+
// Design invariant — NO DATA LOSS:
|
|
11
|
+
// * plans NEVER delete or archive project items, and NEVER delete pm items;
|
|
12
|
+
// * an unmapped status is SKIPPED (with a reason) rather than guessed, so we
|
|
13
|
+
// never overwrite a real state with a wrong one in either direction;
|
|
14
|
+
// * every action is idempotent via the `gh-project:owner/number#itemId` tag.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Reference parsing
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Accept the human shorthand `owner/number` (and the tolerant `owner#number`),
|
|
19
|
+
// or a full Projects v2 URL:
|
|
20
|
+
// https://github.com/orgs/<owner>/projects/<n>
|
|
21
|
+
// https://github.com/users/<owner>/projects/<n>
|
|
22
|
+
// Returns undefined for anything unparseable so callers can fail fast.
|
|
23
|
+
export function parseProjectRef(input) {
|
|
24
|
+
if (!input)
|
|
25
|
+
return undefined;
|
|
26
|
+
const raw = input.trim();
|
|
27
|
+
if (!raw)
|
|
28
|
+
return undefined;
|
|
29
|
+
const urlMatch = /^https?:\/\/github\.com\/(?:orgs|users)\/([^/\s]+)\/projects\/(\d+)/i.exec(raw);
|
|
30
|
+
if (urlMatch) {
|
|
31
|
+
return { owner: urlMatch[1], number: Number(urlMatch[2]) };
|
|
32
|
+
}
|
|
33
|
+
const shortMatch = /^([^/#\s]+)[/#](\d+)$/.exec(raw);
|
|
34
|
+
if (shortMatch) {
|
|
35
|
+
const number = Number(shortMatch[2]);
|
|
36
|
+
if (Number.isInteger(number) && number > 0) {
|
|
37
|
+
return { owner: shortMatch[1], number };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Provenance tags (idempotency keys)
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// A ProjectV2Item node id (e.g. `PVTI_lAHOABGZtc4BdHj8zGYf8pU`) is CASE
|
|
46
|
+
// SENSITIVE, but pm normalizes tag values to lowercase — storing the raw id in a
|
|
47
|
+
// tag corrupts it, breaking idempotency (a re-sync would duplicate the item) and
|
|
48
|
+
// pull (a linked item would look unlinked). To survive that round-trip losslessly
|
|
49
|
+
// we hex-encode the id inside the tag; hex is `[0-9a-f]` so lowercasing is a
|
|
50
|
+
// no-op. This is the difference between "no data loss" and silent double-adds.
|
|
51
|
+
export function encodeItemId(id) {
|
|
52
|
+
return Buffer.from(id, "utf8").toString("hex");
|
|
53
|
+
}
|
|
54
|
+
// Decode a hex-encoded project item id back to its original GraphQL id;
|
|
55
|
+
// returns undefined for malformed (empty, odd-length, non-hex) input.
|
|
56
|
+
export function decodeItemId(encoded) {
|
|
57
|
+
if (encoded.length === 0 || encoded.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(encoded)) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return Buffer.from(encoded, "hex").toString("utf8");
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// The project link rides on a machine-parseable tag, like the issue provenance
|
|
68
|
+
// tag (`gh:owner/repo#N`). The node id is hex-encoded (see above) so it survives
|
|
69
|
+
// pm's lowercasing; a re-import/re-sync then finds the existing pm item and the
|
|
70
|
+
// existing project item instead of duplicating either side.
|
|
71
|
+
export function projectItemTag(ref, itemId) {
|
|
72
|
+
return `gh-project:${ref.owner.toLowerCase()}/${ref.number}#${encodeItemId(itemId)}`;
|
|
73
|
+
}
|
|
74
|
+
// Parse a `gh-project:owner/number#hexItemId` provenance tag into its parts,
|
|
75
|
+
// rejecting non-string tags and malformed encodings. Returns undefined when the
|
|
76
|
+
// tag is not a project-item provenance tag.
|
|
77
|
+
export function parseProjectItemTag(tag) {
|
|
78
|
+
if (typeof tag !== "string")
|
|
79
|
+
return undefined;
|
|
80
|
+
const m = /^gh-project:([^/\s]+)\/(\d+)#([0-9a-f]+)$/i.exec(tag.trim());
|
|
81
|
+
if (!m)
|
|
82
|
+
return undefined;
|
|
83
|
+
const itemId = decodeItemId(m[3]);
|
|
84
|
+
if (!itemId)
|
|
85
|
+
return undefined;
|
|
86
|
+
return { owner: m[1].toLowerCase(), number: Number(m[2]), itemId };
|
|
87
|
+
}
|
|
88
|
+
// Reuse of the issue provenance format so a project item that wraps a real
|
|
89
|
+
// GitHub issue can also carry a `gh:owner/repo#N` tag (dual linkage).
|
|
90
|
+
export function issueProvenanceTag(repo, number) {
|
|
91
|
+
return `gh:${repo.toLowerCase()}#${number}`;
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Status mapping (pm status <-> Project "Status" single-select option)
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Canonical pm statuses we know how to place on a board, mapped to an ordered
|
|
97
|
+
// list of candidate Status-option names (matched case-insensitively against the
|
|
98
|
+
// project's ACTUAL options). First match wins; if none match we skip the write.
|
|
99
|
+
export const DEFAULT_STATUS_CANDIDATES = {
|
|
100
|
+
draft: ["Draft", "Backlog", "Todo", "To Do"],
|
|
101
|
+
open: ["Todo", "To Do", "Backlog", "New", "Open", "Triage", "Ready"],
|
|
102
|
+
in_progress: ["In Progress", "In-Progress", "Doing", "Started", "Active"],
|
|
103
|
+
blocked: ["Blocked", "On Hold", "Waiting"],
|
|
104
|
+
closed: ["Done", "Closed", "Complete", "Completed", "Shipped", "Resolved"],
|
|
105
|
+
canceled: ["Cancelled", "Canceled", "Won't Do", "Wont Do", "Not Planned", "Dropped"],
|
|
106
|
+
};
|
|
107
|
+
// Parse a `--status-map` option into a forward table (pm status → exact Status
|
|
108
|
+
// option name). Accepts `pm=OptionName` pairs, comma-separated or repeated.
|
|
109
|
+
// Entries without a `=` or an empty side are skipped. Returns undefined when no
|
|
110
|
+
// usable mapping was supplied so callers keep the default behavior.
|
|
111
|
+
export function parseStatusMap(raw) {
|
|
112
|
+
if (!raw || raw.length === 0)
|
|
113
|
+
return undefined;
|
|
114
|
+
const map = new Map();
|
|
115
|
+
for (const entry of raw) {
|
|
116
|
+
const eq = entry.indexOf("=");
|
|
117
|
+
if (eq <= 0)
|
|
118
|
+
continue;
|
|
119
|
+
const from = entry.slice(0, eq).trim().toLowerCase();
|
|
120
|
+
const to = entry.slice(eq + 1).trim();
|
|
121
|
+
if (!from || !to)
|
|
122
|
+
continue;
|
|
123
|
+
map.set(from, to);
|
|
124
|
+
}
|
|
125
|
+
return map.size > 0 ? map : undefined;
|
|
126
|
+
}
|
|
127
|
+
const normalizeName = (s) => s.trim().toLowerCase();
|
|
128
|
+
// Resolve the Status option a given pm status should be set to, against the
|
|
129
|
+
// project's real options. An explicit override (`--status-map`) wins; otherwise
|
|
130
|
+
// the default candidate list is tried in order. Returns undefined when nothing
|
|
131
|
+
// matches — the caller must SKIP rather than guess (no data loss).
|
|
132
|
+
export function resolveOptionForStatus(pmStatus, options, override) {
|
|
133
|
+
const status = (pmStatus || "open").toLowerCase();
|
|
134
|
+
const byName = new Map();
|
|
135
|
+
for (const o of options) {
|
|
136
|
+
if (o && typeof o.name === "string")
|
|
137
|
+
byName.set(normalizeName(o.name), o);
|
|
138
|
+
}
|
|
139
|
+
const overrideName = override?.get(status);
|
|
140
|
+
if (overrideName) {
|
|
141
|
+
const hit = byName.get(normalizeName(overrideName));
|
|
142
|
+
if (hit)
|
|
143
|
+
return hit;
|
|
144
|
+
// An explicit override that does not exist on the board is a hard miss:
|
|
145
|
+
// we do NOT silently fall through to a default guess.
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
const candidates = DEFAULT_STATUS_CANDIDATES[status] ?? DEFAULT_STATUS_CANDIDATES.open;
|
|
149
|
+
for (const cand of candidates) {
|
|
150
|
+
const hit = byName.get(normalizeName(cand));
|
|
151
|
+
if (hit)
|
|
152
|
+
return hit;
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
// Reverse map: a Project Status option name → a pm status. Used by pull. An
|
|
157
|
+
// explicit forward `--status-map` is inverted first (option name → pm status);
|
|
158
|
+
// otherwise a keyword heuristic is applied. Returns undefined for names we do
|
|
159
|
+
// not recognize so pull SKIPS them instead of forcing a wrong pm status.
|
|
160
|
+
export function mapOptionNameToPmStatus(optionName, override) {
|
|
161
|
+
if (!optionName)
|
|
162
|
+
return undefined;
|
|
163
|
+
const name = normalizeName(optionName);
|
|
164
|
+
if (override) {
|
|
165
|
+
for (const [pmStatus, optName] of override) {
|
|
166
|
+
if (normalizeName(optName) === name)
|
|
167
|
+
return pmStatus;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Order matters: check the more specific buckets (cancel/blocked/draft) before
|
|
171
|
+
// the generic done/open ones so "Won't do" is canceled and "Draft" is draft,
|
|
172
|
+
// not open. Keeping "draft" ahead of the open/todo bucket makes the push↔pull
|
|
173
|
+
// roundtrip symmetric (a pm "draft" pushes to a "Draft" option and pulls back
|
|
174
|
+
// to "draft", not "open").
|
|
175
|
+
if (/(cancel|won'?t|not\s*planned|drop|abandon)/.test(name))
|
|
176
|
+
return "canceled";
|
|
177
|
+
if (/(block|on\s*hold|waiting)/.test(name))
|
|
178
|
+
return "blocked";
|
|
179
|
+
if (/draft/.test(name))
|
|
180
|
+
return "draft";
|
|
181
|
+
if (/\bnot\s+started\b|\bunstarted\b/.test(name))
|
|
182
|
+
return "open";
|
|
183
|
+
if (/(progress|doing|started|active|review)/.test(name))
|
|
184
|
+
return "in_progress";
|
|
185
|
+
if (/(done|closed|complete|shipped|resolved|merged)/.test(name))
|
|
186
|
+
return "closed";
|
|
187
|
+
if (/(todo|to\s*do|backlog|new|open|triage|ready)/.test(name))
|
|
188
|
+
return "open";
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Indexing helpers
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Index pm items by the project-item id they are linked to (for THIS project).
|
|
195
|
+
export function indexPmByProjectItem(items, ref) {
|
|
196
|
+
const index = new Map();
|
|
197
|
+
const ownerLc = ref.owner.toLowerCase();
|
|
198
|
+
for (const item of items) {
|
|
199
|
+
if (!item?.id)
|
|
200
|
+
continue;
|
|
201
|
+
for (const tag of item.tags ?? []) {
|
|
202
|
+
const p = parseProjectItemTag(tag);
|
|
203
|
+
if (p && p.owner === ownerLc && p.number === ref.number) {
|
|
204
|
+
index.set(p.itemId, item);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return index;
|
|
209
|
+
}
|
|
210
|
+
// Index pm items by `owner/repo#number` issue provenance so a push can link an
|
|
211
|
+
// already-imported pm item to the existing issue's project item (rather than
|
|
212
|
+
// adding a duplicate draft).
|
|
213
|
+
export function indexPmByIssue(items) {
|
|
214
|
+
const index = new Map();
|
|
215
|
+
for (const item of items) {
|
|
216
|
+
if (!item?.id)
|
|
217
|
+
continue;
|
|
218
|
+
for (const tag of item.tags ?? []) {
|
|
219
|
+
const m = /^gh:([^#\s]+)#(\d+)$/.exec(tag.trim());
|
|
220
|
+
if (m)
|
|
221
|
+
index.set(`${m[1].toLowerCase()}#${Number(m[2])}`, item);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return index;
|
|
225
|
+
}
|
|
226
|
+
// Index project items by the issue they wrap (`owner/repo#number`) so a push
|
|
227
|
+
// can find the project item for a pm item that is issue-linked but not yet
|
|
228
|
+
// project-tagged.
|
|
229
|
+
export function indexProjectItemsByIssue(projectItems) {
|
|
230
|
+
const index = new Map();
|
|
231
|
+
for (const pi of projectItems) {
|
|
232
|
+
if (!pi?.id || !pi.content)
|
|
233
|
+
continue;
|
|
234
|
+
const c = pi.content;
|
|
235
|
+
if (c.repo && typeof c.number === "number") {
|
|
236
|
+
index.set(`${c.repo.toLowerCase()}#${c.number}`, pi);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return index;
|
|
240
|
+
}
|
|
241
|
+
// Build the pm → project plan. Pure and side-effect free so it is unit-testable
|
|
242
|
+
// and printable verbatim in --dry-run.
|
|
243
|
+
export function buildProjectPushPlan(pmItems, ref, projectItems, statusField, opts = {}) {
|
|
244
|
+
const addMissing = opts.addMissing !== false;
|
|
245
|
+
const options = statusField?.options ?? [];
|
|
246
|
+
const byProjectItem = indexProjectItemMap(projectItems);
|
|
247
|
+
const byIssue = indexProjectItemsByIssue(projectItems);
|
|
248
|
+
const entries = [];
|
|
249
|
+
const statusSkipped = [];
|
|
250
|
+
for (const item of pmItems) {
|
|
251
|
+
if (!item?.id)
|
|
252
|
+
continue;
|
|
253
|
+
const title = item.title ?? "(untitled)";
|
|
254
|
+
const status = item.status ?? "open";
|
|
255
|
+
// Find the existing project item this pm item maps to: first by project
|
|
256
|
+
// provenance tag, then by the issue it wraps (if issue-linked).
|
|
257
|
+
let linked;
|
|
258
|
+
let linkedByProjectTag = false;
|
|
259
|
+
for (const tag of item.tags ?? []) {
|
|
260
|
+
const p = parseProjectItemTag(tag);
|
|
261
|
+
if (p && p.owner === ref.owner.toLowerCase() && p.number === ref.number) {
|
|
262
|
+
linked = byProjectItem.get(p.itemId);
|
|
263
|
+
linkedByProjectTag = true;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
let issueKey;
|
|
268
|
+
if (!linked) {
|
|
269
|
+
for (const tag of item.tags ?? []) {
|
|
270
|
+
const m = /^gh:([^#\s]+)#(\d+)$/.exec(tag.trim());
|
|
271
|
+
if (m) {
|
|
272
|
+
issueKey = { repo: m[1].toLowerCase(), number: Number(m[2]) };
|
|
273
|
+
linked = byIssue.get(`${issueKey.repo}#${issueKey.number}`);
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Resolve the target Status option for this pm status.
|
|
279
|
+
const targetOption = statusField
|
|
280
|
+
? resolveOptionForStatus(status, options, opts.statusMap)
|
|
281
|
+
: undefined;
|
|
282
|
+
if (statusField && !targetOption) {
|
|
283
|
+
statusSkipped.push({ pmId: item.id, title, status });
|
|
284
|
+
}
|
|
285
|
+
if (linked) {
|
|
286
|
+
// Already on the board: only (maybe) reconcile its Status.
|
|
287
|
+
if (!targetOption) {
|
|
288
|
+
entries.push({
|
|
289
|
+
action: "noop",
|
|
290
|
+
pmId: item.id,
|
|
291
|
+
title,
|
|
292
|
+
itemId: linked.id,
|
|
293
|
+
currentOptionName: linked.statusName,
|
|
294
|
+
reason: statusField ? `pm status "${status}" has no matching board option` : "project has no Status field",
|
|
295
|
+
});
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (linked.statusOptionId === targetOption.id) {
|
|
299
|
+
entries.push({
|
|
300
|
+
action: "noop",
|
|
301
|
+
pmId: item.id,
|
|
302
|
+
title,
|
|
303
|
+
itemId: linked.id,
|
|
304
|
+
currentOptionName: linked.statusName,
|
|
305
|
+
targetOptionName: targetOption.name,
|
|
306
|
+
reason: "already in sync",
|
|
307
|
+
});
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
entries.push({
|
|
311
|
+
action: "set-status",
|
|
312
|
+
pmId: item.id,
|
|
313
|
+
title,
|
|
314
|
+
itemId: linked.id,
|
|
315
|
+
currentOptionName: linked.statusName,
|
|
316
|
+
targetOptionId: targetOption.id,
|
|
317
|
+
targetOptionName: targetOption.name,
|
|
318
|
+
});
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
// Not on the board yet.
|
|
322
|
+
if (!addMissing) {
|
|
323
|
+
entries.push({
|
|
324
|
+
action: "noop",
|
|
325
|
+
pmId: item.id,
|
|
326
|
+
title,
|
|
327
|
+
reason: "not on board (--no-add-missing)",
|
|
328
|
+
});
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (issueKey) {
|
|
332
|
+
// Attach the existing issue rather than creating a duplicate draft.
|
|
333
|
+
entries.push({
|
|
334
|
+
action: "add-issue",
|
|
335
|
+
pmId: item.id,
|
|
336
|
+
title,
|
|
337
|
+
issueRepo: issueKey.repo,
|
|
338
|
+
issueNumber: issueKey.number,
|
|
339
|
+
targetOptionId: targetOption?.id,
|
|
340
|
+
targetOptionName: targetOption?.name,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
entries.push({
|
|
345
|
+
action: "add-draft",
|
|
346
|
+
pmId: item.id,
|
|
347
|
+
title,
|
|
348
|
+
targetOptionId: targetOption?.id,
|
|
349
|
+
targetOptionName: targetOption?.name,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return { entries, statusSkipped };
|
|
354
|
+
}
|
|
355
|
+
// Index project items by their own id for O(1) lookup during sync planning.
|
|
356
|
+
function indexProjectItemMap(projectItems) {
|
|
357
|
+
const m = new Map();
|
|
358
|
+
for (const pi of projectItems)
|
|
359
|
+
m.set(pi.id, pi);
|
|
360
|
+
return m;
|
|
361
|
+
}
|
|
362
|
+
// Build the project → pm plan: for each project item linked to a pm item, if the
|
|
363
|
+
// board's Status maps to a pm status that differs from the pm item's current
|
|
364
|
+
// status, propose an update. Only status changes; never touches title/body/tags.
|
|
365
|
+
export function buildProjectPullPlan(pmItems, ref, projectItems, statusMap) {
|
|
366
|
+
const pmByItemId = indexPmByProjectItem(pmItems, ref);
|
|
367
|
+
const pmByIssue = indexPmByIssue(pmItems);
|
|
368
|
+
const entries = [];
|
|
369
|
+
const statusSkipped = [];
|
|
370
|
+
for (const pi of projectItems) {
|
|
371
|
+
let pm = pmByItemId.get(pi.id);
|
|
372
|
+
if (!pm && pi.content.repo && typeof pi.content.number === "number") {
|
|
373
|
+
pm = pmByIssue.get(`${pi.content.repo.toLowerCase()}#${pi.content.number}`);
|
|
374
|
+
}
|
|
375
|
+
if (!pm || !pm.id)
|
|
376
|
+
continue; // unlinked project items are handled by import
|
|
377
|
+
const toStatus = mapOptionNameToPmStatus(pi.statusName, statusMap);
|
|
378
|
+
if (!toStatus) {
|
|
379
|
+
if (pi.statusName)
|
|
380
|
+
statusSkipped.push({ itemId: pi.id, optionName: pi.statusName });
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const fromStatus = pm.status ?? "open";
|
|
384
|
+
if (fromStatus === toStatus)
|
|
385
|
+
continue;
|
|
386
|
+
entries.push({ itemId: pi.id, pmId: pm.id, title: pm.title ?? "(untitled)", fromStatus, toStatus });
|
|
387
|
+
}
|
|
388
|
+
return { entries, statusSkipped };
|
|
389
|
+
}
|
|
390
|
+
// Build the plan to import project items as pm items. Idempotent: a project item
|
|
391
|
+
// already linked (by project tag, or by the issue it wraps) UPDATEs the existing
|
|
392
|
+
// pm item; everything else CREATEs. Draft issues import as pm items too.
|
|
393
|
+
export function buildProjectImportPlan(projectItems, ref, pmItems, statusMap) {
|
|
394
|
+
const pmByItemId = indexPmByProjectItem(pmItems, ref);
|
|
395
|
+
const pmByIssue = indexPmByIssue(pmItems);
|
|
396
|
+
const plan = [];
|
|
397
|
+
for (const pi of projectItems) {
|
|
398
|
+
const c = pi.content;
|
|
399
|
+
if (c.typename === "Unknown")
|
|
400
|
+
continue; // redacted / inaccessible content
|
|
401
|
+
const title = (c.title || "").trim() || `(project item ${pi.id})`;
|
|
402
|
+
// Prefer the board's Status; fall back to the wrapped issue's own state.
|
|
403
|
+
// `mappedStatus` records only an EXPLICIT mapping (undefined when the board
|
|
404
|
+
// status is unknown) so the re-import update path can skip the status write
|
|
405
|
+
// instead of clobbering an existing pm state (no data loss).
|
|
406
|
+
const mappedStatus = mapOptionNameToPmStatus(pi.statusName, statusMap);
|
|
407
|
+
let status = mappedStatus;
|
|
408
|
+
if (!status) {
|
|
409
|
+
if (c.state === "closed" || c.state === "merged") {
|
|
410
|
+
status = c.stateReason === "not_planned" ? "canceled" : "closed";
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
status = "open";
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
let existing = pmByItemId.get(pi.id);
|
|
417
|
+
if (!existing && c.repo && typeof c.number === "number") {
|
|
418
|
+
existing = pmByIssue.get(`${c.repo.toLowerCase()}#${c.number}`);
|
|
419
|
+
}
|
|
420
|
+
// Provenance tags this import adds, MERGED with any tags the existing pm item
|
|
421
|
+
// already carries (labels from a prior `pm github import`, user-added tags).
|
|
422
|
+
// `pm update --tags` REPLACES the tag set, so passing only the provenance
|
|
423
|
+
// tags would silently wipe everything else — a data-loss bug. Union, dedup,
|
|
424
|
+
// existing-first (preserves order); the Set collapses re-adds of a tag we
|
|
425
|
+
// already own.
|
|
426
|
+
const provenance = [projectItemTag(ref, pi.id)];
|
|
427
|
+
if (c.repo && typeof c.number === "number") {
|
|
428
|
+
provenance.push(issueProvenanceTag(c.repo, c.number));
|
|
429
|
+
}
|
|
430
|
+
const tags = [...new Set([...(existing?.tags ?? []), ...provenance])];
|
|
431
|
+
plan.push({
|
|
432
|
+
action: existing?.id ? "update" : "create",
|
|
433
|
+
itemId: pi.id,
|
|
434
|
+
title,
|
|
435
|
+
status,
|
|
436
|
+
mappedStatus,
|
|
437
|
+
body: c.body,
|
|
438
|
+
tags,
|
|
439
|
+
pmId: existing?.id,
|
|
440
|
+
content: c,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return plan;
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../projects.ts"],"names":[],"mappings":"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"}
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-github",
|
|
3
|
-
"version": "2026.7.
|
|
4
|
-
"description": "GitHub Issues
|
|
3
|
+
"version": "2026.7.13",
|
|
4
|
+
"description": "GitHub Issues + Projects v2 integration. Imports issues as pm items (`pm github import`), exports pm items as GitHub issues, syncs issue state, and bidirectionally syncs pm items with a GitHub Projects v2 board (`pm github project import/sync/list/fields`) — mapping pm status to the board Status column with idempotent, no-data-loss provenance.",
|
|
5
5
|
"author": "@unbraind",
|
|
6
6
|
"entry": "./dist/index.js",
|
|
7
7
|
"priority": 50,
|