hyper-pm 0.1.5 → 0.1.6
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/README.md +8 -0
- package/dist/index.cjs +1261 -1118
- package/dist/main.cjs +1261 -1118
- package/package.json +3 -3
package/dist/main.cjs
CHANGED
|
@@ -12772,6 +12772,7 @@ var sortTicketRecordsForList = (tickets, field, dir) => [...tickets].sort((x, y)
|
|
|
12772
12772
|
// src/cli/list-projection-summaries.ts
|
|
12773
12773
|
var listActiveEpicSummaries = (projection) => [...projection.epics.values()].filter((e) => !e.deleted).map((e) => ({
|
|
12774
12774
|
id: e.id,
|
|
12775
|
+
number: e.number,
|
|
12775
12776
|
title: e.title,
|
|
12776
12777
|
status: e.status,
|
|
12777
12778
|
createdAt: e.createdAt,
|
|
@@ -12783,6 +12784,7 @@ var listActiveStorySummaries = (projection, options) => [...projection.stories.v
|
|
|
12783
12784
|
(s) => !s.deleted && (options?.epicId === void 0 || s.epicId === options.epicId)
|
|
12784
12785
|
).map((s) => ({
|
|
12785
12786
|
id: s.id,
|
|
12787
|
+
number: s.number,
|
|
12786
12788
|
title: s.title,
|
|
12787
12789
|
epicId: s.epicId,
|
|
12788
12790
|
status: s.status,
|
|
@@ -12815,6 +12817,7 @@ var listActiveTicketSummaries = (projection, options) => {
|
|
|
12815
12817
|
const last = recent !== void 0 && recent.length > 0 ? recent[recent.length - 1] : void 0;
|
|
12816
12818
|
return {
|
|
12817
12819
|
id: t.id,
|
|
12820
|
+
number: t.number,
|
|
12818
12821
|
title: t.title,
|
|
12819
12822
|
status: t.status,
|
|
12820
12823
|
storyId: t.storyId,
|
|
@@ -13183,1137 +13186,1222 @@ var partitionGithubIssuesForImport = (params) => {
|
|
|
13183
13186
|
}
|
|
13184
13187
|
return { candidates, skipped };
|
|
13185
13188
|
};
|
|
13186
|
-
var mergeTicketImportCreatePayload = (ticketId, base, storyId) => {
|
|
13189
|
+
var mergeTicketImportCreatePayload = (ticketId, base, storyId, number) => {
|
|
13187
13190
|
const storyTrimmed = storyId !== void 0 && storyId !== "" ? storyId.trim() : void 0;
|
|
13188
13191
|
const storyPayload = storyTrimmed !== void 0 && storyTrimmed !== "" ? { storyId: storyTrimmed } : {};
|
|
13189
|
-
return { id: ticketId, ...base, ...storyPayload };
|
|
13192
|
+
return { id: ticketId, number, ...base, ...storyPayload };
|
|
13190
13193
|
};
|
|
13191
13194
|
|
|
13192
|
-
// src/
|
|
13193
|
-
var
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
var
|
|
13204
|
-
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
const
|
|
13212
|
-
const
|
|
13213
|
-
const
|
|
13214
|
-
const
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
const
|
|
13219
|
-
|
|
13220
|
-
|
|
13195
|
+
// src/lib/github-pr-activity.ts
|
|
13196
|
+
var GITHUB_PR_ACTIVITY_RECENT_CAP = 20;
|
|
13197
|
+
var githubPrActivityKindSchema = external_exports.enum([
|
|
13198
|
+
"opened",
|
|
13199
|
+
"updated",
|
|
13200
|
+
"commented",
|
|
13201
|
+
"reviewed",
|
|
13202
|
+
"merged",
|
|
13203
|
+
"closed",
|
|
13204
|
+
"ready_for_review"
|
|
13205
|
+
]);
|
|
13206
|
+
var githubPrReviewStateSchema = external_exports.enum([
|
|
13207
|
+
"approved",
|
|
13208
|
+
"changes_requested",
|
|
13209
|
+
"commented"
|
|
13210
|
+
]);
|
|
13211
|
+
var buildPrOpenSourceId = (ticketId, prNumber) => `hyper-pm:pr-open:${ticketId}:${prNumber}`;
|
|
13212
|
+
var parseGithubPrActivityPayload = (payload) => {
|
|
13213
|
+
const ticketId = payload["ticketId"];
|
|
13214
|
+
const prRaw = payload["prNumber"];
|
|
13215
|
+
const kindRaw = payload["kind"];
|
|
13216
|
+
const occurredAt = payload["occurredAt"];
|
|
13217
|
+
const sourceId = payload["sourceId"];
|
|
13218
|
+
if (typeof ticketId !== "string" || typeof occurredAt !== "string" || typeof sourceId !== "string") {
|
|
13219
|
+
return void 0;
|
|
13220
|
+
}
|
|
13221
|
+
const prNumber = typeof prRaw === "number" ? prRaw : Number(prRaw);
|
|
13222
|
+
if (!Number.isFinite(prNumber)) return void 0;
|
|
13223
|
+
const kindParsed = githubPrActivityKindSchema.safeParse(kindRaw);
|
|
13224
|
+
if (!kindParsed.success) return void 0;
|
|
13225
|
+
const out = {
|
|
13226
|
+
prNumber,
|
|
13227
|
+
kind: kindParsed.data,
|
|
13228
|
+
occurredAt,
|
|
13229
|
+
sourceId
|
|
13230
|
+
};
|
|
13231
|
+
const url = payload["url"];
|
|
13232
|
+
if (typeof url === "string" && url.length > 0) {
|
|
13233
|
+
out.url = url;
|
|
13234
|
+
}
|
|
13235
|
+
const rs = githubPrReviewStateSchema.safeParse(payload["reviewState"]);
|
|
13236
|
+
if (rs.success) {
|
|
13237
|
+
out.reviewState = rs.data;
|
|
13221
13238
|
}
|
|
13222
13239
|
return out;
|
|
13223
13240
|
};
|
|
13224
13241
|
|
|
13225
|
-
// src/
|
|
13226
|
-
var
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13242
|
+
// src/storage/projection.ts
|
|
13243
|
+
var readOptionalPositiveIntegerFromPayload = (payload, key) => {
|
|
13244
|
+
if (!Object.prototype.hasOwnProperty.call(payload, key)) return void 0;
|
|
13245
|
+
const raw = payload[key];
|
|
13246
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return void 0;
|
|
13247
|
+
if (!Number.isInteger(raw)) return void 0;
|
|
13248
|
+
if (raw < 1 || raw > Number.MAX_SAFE_INTEGER) return void 0;
|
|
13249
|
+
return raw;
|
|
13250
|
+
};
|
|
13251
|
+
var maxNumberAmongRows = (rows) => {
|
|
13252
|
+
let m = 0;
|
|
13253
|
+
for (const r of rows) {
|
|
13254
|
+
if (r.number > m) m = r.number;
|
|
13255
|
+
}
|
|
13256
|
+
return m;
|
|
13257
|
+
};
|
|
13258
|
+
var maxEpicNumberInProjection = (projection) => maxNumberAmongRows(projection.epics.values());
|
|
13259
|
+
var maxStoryNumberInProjection = (projection) => maxNumberAmongRows(projection.stories.values());
|
|
13260
|
+
var maxTicketNumberInProjection = (projection) => maxNumberAmongRows(projection.tickets.values());
|
|
13261
|
+
var nextEpicNumberForCreate = (projection) => maxEpicNumberInProjection(projection) + 1;
|
|
13262
|
+
var nextStoryNumberForCreate = (projection) => maxStoryNumberInProjection(projection) + 1;
|
|
13263
|
+
var nextTicketNumberForCreate = (projection) => maxTicketNumberInProjection(projection) + 1;
|
|
13264
|
+
var resolveWorkItemCreateNumber = (projection, kind, payload) => {
|
|
13265
|
+
const explicit = readOptionalPositiveIntegerFromPayload(payload, "number");
|
|
13266
|
+
if (explicit !== void 0) {
|
|
13267
|
+
return explicit;
|
|
13268
|
+
}
|
|
13269
|
+
return (kind === "epic" ? maxEpicNumberInProjection(projection) : kind === "story" ? maxStoryNumberInProjection(projection) : maxTicketNumberInProjection(projection)) + 1;
|
|
13233
13270
|
};
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
kind: "invalid-json",
|
|
13247
|
-
line: i + 1,
|
|
13248
|
-
message: e instanceof Error ? e.message : "parse error"
|
|
13249
|
-
});
|
|
13250
|
-
return issues;
|
|
13251
|
-
}
|
|
13252
|
-
const parsed = eventLineSchema.safeParse(json);
|
|
13253
|
-
if (!parsed.success) {
|
|
13254
|
-
issues.push({
|
|
13255
|
-
kind: "invalid-event",
|
|
13256
|
-
line: i + 1,
|
|
13257
|
-
message: parsed.error.message
|
|
13258
|
-
});
|
|
13259
|
-
return issues;
|
|
13260
|
-
}
|
|
13271
|
+
var emptyProjection = () => ({
|
|
13272
|
+
epics: /* @__PURE__ */ new Map(),
|
|
13273
|
+
stories: /* @__PURE__ */ new Map(),
|
|
13274
|
+
tickets: /* @__PURE__ */ new Map()
|
|
13275
|
+
});
|
|
13276
|
+
var parsePrRefs = (body) => {
|
|
13277
|
+
const out = /* @__PURE__ */ new Set();
|
|
13278
|
+
const re = /\b(?:Closes|Refs|Fixes)\s+#(\d+)\b/gi;
|
|
13279
|
+
let m = re.exec(body);
|
|
13280
|
+
while (m !== null) {
|
|
13281
|
+
out.add(Number(m[1]));
|
|
13282
|
+
m = re.exec(body);
|
|
13261
13283
|
}
|
|
13262
|
-
return
|
|
13263
|
-
};
|
|
13264
|
-
|
|
13265
|
-
// src/git/create-and-checkout-branch.ts
|
|
13266
|
-
var createAndCheckoutBranch = async (opts) => {
|
|
13267
|
-
await opts.runGit(opts.repoRoot, [
|
|
13268
|
-
"switch",
|
|
13269
|
-
"-c",
|
|
13270
|
-
opts.branchName,
|
|
13271
|
-
opts.startPoint
|
|
13272
|
-
]);
|
|
13273
|
-
};
|
|
13274
|
-
|
|
13275
|
-
// src/git/data-worktree-session.ts
|
|
13276
|
-
var import_promises3 = require("node:fs/promises");
|
|
13277
|
-
var import_node_path3 = require("node:path");
|
|
13278
|
-
var ensureDir = async (path) => {
|
|
13279
|
-
await (0, import_promises3.mkdir)(path, { recursive: true });
|
|
13284
|
+
return [...out];
|
|
13280
13285
|
};
|
|
13281
|
-
var
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
return
|
|
13286
|
+
var applyTicketAssigneeFromPayload = (row, payload) => {
|
|
13287
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "assignee")) return;
|
|
13288
|
+
const v = payload["assignee"];
|
|
13289
|
+
if (v === null) {
|
|
13290
|
+
delete row.assignee;
|
|
13291
|
+
return;
|
|
13287
13292
|
}
|
|
13293
|
+
if (typeof v !== "string") return;
|
|
13294
|
+
const n = normalizeGithubLogin(v);
|
|
13295
|
+
if (n === "") delete row.assignee;
|
|
13296
|
+
else row.assignee = n;
|
|
13288
13297
|
};
|
|
13289
|
-
var
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
for (const block of blocks) {
|
|
13293
|
-
const lines = block.split("\n");
|
|
13294
|
-
let worktreePath;
|
|
13295
|
-
let branch;
|
|
13296
|
-
for (const line of lines) {
|
|
13297
|
-
if (line.startsWith("worktree ")) {
|
|
13298
|
-
worktreePath = line.slice("worktree ".length);
|
|
13299
|
-
} else if (line.startsWith("branch ")) {
|
|
13300
|
-
branch = line.slice("branch ".length);
|
|
13301
|
-
}
|
|
13302
|
-
}
|
|
13303
|
-
if (worktreePath !== void 0 && branch === wantRef) {
|
|
13304
|
-
return worktreePath;
|
|
13305
|
-
}
|
|
13298
|
+
var storyIdFromTicketCreatedPayload = (payload) => {
|
|
13299
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "storyId")) {
|
|
13300
|
+
return null;
|
|
13306
13301
|
}
|
|
13307
|
-
|
|
13302
|
+
const v = payload["storyId"];
|
|
13303
|
+
if (v === null) return null;
|
|
13304
|
+
if (typeof v !== "string") return null;
|
|
13305
|
+
const t = v.trim();
|
|
13306
|
+
return t === "" ? null : t;
|
|
13308
13307
|
};
|
|
13309
|
-
var
|
|
13310
|
-
|
|
13311
|
-
const
|
|
13312
|
-
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
]);
|
|
13316
|
-
const listedPath = parseDataBranchWorktreeFromPorcelain(
|
|
13317
|
-
listOut,
|
|
13318
|
-
opts.dataBranch
|
|
13319
|
-
);
|
|
13320
|
-
if (listedPath !== void 0 && await pathExists(listedPath)) {
|
|
13321
|
-
const dispose2 = async () => {
|
|
13322
|
-
return;
|
|
13323
|
-
};
|
|
13324
|
-
return { worktreePath: listedPath, dispose: dispose2 };
|
|
13308
|
+
var applyTicketStoryIdFromPayload = (row, payload) => {
|
|
13309
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "storyId")) return;
|
|
13310
|
+
const v = payload["storyId"];
|
|
13311
|
+
if (v === null) {
|
|
13312
|
+
row.storyId = null;
|
|
13313
|
+
return;
|
|
13325
13314
|
}
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
"worktree",
|
|
13334
|
-
"add",
|
|
13335
|
-
worktreePath,
|
|
13336
|
-
opts.dataBranch
|
|
13337
|
-
]);
|
|
13338
|
-
} catch (err) {
|
|
13339
|
-
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13340
|
-
});
|
|
13341
|
-
throw err;
|
|
13315
|
+
if (typeof v !== "string") return;
|
|
13316
|
+
const t = v.trim();
|
|
13317
|
+
row.storyId = t === "" ? null : t;
|
|
13318
|
+
};
|
|
13319
|
+
var linkedBranchesFromTicketCreatedPayload = (payload) => {
|
|
13320
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) {
|
|
13321
|
+
return [];
|
|
13342
13322
|
}
|
|
13343
|
-
|
|
13344
|
-
if (opts.keepWorktree) {
|
|
13345
|
-
return;
|
|
13346
|
-
}
|
|
13347
|
-
await opts.runGit(opts.repoRoot, ["worktree", "remove", "--force", worktreePath]).catch(() => {
|
|
13348
|
-
});
|
|
13349
|
-
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13350
|
-
});
|
|
13351
|
-
};
|
|
13352
|
-
return { worktreePath, dispose };
|
|
13323
|
+
return normalizeTicketBranchListFromPayloadValue(payload["branches"]);
|
|
13353
13324
|
};
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13357
|
-
|
|
13358
|
-
|
|
13325
|
+
var applyTicketBranchesFromUpdatePayload = (row, payload) => {
|
|
13326
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) return;
|
|
13327
|
+
const v = payload["branches"];
|
|
13328
|
+
if (!Array.isArray(v)) return;
|
|
13329
|
+
row.linkedBranches = normalizeTicketBranchListFromPayloadValue(v);
|
|
13359
13330
|
};
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
const { stdout: tip } = await opts.runGit(opts.repoRoot, [
|
|
13366
|
-
"rev-parse",
|
|
13367
|
-
"HEAD"
|
|
13368
|
-
]);
|
|
13369
|
-
const tipCommit = tip.trim();
|
|
13370
|
-
await opts.runGit(opts.repoRoot, [
|
|
13371
|
-
"worktree",
|
|
13372
|
-
"add",
|
|
13373
|
-
opts.worktreePath,
|
|
13374
|
-
tipCommit
|
|
13375
|
-
]);
|
|
13376
|
-
await opts.runGit(opts.worktreePath, [
|
|
13377
|
-
"checkout",
|
|
13378
|
-
"--orphan",
|
|
13379
|
-
opts.dataBranch
|
|
13380
|
-
]);
|
|
13381
|
-
await opts.runGit(opts.worktreePath, ["rm", "-rf", "."]).catch(() => {
|
|
13382
|
-
});
|
|
13383
|
-
const marker = (0, import_node_path4.join)(opts.worktreePath, "README.hyper-pm.md");
|
|
13384
|
-
await (0, import_promises4.writeFile)(
|
|
13385
|
-
marker,
|
|
13386
|
-
"# hyper-pm data branch\n\nAppend-only events live under `events/`.\n",
|
|
13387
|
-
"utf8"
|
|
13388
|
-
);
|
|
13389
|
-
await opts.runGit(opts.worktreePath, ["add", "."]);
|
|
13390
|
-
await opts.runGit(opts.worktreePath, [
|
|
13391
|
-
"commit",
|
|
13392
|
-
"-m",
|
|
13393
|
-
"init hyper-pm data branch"
|
|
13394
|
-
]);
|
|
13395
|
-
};
|
|
13396
|
-
|
|
13397
|
-
// src/git/pick-unique-local-branch-name.ts
|
|
13398
|
-
var DEFAULT_MAX_SUFFIX = 1e3;
|
|
13399
|
-
var localBranchRefExists = async (repoRoot, name, git) => {
|
|
13400
|
-
try {
|
|
13401
|
-
await git(repoRoot, ["show-ref", "--verify", `refs/heads/${name}`]);
|
|
13402
|
-
return true;
|
|
13403
|
-
} catch {
|
|
13404
|
-
return false;
|
|
13405
|
-
}
|
|
13406
|
-
};
|
|
13407
|
-
var pickUniqueLocalBranchName = async (opts) => {
|
|
13408
|
-
const max = opts.maxSuffix ?? DEFAULT_MAX_SUFFIX;
|
|
13409
|
-
const { preferredBase, repoRoot, runGit: git } = opts;
|
|
13410
|
-
for (let n = 1; n <= max; n += 1) {
|
|
13411
|
-
const raw = n === 1 ? preferredBase : `${preferredBase}-${n}`;
|
|
13412
|
-
const norm = normalizeTicketBranchName(raw);
|
|
13413
|
-
if (norm === void 0) {
|
|
13414
|
-
continue;
|
|
13415
|
-
}
|
|
13416
|
-
if (!await localBranchRefExists(repoRoot, norm, git)) {
|
|
13417
|
-
return { branch: norm, preferred: preferredBase };
|
|
13331
|
+
var applyTicketPlanningFieldsFromCreatePayload = (row, payload) => {
|
|
13332
|
+
if (Object.prototype.hasOwnProperty.call(payload, "labels")) {
|
|
13333
|
+
const v = ticketLabelsFromPayloadValue(payload["labels"]);
|
|
13334
|
+
if (v !== void 0 && v.length > 0) {
|
|
13335
|
+
row.labels = v;
|
|
13418
13336
|
}
|
|
13419
13337
|
}
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
};
|
|
13424
|
-
|
|
13425
|
-
// src/git/resolve-integration-start-point.ts
|
|
13426
|
-
var assertGitRefResolvable = async (repoRoot, ref, git) => {
|
|
13427
|
-
try {
|
|
13428
|
-
await git(repoRoot, ["rev-parse", "-q", "--verify", ref]);
|
|
13429
|
-
} catch {
|
|
13430
|
-
throw new Error(`Invalid or ambiguous --from ref: ${ref}`);
|
|
13338
|
+
const pr = readTicketPriorityPatch(payload);
|
|
13339
|
+
if (typeof pr === "string") {
|
|
13340
|
+
row.priority = pr;
|
|
13431
13341
|
}
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
try {
|
|
13436
|
-
const { stdout } = await git(repoRoot, ["symbolic-ref", "-q", symRef]);
|
|
13437
|
-
const target = stdout.trim();
|
|
13438
|
-
if (target !== "") {
|
|
13439
|
-
await git(repoRoot, ["rev-parse", "-q", "--verify", target]);
|
|
13440
|
-
return target;
|
|
13441
|
-
}
|
|
13442
|
-
} catch {
|
|
13342
|
+
const sz = readTicketSizePatch(payload);
|
|
13343
|
+
if (typeof sz === "string") {
|
|
13344
|
+
row.size = sz;
|
|
13443
13345
|
}
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
return head;
|
|
13448
|
-
} catch {
|
|
13449
|
-
}
|
|
13346
|
+
const est = readTicketEstimatePatch(payload);
|
|
13347
|
+
if (typeof est === "number") {
|
|
13348
|
+
row.estimate = est;
|
|
13450
13349
|
}
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
|
|
13454
|
-
} catch {
|
|
13350
|
+
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13351
|
+
if (typeof sw === "string") {
|
|
13352
|
+
row.startWorkAt = sw;
|
|
13455
13353
|
}
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
}
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
const { stdout } = await git(repoRoot, [
|
|
13465
|
-
"-c",
|
|
13466
|
-
"log.showSignature=false",
|
|
13467
|
-
"log",
|
|
13468
|
-
"--all",
|
|
13469
|
-
"--format=%an%x1f%ae"
|
|
13470
|
-
]);
|
|
13471
|
-
if (stdout === "") return [];
|
|
13472
|
-
const lines = stdout.split("\n").filter((l) => l.length > 0);
|
|
13473
|
-
const seenEmail = /* @__PURE__ */ new Set();
|
|
13474
|
-
const out = [];
|
|
13475
|
-
for (const line of lines) {
|
|
13476
|
-
const sep2 = line.indexOf("");
|
|
13477
|
-
if (sep2 <= 0) continue;
|
|
13478
|
-
const name = line.slice(0, sep2).trim();
|
|
13479
|
-
const email = line.slice(sep2 + 1).trim();
|
|
13480
|
-
if (email === "") continue;
|
|
13481
|
-
const key = email.toLowerCase();
|
|
13482
|
-
if (seenEmail.has(key)) continue;
|
|
13483
|
-
seenEmail.add(key);
|
|
13484
|
-
const loginGuess = guessGithubLoginFromContact(name, email);
|
|
13485
|
-
out.push(
|
|
13486
|
-
loginGuess !== void 0 ? { name, email, loginGuess } : { name, email }
|
|
13487
|
-
);
|
|
13354
|
+
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13355
|
+
if (typeof tf === "string") {
|
|
13356
|
+
row.targetFinishAt = tf;
|
|
13357
|
+
}
|
|
13358
|
+
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13359
|
+
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13360
|
+
if (v !== void 0 && v.length > 0) {
|
|
13361
|
+
row.dependsOn = v;
|
|
13488
13362
|
}
|
|
13489
|
-
return out;
|
|
13490
|
-
} catch {
|
|
13491
|
-
return [];
|
|
13492
13363
|
}
|
|
13493
13364
|
};
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
const u = new URL(withScheme);
|
|
13508
|
-
const host = u.hostname.toLowerCase();
|
|
13509
|
-
if (host !== "github.com" && host !== "www.github.com") {
|
|
13510
|
-
return void 0;
|
|
13365
|
+
var applyTicketPlanningFieldsFromUpdatePayload = (row, payload) => {
|
|
13366
|
+
if (Object.prototype.hasOwnProperty.call(payload, "labels")) {
|
|
13367
|
+
if (payload["labels"] === null) {
|
|
13368
|
+
delete row.labels;
|
|
13369
|
+
} else {
|
|
13370
|
+
const v = ticketLabelsFromPayloadValue(payload["labels"]);
|
|
13371
|
+
if (v !== void 0) {
|
|
13372
|
+
if (v.length === 0) {
|
|
13373
|
+
delete row.labels;
|
|
13374
|
+
} else {
|
|
13375
|
+
row.labels = v;
|
|
13376
|
+
}
|
|
13377
|
+
}
|
|
13511
13378
|
}
|
|
13512
|
-
return slugFromGithubPath(u.pathname);
|
|
13513
|
-
} catch {
|
|
13514
|
-
return void 0;
|
|
13515
13379
|
}
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
if (
|
|
13520
|
-
|
|
13380
|
+
const pr = readTicketPriorityPatch(payload);
|
|
13381
|
+
if (pr === null) {
|
|
13382
|
+
delete row.priority;
|
|
13383
|
+
} else if (typeof pr === "string") {
|
|
13384
|
+
row.priority = pr;
|
|
13521
13385
|
}
|
|
13522
|
-
const
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13386
|
+
const sz = readTicketSizePatch(payload);
|
|
13387
|
+
if (sz === null) {
|
|
13388
|
+
delete row.size;
|
|
13389
|
+
} else if (typeof sz === "string") {
|
|
13390
|
+
row.size = sz;
|
|
13526
13391
|
}
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
try {
|
|
13533
|
-
const { stdout } = await params.runGit(params.repoRoot, [
|
|
13534
|
-
"remote",
|
|
13535
|
-
"get-url",
|
|
13536
|
-
params.remote
|
|
13537
|
-
]);
|
|
13538
|
-
return parseGithubOwnerRepoFromRemoteUrl(stdout);
|
|
13539
|
-
} catch {
|
|
13540
|
-
return void 0;
|
|
13392
|
+
const est = readTicketEstimatePatch(payload);
|
|
13393
|
+
if (est === null) {
|
|
13394
|
+
delete row.estimate;
|
|
13395
|
+
} else if (typeof est === "number") {
|
|
13396
|
+
row.estimate = est;
|
|
13541
13397
|
}
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
var tryReadGitConfigUserName = async (cwd, runGit2) => {
|
|
13548
|
-
try {
|
|
13549
|
-
const { stdout } = await runGit2(cwd, ["config", "--get", "user.name"]);
|
|
13550
|
-
return stdout.trim();
|
|
13551
|
-
} catch {
|
|
13552
|
-
return "";
|
|
13398
|
+
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13399
|
+
if (sw === null) {
|
|
13400
|
+
delete row.startWorkAt;
|
|
13401
|
+
} else if (typeof sw === "string") {
|
|
13402
|
+
row.startWorkAt = sw;
|
|
13553
13403
|
}
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
}
|
|
13560
|
-
|
|
13404
|
+
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13405
|
+
if (tf === null) {
|
|
13406
|
+
delete row.targetFinishAt;
|
|
13407
|
+
} else if (typeof tf === "string") {
|
|
13408
|
+
row.targetFinishAt = tf;
|
|
13409
|
+
}
|
|
13410
|
+
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13411
|
+
if (payload["dependsOn"] === null) {
|
|
13412
|
+
delete row.dependsOn;
|
|
13413
|
+
} else {
|
|
13414
|
+
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13415
|
+
if (v !== void 0) {
|
|
13416
|
+
if (v.length === 0) {
|
|
13417
|
+
delete row.dependsOn;
|
|
13418
|
+
} else {
|
|
13419
|
+
row.dependsOn = v;
|
|
13420
|
+
}
|
|
13421
|
+
}
|
|
13422
|
+
}
|
|
13561
13423
|
}
|
|
13562
13424
|
};
|
|
13563
|
-
var
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
return { name, email };
|
|
13569
|
-
};
|
|
13570
|
-
|
|
13571
|
-
// src/run/commit-data.ts
|
|
13572
|
-
var maxActorSuffixLen = 60;
|
|
13573
|
-
var formatDataBranchCommitMessage = (base, actorSuffix) => {
|
|
13574
|
-
const raw = actorSuffix?.trim();
|
|
13575
|
-
if (!raw) {
|
|
13576
|
-
return base;
|
|
13577
|
-
}
|
|
13578
|
-
const collapsed = raw.replace(/\s+/g, " ");
|
|
13579
|
-
const suffix = collapsed.length > maxActorSuffixLen ? `${collapsed.slice(0, maxActorSuffixLen - 1)}\u2026` : collapsed;
|
|
13580
|
-
return `${base} (${suffix})`;
|
|
13581
|
-
};
|
|
13582
|
-
var commitDataWorktreeIfNeeded = async (worktreePath, message, runGit2, opts) => {
|
|
13583
|
-
const { stdout } = await runGit2(worktreePath, ["status", "--porcelain"]);
|
|
13584
|
-
if (!stdout.trim()) return;
|
|
13585
|
-
await runGit2(worktreePath, ["add", "."]);
|
|
13586
|
-
const authorEnv = opts?.authorEnv ?? env;
|
|
13587
|
-
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
13588
|
-
worktreePath,
|
|
13589
|
-
runGit2,
|
|
13590
|
-
authorEnv
|
|
13591
|
-
);
|
|
13592
|
-
await runGit2(worktreePath, [
|
|
13593
|
-
"-c",
|
|
13594
|
-
`user.name=${name}`,
|
|
13595
|
-
"-c",
|
|
13596
|
-
`user.email=${email}`,
|
|
13597
|
-
"commit",
|
|
13598
|
-
"-m",
|
|
13599
|
-
message
|
|
13600
|
-
]);
|
|
13601
|
-
};
|
|
13602
|
-
|
|
13603
|
-
// src/run/push-data-branch.ts
|
|
13604
|
-
var firstLineFromUnknown = (err) => {
|
|
13605
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
13606
|
-
const line = raw.trim().split("\n")[0]?.trim() ?? raw.trim();
|
|
13607
|
-
return line.length > 0 ? line : "git error";
|
|
13608
|
-
};
|
|
13609
|
-
var tryPushDataBranchToRemote = async (worktreePath, remote, branch, runGit2) => {
|
|
13610
|
-
try {
|
|
13611
|
-
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
13612
|
-
} catch (e) {
|
|
13613
|
-
return {
|
|
13614
|
-
status: "skipped_no_remote",
|
|
13615
|
-
detail: firstLineFromUnknown(e)
|
|
13616
|
-
};
|
|
13617
|
-
}
|
|
13618
|
-
try {
|
|
13619
|
-
await runGit2(worktreePath, ["push", "-u", remote, branch]);
|
|
13620
|
-
return { status: "pushed" };
|
|
13621
|
-
} catch (e) {
|
|
13622
|
-
return {
|
|
13623
|
-
status: "failed",
|
|
13624
|
-
detail: firstLineFromUnknown(e)
|
|
13625
|
-
};
|
|
13626
|
-
}
|
|
13627
|
-
};
|
|
13628
|
-
|
|
13629
|
-
// src/run/sync-remote-data-branch.ts
|
|
13630
|
-
var SyncRemoteDataBranchMergeError = class extends Error {
|
|
13631
|
-
/** @param message - Human-readable reason (stderr excerpt or generic text). */
|
|
13632
|
-
constructor(message) {
|
|
13633
|
-
super(message);
|
|
13634
|
-
this.name = "SyncRemoteDataBranchMergeError";
|
|
13635
|
-
}
|
|
13636
|
-
};
|
|
13637
|
-
var remoteTrackingRef = (remote, dataBranch) => `refs/remotes/${remote}/${dataBranch}`;
|
|
13638
|
-
var mergeRefSpecifier = (remote, dataBranch) => `${remote}/${dataBranch}`;
|
|
13639
|
-
var isLikelyNonFastForwardPushFailure = (detail) => {
|
|
13640
|
-
if (detail === void 0) return false;
|
|
13641
|
-
const d = detail.toLowerCase();
|
|
13642
|
-
return d.includes("non-fast-forward") || d.includes("failed to push");
|
|
13425
|
+
var applyCreatedAudit = (row, evt) => {
|
|
13426
|
+
row.createdAt = evt.ts;
|
|
13427
|
+
row.createdBy = evt.actor;
|
|
13428
|
+
row.updatedAt = evt.ts;
|
|
13429
|
+
row.updatedBy = evt.actor;
|
|
13643
13430
|
};
|
|
13644
|
-
var
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
return "up_to_date";
|
|
13648
|
-
}
|
|
13649
|
-
if (c.includes("fast-forward")) {
|
|
13650
|
-
return "fast_forward";
|
|
13651
|
-
}
|
|
13652
|
-
return "merge_commit";
|
|
13431
|
+
var applyLastUpdate = (row, evt) => {
|
|
13432
|
+
row.updatedAt = evt.ts;
|
|
13433
|
+
row.updatedBy = evt.actor;
|
|
13653
13434
|
};
|
|
13654
|
-
var
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
}
|
|
13435
|
+
var applyStatusIfChanged = (row, evt, nextStatus) => {
|
|
13436
|
+
if (row.status === nextStatus) return false;
|
|
13437
|
+
row.status = nextStatus;
|
|
13438
|
+
row.statusChangedAt = evt.ts;
|
|
13439
|
+
row.statusChangedBy = evt.actor;
|
|
13440
|
+
return true;
|
|
13661
13441
|
};
|
|
13662
|
-
var
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
} catch (e) {
|
|
13672
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
13673
|
-
if (/couldn't find remote ref|could not find remote ref/i.test(msg)) {
|
|
13674
|
-
return "remote_branch_absent";
|
|
13675
|
-
}
|
|
13676
|
-
throw e;
|
|
13677
|
-
}
|
|
13442
|
+
var appendTicketCommentFromEvent = (ticket, evt) => {
|
|
13443
|
+
const list = ticket.comments ?? (ticket.comments = []);
|
|
13444
|
+
list.push({
|
|
13445
|
+
id: evt.id,
|
|
13446
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13447
|
+
createdAt: evt.ts,
|
|
13448
|
+
createdBy: evt.actor
|
|
13449
|
+
});
|
|
13450
|
+
applyLastUpdate(ticket, evt);
|
|
13678
13451
|
};
|
|
13679
|
-
var
|
|
13680
|
-
const
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
const { stdout, stderr } = await runGit2(worktreePath, [
|
|
13688
|
-
"-c",
|
|
13689
|
-
`user.name=${name}`,
|
|
13690
|
-
"-c",
|
|
13691
|
-
`user.email=${email}`,
|
|
13692
|
-
"merge",
|
|
13693
|
-
"--no-edit",
|
|
13694
|
-
spec
|
|
13695
|
-
]);
|
|
13696
|
-
return classifyMergeOutput(`${stdout}
|
|
13697
|
-
${stderr}`);
|
|
13698
|
-
} catch (e) {
|
|
13699
|
-
await runGit2(worktreePath, ["merge", "--abort"]).catch(() => {
|
|
13452
|
+
var resolveInboundTicketStatusFromPayload = (ticket, payload) => {
|
|
13453
|
+
const explicit = parseWorkItemStatus(payload["status"]);
|
|
13454
|
+
if (explicit !== void 0) return explicit;
|
|
13455
|
+
const legacySt = payload["state"];
|
|
13456
|
+
if (legacySt === "open" || legacySt === "closed") {
|
|
13457
|
+
return resolveTicketInboundStatus({
|
|
13458
|
+
issueState: legacySt,
|
|
13459
|
+
currentStatus: ticket.status
|
|
13700
13460
|
});
|
|
13701
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
13702
|
-
throw new SyncRemoteDataBranchMergeError(
|
|
13703
|
-
msg.toLowerCase().includes("conflict") ? "Merge conflict while syncing hyper-pm data branch; merge aborted. Resolve manually on the data branch if needed." : `git merge failed: ${msg.trim().split("\n")[0] ?? msg}`
|
|
13704
|
-
);
|
|
13705
13461
|
}
|
|
13462
|
+
return void 0;
|
|
13706
13463
|
};
|
|
13707
|
-
var
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
);
|
|
13464
|
+
var applyEvent = (projection, evt) => {
|
|
13465
|
+
switch (evt.type) {
|
|
13466
|
+
case "EpicCreated": {
|
|
13467
|
+
const id = String(evt.payload["id"]);
|
|
13468
|
+
const status = resolveStatusForNewEpicStoryPayload(evt.payload);
|
|
13469
|
+
const row = {
|
|
13470
|
+
id,
|
|
13471
|
+
number: resolveWorkItemCreateNumber(projection, "epic", evt.payload),
|
|
13472
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13473
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13474
|
+
status,
|
|
13475
|
+
statusChangedAt: evt.ts,
|
|
13476
|
+
statusChangedBy: evt.actor,
|
|
13477
|
+
createdAt: "",
|
|
13478
|
+
createdBy: "",
|
|
13479
|
+
updatedAt: "",
|
|
13480
|
+
updatedBy: ""
|
|
13481
|
+
};
|
|
13482
|
+
applyCreatedAudit(row, evt);
|
|
13483
|
+
projection.epics.set(id, row);
|
|
13484
|
+
break;
|
|
13726
13485
|
}
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
dataBranch,
|
|
13744
|
-
runGit2
|
|
13745
|
-
);
|
|
13746
|
-
if (dataBranchFetch !== "ok") {
|
|
13747
|
-
return;
|
|
13486
|
+
case "EpicUpdated": {
|
|
13487
|
+
const id = String(evt.payload["id"]);
|
|
13488
|
+
const cur = projection.epics.get(id);
|
|
13489
|
+
if (!cur) break;
|
|
13490
|
+
if (evt.payload["title"] !== void 0) {
|
|
13491
|
+
cur.title = String(evt.payload["title"]);
|
|
13492
|
+
}
|
|
13493
|
+
if (evt.payload["body"] !== void 0) {
|
|
13494
|
+
cur.body = String(evt.payload["body"]);
|
|
13495
|
+
}
|
|
13496
|
+
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
13497
|
+
if (nextStatus !== void 0) {
|
|
13498
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13499
|
+
}
|
|
13500
|
+
applyLastUpdate(cur, evt);
|
|
13501
|
+
break;
|
|
13748
13502
|
}
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13503
|
+
case "EpicDeleted": {
|
|
13504
|
+
const id = String(evt.payload["id"]);
|
|
13505
|
+
const cur = projection.epics.get(id);
|
|
13506
|
+
if (cur) {
|
|
13507
|
+
cur.deleted = true;
|
|
13508
|
+
applyLastUpdate(cur, evt);
|
|
13509
|
+
}
|
|
13510
|
+
break;
|
|
13753
13511
|
}
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13512
|
+
case "StoryCreated": {
|
|
13513
|
+
const id = String(evt.payload["id"]);
|
|
13514
|
+
const status = resolveStatusForNewEpicStoryPayload(evt.payload);
|
|
13515
|
+
const row = {
|
|
13516
|
+
id,
|
|
13517
|
+
number: resolveWorkItemCreateNumber(projection, "story", evt.payload),
|
|
13518
|
+
epicId: String(evt.payload["epicId"]),
|
|
13519
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13520
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13521
|
+
status,
|
|
13522
|
+
statusChangedAt: evt.ts,
|
|
13523
|
+
statusChangedBy: evt.actor,
|
|
13524
|
+
createdAt: "",
|
|
13525
|
+
createdBy: "",
|
|
13526
|
+
updatedAt: "",
|
|
13527
|
+
updatedBy: ""
|
|
13528
|
+
};
|
|
13529
|
+
applyCreatedAudit(row, evt);
|
|
13530
|
+
projection.stories.set(id, row);
|
|
13766
13531
|
break;
|
|
13767
13532
|
}
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13533
|
+
case "StoryUpdated": {
|
|
13534
|
+
const id = String(evt.payload["id"]);
|
|
13535
|
+
const cur = projection.stories.get(id);
|
|
13536
|
+
if (!cur) break;
|
|
13537
|
+
if (evt.payload["title"] !== void 0) {
|
|
13538
|
+
cur.title = String(evt.payload["title"]);
|
|
13539
|
+
}
|
|
13540
|
+
if (evt.payload["body"] !== void 0) {
|
|
13541
|
+
cur.body = String(evt.payload["body"]);
|
|
13542
|
+
}
|
|
13543
|
+
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
13544
|
+
if (nextStatus !== void 0) {
|
|
13545
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13546
|
+
}
|
|
13547
|
+
applyLastUpdate(cur, evt);
|
|
13548
|
+
break;
|
|
13771
13549
|
}
|
|
13772
|
-
|
|
13550
|
+
case "StoryDeleted": {
|
|
13551
|
+
const id = String(evt.payload["id"]);
|
|
13552
|
+
const cur = projection.stories.get(id);
|
|
13553
|
+
if (cur) {
|
|
13554
|
+
cur.deleted = true;
|
|
13555
|
+
applyLastUpdate(cur, evt);
|
|
13556
|
+
}
|
|
13557
|
+
break;
|
|
13558
|
+
}
|
|
13559
|
+
case "TicketCreated": {
|
|
13560
|
+
const id = String(evt.payload["id"]);
|
|
13561
|
+
const body = String(evt.payload["body"] ?? "");
|
|
13562
|
+
const status = resolveStatusForNewTicketPayload(evt.payload);
|
|
13563
|
+
const row = {
|
|
13564
|
+
id,
|
|
13565
|
+
number: resolveWorkItemCreateNumber(projection, "ticket", evt.payload),
|
|
13566
|
+
storyId: storyIdFromTicketCreatedPayload(evt.payload),
|
|
13567
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13568
|
+
body,
|
|
13569
|
+
status,
|
|
13570
|
+
statusChangedAt: evt.ts,
|
|
13571
|
+
statusChangedBy: evt.actor,
|
|
13572
|
+
linkedPrs: parsePrRefs(body),
|
|
13573
|
+
linkedBranches: linkedBranchesFromTicketCreatedPayload(evt.payload),
|
|
13574
|
+
prActivityRecent: [],
|
|
13575
|
+
createdAt: "",
|
|
13576
|
+
createdBy: "",
|
|
13577
|
+
updatedAt: "",
|
|
13578
|
+
updatedBy: ""
|
|
13579
|
+
};
|
|
13580
|
+
applyCreatedAudit(row, evt);
|
|
13581
|
+
applyTicketAssigneeFromPayload(row, evt.payload);
|
|
13582
|
+
applyTicketPlanningFieldsFromCreatePayload(row, evt.payload);
|
|
13583
|
+
projection.tickets.set(id, row);
|
|
13584
|
+
break;
|
|
13585
|
+
}
|
|
13586
|
+
case "TicketUpdated": {
|
|
13587
|
+
const id = String(evt.payload["id"]);
|
|
13588
|
+
const cur = projection.tickets.get(id);
|
|
13589
|
+
if (!cur) break;
|
|
13590
|
+
if (evt.payload["title"] !== void 0) {
|
|
13591
|
+
cur.title = String(evt.payload["title"]);
|
|
13592
|
+
}
|
|
13593
|
+
if (evt.payload["body"] !== void 0) {
|
|
13594
|
+
cur.body = String(evt.payload["body"]);
|
|
13595
|
+
cur.linkedPrs = parsePrRefs(cur.body);
|
|
13596
|
+
}
|
|
13597
|
+
const nextStatus = resolveTicketStatusFromUpdatePayload(evt.payload);
|
|
13598
|
+
if (nextStatus !== void 0) {
|
|
13599
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13600
|
+
}
|
|
13601
|
+
applyTicketAssigneeFromPayload(cur, evt.payload);
|
|
13602
|
+
applyTicketStoryIdFromPayload(cur, evt.payload);
|
|
13603
|
+
applyTicketBranchesFromUpdatePayload(cur, evt.payload);
|
|
13604
|
+
applyTicketPlanningFieldsFromUpdatePayload(cur, evt.payload);
|
|
13605
|
+
applyLastUpdate(cur, evt);
|
|
13606
|
+
break;
|
|
13607
|
+
}
|
|
13608
|
+
case "TicketDeleted": {
|
|
13609
|
+
const id = String(evt.payload["id"]);
|
|
13610
|
+
const cur = projection.tickets.get(id);
|
|
13611
|
+
if (cur) {
|
|
13612
|
+
cur.deleted = true;
|
|
13613
|
+
applyLastUpdate(cur, evt);
|
|
13614
|
+
}
|
|
13615
|
+
break;
|
|
13616
|
+
}
|
|
13617
|
+
case "TicketCommentAdded": {
|
|
13618
|
+
const ticketId = String(evt.payload["ticketId"] ?? "");
|
|
13619
|
+
const ticket = projection.tickets.get(ticketId);
|
|
13620
|
+
if (!ticket || ticket.deleted) break;
|
|
13621
|
+
appendTicketCommentFromEvent(ticket, evt);
|
|
13622
|
+
break;
|
|
13623
|
+
}
|
|
13624
|
+
case "SyncCursor": {
|
|
13625
|
+
projection.syncCursor = String(evt.payload["cursor"] ?? "");
|
|
13626
|
+
break;
|
|
13627
|
+
}
|
|
13628
|
+
case "GithubIssueLinked": {
|
|
13629
|
+
const ticketId = String(evt.payload["ticketId"]);
|
|
13630
|
+
const num = Number(evt.payload["issueNumber"]);
|
|
13631
|
+
const ticket = projection.tickets.get(ticketId);
|
|
13632
|
+
if (ticket && Number.isFinite(num)) {
|
|
13633
|
+
ticket.githubIssueNumber = num;
|
|
13634
|
+
applyLastUpdate(ticket, evt);
|
|
13635
|
+
}
|
|
13636
|
+
break;
|
|
13637
|
+
}
|
|
13638
|
+
case "GithubInboundUpdate": {
|
|
13639
|
+
const entity = String(evt.payload["entity"]);
|
|
13640
|
+
const entityId = String(evt.payload["entityId"]);
|
|
13641
|
+
if (entity === "ticket") {
|
|
13642
|
+
const ticket = projection.tickets.get(entityId);
|
|
13643
|
+
if (!ticket) break;
|
|
13644
|
+
if (evt.payload["title"] !== void 0) {
|
|
13645
|
+
ticket.title = String(evt.payload["title"]);
|
|
13646
|
+
}
|
|
13647
|
+
if (evt.payload["body"] !== void 0) {
|
|
13648
|
+
ticket.body = String(evt.payload["body"]);
|
|
13649
|
+
ticket.linkedPrs = parsePrRefs(ticket.body);
|
|
13650
|
+
}
|
|
13651
|
+
const inboundStatus = resolveInboundTicketStatusFromPayload(
|
|
13652
|
+
ticket,
|
|
13653
|
+
evt.payload
|
|
13654
|
+
);
|
|
13655
|
+
if (inboundStatus !== void 0) {
|
|
13656
|
+
applyStatusIfChanged(ticket, evt, inboundStatus);
|
|
13657
|
+
}
|
|
13658
|
+
applyTicketAssigneeFromPayload(ticket, evt.payload);
|
|
13659
|
+
applyTicketPlanningFieldsFromUpdatePayload(ticket, evt.payload);
|
|
13660
|
+
applyLastUpdate(ticket, evt);
|
|
13661
|
+
}
|
|
13662
|
+
break;
|
|
13663
|
+
}
|
|
13664
|
+
case "GithubPrActivity": {
|
|
13665
|
+
const summary = parseGithubPrActivityPayload(evt.payload);
|
|
13666
|
+
if (!summary) break;
|
|
13667
|
+
const ticket = projection.tickets.get(
|
|
13668
|
+
String(evt.payload["ticketId"] ?? "")
|
|
13669
|
+
);
|
|
13670
|
+
if (!ticket || ticket.deleted) break;
|
|
13671
|
+
const list = ticket.prActivityRecent ?? (ticket.prActivityRecent = []);
|
|
13672
|
+
list.push(summary);
|
|
13673
|
+
if (list.length > GITHUB_PR_ACTIVITY_RECENT_CAP) {
|
|
13674
|
+
ticket.prActivityRecent = list.slice(-GITHUB_PR_ACTIVITY_RECENT_CAP);
|
|
13675
|
+
}
|
|
13676
|
+
break;
|
|
13677
|
+
}
|
|
13678
|
+
default:
|
|
13679
|
+
break;
|
|
13773
13680
|
}
|
|
13774
|
-
return {
|
|
13775
|
-
dataBranchFetch,
|
|
13776
|
-
dataBranchMerge,
|
|
13777
|
-
dataBranchPush: lastPush.status,
|
|
13778
|
-
...lastPush.detail !== void 0 ? { dataBranchPushDetail: lastPush.detail } : {},
|
|
13779
|
-
pushAttempts
|
|
13780
|
-
};
|
|
13781
13681
|
};
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13682
|
+
var replayEvents = (lines) => {
|
|
13683
|
+
const proj = emptyProjection();
|
|
13684
|
+
const events = [];
|
|
13685
|
+
for (const line of lines) {
|
|
13686
|
+
const trimmed = line.trim();
|
|
13687
|
+
if (!trimmed) continue;
|
|
13688
|
+
const json = JSON.parse(trimmed);
|
|
13689
|
+
events.push(eventLineSchema.parse(json));
|
|
13690
|
+
}
|
|
13691
|
+
events.sort((a, b) => {
|
|
13692
|
+
const t = a.ts.localeCompare(b.ts);
|
|
13693
|
+
if (t !== 0) return t;
|
|
13694
|
+
return a.id.localeCompare(b.id);
|
|
13695
|
+
});
|
|
13696
|
+
for (const e of events) {
|
|
13697
|
+
applyEvent(proj, e);
|
|
13698
|
+
}
|
|
13699
|
+
return proj;
|
|
13794
13700
|
};
|
|
13795
13701
|
|
|
13796
|
-
// src/
|
|
13797
|
-
var
|
|
13798
|
-
|
|
13799
|
-
|
|
13702
|
+
// src/cli/resolve-projection-work-item-id.ts
|
|
13703
|
+
var isDigitOnlyWorkItemRef = (raw) => /^\d+$/.test(raw.trim());
|
|
13704
|
+
var resolveEpicId = (projection, raw) => {
|
|
13705
|
+
const t = raw.trim();
|
|
13706
|
+
if (t === "") return void 0;
|
|
13707
|
+
if (projection.epics.has(t)) return t;
|
|
13708
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13709
|
+
const n = Number(t);
|
|
13710
|
+
const hits = [...projection.epics.values()].filter((e) => e.number === n);
|
|
13711
|
+
if (hits.length !== 1) return void 0;
|
|
13712
|
+
return hits[0].id;
|
|
13713
|
+
};
|
|
13714
|
+
var resolveStoryId = (projection, raw) => {
|
|
13715
|
+
const t = raw.trim();
|
|
13716
|
+
if (t === "") return void 0;
|
|
13717
|
+
if (projection.stories.has(t)) return t;
|
|
13718
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13719
|
+
const n = Number(t);
|
|
13720
|
+
const hits = [...projection.stories.values()].filter((s) => s.number === n);
|
|
13721
|
+
if (hits.length !== 1) return void 0;
|
|
13722
|
+
return hits[0].id;
|
|
13723
|
+
};
|
|
13724
|
+
var resolveTicketId = (projection, raw) => {
|
|
13725
|
+
const t = raw.trim();
|
|
13726
|
+
if (t === "") return void 0;
|
|
13727
|
+
if (projection.tickets.has(t)) return t;
|
|
13728
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13729
|
+
const n = Number(t);
|
|
13730
|
+
const hits = [...projection.tickets.values()].filter((x) => x.number === n);
|
|
13731
|
+
if (hits.length !== 1) return void 0;
|
|
13732
|
+
return hits[0].id;
|
|
13733
|
+
};
|
|
13734
|
+
var resolveTicketDependsOnTokensToIds = (projection, tokens) => {
|
|
13735
|
+
const mapped = tokens.map((raw) => {
|
|
13736
|
+
const t = raw.trim();
|
|
13737
|
+
if (t === "") return "";
|
|
13738
|
+
if (projection.tickets.has(t)) return t;
|
|
13739
|
+
if (!isDigitOnlyWorkItemRef(t)) return t;
|
|
13740
|
+
const hit = resolveTicketId(projection, t);
|
|
13741
|
+
return hit ?? t;
|
|
13800
13742
|
});
|
|
13801
|
-
|
|
13802
|
-
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(abs), { recursive: true });
|
|
13803
|
-
await (0, import_promises5.appendFile)(abs, `${JSON.stringify(event)}
|
|
13804
|
-
`, "utf8");
|
|
13805
|
-
return rel;
|
|
13743
|
+
return normalizeTicketDependsOnIds(mapped);
|
|
13806
13744
|
};
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
const abs = (0, import_node_path6.join)(dir, e.name);
|
|
13816
|
-
if (e.isDirectory()) {
|
|
13817
|
-
out.push(...await listJsonlFiles(abs, root));
|
|
13818
|
-
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
13819
|
-
out.push((0, import_node_path6.relative)(root, abs).split("\\").join("/"));
|
|
13820
|
-
}
|
|
13745
|
+
var assertCreatePayloadUsesExpectedHeadNumber = (projection, kind, payload) => {
|
|
13746
|
+
const n = readOptionalPositiveIntegerFromPayload(payload, "number");
|
|
13747
|
+
const expected = kind === "epic" ? nextEpicNumberForCreate(projection) : kind === "story" ? nextStoryNumberForCreate(projection) : nextTicketNumberForCreate(projection);
|
|
13748
|
+
if (n !== expected) {
|
|
13749
|
+
const got = n === void 0 ? "missing" : String(n);
|
|
13750
|
+
throw new Error(
|
|
13751
|
+
`Invalid ${kind} number for this data branch: expected ${String(expected)}, got ${got}.`
|
|
13752
|
+
);
|
|
13821
13753
|
}
|
|
13822
|
-
return out;
|
|
13823
|
-
};
|
|
13824
|
-
var readAllEventLines = async (dataRoot) => {
|
|
13825
|
-
const eventsRoot = (0, import_node_path6.join)(dataRoot, "events");
|
|
13826
|
-
let files = [];
|
|
13827
|
-
try {
|
|
13828
|
-
files = await listJsonlFiles(eventsRoot, dataRoot);
|
|
13829
|
-
} catch {
|
|
13830
|
-
return [];
|
|
13831
|
-
}
|
|
13832
|
-
files.sort((a, b) => a.localeCompare(b));
|
|
13833
|
-
const lines = [];
|
|
13834
|
-
for (const rel of files) {
|
|
13835
|
-
const content = await (0, import_promises6.readFile)((0, import_node_path6.join)(dataRoot, rel), "utf8");
|
|
13836
|
-
for (const line of content.split("\n")) {
|
|
13837
|
-
if (line.trim()) lines.push(line);
|
|
13838
|
-
}
|
|
13839
|
-
}
|
|
13840
|
-
return lines;
|
|
13841
13754
|
};
|
|
13842
13755
|
|
|
13843
|
-
// src/
|
|
13844
|
-
var
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
"
|
|
13848
|
-
"
|
|
13849
|
-
|
|
13850
|
-
"
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
var
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
const
|
|
13863
|
-
const
|
|
13864
|
-
const
|
|
13865
|
-
const
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
const
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
if (!kindParsed.success) return void 0;
|
|
13873
|
-
const out = {
|
|
13874
|
-
prNumber,
|
|
13875
|
-
kind: kindParsed.data,
|
|
13876
|
-
occurredAt,
|
|
13877
|
-
sourceId
|
|
13878
|
-
};
|
|
13879
|
-
const url = payload["url"];
|
|
13880
|
-
if (typeof url === "string" && url.length > 0) {
|
|
13881
|
-
out.url = url;
|
|
13882
|
-
}
|
|
13883
|
-
const rs = githubPrReviewStateSchema.safeParse(payload["reviewState"]);
|
|
13884
|
-
if (rs.success) {
|
|
13885
|
-
out.reviewState = rs.data;
|
|
13756
|
+
// src/config/hyper-pm-config.ts
|
|
13757
|
+
var hyperPmConfigSchema = external_exports.object({
|
|
13758
|
+
schema: external_exports.literal(1),
|
|
13759
|
+
dataBranch: external_exports.string().min(1),
|
|
13760
|
+
remote: external_exports.string().min(1).default("origin"),
|
|
13761
|
+
sync: external_exports.enum(["off", "outbound", "full"]).default("outbound"),
|
|
13762
|
+
githubRepo: external_exports.string().optional(),
|
|
13763
|
+
issueMapping: external_exports.enum(["ticket", "story", "epic"]).default("ticket")
|
|
13764
|
+
});
|
|
13765
|
+
|
|
13766
|
+
// src/config/load-config.ts
|
|
13767
|
+
var import_promises = require("node:fs/promises");
|
|
13768
|
+
var import_node_path = require("node:path");
|
|
13769
|
+
var CONFIG_DIR = ".hyper-pm";
|
|
13770
|
+
var CONFIG_FILE = "config.json";
|
|
13771
|
+
var getHyperPmConfigPath = (repoRoot) => {
|
|
13772
|
+
return (0, import_node_path.join)(repoRoot, CONFIG_DIR, CONFIG_FILE);
|
|
13773
|
+
};
|
|
13774
|
+
var loadHyperPmConfig = async (repoRoot, overrides = {}) => {
|
|
13775
|
+
const raw = await (0, import_promises.readFile)(getHyperPmConfigPath(repoRoot), "utf8");
|
|
13776
|
+
const parsed = JSON.parse(raw);
|
|
13777
|
+
const base = hyperPmConfigSchema.parse(parsed);
|
|
13778
|
+
const merged = { ...base, ...stripUndefined(overrides) };
|
|
13779
|
+
return hyperPmConfigSchema.parse(merged);
|
|
13780
|
+
};
|
|
13781
|
+
var stripUndefined = (obj) => {
|
|
13782
|
+
const out = {};
|
|
13783
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
13784
|
+
if (v !== void 0) out[k] = v;
|
|
13886
13785
|
}
|
|
13887
13786
|
return out;
|
|
13888
13787
|
};
|
|
13889
13788
|
|
|
13890
|
-
// src/
|
|
13891
|
-
var
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
});
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
const re = /\b(?:Closes|Refs|Fixes)\s+#(\d+)\b/gi;
|
|
13899
|
-
let m = re.exec(body);
|
|
13900
|
-
while (m !== null) {
|
|
13901
|
-
out.add(Number(m[1]));
|
|
13902
|
-
m = re.exec(body);
|
|
13903
|
-
}
|
|
13904
|
-
return [...out];
|
|
13789
|
+
// src/config/save-config.ts
|
|
13790
|
+
var import_promises2 = require("node:fs/promises");
|
|
13791
|
+
var import_node_path2 = require("node:path");
|
|
13792
|
+
var saveHyperPmConfig = async (repoRoot, config) => {
|
|
13793
|
+
const target = getHyperPmConfigPath(repoRoot);
|
|
13794
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(target), { recursive: true });
|
|
13795
|
+
await (0, import_promises2.writeFile)(target, `${JSON.stringify(config, null, 2)}
|
|
13796
|
+
`, "utf8");
|
|
13905
13797
|
};
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13798
|
+
|
|
13799
|
+
// src/doctor/run-doctor.ts
|
|
13800
|
+
var runDoctorOnLines = (lines) => {
|
|
13801
|
+
const issues = [];
|
|
13802
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13803
|
+
const line = lines[i]?.trim() ?? "";
|
|
13804
|
+
if (!line) continue;
|
|
13805
|
+
let json;
|
|
13806
|
+
try {
|
|
13807
|
+
json = JSON.parse(line);
|
|
13808
|
+
} catch (e) {
|
|
13809
|
+
issues.push({
|
|
13810
|
+
kind: "invalid-json",
|
|
13811
|
+
line: i + 1,
|
|
13812
|
+
message: e instanceof Error ? e.message : "parse error"
|
|
13813
|
+
});
|
|
13814
|
+
return issues;
|
|
13815
|
+
}
|
|
13816
|
+
const parsed = eventLineSchema.safeParse(json);
|
|
13817
|
+
if (!parsed.success) {
|
|
13818
|
+
issues.push({
|
|
13819
|
+
kind: "invalid-event",
|
|
13820
|
+
line: i + 1,
|
|
13821
|
+
message: parsed.error.message
|
|
13822
|
+
});
|
|
13823
|
+
return issues;
|
|
13824
|
+
}
|
|
13912
13825
|
}
|
|
13913
|
-
|
|
13914
|
-
const n = normalizeGithubLogin(v);
|
|
13915
|
-
if (n === "") delete row.assignee;
|
|
13916
|
-
else row.assignee = n;
|
|
13826
|
+
return issues;
|
|
13917
13827
|
};
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13828
|
+
|
|
13829
|
+
// src/git/create-and-checkout-branch.ts
|
|
13830
|
+
var createAndCheckoutBranch = async (opts) => {
|
|
13831
|
+
await opts.runGit(opts.repoRoot, [
|
|
13832
|
+
"switch",
|
|
13833
|
+
"-c",
|
|
13834
|
+
opts.branchName,
|
|
13835
|
+
opts.startPoint
|
|
13836
|
+
]);
|
|
13927
13837
|
};
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
}
|
|
13935
|
-
if (typeof v !== "string") return;
|
|
13936
|
-
const t = v.trim();
|
|
13937
|
-
row.storyId = t === "" ? null : t;
|
|
13838
|
+
|
|
13839
|
+
// src/git/data-worktree-session.ts
|
|
13840
|
+
var import_promises3 = require("node:fs/promises");
|
|
13841
|
+
var import_node_path3 = require("node:path");
|
|
13842
|
+
var ensureDir = async (path) => {
|
|
13843
|
+
await (0, import_promises3.mkdir)(path, { recursive: true });
|
|
13938
13844
|
};
|
|
13939
|
-
var
|
|
13940
|
-
|
|
13941
|
-
|
|
13845
|
+
var defaultPathExists = async (path) => {
|
|
13846
|
+
try {
|
|
13847
|
+
await (0, import_promises3.access)(path);
|
|
13848
|
+
return true;
|
|
13849
|
+
} catch {
|
|
13850
|
+
return false;
|
|
13942
13851
|
}
|
|
13943
|
-
return normalizeTicketBranchListFromPayloadValue(payload["branches"]);
|
|
13944
|
-
};
|
|
13945
|
-
var applyTicketBranchesFromUpdatePayload = (row, payload) => {
|
|
13946
|
-
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) return;
|
|
13947
|
-
const v = payload["branches"];
|
|
13948
|
-
if (!Array.isArray(v)) return;
|
|
13949
|
-
row.linkedBranches = normalizeTicketBranchListFromPayloadValue(v);
|
|
13950
13852
|
};
|
|
13951
|
-
var
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13853
|
+
var parseDataBranchWorktreeFromPorcelain = (stdout, dataBranch) => {
|
|
13854
|
+
const wantRef = `refs/heads/${dataBranch}`;
|
|
13855
|
+
const blocks = stdout.split(/\n\n+/).map((b) => b.trim()).filter(Boolean);
|
|
13856
|
+
for (const block of blocks) {
|
|
13857
|
+
const lines = block.split("\n");
|
|
13858
|
+
let worktreePath;
|
|
13859
|
+
let branch;
|
|
13860
|
+
for (const line of lines) {
|
|
13861
|
+
if (line.startsWith("worktree ")) {
|
|
13862
|
+
worktreePath = line.slice("worktree ".length);
|
|
13863
|
+
} else if (line.startsWith("branch ")) {
|
|
13864
|
+
branch = line.slice("branch ".length);
|
|
13865
|
+
}
|
|
13956
13866
|
}
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
if (typeof pr === "string") {
|
|
13960
|
-
row.priority = pr;
|
|
13961
|
-
}
|
|
13962
|
-
const sz = readTicketSizePatch(payload);
|
|
13963
|
-
if (typeof sz === "string") {
|
|
13964
|
-
row.size = sz;
|
|
13965
|
-
}
|
|
13966
|
-
const est = readTicketEstimatePatch(payload);
|
|
13967
|
-
if (typeof est === "number") {
|
|
13968
|
-
row.estimate = est;
|
|
13969
|
-
}
|
|
13970
|
-
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13971
|
-
if (typeof sw === "string") {
|
|
13972
|
-
row.startWorkAt = sw;
|
|
13973
|
-
}
|
|
13974
|
-
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13975
|
-
if (typeof tf === "string") {
|
|
13976
|
-
row.targetFinishAt = tf;
|
|
13977
|
-
}
|
|
13978
|
-
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13979
|
-
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13980
|
-
if (v !== void 0 && v.length > 0) {
|
|
13981
|
-
row.dependsOn = v;
|
|
13867
|
+
if (worktreePath !== void 0 && branch === wantRef) {
|
|
13868
|
+
return worktreePath;
|
|
13982
13869
|
}
|
|
13983
13870
|
}
|
|
13871
|
+
return void 0;
|
|
13984
13872
|
};
|
|
13985
|
-
var
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
if (pr === null) {
|
|
14002
|
-
delete row.priority;
|
|
14003
|
-
} else if (typeof pr === "string") {
|
|
14004
|
-
row.priority = pr;
|
|
14005
|
-
}
|
|
14006
|
-
const sz = readTicketSizePatch(payload);
|
|
14007
|
-
if (sz === null) {
|
|
14008
|
-
delete row.size;
|
|
14009
|
-
} else if (typeof sz === "string") {
|
|
14010
|
-
row.size = sz;
|
|
14011
|
-
}
|
|
14012
|
-
const est = readTicketEstimatePatch(payload);
|
|
14013
|
-
if (est === null) {
|
|
14014
|
-
delete row.estimate;
|
|
14015
|
-
} else if (typeof est === "number") {
|
|
14016
|
-
row.estimate = est;
|
|
14017
|
-
}
|
|
14018
|
-
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
14019
|
-
if (sw === null) {
|
|
14020
|
-
delete row.startWorkAt;
|
|
14021
|
-
} else if (typeof sw === "string") {
|
|
14022
|
-
row.startWorkAt = sw;
|
|
13873
|
+
var openDataBranchWorktree = async (opts) => {
|
|
13874
|
+
const pathExists = opts.pathExists ?? defaultPathExists;
|
|
13875
|
+
const { stdout: listOut } = await opts.runGit(opts.repoRoot, [
|
|
13876
|
+
"worktree",
|
|
13877
|
+
"list",
|
|
13878
|
+
"--porcelain"
|
|
13879
|
+
]);
|
|
13880
|
+
const listedPath = parseDataBranchWorktreeFromPorcelain(
|
|
13881
|
+
listOut,
|
|
13882
|
+
opts.dataBranch
|
|
13883
|
+
);
|
|
13884
|
+
if (listedPath !== void 0 && await pathExists(listedPath)) {
|
|
13885
|
+
const dispose2 = async () => {
|
|
13886
|
+
return;
|
|
13887
|
+
};
|
|
13888
|
+
return { worktreePath: listedPath, dispose: dispose2 };
|
|
14023
13889
|
}
|
|
14024
|
-
const
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
13890
|
+
const worktreePath = (0, import_node_path3.join)(
|
|
13891
|
+
opts.tmpBase,
|
|
13892
|
+
`hyper-pm-worktree-${ulid().toLowerCase()}`
|
|
13893
|
+
);
|
|
13894
|
+
await ensureDir(opts.tmpBase);
|
|
13895
|
+
try {
|
|
13896
|
+
await opts.runGit(opts.repoRoot, [
|
|
13897
|
+
"worktree",
|
|
13898
|
+
"add",
|
|
13899
|
+
worktreePath,
|
|
13900
|
+
opts.dataBranch
|
|
13901
|
+
]);
|
|
13902
|
+
} catch (err) {
|
|
13903
|
+
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13904
|
+
});
|
|
13905
|
+
throw err;
|
|
14029
13906
|
}
|
|
14030
|
-
|
|
14031
|
-
if (
|
|
14032
|
-
|
|
14033
|
-
} else {
|
|
14034
|
-
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
14035
|
-
if (v !== void 0) {
|
|
14036
|
-
if (v.length === 0) {
|
|
14037
|
-
delete row.dependsOn;
|
|
14038
|
-
} else {
|
|
14039
|
-
row.dependsOn = v;
|
|
14040
|
-
}
|
|
14041
|
-
}
|
|
13907
|
+
const dispose = async () => {
|
|
13908
|
+
if (opts.keepWorktree) {
|
|
13909
|
+
return;
|
|
14042
13910
|
}
|
|
14043
|
-
|
|
14044
|
-
};
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
row.updatedBy = evt.actor;
|
|
14050
|
-
};
|
|
14051
|
-
var applyLastUpdate = (row, evt) => {
|
|
14052
|
-
row.updatedAt = evt.ts;
|
|
14053
|
-
row.updatedBy = evt.actor;
|
|
13911
|
+
await opts.runGit(opts.repoRoot, ["worktree", "remove", "--force", worktreePath]).catch(() => {
|
|
13912
|
+
});
|
|
13913
|
+
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13914
|
+
});
|
|
13915
|
+
};
|
|
13916
|
+
return { worktreePath, dispose };
|
|
14054
13917
|
};
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
return true;
|
|
13918
|
+
|
|
13919
|
+
// src/git/find-git-root.ts
|
|
13920
|
+
var findGitRoot = async (cwd, deps) => {
|
|
13921
|
+
const { stdout } = await deps.runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
13922
|
+
return stdout;
|
|
14061
13923
|
};
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
13924
|
+
|
|
13925
|
+
// src/git/init-orphan-data-branch.ts
|
|
13926
|
+
var import_promises4 = require("node:fs/promises");
|
|
13927
|
+
var import_node_path4 = require("node:path");
|
|
13928
|
+
var initOrphanDataBranchInWorktree = async (opts) => {
|
|
13929
|
+
const { stdout: tip } = await opts.runGit(opts.repoRoot, [
|
|
13930
|
+
"rev-parse",
|
|
13931
|
+
"HEAD"
|
|
13932
|
+
]);
|
|
13933
|
+
const tipCommit = tip.trim();
|
|
13934
|
+
await opts.runGit(opts.repoRoot, [
|
|
13935
|
+
"worktree",
|
|
13936
|
+
"add",
|
|
13937
|
+
opts.worktreePath,
|
|
13938
|
+
tipCommit
|
|
13939
|
+
]);
|
|
13940
|
+
await opts.runGit(opts.worktreePath, [
|
|
13941
|
+
"checkout",
|
|
13942
|
+
"--orphan",
|
|
13943
|
+
opts.dataBranch
|
|
13944
|
+
]);
|
|
13945
|
+
await opts.runGit(opts.worktreePath, ["rm", "-rf", "."]).catch(() => {
|
|
14069
13946
|
});
|
|
14070
|
-
|
|
13947
|
+
const marker = (0, import_node_path4.join)(opts.worktreePath, "README.hyper-pm.md");
|
|
13948
|
+
await (0, import_promises4.writeFile)(
|
|
13949
|
+
marker,
|
|
13950
|
+
"# hyper-pm data branch\n\nAppend-only events live under `events/`.\n",
|
|
13951
|
+
"utf8"
|
|
13952
|
+
);
|
|
13953
|
+
await opts.runGit(opts.worktreePath, ["add", "."]);
|
|
13954
|
+
await opts.runGit(opts.worktreePath, [
|
|
13955
|
+
"commit",
|
|
13956
|
+
"-m",
|
|
13957
|
+
"init hyper-pm data branch"
|
|
13958
|
+
]);
|
|
14071
13959
|
};
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
13960
|
+
|
|
13961
|
+
// src/git/pick-unique-local-branch-name.ts
|
|
13962
|
+
var DEFAULT_MAX_SUFFIX = 1e3;
|
|
13963
|
+
var localBranchRefExists = async (repoRoot, name, git) => {
|
|
13964
|
+
try {
|
|
13965
|
+
await git(repoRoot, ["show-ref", "--verify", `refs/heads/${name}`]);
|
|
13966
|
+
return true;
|
|
13967
|
+
} catch {
|
|
13968
|
+
return false;
|
|
14081
13969
|
}
|
|
14082
|
-
return void 0;
|
|
14083
13970
|
};
|
|
14084
|
-
var
|
|
14085
|
-
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
body: String(evt.payload["body"] ?? ""),
|
|
14093
|
-
status,
|
|
14094
|
-
statusChangedAt: evt.ts,
|
|
14095
|
-
statusChangedBy: evt.actor,
|
|
14096
|
-
createdAt: "",
|
|
14097
|
-
createdBy: "",
|
|
14098
|
-
updatedAt: "",
|
|
14099
|
-
updatedBy: ""
|
|
14100
|
-
};
|
|
14101
|
-
applyCreatedAudit(row, evt);
|
|
14102
|
-
projection.epics.set(id, row);
|
|
14103
|
-
break;
|
|
13971
|
+
var pickUniqueLocalBranchName = async (opts) => {
|
|
13972
|
+
const max = opts.maxSuffix ?? DEFAULT_MAX_SUFFIX;
|
|
13973
|
+
const { preferredBase, repoRoot, runGit: git } = opts;
|
|
13974
|
+
for (let n = 1; n <= max; n += 1) {
|
|
13975
|
+
const raw = n === 1 ? preferredBase : `${preferredBase}-${n}`;
|
|
13976
|
+
const norm = normalizeTicketBranchName(raw);
|
|
13977
|
+
if (norm === void 0) {
|
|
13978
|
+
continue;
|
|
14104
13979
|
}
|
|
14105
|
-
|
|
14106
|
-
|
|
14107
|
-
const cur = projection.epics.get(id);
|
|
14108
|
-
if (!cur) break;
|
|
14109
|
-
if (evt.payload["title"] !== void 0) {
|
|
14110
|
-
cur.title = String(evt.payload["title"]);
|
|
14111
|
-
}
|
|
14112
|
-
if (evt.payload["body"] !== void 0) {
|
|
14113
|
-
cur.body = String(evt.payload["body"]);
|
|
14114
|
-
}
|
|
14115
|
-
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
14116
|
-
if (nextStatus !== void 0) {
|
|
14117
|
-
applyStatusIfChanged(cur, evt, nextStatus);
|
|
14118
|
-
}
|
|
14119
|
-
applyLastUpdate(cur, evt);
|
|
14120
|
-
break;
|
|
13980
|
+
if (!await localBranchRefExists(repoRoot, norm, git)) {
|
|
13981
|
+
return { branch: norm, preferred: preferredBase };
|
|
14121
13982
|
}
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
13983
|
+
}
|
|
13984
|
+
throw new Error(
|
|
13985
|
+
`Could not allocate a free local branch name from ${JSON.stringify(preferredBase)} (tried suffixes up to -${String(max)})`
|
|
13986
|
+
);
|
|
13987
|
+
};
|
|
13988
|
+
|
|
13989
|
+
// src/git/resolve-integration-start-point.ts
|
|
13990
|
+
var assertGitRefResolvable = async (repoRoot, ref, git) => {
|
|
13991
|
+
try {
|
|
13992
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", ref]);
|
|
13993
|
+
} catch {
|
|
13994
|
+
throw new Error(`Invalid or ambiguous --from ref: ${ref}`);
|
|
13995
|
+
}
|
|
13996
|
+
};
|
|
13997
|
+
var resolveIntegrationStartPoint = async (repoRoot, remote, git) => {
|
|
13998
|
+
const symRef = `refs/remotes/${remote}/HEAD`;
|
|
13999
|
+
try {
|
|
14000
|
+
const { stdout } = await git(repoRoot, ["symbolic-ref", "-q", symRef]);
|
|
14001
|
+
const target = stdout.trim();
|
|
14002
|
+
if (target !== "") {
|
|
14003
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", target]);
|
|
14004
|
+
return target;
|
|
14130
14005
|
}
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
body: String(evt.payload["body"] ?? ""),
|
|
14139
|
-
status,
|
|
14140
|
-
statusChangedAt: evt.ts,
|
|
14141
|
-
statusChangedBy: evt.actor,
|
|
14142
|
-
createdAt: "",
|
|
14143
|
-
createdBy: "",
|
|
14144
|
-
updatedAt: "",
|
|
14145
|
-
updatedBy: ""
|
|
14146
|
-
};
|
|
14147
|
-
applyCreatedAudit(row, evt);
|
|
14148
|
-
projection.stories.set(id, row);
|
|
14149
|
-
break;
|
|
14150
|
-
}
|
|
14151
|
-
case "StoryUpdated": {
|
|
14152
|
-
const id = String(evt.payload["id"]);
|
|
14153
|
-
const cur = projection.stories.get(id);
|
|
14154
|
-
if (!cur) break;
|
|
14155
|
-
if (evt.payload["title"] !== void 0) {
|
|
14156
|
-
cur.title = String(evt.payload["title"]);
|
|
14157
|
-
}
|
|
14158
|
-
if (evt.payload["body"] !== void 0) {
|
|
14159
|
-
cur.body = String(evt.payload["body"]);
|
|
14160
|
-
}
|
|
14161
|
-
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
14162
|
-
if (nextStatus !== void 0) {
|
|
14163
|
-
applyStatusIfChanged(cur, evt, nextStatus);
|
|
14164
|
-
}
|
|
14165
|
-
applyLastUpdate(cur, evt);
|
|
14166
|
-
break;
|
|
14006
|
+
} catch {
|
|
14007
|
+
}
|
|
14008
|
+
for (const head of ["refs/heads/main", "refs/heads/master"]) {
|
|
14009
|
+
try {
|
|
14010
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", head]);
|
|
14011
|
+
return head;
|
|
14012
|
+
} catch {
|
|
14167
14013
|
}
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14014
|
+
}
|
|
14015
|
+
try {
|
|
14016
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", "HEAD"]);
|
|
14017
|
+
return "HEAD";
|
|
14018
|
+
} catch {
|
|
14019
|
+
}
|
|
14020
|
+
throw new Error(
|
|
14021
|
+
"Could not resolve a default branch to branch from; pass --from <ref> (e.g. main or origin/main)."
|
|
14022
|
+
);
|
|
14023
|
+
};
|
|
14024
|
+
|
|
14025
|
+
// src/git/list-repo-commit-authors.ts
|
|
14026
|
+
var listRepoCommitAuthors = async (repoRoot, git) => {
|
|
14027
|
+
try {
|
|
14028
|
+
const { stdout } = await git(repoRoot, [
|
|
14029
|
+
"-c",
|
|
14030
|
+
"log.showSignature=false",
|
|
14031
|
+
"log",
|
|
14032
|
+
"--all",
|
|
14033
|
+
"--format=%an%x1f%ae"
|
|
14034
|
+
]);
|
|
14035
|
+
if (stdout === "") return [];
|
|
14036
|
+
const lines = stdout.split("\n").filter((l) => l.length > 0);
|
|
14037
|
+
const seenEmail = /* @__PURE__ */ new Set();
|
|
14038
|
+
const out = [];
|
|
14039
|
+
for (const line of lines) {
|
|
14040
|
+
const sep2 = line.indexOf("");
|
|
14041
|
+
if (sep2 <= 0) continue;
|
|
14042
|
+
const name = line.slice(0, sep2).trim();
|
|
14043
|
+
const email = line.slice(sep2 + 1).trim();
|
|
14044
|
+
if (email === "") continue;
|
|
14045
|
+
const key = email.toLowerCase();
|
|
14046
|
+
if (seenEmail.has(key)) continue;
|
|
14047
|
+
seenEmail.add(key);
|
|
14048
|
+
const loginGuess = guessGithubLoginFromContact(name, email);
|
|
14049
|
+
out.push(
|
|
14050
|
+
loginGuess !== void 0 ? { name, email, loginGuess } : { name, email }
|
|
14051
|
+
);
|
|
14176
14052
|
}
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14186
|
-
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
|
|
14193
|
-
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
applyTicketPlanningFieldsFromCreatePayload(row, evt.payload);
|
|
14200
|
-
projection.tickets.set(id, row);
|
|
14201
|
-
break;
|
|
14053
|
+
return out;
|
|
14054
|
+
} catch {
|
|
14055
|
+
return [];
|
|
14056
|
+
}
|
|
14057
|
+
};
|
|
14058
|
+
|
|
14059
|
+
// src/git/parse-github-owner-repo-from-remote-url.ts
|
|
14060
|
+
var parseGithubOwnerRepoFromRemoteUrl = (rawUrl) => {
|
|
14061
|
+
const trimmed = rawUrl.trim();
|
|
14062
|
+
if (!trimmed) {
|
|
14063
|
+
return void 0;
|
|
14064
|
+
}
|
|
14065
|
+
const scpMatch = /^git@github\.com:(?<path>.+)$/i.exec(trimmed);
|
|
14066
|
+
if (scpMatch?.groups?.path) {
|
|
14067
|
+
return slugFromGithubPath(scpMatch.groups.path);
|
|
14068
|
+
}
|
|
14069
|
+
try {
|
|
14070
|
+
const withScheme = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
|
|
14071
|
+
const u = new URL(withScheme);
|
|
14072
|
+
const host = u.hostname.toLowerCase();
|
|
14073
|
+
if (host !== "github.com" && host !== "www.github.com") {
|
|
14074
|
+
return void 0;
|
|
14202
14075
|
}
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14076
|
+
return slugFromGithubPath(u.pathname);
|
|
14077
|
+
} catch {
|
|
14078
|
+
return void 0;
|
|
14079
|
+
}
|
|
14080
|
+
};
|
|
14081
|
+
var slugFromGithubPath = (path) => {
|
|
14082
|
+
const segments = path.replace(/^\/+/, "").split("/").filter((s) => s.length > 0).map((s) => s.replace(/\.git$/i, ""));
|
|
14083
|
+
if (segments.length < 2) {
|
|
14084
|
+
return void 0;
|
|
14085
|
+
}
|
|
14086
|
+
const owner = segments[0];
|
|
14087
|
+
const repo = segments[1];
|
|
14088
|
+
if (!owner || !repo) {
|
|
14089
|
+
return void 0;
|
|
14090
|
+
}
|
|
14091
|
+
return `${owner}/${repo}`;
|
|
14092
|
+
};
|
|
14093
|
+
|
|
14094
|
+
// src/git/try-read-github-owner-repo-slug-from-git.ts
|
|
14095
|
+
var tryReadGithubOwnerRepoSlugFromGit = async (params) => {
|
|
14096
|
+
try {
|
|
14097
|
+
const { stdout } = await params.runGit(params.repoRoot, [
|
|
14098
|
+
"remote",
|
|
14099
|
+
"get-url",
|
|
14100
|
+
params.remote
|
|
14101
|
+
]);
|
|
14102
|
+
return parseGithubOwnerRepoFromRemoteUrl(stdout);
|
|
14103
|
+
} catch {
|
|
14104
|
+
return void 0;
|
|
14105
|
+
}
|
|
14106
|
+
};
|
|
14107
|
+
|
|
14108
|
+
// src/git/resolve-effective-git-author-for-data-commit.ts
|
|
14109
|
+
var defaultDataCommitName = "hyper-pm";
|
|
14110
|
+
var defaultDataCommitEmail = "hyper-pm@users.noreply.github.com";
|
|
14111
|
+
var tryReadGitConfigUserName = async (cwd, runGit2) => {
|
|
14112
|
+
try {
|
|
14113
|
+
const { stdout } = await runGit2(cwd, ["config", "--get", "user.name"]);
|
|
14114
|
+
return stdout.trim();
|
|
14115
|
+
} catch {
|
|
14116
|
+
return "";
|
|
14117
|
+
}
|
|
14118
|
+
};
|
|
14119
|
+
var tryReadGitConfigUserEmail = async (cwd, runGit2) => {
|
|
14120
|
+
try {
|
|
14121
|
+
const { stdout } = await runGit2(cwd, ["config", "--get", "user.email"]);
|
|
14122
|
+
return stdout.trim();
|
|
14123
|
+
} catch {
|
|
14124
|
+
return "";
|
|
14125
|
+
}
|
|
14126
|
+
};
|
|
14127
|
+
var resolveEffectiveGitAuthorForDataCommit = async (cwd, runGit2, authorEnv) => {
|
|
14128
|
+
const fromGitName = await tryReadGitConfigUserName(cwd, runGit2);
|
|
14129
|
+
const fromGitEmail = await tryReadGitConfigUserEmail(cwd, runGit2);
|
|
14130
|
+
const name = fromGitName || authorEnv.HYPER_PM_GIT_USER_NAME?.trim() || authorEnv.GIT_AUTHOR_NAME?.trim() || defaultDataCommitName;
|
|
14131
|
+
const email = fromGitEmail || authorEnv.HYPER_PM_GIT_USER_EMAIL?.trim() || authorEnv.GIT_AUTHOR_EMAIL?.trim() || defaultDataCommitEmail;
|
|
14132
|
+
return { name, email };
|
|
14133
|
+
};
|
|
14134
|
+
|
|
14135
|
+
// src/run/commit-data.ts
|
|
14136
|
+
var maxActorSuffixLen = 60;
|
|
14137
|
+
var formatDataBranchCommitMessage = (base, actorSuffix) => {
|
|
14138
|
+
const raw = actorSuffix?.trim();
|
|
14139
|
+
if (!raw) {
|
|
14140
|
+
return base;
|
|
14141
|
+
}
|
|
14142
|
+
const collapsed = raw.replace(/\s+/g, " ");
|
|
14143
|
+
const suffix = collapsed.length > maxActorSuffixLen ? `${collapsed.slice(0, maxActorSuffixLen - 1)}\u2026` : collapsed;
|
|
14144
|
+
return `${base} (${suffix})`;
|
|
14145
|
+
};
|
|
14146
|
+
var commitDataWorktreeIfNeeded = async (worktreePath, message, runGit2, opts) => {
|
|
14147
|
+
const { stdout } = await runGit2(worktreePath, ["status", "--porcelain"]);
|
|
14148
|
+
if (!stdout.trim()) return;
|
|
14149
|
+
await runGit2(worktreePath, ["add", "."]);
|
|
14150
|
+
const authorEnv = opts?.authorEnv ?? env;
|
|
14151
|
+
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
14152
|
+
worktreePath,
|
|
14153
|
+
runGit2,
|
|
14154
|
+
authorEnv
|
|
14155
|
+
);
|
|
14156
|
+
await runGit2(worktreePath, [
|
|
14157
|
+
"-c",
|
|
14158
|
+
`user.name=${name}`,
|
|
14159
|
+
"-c",
|
|
14160
|
+
`user.email=${email}`,
|
|
14161
|
+
"commit",
|
|
14162
|
+
"-m",
|
|
14163
|
+
message
|
|
14164
|
+
]);
|
|
14165
|
+
};
|
|
14166
|
+
|
|
14167
|
+
// src/run/push-data-branch.ts
|
|
14168
|
+
var firstLineFromUnknown = (err) => {
|
|
14169
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
14170
|
+
const line = raw.trim().split("\n")[0]?.trim() ?? raw.trim();
|
|
14171
|
+
return line.length > 0 ? line : "git error";
|
|
14172
|
+
};
|
|
14173
|
+
var tryPushDataBranchToRemote = async (worktreePath, remote, branch, runGit2) => {
|
|
14174
|
+
try {
|
|
14175
|
+
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
14176
|
+
} catch (e) {
|
|
14177
|
+
return {
|
|
14178
|
+
status: "skipped_no_remote",
|
|
14179
|
+
detail: firstLineFromUnknown(e)
|
|
14180
|
+
};
|
|
14181
|
+
}
|
|
14182
|
+
try {
|
|
14183
|
+
await runGit2(worktreePath, ["push", "-u", remote, branch]);
|
|
14184
|
+
return { status: "pushed" };
|
|
14185
|
+
} catch (e) {
|
|
14186
|
+
return {
|
|
14187
|
+
status: "failed",
|
|
14188
|
+
detail: firstLineFromUnknown(e)
|
|
14189
|
+
};
|
|
14190
|
+
}
|
|
14191
|
+
};
|
|
14192
|
+
|
|
14193
|
+
// src/run/sync-remote-data-branch.ts
|
|
14194
|
+
var SyncRemoteDataBranchMergeError = class extends Error {
|
|
14195
|
+
/** @param message - Human-readable reason (stderr excerpt or generic text). */
|
|
14196
|
+
constructor(message) {
|
|
14197
|
+
super(message);
|
|
14198
|
+
this.name = "SyncRemoteDataBranchMergeError";
|
|
14199
|
+
}
|
|
14200
|
+
};
|
|
14201
|
+
var remoteTrackingRef = (remote, dataBranch) => `refs/remotes/${remote}/${dataBranch}`;
|
|
14202
|
+
var mergeRefSpecifier = (remote, dataBranch) => `${remote}/${dataBranch}`;
|
|
14203
|
+
var isLikelyNonFastForwardPushFailure = (detail) => {
|
|
14204
|
+
if (detail === void 0) return false;
|
|
14205
|
+
const d = detail.toLowerCase();
|
|
14206
|
+
return d.includes("non-fast-forward") || d.includes("failed to push");
|
|
14207
|
+
};
|
|
14208
|
+
var classifyMergeOutput = (combined) => {
|
|
14209
|
+
const c = combined.toLowerCase();
|
|
14210
|
+
if (c.includes("already up to date")) {
|
|
14211
|
+
return "up_to_date";
|
|
14212
|
+
}
|
|
14213
|
+
if (c.includes("fast-forward")) {
|
|
14214
|
+
return "fast_forward";
|
|
14215
|
+
}
|
|
14216
|
+
return "merge_commit";
|
|
14217
|
+
};
|
|
14218
|
+
var refExists = async (cwd, ref, runGit2) => {
|
|
14219
|
+
try {
|
|
14220
|
+
await runGit2(cwd, ["show-ref", "--verify", "--quiet", ref]);
|
|
14221
|
+
return true;
|
|
14222
|
+
} catch {
|
|
14223
|
+
return false;
|
|
14224
|
+
}
|
|
14225
|
+
};
|
|
14226
|
+
var fetchRemoteDataBranch = async (worktreePath, remote, dataBranch, runGit2) => {
|
|
14227
|
+
try {
|
|
14228
|
+
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
14229
|
+
} catch {
|
|
14230
|
+
return "skipped_no_remote";
|
|
14231
|
+
}
|
|
14232
|
+
try {
|
|
14233
|
+
await runGit2(worktreePath, ["fetch", remote, dataBranch]);
|
|
14234
|
+
return "ok";
|
|
14235
|
+
} catch (e) {
|
|
14236
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14237
|
+
if (/couldn't find remote ref|could not find remote ref/i.test(msg)) {
|
|
14238
|
+
return "remote_branch_absent";
|
|
14224
14239
|
}
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14240
|
+
throw e;
|
|
14241
|
+
}
|
|
14242
|
+
};
|
|
14243
|
+
var mergeRemoteTrackingIntoHead = async (worktreePath, remote, dataBranch, runGit2, authorEnv = env) => {
|
|
14244
|
+
const spec = mergeRefSpecifier(remote, dataBranch);
|
|
14245
|
+
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
14246
|
+
worktreePath,
|
|
14247
|
+
runGit2,
|
|
14248
|
+
authorEnv
|
|
14249
|
+
);
|
|
14250
|
+
try {
|
|
14251
|
+
const { stdout, stderr } = await runGit2(worktreePath, [
|
|
14252
|
+
"-c",
|
|
14253
|
+
`user.name=${name}`,
|
|
14254
|
+
"-c",
|
|
14255
|
+
`user.email=${email}`,
|
|
14256
|
+
"merge",
|
|
14257
|
+
"--no-edit",
|
|
14258
|
+
spec
|
|
14259
|
+
]);
|
|
14260
|
+
return classifyMergeOutput(`${stdout}
|
|
14261
|
+
${stderr}`);
|
|
14262
|
+
} catch (e) {
|
|
14263
|
+
await runGit2(worktreePath, ["merge", "--abort"]).catch(() => {
|
|
14264
|
+
});
|
|
14265
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14266
|
+
throw new SyncRemoteDataBranchMergeError(
|
|
14267
|
+
msg.toLowerCase().includes("conflict") ? "Merge conflict while syncing hyper-pm data branch; merge aborted. Resolve manually on the data branch if needed." : `git merge failed: ${msg.trim().split("\n")[0] ?? msg}`
|
|
14268
|
+
);
|
|
14269
|
+
}
|
|
14270
|
+
};
|
|
14271
|
+
var runRemoteDataBranchGitSync = async (worktreePath, remote, dataBranch, runGit2, skipPush, deps = {}) => {
|
|
14272
|
+
const tryPushFn = deps.tryPush ?? tryPushDataBranchToRemote;
|
|
14273
|
+
const maxPushAttempts = deps.maxPushAttempts ?? 3;
|
|
14274
|
+
const authorEnv = deps.authorEnv ?? env;
|
|
14275
|
+
let dataBranchFetch = await fetchRemoteDataBranch(worktreePath, remote, dataBranch, runGit2);
|
|
14276
|
+
let dataBranchMerge = dataBranchFetch === "skipped_no_remote" ? "skipped_no_remote" : dataBranchFetch === "remote_branch_absent" ? "skipped_missing_remote_branch" : "up_to_date";
|
|
14277
|
+
if (dataBranchFetch === "ok") {
|
|
14278
|
+
const tracking = remoteTrackingRef(remote, dataBranch);
|
|
14279
|
+
const exists = await refExists(worktreePath, tracking, runGit2);
|
|
14280
|
+
if (!exists) {
|
|
14281
|
+
dataBranchMerge = "skipped_missing_remote_branch";
|
|
14282
|
+
} else {
|
|
14283
|
+
dataBranchMerge = await mergeRemoteTrackingIntoHead(
|
|
14284
|
+
worktreePath,
|
|
14285
|
+
remote,
|
|
14286
|
+
dataBranch,
|
|
14287
|
+
runGit2,
|
|
14288
|
+
authorEnv
|
|
14289
|
+
);
|
|
14233
14290
|
}
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14291
|
+
}
|
|
14292
|
+
if (skipPush) {
|
|
14293
|
+
return {
|
|
14294
|
+
dataBranchFetch,
|
|
14295
|
+
dataBranchMerge,
|
|
14296
|
+
dataBranchPush: "skipped_cli",
|
|
14297
|
+
dataBranchPushDetail: "skip-push",
|
|
14298
|
+
pushAttempts: 0
|
|
14299
|
+
};
|
|
14300
|
+
}
|
|
14301
|
+
let pushAttempts = 0;
|
|
14302
|
+
let lastPush = { status: "skipped_no_remote" };
|
|
14303
|
+
const refetchAndMerge = async () => {
|
|
14304
|
+
dataBranchFetch = await fetchRemoteDataBranch(
|
|
14305
|
+
worktreePath,
|
|
14306
|
+
remote,
|
|
14307
|
+
dataBranch,
|
|
14308
|
+
runGit2
|
|
14309
|
+
);
|
|
14310
|
+
if (dataBranchFetch !== "ok") {
|
|
14311
|
+
return;
|
|
14240
14312
|
}
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14313
|
+
const tracking = remoteTrackingRef(remote, dataBranch);
|
|
14314
|
+
const exists = await refExists(worktreePath, tracking, runGit2);
|
|
14315
|
+
if (!exists) {
|
|
14316
|
+
return;
|
|
14244
14317
|
}
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14318
|
+
dataBranchMerge = await mergeRemoteTrackingIntoHead(
|
|
14319
|
+
worktreePath,
|
|
14320
|
+
remote,
|
|
14321
|
+
dataBranch,
|
|
14322
|
+
runGit2,
|
|
14323
|
+
authorEnv
|
|
14324
|
+
);
|
|
14325
|
+
};
|
|
14326
|
+
for (let attempt = 1; attempt <= maxPushAttempts; attempt += 1) {
|
|
14327
|
+
pushAttempts = attempt;
|
|
14328
|
+
lastPush = await tryPushFn(worktreePath, remote, dataBranch, runGit2);
|
|
14329
|
+
if (lastPush.status === "pushed" || lastPush.status === "skipped_no_remote") {
|
|
14253
14330
|
break;
|
|
14254
14331
|
}
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
if (entity === "ticket") {
|
|
14259
|
-
const ticket = projection.tickets.get(entityId);
|
|
14260
|
-
if (!ticket) break;
|
|
14261
|
-
if (evt.payload["title"] !== void 0) {
|
|
14262
|
-
ticket.title = String(evt.payload["title"]);
|
|
14263
|
-
}
|
|
14264
|
-
if (evt.payload["body"] !== void 0) {
|
|
14265
|
-
ticket.body = String(evt.payload["body"]);
|
|
14266
|
-
ticket.linkedPrs = parsePrRefs(ticket.body);
|
|
14267
|
-
}
|
|
14268
|
-
const inboundStatus = resolveInboundTicketStatusFromPayload(
|
|
14269
|
-
ticket,
|
|
14270
|
-
evt.payload
|
|
14271
|
-
);
|
|
14272
|
-
if (inboundStatus !== void 0) {
|
|
14273
|
-
applyStatusIfChanged(ticket, evt, inboundStatus);
|
|
14274
|
-
}
|
|
14275
|
-
applyTicketAssigneeFromPayload(ticket, evt.payload);
|
|
14276
|
-
applyTicketPlanningFieldsFromUpdatePayload(ticket, evt.payload);
|
|
14277
|
-
applyLastUpdate(ticket, evt);
|
|
14278
|
-
}
|
|
14279
|
-
break;
|
|
14332
|
+
if (lastPush.status === "failed" && isLikelyNonFastForwardPushFailure(lastPush.detail) && attempt < maxPushAttempts) {
|
|
14333
|
+
await refetchAndMerge();
|
|
14334
|
+
continue;
|
|
14280
14335
|
}
|
|
14281
|
-
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14285
|
-
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14336
|
+
break;
|
|
14337
|
+
}
|
|
14338
|
+
return {
|
|
14339
|
+
dataBranchFetch,
|
|
14340
|
+
dataBranchMerge,
|
|
14341
|
+
dataBranchPush: lastPush.status,
|
|
14342
|
+
...lastPush.detail !== void 0 ? { dataBranchPushDetail: lastPush.detail } : {},
|
|
14343
|
+
pushAttempts
|
|
14344
|
+
};
|
|
14345
|
+
};
|
|
14346
|
+
|
|
14347
|
+
// src/storage/append-event.ts
|
|
14348
|
+
var import_promises5 = require("node:fs/promises");
|
|
14349
|
+
var import_node_path5 = require("node:path");
|
|
14350
|
+
|
|
14351
|
+
// src/storage/event-path.ts
|
|
14352
|
+
var nextEventRelPath = (now, deps) => {
|
|
14353
|
+
const y = String(now.getUTCFullYear());
|
|
14354
|
+
const m = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
14355
|
+
const nextId = deps?.nextId ?? (() => ulid().toLowerCase());
|
|
14356
|
+
const part = `part-${nextId()}`;
|
|
14357
|
+
return `events/${y}/${m}/${part}.jsonl`;
|
|
14358
|
+
};
|
|
14359
|
+
|
|
14360
|
+
// src/storage/append-event.ts
|
|
14361
|
+
var appendEventLine = async (dataRoot, event, clock, opts) => {
|
|
14362
|
+
const rel = nextEventRelPath(clock.now(), {
|
|
14363
|
+
nextId: opts?.nextEventId
|
|
14364
|
+
});
|
|
14365
|
+
const abs = `${dataRoot.replace(/\/$/, "")}/${rel}`;
|
|
14366
|
+
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(abs), { recursive: true });
|
|
14367
|
+
await (0, import_promises5.appendFile)(abs, `${JSON.stringify(event)}
|
|
14368
|
+
`, "utf8");
|
|
14369
|
+
return rel;
|
|
14370
|
+
};
|
|
14371
|
+
|
|
14372
|
+
// src/storage/read-event-lines.ts
|
|
14373
|
+
var import_promises6 = require("node:fs/promises");
|
|
14374
|
+
var import_node_path6 = require("node:path");
|
|
14375
|
+
var listJsonlFiles = async (dir, root) => {
|
|
14376
|
+
const out = [];
|
|
14377
|
+
const entries = await (0, import_promises6.readdir)(dir, { withFileTypes: true });
|
|
14378
|
+
for (const e of entries) {
|
|
14379
|
+
const abs = (0, import_node_path6.join)(dir, e.name);
|
|
14380
|
+
if (e.isDirectory()) {
|
|
14381
|
+
out.push(...await listJsonlFiles(abs, root));
|
|
14382
|
+
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
14383
|
+
out.push((0, import_node_path6.relative)(root, abs).split("\\").join("/"));
|
|
14294
14384
|
}
|
|
14295
|
-
default:
|
|
14296
|
-
break;
|
|
14297
14385
|
}
|
|
14386
|
+
return out;
|
|
14298
14387
|
};
|
|
14299
|
-
var
|
|
14300
|
-
const
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
events.push(eventLineSchema.parse(json));
|
|
14388
|
+
var readAllEventLines = async (dataRoot) => {
|
|
14389
|
+
const eventsRoot = (0, import_node_path6.join)(dataRoot, "events");
|
|
14390
|
+
let files = [];
|
|
14391
|
+
try {
|
|
14392
|
+
files = await listJsonlFiles(eventsRoot, dataRoot);
|
|
14393
|
+
} catch {
|
|
14394
|
+
return [];
|
|
14307
14395
|
}
|
|
14308
|
-
|
|
14309
|
-
|
|
14310
|
-
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14396
|
+
files.sort((a, b) => a.localeCompare(b));
|
|
14397
|
+
const lines = [];
|
|
14398
|
+
for (const rel of files) {
|
|
14399
|
+
const content = await (0, import_promises6.readFile)((0, import_node_path6.join)(dataRoot, rel), "utf8");
|
|
14400
|
+
for (const line of content.split("\n")) {
|
|
14401
|
+
if (line.trim()) lines.push(line);
|
|
14402
|
+
}
|
|
14315
14403
|
}
|
|
14316
|
-
return
|
|
14404
|
+
return lines;
|
|
14317
14405
|
};
|
|
14318
14406
|
|
|
14319
14407
|
// src/sync/collect-github-pr-activity-source-ids.ts
|
|
@@ -14873,14 +14961,15 @@ var parseCliWorkItemStatusList = (raws, deps) => {
|
|
|
14873
14961
|
}
|
|
14874
14962
|
return out;
|
|
14875
14963
|
};
|
|
14876
|
-
var buildTicketListQueryFromReadListOpts = (o, deps) => {
|
|
14964
|
+
var buildTicketListQueryFromReadListOpts = (projection, o, deps) => {
|
|
14877
14965
|
const query = {};
|
|
14878
14966
|
const statusTokens = normalizeCliStringList(o.status);
|
|
14879
14967
|
if (statusTokens.length > 0) {
|
|
14880
14968
|
query.statuses = parseCliWorkItemStatusList(statusTokens, deps);
|
|
14881
14969
|
}
|
|
14882
14970
|
if (o.epic !== void 0 && o.epic !== "") {
|
|
14883
|
-
|
|
14971
|
+
const trimmed = o.epic.trim();
|
|
14972
|
+
query.epicId = resolveEpicId(projection, trimmed) ?? trimmed;
|
|
14884
14973
|
}
|
|
14885
14974
|
const createdAfterMs = parseCliOptionalIsoMillis(
|
|
14886
14975
|
o.createdAfter,
|
|
@@ -15018,7 +15107,8 @@ var buildTicketListQueryFromReadListOpts = (o, deps) => {
|
|
|
15018
15107
|
query.targetFinishBeforeMs = targetFinishBeforeMs;
|
|
15019
15108
|
}
|
|
15020
15109
|
if (o.dependsOn !== void 0 && o.dependsOn.trim() !== "") {
|
|
15021
|
-
|
|
15110
|
+
const trimmed = o.dependsOn.trim();
|
|
15111
|
+
query.dependsOnIncludesId = resolveTicketId(projection, trimmed) ?? trimmed;
|
|
15022
15112
|
}
|
|
15023
15113
|
return Object.keys(query).length > 0 ? query : void 0;
|
|
15024
15114
|
};
|
|
@@ -15095,19 +15185,19 @@ var runCli = async (argv, deps = {
|
|
|
15095
15185
|
const g = readGlobals(this);
|
|
15096
15186
|
const o = this.opts();
|
|
15097
15187
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15188
|
+
const lines = await readAllEventLines(root);
|
|
15189
|
+
const proj = replayEvents(lines);
|
|
15098
15190
|
const id = o.id ?? ulid();
|
|
15099
15191
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15100
|
-
const
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
actor
|
|
15110
|
-
);
|
|
15192
|
+
const payload = {
|
|
15193
|
+
id,
|
|
15194
|
+
number: nextEpicNumberForCreate(proj),
|
|
15195
|
+
title: o.title,
|
|
15196
|
+
body: o.body,
|
|
15197
|
+
...status !== void 0 ? { status } : {}
|
|
15198
|
+
};
|
|
15199
|
+
assertCreatePayloadUsesExpectedHeadNumber(proj, "epic", payload);
|
|
15200
|
+
const evt = makeEvent("EpicCreated", payload, deps.clock, actor);
|
|
15111
15201
|
await appendEventLine(root, evt, deps.clock);
|
|
15112
15202
|
return evt.payload;
|
|
15113
15203
|
});
|
|
@@ -15123,18 +15213,19 @@ var runCli = async (argv, deps = {
|
|
|
15123
15213
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15124
15214
|
const lines = await readAllEventLines(root);
|
|
15125
15215
|
const proj = replayEvents(lines);
|
|
15126
|
-
const
|
|
15216
|
+
const epicId = resolveEpicId(proj, o.id) ?? o.id.trim();
|
|
15217
|
+
const cur = proj.epics.get(epicId);
|
|
15127
15218
|
if (!cur || cur.deleted) {
|
|
15128
15219
|
throw new Error(`Epic not found: ${o.id}`);
|
|
15129
15220
|
}
|
|
15130
15221
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15131
|
-
const draft = { id:
|
|
15222
|
+
const draft = { id: epicId };
|
|
15132
15223
|
if (o.title !== void 0) draft["title"] = o.title;
|
|
15133
15224
|
if (o.body !== void 0) draft["body"] = o.body;
|
|
15134
15225
|
if (status !== void 0) draft["status"] = status;
|
|
15135
15226
|
const payload = pruneEpicOrStoryUpdatePayloadAgainstRow(cur, draft);
|
|
15136
15227
|
if (isNoOpUpdatePayload(payload)) {
|
|
15137
|
-
return { id:
|
|
15228
|
+
return { id: epicId, noChanges: true };
|
|
15138
15229
|
}
|
|
15139
15230
|
const evt = makeEvent("EpicUpdated", payload, deps.clock, actor);
|
|
15140
15231
|
await appendEventLine(root, evt, deps.clock);
|
|
@@ -15145,9 +15236,12 @@ var runCli = async (argv, deps = {
|
|
|
15145
15236
|
const g = readGlobals(this);
|
|
15146
15237
|
const o = this.opts();
|
|
15147
15238
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15148
|
-
const
|
|
15239
|
+
const lines = await readAllEventLines(root);
|
|
15240
|
+
const proj = replayEvents(lines);
|
|
15241
|
+
const epicId = resolveEpicId(proj, o.id) ?? o.id.trim();
|
|
15242
|
+
const evt = makeEvent("EpicDeleted", { id: epicId }, deps.clock, actor);
|
|
15149
15243
|
await appendEventLine(root, evt, deps.clock);
|
|
15150
|
-
return { id:
|
|
15244
|
+
return { id: epicId, deleted: true };
|
|
15151
15245
|
});
|
|
15152
15246
|
});
|
|
15153
15247
|
const story = program2.command("story");
|
|
@@ -15160,24 +15254,23 @@ var runCli = async (argv, deps = {
|
|
|
15160
15254
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15161
15255
|
const lines = await readAllEventLines(root);
|
|
15162
15256
|
const proj = replayEvents(lines);
|
|
15163
|
-
const
|
|
15257
|
+
const epicId = resolveEpicId(proj, o.epic) ?? o.epic.trim();
|
|
15258
|
+
const epic2 = proj.epics.get(epicId);
|
|
15164
15259
|
if (!epic2 || epic2.deleted) {
|
|
15165
15260
|
throw new Error(`Epic not found: ${o.epic}`);
|
|
15166
15261
|
}
|
|
15167
15262
|
const id = o.id ?? ulid();
|
|
15168
15263
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15169
|
-
const
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
actor
|
|
15180
|
-
);
|
|
15264
|
+
const payload = {
|
|
15265
|
+
id,
|
|
15266
|
+
number: nextStoryNumberForCreate(proj),
|
|
15267
|
+
epicId,
|
|
15268
|
+
title: o.title,
|
|
15269
|
+
body: o.body,
|
|
15270
|
+
...status !== void 0 ? { status } : {}
|
|
15271
|
+
};
|
|
15272
|
+
assertCreatePayloadUsesExpectedHeadNumber(proj, "story", payload);
|
|
15273
|
+
const evt = makeEvent("StoryCreated", payload, deps.clock, actor);
|
|
15181
15274
|
await appendEventLine(root, evt, deps.clock);
|
|
15182
15275
|
return evt.payload;
|
|
15183
15276
|
});
|
|
@@ -15196,18 +15289,19 @@ var runCli = async (argv, deps = {
|
|
|
15196
15289
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15197
15290
|
const lines = await readAllEventLines(root);
|
|
15198
15291
|
const proj = replayEvents(lines);
|
|
15199
|
-
const
|
|
15292
|
+
const storyId = resolveStoryId(proj, o.id) ?? o.id.trim();
|
|
15293
|
+
const cur = proj.stories.get(storyId);
|
|
15200
15294
|
if (!cur || cur.deleted) {
|
|
15201
15295
|
throw new Error(`Story not found: ${o.id}`);
|
|
15202
15296
|
}
|
|
15203
15297
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15204
|
-
const draft = { id:
|
|
15298
|
+
const draft = { id: storyId };
|
|
15205
15299
|
if (o.title !== void 0) draft["title"] = o.title;
|
|
15206
15300
|
if (o.body !== void 0) draft["body"] = o.body;
|
|
15207
15301
|
if (status !== void 0) draft["status"] = status;
|
|
15208
15302
|
const payload = pruneEpicOrStoryUpdatePayloadAgainstRow(cur, draft);
|
|
15209
15303
|
if (isNoOpUpdatePayload(payload)) {
|
|
15210
|
-
return { id:
|
|
15304
|
+
return { id: storyId, noChanges: true };
|
|
15211
15305
|
}
|
|
15212
15306
|
const evt = makeEvent("StoryUpdated", payload, deps.clock, actor);
|
|
15213
15307
|
await appendEventLine(root, evt, deps.clock);
|
|
@@ -15218,9 +15312,17 @@ var runCli = async (argv, deps = {
|
|
|
15218
15312
|
const g = readGlobals(this);
|
|
15219
15313
|
const o = this.opts();
|
|
15220
15314
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15221
|
-
const
|
|
15315
|
+
const lines = await readAllEventLines(root);
|
|
15316
|
+
const proj = replayEvents(lines);
|
|
15317
|
+
const storyId = resolveStoryId(proj, o.id) ?? o.id.trim();
|
|
15318
|
+
const evt = makeEvent(
|
|
15319
|
+
"StoryDeleted",
|
|
15320
|
+
{ id: storyId },
|
|
15321
|
+
deps.clock,
|
|
15322
|
+
actor
|
|
15323
|
+
);
|
|
15222
15324
|
await appendEventLine(root, evt, deps.clock);
|
|
15223
|
-
return { id:
|
|
15325
|
+
return { id: storyId, deleted: true };
|
|
15224
15326
|
});
|
|
15225
15327
|
});
|
|
15226
15328
|
const ticket = program2.command("ticket");
|
|
@@ -15311,9 +15413,6 @@ var runCli = async (argv, deps = {
|
|
|
15311
15413
|
deps
|
|
15312
15414
|
);
|
|
15313
15415
|
const dependsOnTokensCreate = normalizeCliStringList(o.dependsOn);
|
|
15314
|
-
const dependsOnNormCreate = normalizeTicketDependsOnIds(
|
|
15315
|
-
dependsOnTokensCreate
|
|
15316
|
-
);
|
|
15317
15416
|
const planningPayload = {
|
|
15318
15417
|
...labelsPayloadCreate,
|
|
15319
15418
|
...priorityParsed !== void 0 ? { priority: priorityParsed } : {},
|
|
@@ -15327,16 +15426,21 @@ var runCli = async (argv, deps = {
|
|
|
15327
15426
|
const proj = replayEvents(lines);
|
|
15328
15427
|
const storyRaw = o.story;
|
|
15329
15428
|
const storyTrimmed = storyRaw !== void 0 && storyRaw !== "" ? storyRaw.trim() : void 0;
|
|
15429
|
+
const storyIdResolved = storyTrimmed !== void 0 ? resolveStoryId(proj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
15330
15430
|
if (storyTrimmed !== void 0) {
|
|
15331
|
-
const storyRow = proj.stories.get(
|
|
15431
|
+
const storyRow = proj.stories.get(storyIdResolved ?? "");
|
|
15332
15432
|
if (!storyRow || storyRow.deleted) {
|
|
15333
15433
|
throw new Error(`Story not found: ${storyTrimmed}`);
|
|
15334
15434
|
}
|
|
15335
15435
|
}
|
|
15336
15436
|
const id = o.id ?? ulid();
|
|
15437
|
+
const dependsOnNormCreate = resolveTicketDependsOnTokensToIds(
|
|
15438
|
+
proj,
|
|
15439
|
+
dependsOnTokensCreate
|
|
15440
|
+
);
|
|
15337
15441
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15338
15442
|
const assigneeCreate = o.assignee !== void 0 ? { assignee: normalizeGithubLogin(o.assignee) } : {};
|
|
15339
|
-
const storyPayload =
|
|
15443
|
+
const storyPayload = storyIdResolved !== void 0 ? { storyId: storyIdResolved } : {};
|
|
15340
15444
|
const branchTokens = normalizeCliStringList(o.branch);
|
|
15341
15445
|
const branchesNorm = normalizeTicketBranchListFromStrings(branchTokens);
|
|
15342
15446
|
const branchesPayload = branchesNorm.length > 0 ? { branches: branchesNorm } : {};
|
|
@@ -15349,19 +15453,26 @@ var runCli = async (argv, deps = {
|
|
|
15349
15453
|
throw new Error(dependsOnErr);
|
|
15350
15454
|
}
|
|
15351
15455
|
const dependsOnPayloadCreate = dependsOnNormCreate.length > 0 ? { dependsOn: dependsOnNormCreate } : {};
|
|
15456
|
+
const createPayload = {
|
|
15457
|
+
id,
|
|
15458
|
+
number: nextTicketNumberForCreate(proj),
|
|
15459
|
+
...storyPayload,
|
|
15460
|
+
title: o.title,
|
|
15461
|
+
body,
|
|
15462
|
+
...status !== void 0 ? { status } : {},
|
|
15463
|
+
...assigneeCreate,
|
|
15464
|
+
...branchesPayload,
|
|
15465
|
+
...dependsOnPayloadCreate,
|
|
15466
|
+
...planningPayload
|
|
15467
|
+
};
|
|
15468
|
+
assertCreatePayloadUsesExpectedHeadNumber(
|
|
15469
|
+
proj,
|
|
15470
|
+
"ticket",
|
|
15471
|
+
createPayload
|
|
15472
|
+
);
|
|
15352
15473
|
const evt = makeEvent(
|
|
15353
15474
|
"TicketCreated",
|
|
15354
|
-
|
|
15355
|
-
id,
|
|
15356
|
-
...storyPayload,
|
|
15357
|
-
title: o.title,
|
|
15358
|
-
body,
|
|
15359
|
-
...status !== void 0 ? { status } : {},
|
|
15360
|
-
...assigneeCreate,
|
|
15361
|
-
...branchesPayload,
|
|
15362
|
-
...dependsOnPayloadCreate,
|
|
15363
|
-
...planningPayload
|
|
15364
|
-
},
|
|
15475
|
+
createPayload,
|
|
15365
15476
|
deps.clock,
|
|
15366
15477
|
actor
|
|
15367
15478
|
);
|
|
@@ -15633,25 +15744,27 @@ ${body}`
|
|
|
15633
15744
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15634
15745
|
const lines = await readAllEventLines(root);
|
|
15635
15746
|
const proj = replayEvents(lines);
|
|
15747
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15748
|
+
const storyIdResolved = storyTrimmed !== void 0 ? resolveStoryId(proj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
15636
15749
|
if (storyTrimmed !== void 0) {
|
|
15637
|
-
const storyRow = proj.stories.get(
|
|
15750
|
+
const storyRow = proj.stories.get(storyIdResolved ?? "");
|
|
15638
15751
|
if (!storyRow || storyRow.deleted) {
|
|
15639
15752
|
throw new Error(`Story not found: ${storyTrimmed}`);
|
|
15640
15753
|
}
|
|
15641
15754
|
}
|
|
15642
|
-
const curTicket = proj.tickets.get(
|
|
15755
|
+
const curTicket = proj.tickets.get(ticketId);
|
|
15643
15756
|
if (curTicket === void 0 || curTicket.deleted) {
|
|
15644
15757
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15645
15758
|
}
|
|
15646
15759
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15647
|
-
const payload = { id:
|
|
15760
|
+
const payload = { id: ticketId };
|
|
15648
15761
|
if (o.title !== void 0) payload["title"] = o.title;
|
|
15649
15762
|
if (body !== void 0) payload["body"] = body;
|
|
15650
15763
|
if (status !== void 0) payload["status"] = status;
|
|
15651
15764
|
if (o.unlinkStory) {
|
|
15652
15765
|
payload["storyId"] = null;
|
|
15653
15766
|
} else if (storyTrimmed !== void 0) {
|
|
15654
|
-
payload["storyId"] =
|
|
15767
|
+
payload["storyId"] = storyIdResolved;
|
|
15655
15768
|
}
|
|
15656
15769
|
if (o.unassign) {
|
|
15657
15770
|
payload["assignee"] = null;
|
|
@@ -15708,19 +15821,19 @@ ${body}`
|
|
|
15708
15821
|
nextDepends = [];
|
|
15709
15822
|
} else {
|
|
15710
15823
|
const removeDepSet = new Set(
|
|
15711
|
-
|
|
15824
|
+
resolveTicketDependsOnTokensToIds(proj, removeDependsOnTokens)
|
|
15712
15825
|
);
|
|
15713
15826
|
nextDepends = normalizeTicketDependsOnIds(
|
|
15714
15827
|
(curTicket.dependsOn ?? []).filter((d) => !removeDepSet.has(d))
|
|
15715
15828
|
);
|
|
15716
15829
|
nextDepends = normalizeTicketDependsOnIds([
|
|
15717
15830
|
...nextDepends,
|
|
15718
|
-
...addDependsOnTokens
|
|
15831
|
+
...resolveTicketDependsOnTokensToIds(proj, addDependsOnTokens)
|
|
15719
15832
|
]);
|
|
15720
15833
|
}
|
|
15721
15834
|
const depErr = validateTicketDependsOnForWrite({
|
|
15722
15835
|
projection: proj,
|
|
15723
|
-
fromTicketId:
|
|
15836
|
+
fromTicketId: ticketId,
|
|
15724
15837
|
nextDependsOn: nextDepends
|
|
15725
15838
|
});
|
|
15726
15839
|
if (depErr !== void 0) {
|
|
@@ -15750,7 +15863,7 @@ ${body}`
|
|
|
15750
15863
|
payload
|
|
15751
15864
|
);
|
|
15752
15865
|
if (isNoOpUpdatePayload(prunedPayload)) {
|
|
15753
|
-
return { id:
|
|
15866
|
+
return { id: ticketId, noChanges: true };
|
|
15754
15867
|
}
|
|
15755
15868
|
const evt = makeEvent(
|
|
15756
15869
|
"TicketUpdated",
|
|
@@ -15787,25 +15900,25 @@ ${body}`
|
|
|
15787
15900
|
runGit
|
|
15788
15901
|
);
|
|
15789
15902
|
}
|
|
15790
|
-
const preferred = normalizeTicketBranchName(
|
|
15791
|
-
o.branch ?? `hyper-pm/${o.id}`
|
|
15792
|
-
);
|
|
15793
|
-
if (preferred === void 0) {
|
|
15794
|
-
deps.error(
|
|
15795
|
-
"Invalid --branch or default branch name for this ticket id"
|
|
15796
|
-
);
|
|
15797
|
-
deps.exit(ExitCode.UserError);
|
|
15798
|
-
}
|
|
15799
15903
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15800
15904
|
const lines = await readAllEventLines(root);
|
|
15801
15905
|
const proj = replayEvents(lines);
|
|
15802
|
-
const
|
|
15906
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15907
|
+
const preferred = normalizeTicketBranchName(
|
|
15908
|
+
o.branch ?? `hyper-pm/${ticketId}`
|
|
15909
|
+
);
|
|
15910
|
+
if (preferred === void 0) {
|
|
15911
|
+
throw new Error(
|
|
15912
|
+
"Invalid --branch or default branch name for this ticket id"
|
|
15913
|
+
);
|
|
15914
|
+
}
|
|
15915
|
+
const curRow = proj.tickets.get(ticketId);
|
|
15803
15916
|
if (curRow === void 0 || curRow.deleted) {
|
|
15804
15917
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15805
15918
|
}
|
|
15806
15919
|
if (curRow.status === "done" || curRow.status === "cancelled") {
|
|
15807
15920
|
throw new Error(
|
|
15808
|
-
`Ticket ${
|
|
15921
|
+
`Ticket ${ticketId} is ${curRow.status}; change status before starting work`
|
|
15809
15922
|
);
|
|
15810
15923
|
}
|
|
15811
15924
|
const { branch: chosenBranch } = await pickUniqueLocalBranchName({
|
|
@@ -15826,7 +15939,7 @@ ${body}`
|
|
|
15826
15939
|
}
|
|
15827
15940
|
next = normalizeTicketBranchListFromStrings(next);
|
|
15828
15941
|
const payload = {
|
|
15829
|
-
id:
|
|
15942
|
+
id: ticketId,
|
|
15830
15943
|
status: "in_progress"
|
|
15831
15944
|
};
|
|
15832
15945
|
if (!ticketBranchListsEqual(next, curRow.linkedBranches)) {
|
|
@@ -15835,7 +15948,7 @@ ${body}`
|
|
|
15835
15948
|
const evt = makeEvent("TicketUpdated", payload, deps.clock, actor);
|
|
15836
15949
|
await appendEventLine(root, evt, deps.clock);
|
|
15837
15950
|
const result = {
|
|
15838
|
-
id:
|
|
15951
|
+
id: ticketId,
|
|
15839
15952
|
status: "in_progress",
|
|
15840
15953
|
branch: chosenBranch,
|
|
15841
15954
|
branches: next
|
|
@@ -15857,27 +15970,36 @@ ${body}`
|
|
|
15857
15970
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15858
15971
|
const lines = await readAllEventLines(root);
|
|
15859
15972
|
const proj = replayEvents(lines);
|
|
15860
|
-
const
|
|
15973
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15974
|
+
const row = proj.tickets.get(ticketId);
|
|
15861
15975
|
if (!row || row.deleted) {
|
|
15862
15976
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15863
15977
|
}
|
|
15864
15978
|
const evt = makeEvent(
|
|
15865
15979
|
"TicketCommentAdded",
|
|
15866
|
-
{ ticketId
|
|
15980
|
+
{ ticketId, body: trimmed },
|
|
15867
15981
|
deps.clock,
|
|
15868
15982
|
actor
|
|
15869
15983
|
);
|
|
15870
15984
|
await appendEventLine(root, evt, deps.clock);
|
|
15871
|
-
return { commentId: evt.id, ticketId
|
|
15985
|
+
return { commentId: evt.id, ticketId, body: trimmed };
|
|
15872
15986
|
});
|
|
15873
15987
|
});
|
|
15874
15988
|
ticket.command("delete").requiredOption("--id <id>").action(async function() {
|
|
15875
15989
|
const g = readGlobals(this);
|
|
15876
15990
|
const o = this.opts();
|
|
15877
15991
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15878
|
-
const
|
|
15992
|
+
const lines = await readAllEventLines(root);
|
|
15993
|
+
const proj = replayEvents(lines);
|
|
15994
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15995
|
+
const evt = makeEvent(
|
|
15996
|
+
"TicketDeleted",
|
|
15997
|
+
{ id: ticketId },
|
|
15998
|
+
deps.clock,
|
|
15999
|
+
actor
|
|
16000
|
+
);
|
|
15879
16001
|
await appendEventLine(root, evt, deps.clock);
|
|
15880
|
-
return { id:
|
|
16002
|
+
return { id: ticketId, deleted: true };
|
|
15881
16003
|
});
|
|
15882
16004
|
});
|
|
15883
16005
|
ticket.command("import-github").description(
|
|
@@ -15948,7 +16070,8 @@ ${body}`
|
|
|
15948
16070
|
const storyRaw = o.story;
|
|
15949
16071
|
const storyTrimmed = storyRaw !== void 0 && storyRaw !== "" ? storyRaw.trim() : void 0;
|
|
15950
16072
|
if (storyTrimmed !== void 0 && storyTrimmed !== "") {
|
|
15951
|
-
const
|
|
16073
|
+
const storyIdForImport = resolveStoryId(proj, storyTrimmed) ?? storyTrimmed;
|
|
16074
|
+
const storyRow = proj.stories.get(storyIdForImport);
|
|
15952
16075
|
if (!storyRow || storyRow.deleted) {
|
|
15953
16076
|
deps.error(`Story not found: ${storyTrimmed}`);
|
|
15954
16077
|
deps.exit(ExitCode.UserError);
|
|
@@ -15991,12 +16114,22 @@ ${body}`
|
|
|
15991
16114
|
);
|
|
15992
16115
|
} else {
|
|
15993
16116
|
const imported = [];
|
|
16117
|
+
let importProj = proj;
|
|
16118
|
+
let importLines = lines;
|
|
16119
|
+
const storyIdForPayload = storyTrimmed !== void 0 && storyTrimmed !== "" ? resolveStoryId(importProj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
15994
16120
|
for (const c of candidates) {
|
|
15995
16121
|
const ticketId = ulid();
|
|
16122
|
+
const nextNum = nextTicketNumberForCreate(importProj);
|
|
15996
16123
|
const createPayload = mergeTicketImportCreatePayload(
|
|
15997
16124
|
ticketId,
|
|
15998
16125
|
c.ticketCreatedPayloadBase,
|
|
15999
|
-
|
|
16126
|
+
storyIdForPayload,
|
|
16127
|
+
nextNum
|
|
16128
|
+
);
|
|
16129
|
+
assertCreatePayloadUsesExpectedHeadNumber(
|
|
16130
|
+
importProj,
|
|
16131
|
+
"ticket",
|
|
16132
|
+
createPayload
|
|
16000
16133
|
);
|
|
16001
16134
|
const createdEvt = makeEvent(
|
|
16002
16135
|
"TicketCreated",
|
|
@@ -16017,6 +16150,8 @@ ${body}`
|
|
|
16017
16150
|
);
|
|
16018
16151
|
await appendEventLine(session.worktreePath, linkEvt, deps.clock);
|
|
16019
16152
|
imported.push({ ticketId, issueNumber: c.issueNumber });
|
|
16153
|
+
importLines = await readAllEventLines(session.worktreePath);
|
|
16154
|
+
importProj = replayEvents(importLines);
|
|
16020
16155
|
}
|
|
16021
16156
|
await commitDataWorktreeIfNeeded(
|
|
16022
16157
|
session.worktreePath,
|
|
@@ -16484,7 +16619,8 @@ var readEpic = async (g, id, deps) => {
|
|
|
16484
16619
|
formatOutput(g.format, { items: listActiveEpicSummaries(proj) })
|
|
16485
16620
|
);
|
|
16486
16621
|
} else {
|
|
16487
|
-
const
|
|
16622
|
+
const epicId = resolveEpicId(proj, id) ?? id.trim();
|
|
16623
|
+
const row = proj.epics.get(epicId);
|
|
16488
16624
|
if (!row || row.deleted) {
|
|
16489
16625
|
deps.error("Epic not found");
|
|
16490
16626
|
exitCode = ExitCode.UserError;
|
|
@@ -16519,7 +16655,8 @@ var readStory = async (g, opts, deps) => {
|
|
|
16519
16655
|
const proj = replayEvents(lines);
|
|
16520
16656
|
const { id, epicId } = opts;
|
|
16521
16657
|
if (id === void 0 || id === "") {
|
|
16522
|
-
const
|
|
16658
|
+
const epicFilterRaw = epicId !== void 0 && epicId !== "" ? epicId : void 0;
|
|
16659
|
+
const epicFilter = epicFilterRaw !== void 0 ? resolveEpicId(proj, epicFilterRaw) ?? epicFilterRaw.trim() : void 0;
|
|
16523
16660
|
if (epicFilter !== void 0) {
|
|
16524
16661
|
const epicRow = proj.epics.get(epicFilter);
|
|
16525
16662
|
if (!epicRow || epicRow.deleted) {
|
|
@@ -16540,7 +16677,8 @@ var readStory = async (g, opts, deps) => {
|
|
|
16540
16677
|
);
|
|
16541
16678
|
}
|
|
16542
16679
|
} else {
|
|
16543
|
-
const
|
|
16680
|
+
const storyId = resolveStoryId(proj, id) ?? id.trim();
|
|
16681
|
+
const row = proj.stories.get(storyId);
|
|
16544
16682
|
if (!row || row.deleted) {
|
|
16545
16683
|
deps.error("Story not found");
|
|
16546
16684
|
exitCode = ExitCode.UserError;
|
|
@@ -16584,8 +16722,8 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16584
16722
|
} = opts;
|
|
16585
16723
|
if (id === void 0 || id === "") {
|
|
16586
16724
|
const listWithoutStory = withoutStoryRaw === true;
|
|
16587
|
-
const storyFilter = storyIdRaw !== void 0 && storyIdRaw !== "" ? storyIdRaw : void 0;
|
|
16588
|
-
const epicFilter = epicIdRaw !== void 0 && epicIdRaw !== "" ? epicIdRaw : void 0;
|
|
16725
|
+
const storyFilter = storyIdRaw !== void 0 && storyIdRaw !== "" ? resolveStoryId(proj, storyIdRaw) ?? storyIdRaw.trim() : void 0;
|
|
16726
|
+
const epicFilter = epicIdRaw !== void 0 && epicIdRaw !== "" ? resolveEpicId(proj, epicIdRaw) ?? epicIdRaw.trim() : void 0;
|
|
16589
16727
|
const sortBy = tryParseTicketListSortField(sortByOpt);
|
|
16590
16728
|
const sortDir = tryParseTicketListSortDir(sortDirOpt);
|
|
16591
16729
|
if (sortBy === void 0) {
|
|
@@ -16624,6 +16762,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16624
16762
|
exitCode = ExitCode.UserError;
|
|
16625
16763
|
} else {
|
|
16626
16764
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16765
|
+
proj,
|
|
16627
16766
|
{ epic: epicFilter, ...listFlagRest },
|
|
16628
16767
|
deps
|
|
16629
16768
|
);
|
|
@@ -16644,6 +16783,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16644
16783
|
exitCode = ExitCode.UserError;
|
|
16645
16784
|
} else {
|
|
16646
16785
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16786
|
+
proj,
|
|
16647
16787
|
listFlagRest,
|
|
16648
16788
|
deps
|
|
16649
16789
|
);
|
|
@@ -16660,6 +16800,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16660
16800
|
}
|
|
16661
16801
|
} else if (listWithoutStory) {
|
|
16662
16802
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16803
|
+
proj,
|
|
16663
16804
|
{ withoutStory: true, ...listFlagRest },
|
|
16664
16805
|
deps
|
|
16665
16806
|
);
|
|
@@ -16674,6 +16815,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16674
16815
|
);
|
|
16675
16816
|
} else {
|
|
16676
16817
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16818
|
+
proj,
|
|
16677
16819
|
{ epic: epicFilter, ...listFlagRest },
|
|
16678
16820
|
deps
|
|
16679
16821
|
);
|
|
@@ -16688,7 +16830,8 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16688
16830
|
);
|
|
16689
16831
|
}
|
|
16690
16832
|
} else {
|
|
16691
|
-
const
|
|
16833
|
+
const ticketId = resolveTicketId(proj, id) ?? id.trim();
|
|
16834
|
+
const row = proj.tickets.get(ticketId);
|
|
16692
16835
|
if (!row || row.deleted) {
|
|
16693
16836
|
deps.error("Ticket not found");
|
|
16694
16837
|
exitCode = ExitCode.UserError;
|