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/index.cjs
CHANGED
|
@@ -12782,6 +12782,7 @@ var sortTicketRecordsForList = (tickets, field, dir) => [...tickets].sort((x, y)
|
|
|
12782
12782
|
// src/cli/list-projection-summaries.ts
|
|
12783
12783
|
var listActiveEpicSummaries = (projection) => [...projection.epics.values()].filter((e) => !e.deleted).map((e) => ({
|
|
12784
12784
|
id: e.id,
|
|
12785
|
+
number: e.number,
|
|
12785
12786
|
title: e.title,
|
|
12786
12787
|
status: e.status,
|
|
12787
12788
|
createdAt: e.createdAt,
|
|
@@ -12793,6 +12794,7 @@ var listActiveStorySummaries = (projection, options) => [...projection.stories.v
|
|
|
12793
12794
|
(s) => !s.deleted && (options?.epicId === void 0 || s.epicId === options.epicId)
|
|
12794
12795
|
).map((s) => ({
|
|
12795
12796
|
id: s.id,
|
|
12797
|
+
number: s.number,
|
|
12796
12798
|
title: s.title,
|
|
12797
12799
|
epicId: s.epicId,
|
|
12798
12800
|
status: s.status,
|
|
@@ -12825,6 +12827,7 @@ var listActiveTicketSummaries = (projection, options) => {
|
|
|
12825
12827
|
const last = recent !== void 0 && recent.length > 0 ? recent[recent.length - 1] : void 0;
|
|
12826
12828
|
return {
|
|
12827
12829
|
id: t.id,
|
|
12830
|
+
number: t.number,
|
|
12828
12831
|
title: t.title,
|
|
12829
12832
|
status: t.status,
|
|
12830
12833
|
storyId: t.storyId,
|
|
@@ -13193,1137 +13196,1222 @@ var partitionGithubIssuesForImport = (params) => {
|
|
|
13193
13196
|
}
|
|
13194
13197
|
return { candidates, skipped };
|
|
13195
13198
|
};
|
|
13196
|
-
var mergeTicketImportCreatePayload = (ticketId, base, storyId) => {
|
|
13199
|
+
var mergeTicketImportCreatePayload = (ticketId, base, storyId, number) => {
|
|
13197
13200
|
const storyTrimmed = storyId !== void 0 && storyId !== "" ? storyId.trim() : void 0;
|
|
13198
13201
|
const storyPayload = storyTrimmed !== void 0 && storyTrimmed !== "" ? { storyId: storyTrimmed } : {};
|
|
13199
|
-
return { id: ticketId, ...base, ...storyPayload };
|
|
13202
|
+
return { id: ticketId, number, ...base, ...storyPayload };
|
|
13200
13203
|
};
|
|
13201
13204
|
|
|
13202
|
-
// src/
|
|
13203
|
-
var
|
|
13204
|
-
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
var
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
const
|
|
13222
|
-
const
|
|
13223
|
-
const
|
|
13224
|
-
const
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
const
|
|
13229
|
-
|
|
13230
|
-
|
|
13205
|
+
// src/lib/github-pr-activity.ts
|
|
13206
|
+
var GITHUB_PR_ACTIVITY_RECENT_CAP = 20;
|
|
13207
|
+
var githubPrActivityKindSchema = external_exports.enum([
|
|
13208
|
+
"opened",
|
|
13209
|
+
"updated",
|
|
13210
|
+
"commented",
|
|
13211
|
+
"reviewed",
|
|
13212
|
+
"merged",
|
|
13213
|
+
"closed",
|
|
13214
|
+
"ready_for_review"
|
|
13215
|
+
]);
|
|
13216
|
+
var githubPrReviewStateSchema = external_exports.enum([
|
|
13217
|
+
"approved",
|
|
13218
|
+
"changes_requested",
|
|
13219
|
+
"commented"
|
|
13220
|
+
]);
|
|
13221
|
+
var buildPrOpenSourceId = (ticketId, prNumber) => `hyper-pm:pr-open:${ticketId}:${prNumber}`;
|
|
13222
|
+
var parseGithubPrActivityPayload = (payload) => {
|
|
13223
|
+
const ticketId = payload["ticketId"];
|
|
13224
|
+
const prRaw = payload["prNumber"];
|
|
13225
|
+
const kindRaw = payload["kind"];
|
|
13226
|
+
const occurredAt = payload["occurredAt"];
|
|
13227
|
+
const sourceId = payload["sourceId"];
|
|
13228
|
+
if (typeof ticketId !== "string" || typeof occurredAt !== "string" || typeof sourceId !== "string") {
|
|
13229
|
+
return void 0;
|
|
13230
|
+
}
|
|
13231
|
+
const prNumber = typeof prRaw === "number" ? prRaw : Number(prRaw);
|
|
13232
|
+
if (!Number.isFinite(prNumber)) return void 0;
|
|
13233
|
+
const kindParsed = githubPrActivityKindSchema.safeParse(kindRaw);
|
|
13234
|
+
if (!kindParsed.success) return void 0;
|
|
13235
|
+
const out = {
|
|
13236
|
+
prNumber,
|
|
13237
|
+
kind: kindParsed.data,
|
|
13238
|
+
occurredAt,
|
|
13239
|
+
sourceId
|
|
13240
|
+
};
|
|
13241
|
+
const url = payload["url"];
|
|
13242
|
+
if (typeof url === "string" && url.length > 0) {
|
|
13243
|
+
out.url = url;
|
|
13244
|
+
}
|
|
13245
|
+
const rs = githubPrReviewStateSchema.safeParse(payload["reviewState"]);
|
|
13246
|
+
if (rs.success) {
|
|
13247
|
+
out.reviewState = rs.data;
|
|
13231
13248
|
}
|
|
13232
13249
|
return out;
|
|
13233
13250
|
};
|
|
13234
13251
|
|
|
13235
|
-
// src/
|
|
13236
|
-
var
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13242
|
-
|
|
13252
|
+
// src/storage/projection.ts
|
|
13253
|
+
var readOptionalPositiveIntegerFromPayload = (payload, key) => {
|
|
13254
|
+
if (!Object.prototype.hasOwnProperty.call(payload, key)) return void 0;
|
|
13255
|
+
const raw = payload[key];
|
|
13256
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return void 0;
|
|
13257
|
+
if (!Number.isInteger(raw)) return void 0;
|
|
13258
|
+
if (raw < 1 || raw > Number.MAX_SAFE_INTEGER) return void 0;
|
|
13259
|
+
return raw;
|
|
13260
|
+
};
|
|
13261
|
+
var maxNumberAmongRows = (rows) => {
|
|
13262
|
+
let m = 0;
|
|
13263
|
+
for (const r of rows) {
|
|
13264
|
+
if (r.number > m) m = r.number;
|
|
13265
|
+
}
|
|
13266
|
+
return m;
|
|
13267
|
+
};
|
|
13268
|
+
var maxEpicNumberInProjection = (projection) => maxNumberAmongRows(projection.epics.values());
|
|
13269
|
+
var maxStoryNumberInProjection = (projection) => maxNumberAmongRows(projection.stories.values());
|
|
13270
|
+
var maxTicketNumberInProjection = (projection) => maxNumberAmongRows(projection.tickets.values());
|
|
13271
|
+
var nextEpicNumberForCreate = (projection) => maxEpicNumberInProjection(projection) + 1;
|
|
13272
|
+
var nextStoryNumberForCreate = (projection) => maxStoryNumberInProjection(projection) + 1;
|
|
13273
|
+
var nextTicketNumberForCreate = (projection) => maxTicketNumberInProjection(projection) + 1;
|
|
13274
|
+
var resolveWorkItemCreateNumber = (projection, kind, payload) => {
|
|
13275
|
+
const explicit = readOptionalPositiveIntegerFromPayload(payload, "number");
|
|
13276
|
+
if (explicit !== void 0) {
|
|
13277
|
+
return explicit;
|
|
13278
|
+
}
|
|
13279
|
+
return (kind === "epic" ? maxEpicNumberInProjection(projection) : kind === "story" ? maxStoryNumberInProjection(projection) : maxTicketNumberInProjection(projection)) + 1;
|
|
13243
13280
|
};
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
kind: "invalid-json",
|
|
13257
|
-
line: i + 1,
|
|
13258
|
-
message: e instanceof Error ? e.message : "parse error"
|
|
13259
|
-
});
|
|
13260
|
-
return issues;
|
|
13261
|
-
}
|
|
13262
|
-
const parsed = eventLineSchema.safeParse(json);
|
|
13263
|
-
if (!parsed.success) {
|
|
13264
|
-
issues.push({
|
|
13265
|
-
kind: "invalid-event",
|
|
13266
|
-
line: i + 1,
|
|
13267
|
-
message: parsed.error.message
|
|
13268
|
-
});
|
|
13269
|
-
return issues;
|
|
13270
|
-
}
|
|
13281
|
+
var emptyProjection = () => ({
|
|
13282
|
+
epics: /* @__PURE__ */ new Map(),
|
|
13283
|
+
stories: /* @__PURE__ */ new Map(),
|
|
13284
|
+
tickets: /* @__PURE__ */ new Map()
|
|
13285
|
+
});
|
|
13286
|
+
var parsePrRefs = (body) => {
|
|
13287
|
+
const out = /* @__PURE__ */ new Set();
|
|
13288
|
+
const re = /\b(?:Closes|Refs|Fixes)\s+#(\d+)\b/gi;
|
|
13289
|
+
let m = re.exec(body);
|
|
13290
|
+
while (m !== null) {
|
|
13291
|
+
out.add(Number(m[1]));
|
|
13292
|
+
m = re.exec(body);
|
|
13271
13293
|
}
|
|
13272
|
-
return
|
|
13273
|
-
};
|
|
13274
|
-
|
|
13275
|
-
// src/git/create-and-checkout-branch.ts
|
|
13276
|
-
var createAndCheckoutBranch = async (opts) => {
|
|
13277
|
-
await opts.runGit(opts.repoRoot, [
|
|
13278
|
-
"switch",
|
|
13279
|
-
"-c",
|
|
13280
|
-
opts.branchName,
|
|
13281
|
-
opts.startPoint
|
|
13282
|
-
]);
|
|
13283
|
-
};
|
|
13284
|
-
|
|
13285
|
-
// src/git/data-worktree-session.ts
|
|
13286
|
-
var import_promises3 = require("node:fs/promises");
|
|
13287
|
-
var import_node_path3 = require("node:path");
|
|
13288
|
-
var ensureDir = async (path) => {
|
|
13289
|
-
await (0, import_promises3.mkdir)(path, { recursive: true });
|
|
13294
|
+
return [...out];
|
|
13290
13295
|
};
|
|
13291
|
-
var
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
return
|
|
13296
|
+
var applyTicketAssigneeFromPayload = (row, payload) => {
|
|
13297
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "assignee")) return;
|
|
13298
|
+
const v = payload["assignee"];
|
|
13299
|
+
if (v === null) {
|
|
13300
|
+
delete row.assignee;
|
|
13301
|
+
return;
|
|
13297
13302
|
}
|
|
13303
|
+
if (typeof v !== "string") return;
|
|
13304
|
+
const n = normalizeGithubLogin(v);
|
|
13305
|
+
if (n === "") delete row.assignee;
|
|
13306
|
+
else row.assignee = n;
|
|
13298
13307
|
};
|
|
13299
|
-
var
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
for (const block of blocks) {
|
|
13303
|
-
const lines = block.split("\n");
|
|
13304
|
-
let worktreePath;
|
|
13305
|
-
let branch;
|
|
13306
|
-
for (const line of lines) {
|
|
13307
|
-
if (line.startsWith("worktree ")) {
|
|
13308
|
-
worktreePath = line.slice("worktree ".length);
|
|
13309
|
-
} else if (line.startsWith("branch ")) {
|
|
13310
|
-
branch = line.slice("branch ".length);
|
|
13311
|
-
}
|
|
13312
|
-
}
|
|
13313
|
-
if (worktreePath !== void 0 && branch === wantRef) {
|
|
13314
|
-
return worktreePath;
|
|
13315
|
-
}
|
|
13308
|
+
var storyIdFromTicketCreatedPayload = (payload) => {
|
|
13309
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "storyId")) {
|
|
13310
|
+
return null;
|
|
13316
13311
|
}
|
|
13317
|
-
|
|
13312
|
+
const v = payload["storyId"];
|
|
13313
|
+
if (v === null) return null;
|
|
13314
|
+
if (typeof v !== "string") return null;
|
|
13315
|
+
const t = v.trim();
|
|
13316
|
+
return t === "" ? null : t;
|
|
13318
13317
|
};
|
|
13319
|
-
var
|
|
13320
|
-
|
|
13321
|
-
const
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
]);
|
|
13326
|
-
const listedPath = parseDataBranchWorktreeFromPorcelain(
|
|
13327
|
-
listOut,
|
|
13328
|
-
opts.dataBranch
|
|
13329
|
-
);
|
|
13330
|
-
if (listedPath !== void 0 && await pathExists(listedPath)) {
|
|
13331
|
-
const dispose2 = async () => {
|
|
13332
|
-
return;
|
|
13333
|
-
};
|
|
13334
|
-
return { worktreePath: listedPath, dispose: dispose2 };
|
|
13318
|
+
var applyTicketStoryIdFromPayload = (row, payload) => {
|
|
13319
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "storyId")) return;
|
|
13320
|
+
const v = payload["storyId"];
|
|
13321
|
+
if (v === null) {
|
|
13322
|
+
row.storyId = null;
|
|
13323
|
+
return;
|
|
13335
13324
|
}
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
|
|
13343
|
-
"worktree",
|
|
13344
|
-
"add",
|
|
13345
|
-
worktreePath,
|
|
13346
|
-
opts.dataBranch
|
|
13347
|
-
]);
|
|
13348
|
-
} catch (err) {
|
|
13349
|
-
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13350
|
-
});
|
|
13351
|
-
throw err;
|
|
13325
|
+
if (typeof v !== "string") return;
|
|
13326
|
+
const t = v.trim();
|
|
13327
|
+
row.storyId = t === "" ? null : t;
|
|
13328
|
+
};
|
|
13329
|
+
var linkedBranchesFromTicketCreatedPayload = (payload) => {
|
|
13330
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) {
|
|
13331
|
+
return [];
|
|
13352
13332
|
}
|
|
13353
|
-
|
|
13354
|
-
if (opts.keepWorktree) {
|
|
13355
|
-
return;
|
|
13356
|
-
}
|
|
13357
|
-
await opts.runGit(opts.repoRoot, ["worktree", "remove", "--force", worktreePath]).catch(() => {
|
|
13358
|
-
});
|
|
13359
|
-
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13360
|
-
});
|
|
13361
|
-
};
|
|
13362
|
-
return { worktreePath, dispose };
|
|
13333
|
+
return normalizeTicketBranchListFromPayloadValue(payload["branches"]);
|
|
13363
13334
|
};
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13335
|
+
var applyTicketBranchesFromUpdatePayload = (row, payload) => {
|
|
13336
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) return;
|
|
13337
|
+
const v = payload["branches"];
|
|
13338
|
+
if (!Array.isArray(v)) return;
|
|
13339
|
+
row.linkedBranches = normalizeTicketBranchListFromPayloadValue(v);
|
|
13369
13340
|
};
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
|
|
13375
|
-
const { stdout: tip } = await opts.runGit(opts.repoRoot, [
|
|
13376
|
-
"rev-parse",
|
|
13377
|
-
"HEAD"
|
|
13378
|
-
]);
|
|
13379
|
-
const tipCommit = tip.trim();
|
|
13380
|
-
await opts.runGit(opts.repoRoot, [
|
|
13381
|
-
"worktree",
|
|
13382
|
-
"add",
|
|
13383
|
-
opts.worktreePath,
|
|
13384
|
-
tipCommit
|
|
13385
|
-
]);
|
|
13386
|
-
await opts.runGit(opts.worktreePath, [
|
|
13387
|
-
"checkout",
|
|
13388
|
-
"--orphan",
|
|
13389
|
-
opts.dataBranch
|
|
13390
|
-
]);
|
|
13391
|
-
await opts.runGit(opts.worktreePath, ["rm", "-rf", "."]).catch(() => {
|
|
13392
|
-
});
|
|
13393
|
-
const marker = (0, import_node_path4.join)(opts.worktreePath, "README.hyper-pm.md");
|
|
13394
|
-
await (0, import_promises4.writeFile)(
|
|
13395
|
-
marker,
|
|
13396
|
-
"# hyper-pm data branch\n\nAppend-only events live under `events/`.\n",
|
|
13397
|
-
"utf8"
|
|
13398
|
-
);
|
|
13399
|
-
await opts.runGit(opts.worktreePath, ["add", "."]);
|
|
13400
|
-
await opts.runGit(opts.worktreePath, [
|
|
13401
|
-
"commit",
|
|
13402
|
-
"-m",
|
|
13403
|
-
"init hyper-pm data branch"
|
|
13404
|
-
]);
|
|
13405
|
-
};
|
|
13406
|
-
|
|
13407
|
-
// src/git/pick-unique-local-branch-name.ts
|
|
13408
|
-
var DEFAULT_MAX_SUFFIX = 1e3;
|
|
13409
|
-
var localBranchRefExists = async (repoRoot, name, git) => {
|
|
13410
|
-
try {
|
|
13411
|
-
await git(repoRoot, ["show-ref", "--verify", `refs/heads/${name}`]);
|
|
13412
|
-
return true;
|
|
13413
|
-
} catch {
|
|
13414
|
-
return false;
|
|
13415
|
-
}
|
|
13416
|
-
};
|
|
13417
|
-
var pickUniqueLocalBranchName = async (opts) => {
|
|
13418
|
-
const max = opts.maxSuffix ?? DEFAULT_MAX_SUFFIX;
|
|
13419
|
-
const { preferredBase, repoRoot, runGit: git } = opts;
|
|
13420
|
-
for (let n = 1; n <= max; n += 1) {
|
|
13421
|
-
const raw = n === 1 ? preferredBase : `${preferredBase}-${n}`;
|
|
13422
|
-
const norm = normalizeTicketBranchName(raw);
|
|
13423
|
-
if (norm === void 0) {
|
|
13424
|
-
continue;
|
|
13425
|
-
}
|
|
13426
|
-
if (!await localBranchRefExists(repoRoot, norm, git)) {
|
|
13427
|
-
return { branch: norm, preferred: preferredBase };
|
|
13341
|
+
var applyTicketPlanningFieldsFromCreatePayload = (row, payload) => {
|
|
13342
|
+
if (Object.prototype.hasOwnProperty.call(payload, "labels")) {
|
|
13343
|
+
const v = ticketLabelsFromPayloadValue(payload["labels"]);
|
|
13344
|
+
if (v !== void 0 && v.length > 0) {
|
|
13345
|
+
row.labels = v;
|
|
13428
13346
|
}
|
|
13429
13347
|
}
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
};
|
|
13434
|
-
|
|
13435
|
-
// src/git/resolve-integration-start-point.ts
|
|
13436
|
-
var assertGitRefResolvable = async (repoRoot, ref, git) => {
|
|
13437
|
-
try {
|
|
13438
|
-
await git(repoRoot, ["rev-parse", "-q", "--verify", ref]);
|
|
13439
|
-
} catch {
|
|
13440
|
-
throw new Error(`Invalid or ambiguous --from ref: ${ref}`);
|
|
13348
|
+
const pr = readTicketPriorityPatch(payload);
|
|
13349
|
+
if (typeof pr === "string") {
|
|
13350
|
+
row.priority = pr;
|
|
13441
13351
|
}
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
try {
|
|
13446
|
-
const { stdout } = await git(repoRoot, ["symbolic-ref", "-q", symRef]);
|
|
13447
|
-
const target = stdout.trim();
|
|
13448
|
-
if (target !== "") {
|
|
13449
|
-
await git(repoRoot, ["rev-parse", "-q", "--verify", target]);
|
|
13450
|
-
return target;
|
|
13451
|
-
}
|
|
13452
|
-
} catch {
|
|
13352
|
+
const sz = readTicketSizePatch(payload);
|
|
13353
|
+
if (typeof sz === "string") {
|
|
13354
|
+
row.size = sz;
|
|
13453
13355
|
}
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
return head;
|
|
13458
|
-
} catch {
|
|
13459
|
-
}
|
|
13356
|
+
const est = readTicketEstimatePatch(payload);
|
|
13357
|
+
if (typeof est === "number") {
|
|
13358
|
+
row.estimate = est;
|
|
13460
13359
|
}
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
} catch {
|
|
13360
|
+
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13361
|
+
if (typeof sw === "string") {
|
|
13362
|
+
row.startWorkAt = sw;
|
|
13465
13363
|
}
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
}
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
const { stdout } = await git(repoRoot, [
|
|
13475
|
-
"-c",
|
|
13476
|
-
"log.showSignature=false",
|
|
13477
|
-
"log",
|
|
13478
|
-
"--all",
|
|
13479
|
-
"--format=%an%x1f%ae"
|
|
13480
|
-
]);
|
|
13481
|
-
if (stdout === "") return [];
|
|
13482
|
-
const lines = stdout.split("\n").filter((l) => l.length > 0);
|
|
13483
|
-
const seenEmail = /* @__PURE__ */ new Set();
|
|
13484
|
-
const out = [];
|
|
13485
|
-
for (const line of lines) {
|
|
13486
|
-
const sep2 = line.indexOf("");
|
|
13487
|
-
if (sep2 <= 0) continue;
|
|
13488
|
-
const name = line.slice(0, sep2).trim();
|
|
13489
|
-
const email = line.slice(sep2 + 1).trim();
|
|
13490
|
-
if (email === "") continue;
|
|
13491
|
-
const key = email.toLowerCase();
|
|
13492
|
-
if (seenEmail.has(key)) continue;
|
|
13493
|
-
seenEmail.add(key);
|
|
13494
|
-
const loginGuess = guessGithubLoginFromContact(name, email);
|
|
13495
|
-
out.push(
|
|
13496
|
-
loginGuess !== void 0 ? { name, email, loginGuess } : { name, email }
|
|
13497
|
-
);
|
|
13364
|
+
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13365
|
+
if (typeof tf === "string") {
|
|
13366
|
+
row.targetFinishAt = tf;
|
|
13367
|
+
}
|
|
13368
|
+
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13369
|
+
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13370
|
+
if (v !== void 0 && v.length > 0) {
|
|
13371
|
+
row.dependsOn = v;
|
|
13498
13372
|
}
|
|
13499
|
-
return out;
|
|
13500
|
-
} catch {
|
|
13501
|
-
return [];
|
|
13502
13373
|
}
|
|
13503
13374
|
};
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
const u = new URL(withScheme);
|
|
13518
|
-
const host = u.hostname.toLowerCase();
|
|
13519
|
-
if (host !== "github.com" && host !== "www.github.com") {
|
|
13520
|
-
return void 0;
|
|
13375
|
+
var applyTicketPlanningFieldsFromUpdatePayload = (row, payload) => {
|
|
13376
|
+
if (Object.prototype.hasOwnProperty.call(payload, "labels")) {
|
|
13377
|
+
if (payload["labels"] === null) {
|
|
13378
|
+
delete row.labels;
|
|
13379
|
+
} else {
|
|
13380
|
+
const v = ticketLabelsFromPayloadValue(payload["labels"]);
|
|
13381
|
+
if (v !== void 0) {
|
|
13382
|
+
if (v.length === 0) {
|
|
13383
|
+
delete row.labels;
|
|
13384
|
+
} else {
|
|
13385
|
+
row.labels = v;
|
|
13386
|
+
}
|
|
13387
|
+
}
|
|
13521
13388
|
}
|
|
13522
|
-
return slugFromGithubPath(u.pathname);
|
|
13523
|
-
} catch {
|
|
13524
|
-
return void 0;
|
|
13525
13389
|
}
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
if (
|
|
13530
|
-
|
|
13390
|
+
const pr = readTicketPriorityPatch(payload);
|
|
13391
|
+
if (pr === null) {
|
|
13392
|
+
delete row.priority;
|
|
13393
|
+
} else if (typeof pr === "string") {
|
|
13394
|
+
row.priority = pr;
|
|
13531
13395
|
}
|
|
13532
|
-
const
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13396
|
+
const sz = readTicketSizePatch(payload);
|
|
13397
|
+
if (sz === null) {
|
|
13398
|
+
delete row.size;
|
|
13399
|
+
} else if (typeof sz === "string") {
|
|
13400
|
+
row.size = sz;
|
|
13536
13401
|
}
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
try {
|
|
13543
|
-
const { stdout } = await params.runGit(params.repoRoot, [
|
|
13544
|
-
"remote",
|
|
13545
|
-
"get-url",
|
|
13546
|
-
params.remote
|
|
13547
|
-
]);
|
|
13548
|
-
return parseGithubOwnerRepoFromRemoteUrl(stdout);
|
|
13549
|
-
} catch {
|
|
13550
|
-
return void 0;
|
|
13402
|
+
const est = readTicketEstimatePatch(payload);
|
|
13403
|
+
if (est === null) {
|
|
13404
|
+
delete row.estimate;
|
|
13405
|
+
} else if (typeof est === "number") {
|
|
13406
|
+
row.estimate = est;
|
|
13551
13407
|
}
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
var tryReadGitConfigUserName = async (cwd, runGit2) => {
|
|
13558
|
-
try {
|
|
13559
|
-
const { stdout } = await runGit2(cwd, ["config", "--get", "user.name"]);
|
|
13560
|
-
return stdout.trim();
|
|
13561
|
-
} catch {
|
|
13562
|
-
return "";
|
|
13408
|
+
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13409
|
+
if (sw === null) {
|
|
13410
|
+
delete row.startWorkAt;
|
|
13411
|
+
} else if (typeof sw === "string") {
|
|
13412
|
+
row.startWorkAt = sw;
|
|
13563
13413
|
}
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
}
|
|
13570
|
-
|
|
13414
|
+
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13415
|
+
if (tf === null) {
|
|
13416
|
+
delete row.targetFinishAt;
|
|
13417
|
+
} else if (typeof tf === "string") {
|
|
13418
|
+
row.targetFinishAt = tf;
|
|
13419
|
+
}
|
|
13420
|
+
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13421
|
+
if (payload["dependsOn"] === null) {
|
|
13422
|
+
delete row.dependsOn;
|
|
13423
|
+
} else {
|
|
13424
|
+
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13425
|
+
if (v !== void 0) {
|
|
13426
|
+
if (v.length === 0) {
|
|
13427
|
+
delete row.dependsOn;
|
|
13428
|
+
} else {
|
|
13429
|
+
row.dependsOn = v;
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13432
|
+
}
|
|
13571
13433
|
}
|
|
13572
13434
|
};
|
|
13573
|
-
var
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
return { name, email };
|
|
13579
|
-
};
|
|
13580
|
-
|
|
13581
|
-
// src/run/commit-data.ts
|
|
13582
|
-
var maxActorSuffixLen = 60;
|
|
13583
|
-
var formatDataBranchCommitMessage = (base, actorSuffix) => {
|
|
13584
|
-
const raw = actorSuffix?.trim();
|
|
13585
|
-
if (!raw) {
|
|
13586
|
-
return base;
|
|
13587
|
-
}
|
|
13588
|
-
const collapsed = raw.replace(/\s+/g, " ");
|
|
13589
|
-
const suffix = collapsed.length > maxActorSuffixLen ? `${collapsed.slice(0, maxActorSuffixLen - 1)}\u2026` : collapsed;
|
|
13590
|
-
return `${base} (${suffix})`;
|
|
13591
|
-
};
|
|
13592
|
-
var commitDataWorktreeIfNeeded = async (worktreePath, message, runGit2, opts) => {
|
|
13593
|
-
const { stdout } = await runGit2(worktreePath, ["status", "--porcelain"]);
|
|
13594
|
-
if (!stdout.trim()) return;
|
|
13595
|
-
await runGit2(worktreePath, ["add", "."]);
|
|
13596
|
-
const authorEnv = opts?.authorEnv ?? env;
|
|
13597
|
-
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
13598
|
-
worktreePath,
|
|
13599
|
-
runGit2,
|
|
13600
|
-
authorEnv
|
|
13601
|
-
);
|
|
13602
|
-
await runGit2(worktreePath, [
|
|
13603
|
-
"-c",
|
|
13604
|
-
`user.name=${name}`,
|
|
13605
|
-
"-c",
|
|
13606
|
-
`user.email=${email}`,
|
|
13607
|
-
"commit",
|
|
13608
|
-
"-m",
|
|
13609
|
-
message
|
|
13610
|
-
]);
|
|
13611
|
-
};
|
|
13612
|
-
|
|
13613
|
-
// src/run/push-data-branch.ts
|
|
13614
|
-
var firstLineFromUnknown = (err) => {
|
|
13615
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
13616
|
-
const line = raw.trim().split("\n")[0]?.trim() ?? raw.trim();
|
|
13617
|
-
return line.length > 0 ? line : "git error";
|
|
13618
|
-
};
|
|
13619
|
-
var tryPushDataBranchToRemote = async (worktreePath, remote, branch, runGit2) => {
|
|
13620
|
-
try {
|
|
13621
|
-
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
13622
|
-
} catch (e) {
|
|
13623
|
-
return {
|
|
13624
|
-
status: "skipped_no_remote",
|
|
13625
|
-
detail: firstLineFromUnknown(e)
|
|
13626
|
-
};
|
|
13627
|
-
}
|
|
13628
|
-
try {
|
|
13629
|
-
await runGit2(worktreePath, ["push", "-u", remote, branch]);
|
|
13630
|
-
return { status: "pushed" };
|
|
13631
|
-
} catch (e) {
|
|
13632
|
-
return {
|
|
13633
|
-
status: "failed",
|
|
13634
|
-
detail: firstLineFromUnknown(e)
|
|
13635
|
-
};
|
|
13636
|
-
}
|
|
13637
|
-
};
|
|
13638
|
-
|
|
13639
|
-
// src/run/sync-remote-data-branch.ts
|
|
13640
|
-
var SyncRemoteDataBranchMergeError = class extends Error {
|
|
13641
|
-
/** @param message - Human-readable reason (stderr excerpt or generic text). */
|
|
13642
|
-
constructor(message) {
|
|
13643
|
-
super(message);
|
|
13644
|
-
this.name = "SyncRemoteDataBranchMergeError";
|
|
13645
|
-
}
|
|
13646
|
-
};
|
|
13647
|
-
var remoteTrackingRef = (remote, dataBranch) => `refs/remotes/${remote}/${dataBranch}`;
|
|
13648
|
-
var mergeRefSpecifier = (remote, dataBranch) => `${remote}/${dataBranch}`;
|
|
13649
|
-
var isLikelyNonFastForwardPushFailure = (detail) => {
|
|
13650
|
-
if (detail === void 0) return false;
|
|
13651
|
-
const d = detail.toLowerCase();
|
|
13652
|
-
return d.includes("non-fast-forward") || d.includes("failed to push");
|
|
13435
|
+
var applyCreatedAudit = (row, evt) => {
|
|
13436
|
+
row.createdAt = evt.ts;
|
|
13437
|
+
row.createdBy = evt.actor;
|
|
13438
|
+
row.updatedAt = evt.ts;
|
|
13439
|
+
row.updatedBy = evt.actor;
|
|
13653
13440
|
};
|
|
13654
|
-
var
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
return "up_to_date";
|
|
13658
|
-
}
|
|
13659
|
-
if (c.includes("fast-forward")) {
|
|
13660
|
-
return "fast_forward";
|
|
13661
|
-
}
|
|
13662
|
-
return "merge_commit";
|
|
13441
|
+
var applyLastUpdate = (row, evt) => {
|
|
13442
|
+
row.updatedAt = evt.ts;
|
|
13443
|
+
row.updatedBy = evt.actor;
|
|
13663
13444
|
};
|
|
13664
|
-
var
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
}
|
|
13445
|
+
var applyStatusIfChanged = (row, evt, nextStatus) => {
|
|
13446
|
+
if (row.status === nextStatus) return false;
|
|
13447
|
+
row.status = nextStatus;
|
|
13448
|
+
row.statusChangedAt = evt.ts;
|
|
13449
|
+
row.statusChangedBy = evt.actor;
|
|
13450
|
+
return true;
|
|
13671
13451
|
};
|
|
13672
|
-
var
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
} catch (e) {
|
|
13682
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
13683
|
-
if (/couldn't find remote ref|could not find remote ref/i.test(msg)) {
|
|
13684
|
-
return "remote_branch_absent";
|
|
13685
|
-
}
|
|
13686
|
-
throw e;
|
|
13687
|
-
}
|
|
13452
|
+
var appendTicketCommentFromEvent = (ticket, evt) => {
|
|
13453
|
+
const list = ticket.comments ?? (ticket.comments = []);
|
|
13454
|
+
list.push({
|
|
13455
|
+
id: evt.id,
|
|
13456
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13457
|
+
createdAt: evt.ts,
|
|
13458
|
+
createdBy: evt.actor
|
|
13459
|
+
});
|
|
13460
|
+
applyLastUpdate(ticket, evt);
|
|
13688
13461
|
};
|
|
13689
|
-
var
|
|
13690
|
-
const
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
const { stdout, stderr } = await runGit2(worktreePath, [
|
|
13698
|
-
"-c",
|
|
13699
|
-
`user.name=${name}`,
|
|
13700
|
-
"-c",
|
|
13701
|
-
`user.email=${email}`,
|
|
13702
|
-
"merge",
|
|
13703
|
-
"--no-edit",
|
|
13704
|
-
spec
|
|
13705
|
-
]);
|
|
13706
|
-
return classifyMergeOutput(`${stdout}
|
|
13707
|
-
${stderr}`);
|
|
13708
|
-
} catch (e) {
|
|
13709
|
-
await runGit2(worktreePath, ["merge", "--abort"]).catch(() => {
|
|
13462
|
+
var resolveInboundTicketStatusFromPayload = (ticket, payload) => {
|
|
13463
|
+
const explicit = parseWorkItemStatus(payload["status"]);
|
|
13464
|
+
if (explicit !== void 0) return explicit;
|
|
13465
|
+
const legacySt = payload["state"];
|
|
13466
|
+
if (legacySt === "open" || legacySt === "closed") {
|
|
13467
|
+
return resolveTicketInboundStatus({
|
|
13468
|
+
issueState: legacySt,
|
|
13469
|
+
currentStatus: ticket.status
|
|
13710
13470
|
});
|
|
13711
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
13712
|
-
throw new SyncRemoteDataBranchMergeError(
|
|
13713
|
-
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}`
|
|
13714
|
-
);
|
|
13715
13471
|
}
|
|
13472
|
+
return void 0;
|
|
13716
13473
|
};
|
|
13717
|
-
var
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
);
|
|
13474
|
+
var applyEvent = (projection, evt) => {
|
|
13475
|
+
switch (evt.type) {
|
|
13476
|
+
case "EpicCreated": {
|
|
13477
|
+
const id = String(evt.payload["id"]);
|
|
13478
|
+
const status = resolveStatusForNewEpicStoryPayload(evt.payload);
|
|
13479
|
+
const row = {
|
|
13480
|
+
id,
|
|
13481
|
+
number: resolveWorkItemCreateNumber(projection, "epic", evt.payload),
|
|
13482
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13483
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13484
|
+
status,
|
|
13485
|
+
statusChangedAt: evt.ts,
|
|
13486
|
+
statusChangedBy: evt.actor,
|
|
13487
|
+
createdAt: "",
|
|
13488
|
+
createdBy: "",
|
|
13489
|
+
updatedAt: "",
|
|
13490
|
+
updatedBy: ""
|
|
13491
|
+
};
|
|
13492
|
+
applyCreatedAudit(row, evt);
|
|
13493
|
+
projection.epics.set(id, row);
|
|
13494
|
+
break;
|
|
13736
13495
|
}
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
dataBranch,
|
|
13754
|
-
runGit2
|
|
13755
|
-
);
|
|
13756
|
-
if (dataBranchFetch !== "ok") {
|
|
13757
|
-
return;
|
|
13496
|
+
case "EpicUpdated": {
|
|
13497
|
+
const id = String(evt.payload["id"]);
|
|
13498
|
+
const cur = projection.epics.get(id);
|
|
13499
|
+
if (!cur) break;
|
|
13500
|
+
if (evt.payload["title"] !== void 0) {
|
|
13501
|
+
cur.title = String(evt.payload["title"]);
|
|
13502
|
+
}
|
|
13503
|
+
if (evt.payload["body"] !== void 0) {
|
|
13504
|
+
cur.body = String(evt.payload["body"]);
|
|
13505
|
+
}
|
|
13506
|
+
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
13507
|
+
if (nextStatus !== void 0) {
|
|
13508
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13509
|
+
}
|
|
13510
|
+
applyLastUpdate(cur, evt);
|
|
13511
|
+
break;
|
|
13758
13512
|
}
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13513
|
+
case "EpicDeleted": {
|
|
13514
|
+
const id = String(evt.payload["id"]);
|
|
13515
|
+
const cur = projection.epics.get(id);
|
|
13516
|
+
if (cur) {
|
|
13517
|
+
cur.deleted = true;
|
|
13518
|
+
applyLastUpdate(cur, evt);
|
|
13519
|
+
}
|
|
13520
|
+
break;
|
|
13763
13521
|
}
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13522
|
+
case "StoryCreated": {
|
|
13523
|
+
const id = String(evt.payload["id"]);
|
|
13524
|
+
const status = resolveStatusForNewEpicStoryPayload(evt.payload);
|
|
13525
|
+
const row = {
|
|
13526
|
+
id,
|
|
13527
|
+
number: resolveWorkItemCreateNumber(projection, "story", evt.payload),
|
|
13528
|
+
epicId: String(evt.payload["epicId"]),
|
|
13529
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13530
|
+
body: String(evt.payload["body"] ?? ""),
|
|
13531
|
+
status,
|
|
13532
|
+
statusChangedAt: evt.ts,
|
|
13533
|
+
statusChangedBy: evt.actor,
|
|
13534
|
+
createdAt: "",
|
|
13535
|
+
createdBy: "",
|
|
13536
|
+
updatedAt: "",
|
|
13537
|
+
updatedBy: ""
|
|
13538
|
+
};
|
|
13539
|
+
applyCreatedAudit(row, evt);
|
|
13540
|
+
projection.stories.set(id, row);
|
|
13776
13541
|
break;
|
|
13777
13542
|
}
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13543
|
+
case "StoryUpdated": {
|
|
13544
|
+
const id = String(evt.payload["id"]);
|
|
13545
|
+
const cur = projection.stories.get(id);
|
|
13546
|
+
if (!cur) break;
|
|
13547
|
+
if (evt.payload["title"] !== void 0) {
|
|
13548
|
+
cur.title = String(evt.payload["title"]);
|
|
13549
|
+
}
|
|
13550
|
+
if (evt.payload["body"] !== void 0) {
|
|
13551
|
+
cur.body = String(evt.payload["body"]);
|
|
13552
|
+
}
|
|
13553
|
+
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
13554
|
+
if (nextStatus !== void 0) {
|
|
13555
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13556
|
+
}
|
|
13557
|
+
applyLastUpdate(cur, evt);
|
|
13558
|
+
break;
|
|
13781
13559
|
}
|
|
13782
|
-
|
|
13560
|
+
case "StoryDeleted": {
|
|
13561
|
+
const id = String(evt.payload["id"]);
|
|
13562
|
+
const cur = projection.stories.get(id);
|
|
13563
|
+
if (cur) {
|
|
13564
|
+
cur.deleted = true;
|
|
13565
|
+
applyLastUpdate(cur, evt);
|
|
13566
|
+
}
|
|
13567
|
+
break;
|
|
13568
|
+
}
|
|
13569
|
+
case "TicketCreated": {
|
|
13570
|
+
const id = String(evt.payload["id"]);
|
|
13571
|
+
const body = String(evt.payload["body"] ?? "");
|
|
13572
|
+
const status = resolveStatusForNewTicketPayload(evt.payload);
|
|
13573
|
+
const row = {
|
|
13574
|
+
id,
|
|
13575
|
+
number: resolveWorkItemCreateNumber(projection, "ticket", evt.payload),
|
|
13576
|
+
storyId: storyIdFromTicketCreatedPayload(evt.payload),
|
|
13577
|
+
title: String(evt.payload["title"] ?? ""),
|
|
13578
|
+
body,
|
|
13579
|
+
status,
|
|
13580
|
+
statusChangedAt: evt.ts,
|
|
13581
|
+
statusChangedBy: evt.actor,
|
|
13582
|
+
linkedPrs: parsePrRefs(body),
|
|
13583
|
+
linkedBranches: linkedBranchesFromTicketCreatedPayload(evt.payload),
|
|
13584
|
+
prActivityRecent: [],
|
|
13585
|
+
createdAt: "",
|
|
13586
|
+
createdBy: "",
|
|
13587
|
+
updatedAt: "",
|
|
13588
|
+
updatedBy: ""
|
|
13589
|
+
};
|
|
13590
|
+
applyCreatedAudit(row, evt);
|
|
13591
|
+
applyTicketAssigneeFromPayload(row, evt.payload);
|
|
13592
|
+
applyTicketPlanningFieldsFromCreatePayload(row, evt.payload);
|
|
13593
|
+
projection.tickets.set(id, row);
|
|
13594
|
+
break;
|
|
13595
|
+
}
|
|
13596
|
+
case "TicketUpdated": {
|
|
13597
|
+
const id = String(evt.payload["id"]);
|
|
13598
|
+
const cur = projection.tickets.get(id);
|
|
13599
|
+
if (!cur) break;
|
|
13600
|
+
if (evt.payload["title"] !== void 0) {
|
|
13601
|
+
cur.title = String(evt.payload["title"]);
|
|
13602
|
+
}
|
|
13603
|
+
if (evt.payload["body"] !== void 0) {
|
|
13604
|
+
cur.body = String(evt.payload["body"]);
|
|
13605
|
+
cur.linkedPrs = parsePrRefs(cur.body);
|
|
13606
|
+
}
|
|
13607
|
+
const nextStatus = resolveTicketStatusFromUpdatePayload(evt.payload);
|
|
13608
|
+
if (nextStatus !== void 0) {
|
|
13609
|
+
applyStatusIfChanged(cur, evt, nextStatus);
|
|
13610
|
+
}
|
|
13611
|
+
applyTicketAssigneeFromPayload(cur, evt.payload);
|
|
13612
|
+
applyTicketStoryIdFromPayload(cur, evt.payload);
|
|
13613
|
+
applyTicketBranchesFromUpdatePayload(cur, evt.payload);
|
|
13614
|
+
applyTicketPlanningFieldsFromUpdatePayload(cur, evt.payload);
|
|
13615
|
+
applyLastUpdate(cur, evt);
|
|
13616
|
+
break;
|
|
13617
|
+
}
|
|
13618
|
+
case "TicketDeleted": {
|
|
13619
|
+
const id = String(evt.payload["id"]);
|
|
13620
|
+
const cur = projection.tickets.get(id);
|
|
13621
|
+
if (cur) {
|
|
13622
|
+
cur.deleted = true;
|
|
13623
|
+
applyLastUpdate(cur, evt);
|
|
13624
|
+
}
|
|
13625
|
+
break;
|
|
13626
|
+
}
|
|
13627
|
+
case "TicketCommentAdded": {
|
|
13628
|
+
const ticketId = String(evt.payload["ticketId"] ?? "");
|
|
13629
|
+
const ticket = projection.tickets.get(ticketId);
|
|
13630
|
+
if (!ticket || ticket.deleted) break;
|
|
13631
|
+
appendTicketCommentFromEvent(ticket, evt);
|
|
13632
|
+
break;
|
|
13633
|
+
}
|
|
13634
|
+
case "SyncCursor": {
|
|
13635
|
+
projection.syncCursor = String(evt.payload["cursor"] ?? "");
|
|
13636
|
+
break;
|
|
13637
|
+
}
|
|
13638
|
+
case "GithubIssueLinked": {
|
|
13639
|
+
const ticketId = String(evt.payload["ticketId"]);
|
|
13640
|
+
const num = Number(evt.payload["issueNumber"]);
|
|
13641
|
+
const ticket = projection.tickets.get(ticketId);
|
|
13642
|
+
if (ticket && Number.isFinite(num)) {
|
|
13643
|
+
ticket.githubIssueNumber = num;
|
|
13644
|
+
applyLastUpdate(ticket, evt);
|
|
13645
|
+
}
|
|
13646
|
+
break;
|
|
13647
|
+
}
|
|
13648
|
+
case "GithubInboundUpdate": {
|
|
13649
|
+
const entity = String(evt.payload["entity"]);
|
|
13650
|
+
const entityId = String(evt.payload["entityId"]);
|
|
13651
|
+
if (entity === "ticket") {
|
|
13652
|
+
const ticket = projection.tickets.get(entityId);
|
|
13653
|
+
if (!ticket) break;
|
|
13654
|
+
if (evt.payload["title"] !== void 0) {
|
|
13655
|
+
ticket.title = String(evt.payload["title"]);
|
|
13656
|
+
}
|
|
13657
|
+
if (evt.payload["body"] !== void 0) {
|
|
13658
|
+
ticket.body = String(evt.payload["body"]);
|
|
13659
|
+
ticket.linkedPrs = parsePrRefs(ticket.body);
|
|
13660
|
+
}
|
|
13661
|
+
const inboundStatus = resolveInboundTicketStatusFromPayload(
|
|
13662
|
+
ticket,
|
|
13663
|
+
evt.payload
|
|
13664
|
+
);
|
|
13665
|
+
if (inboundStatus !== void 0) {
|
|
13666
|
+
applyStatusIfChanged(ticket, evt, inboundStatus);
|
|
13667
|
+
}
|
|
13668
|
+
applyTicketAssigneeFromPayload(ticket, evt.payload);
|
|
13669
|
+
applyTicketPlanningFieldsFromUpdatePayload(ticket, evt.payload);
|
|
13670
|
+
applyLastUpdate(ticket, evt);
|
|
13671
|
+
}
|
|
13672
|
+
break;
|
|
13673
|
+
}
|
|
13674
|
+
case "GithubPrActivity": {
|
|
13675
|
+
const summary = parseGithubPrActivityPayload(evt.payload);
|
|
13676
|
+
if (!summary) break;
|
|
13677
|
+
const ticket = projection.tickets.get(
|
|
13678
|
+
String(evt.payload["ticketId"] ?? "")
|
|
13679
|
+
);
|
|
13680
|
+
if (!ticket || ticket.deleted) break;
|
|
13681
|
+
const list = ticket.prActivityRecent ?? (ticket.prActivityRecent = []);
|
|
13682
|
+
list.push(summary);
|
|
13683
|
+
if (list.length > GITHUB_PR_ACTIVITY_RECENT_CAP) {
|
|
13684
|
+
ticket.prActivityRecent = list.slice(-GITHUB_PR_ACTIVITY_RECENT_CAP);
|
|
13685
|
+
}
|
|
13686
|
+
break;
|
|
13687
|
+
}
|
|
13688
|
+
default:
|
|
13689
|
+
break;
|
|
13783
13690
|
}
|
|
13784
|
-
return {
|
|
13785
|
-
dataBranchFetch,
|
|
13786
|
-
dataBranchMerge,
|
|
13787
|
-
dataBranchPush: lastPush.status,
|
|
13788
|
-
...lastPush.detail !== void 0 ? { dataBranchPushDetail: lastPush.detail } : {},
|
|
13789
|
-
pushAttempts
|
|
13790
|
-
};
|
|
13791
13691
|
};
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13692
|
+
var replayEvents = (lines) => {
|
|
13693
|
+
const proj = emptyProjection();
|
|
13694
|
+
const events = [];
|
|
13695
|
+
for (const line of lines) {
|
|
13696
|
+
const trimmed = line.trim();
|
|
13697
|
+
if (!trimmed) continue;
|
|
13698
|
+
const json = JSON.parse(trimmed);
|
|
13699
|
+
events.push(eventLineSchema.parse(json));
|
|
13700
|
+
}
|
|
13701
|
+
events.sort((a, b) => {
|
|
13702
|
+
const t = a.ts.localeCompare(b.ts);
|
|
13703
|
+
if (t !== 0) return t;
|
|
13704
|
+
return a.id.localeCompare(b.id);
|
|
13705
|
+
});
|
|
13706
|
+
for (const e of events) {
|
|
13707
|
+
applyEvent(proj, e);
|
|
13708
|
+
}
|
|
13709
|
+
return proj;
|
|
13804
13710
|
};
|
|
13805
13711
|
|
|
13806
|
-
// src/
|
|
13807
|
-
var
|
|
13808
|
-
|
|
13809
|
-
|
|
13712
|
+
// src/cli/resolve-projection-work-item-id.ts
|
|
13713
|
+
var isDigitOnlyWorkItemRef = (raw) => /^\d+$/.test(raw.trim());
|
|
13714
|
+
var resolveEpicId = (projection, raw) => {
|
|
13715
|
+
const t = raw.trim();
|
|
13716
|
+
if (t === "") return void 0;
|
|
13717
|
+
if (projection.epics.has(t)) return t;
|
|
13718
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13719
|
+
const n = Number(t);
|
|
13720
|
+
const hits = [...projection.epics.values()].filter((e) => e.number === n);
|
|
13721
|
+
if (hits.length !== 1) return void 0;
|
|
13722
|
+
return hits[0].id;
|
|
13723
|
+
};
|
|
13724
|
+
var resolveStoryId = (projection, raw) => {
|
|
13725
|
+
const t = raw.trim();
|
|
13726
|
+
if (t === "") return void 0;
|
|
13727
|
+
if (projection.stories.has(t)) return t;
|
|
13728
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13729
|
+
const n = Number(t);
|
|
13730
|
+
const hits = [...projection.stories.values()].filter((s) => s.number === n);
|
|
13731
|
+
if (hits.length !== 1) return void 0;
|
|
13732
|
+
return hits[0].id;
|
|
13733
|
+
};
|
|
13734
|
+
var resolveTicketId = (projection, raw) => {
|
|
13735
|
+
const t = raw.trim();
|
|
13736
|
+
if (t === "") return void 0;
|
|
13737
|
+
if (projection.tickets.has(t)) return t;
|
|
13738
|
+
if (!isDigitOnlyWorkItemRef(t)) return void 0;
|
|
13739
|
+
const n = Number(t);
|
|
13740
|
+
const hits = [...projection.tickets.values()].filter((x) => x.number === n);
|
|
13741
|
+
if (hits.length !== 1) return void 0;
|
|
13742
|
+
return hits[0].id;
|
|
13743
|
+
};
|
|
13744
|
+
var resolveTicketDependsOnTokensToIds = (projection, tokens) => {
|
|
13745
|
+
const mapped = tokens.map((raw) => {
|
|
13746
|
+
const t = raw.trim();
|
|
13747
|
+
if (t === "") return "";
|
|
13748
|
+
if (projection.tickets.has(t)) return t;
|
|
13749
|
+
if (!isDigitOnlyWorkItemRef(t)) return t;
|
|
13750
|
+
const hit = resolveTicketId(projection, t);
|
|
13751
|
+
return hit ?? t;
|
|
13810
13752
|
});
|
|
13811
|
-
|
|
13812
|
-
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(abs), { recursive: true });
|
|
13813
|
-
await (0, import_promises5.appendFile)(abs, `${JSON.stringify(event)}
|
|
13814
|
-
`, "utf8");
|
|
13815
|
-
return rel;
|
|
13753
|
+
return normalizeTicketDependsOnIds(mapped);
|
|
13816
13754
|
};
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
|
|
13825
|
-
const abs = (0, import_node_path6.join)(dir, e.name);
|
|
13826
|
-
if (e.isDirectory()) {
|
|
13827
|
-
out.push(...await listJsonlFiles(abs, root));
|
|
13828
|
-
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
13829
|
-
out.push((0, import_node_path6.relative)(root, abs).split("\\").join("/"));
|
|
13830
|
-
}
|
|
13755
|
+
var assertCreatePayloadUsesExpectedHeadNumber = (projection, kind, payload) => {
|
|
13756
|
+
const n = readOptionalPositiveIntegerFromPayload(payload, "number");
|
|
13757
|
+
const expected = kind === "epic" ? nextEpicNumberForCreate(projection) : kind === "story" ? nextStoryNumberForCreate(projection) : nextTicketNumberForCreate(projection);
|
|
13758
|
+
if (n !== expected) {
|
|
13759
|
+
const got = n === void 0 ? "missing" : String(n);
|
|
13760
|
+
throw new Error(
|
|
13761
|
+
`Invalid ${kind} number for this data branch: expected ${String(expected)}, got ${got}.`
|
|
13762
|
+
);
|
|
13831
13763
|
}
|
|
13832
|
-
return out;
|
|
13833
|
-
};
|
|
13834
|
-
var readAllEventLines = async (dataRoot) => {
|
|
13835
|
-
const eventsRoot = (0, import_node_path6.join)(dataRoot, "events");
|
|
13836
|
-
let files = [];
|
|
13837
|
-
try {
|
|
13838
|
-
files = await listJsonlFiles(eventsRoot, dataRoot);
|
|
13839
|
-
} catch {
|
|
13840
|
-
return [];
|
|
13841
|
-
}
|
|
13842
|
-
files.sort((a, b) => a.localeCompare(b));
|
|
13843
|
-
const lines = [];
|
|
13844
|
-
for (const rel of files) {
|
|
13845
|
-
const content = await (0, import_promises6.readFile)((0, import_node_path6.join)(dataRoot, rel), "utf8");
|
|
13846
|
-
for (const line of content.split("\n")) {
|
|
13847
|
-
if (line.trim()) lines.push(line);
|
|
13848
|
-
}
|
|
13849
|
-
}
|
|
13850
|
-
return lines;
|
|
13851
13764
|
};
|
|
13852
13765
|
|
|
13853
|
-
// src/
|
|
13854
|
-
var
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
"
|
|
13858
|
-
"
|
|
13859
|
-
|
|
13860
|
-
"
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
var
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
const
|
|
13873
|
-
const
|
|
13874
|
-
const
|
|
13875
|
-
const
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
const
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
if (!kindParsed.success) return void 0;
|
|
13883
|
-
const out = {
|
|
13884
|
-
prNumber,
|
|
13885
|
-
kind: kindParsed.data,
|
|
13886
|
-
occurredAt,
|
|
13887
|
-
sourceId
|
|
13888
|
-
};
|
|
13889
|
-
const url = payload["url"];
|
|
13890
|
-
if (typeof url === "string" && url.length > 0) {
|
|
13891
|
-
out.url = url;
|
|
13892
|
-
}
|
|
13893
|
-
const rs = githubPrReviewStateSchema.safeParse(payload["reviewState"]);
|
|
13894
|
-
if (rs.success) {
|
|
13895
|
-
out.reviewState = rs.data;
|
|
13766
|
+
// src/config/hyper-pm-config.ts
|
|
13767
|
+
var hyperPmConfigSchema = external_exports.object({
|
|
13768
|
+
schema: external_exports.literal(1),
|
|
13769
|
+
dataBranch: external_exports.string().min(1),
|
|
13770
|
+
remote: external_exports.string().min(1).default("origin"),
|
|
13771
|
+
sync: external_exports.enum(["off", "outbound", "full"]).default("outbound"),
|
|
13772
|
+
githubRepo: external_exports.string().optional(),
|
|
13773
|
+
issueMapping: external_exports.enum(["ticket", "story", "epic"]).default("ticket")
|
|
13774
|
+
});
|
|
13775
|
+
|
|
13776
|
+
// src/config/load-config.ts
|
|
13777
|
+
var import_promises = require("node:fs/promises");
|
|
13778
|
+
var import_node_path = require("node:path");
|
|
13779
|
+
var CONFIG_DIR = ".hyper-pm";
|
|
13780
|
+
var CONFIG_FILE = "config.json";
|
|
13781
|
+
var getHyperPmConfigPath = (repoRoot) => {
|
|
13782
|
+
return (0, import_node_path.join)(repoRoot, CONFIG_DIR, CONFIG_FILE);
|
|
13783
|
+
};
|
|
13784
|
+
var loadHyperPmConfig = async (repoRoot, overrides = {}) => {
|
|
13785
|
+
const raw = await (0, import_promises.readFile)(getHyperPmConfigPath(repoRoot), "utf8");
|
|
13786
|
+
const parsed = JSON.parse(raw);
|
|
13787
|
+
const base = hyperPmConfigSchema.parse(parsed);
|
|
13788
|
+
const merged = { ...base, ...stripUndefined(overrides) };
|
|
13789
|
+
return hyperPmConfigSchema.parse(merged);
|
|
13790
|
+
};
|
|
13791
|
+
var stripUndefined = (obj) => {
|
|
13792
|
+
const out = {};
|
|
13793
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
13794
|
+
if (v !== void 0) out[k] = v;
|
|
13896
13795
|
}
|
|
13897
13796
|
return out;
|
|
13898
13797
|
};
|
|
13899
13798
|
|
|
13900
|
-
// src/
|
|
13901
|
-
var
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
});
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
const re = /\b(?:Closes|Refs|Fixes)\s+#(\d+)\b/gi;
|
|
13909
|
-
let m = re.exec(body);
|
|
13910
|
-
while (m !== null) {
|
|
13911
|
-
out.add(Number(m[1]));
|
|
13912
|
-
m = re.exec(body);
|
|
13913
|
-
}
|
|
13914
|
-
return [...out];
|
|
13799
|
+
// src/config/save-config.ts
|
|
13800
|
+
var import_promises2 = require("node:fs/promises");
|
|
13801
|
+
var import_node_path2 = require("node:path");
|
|
13802
|
+
var saveHyperPmConfig = async (repoRoot, config) => {
|
|
13803
|
+
const target = getHyperPmConfigPath(repoRoot);
|
|
13804
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(target), { recursive: true });
|
|
13805
|
+
await (0, import_promises2.writeFile)(target, `${JSON.stringify(config, null, 2)}
|
|
13806
|
+
`, "utf8");
|
|
13915
13807
|
};
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13808
|
+
|
|
13809
|
+
// src/doctor/run-doctor.ts
|
|
13810
|
+
var runDoctorOnLines = (lines) => {
|
|
13811
|
+
const issues = [];
|
|
13812
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13813
|
+
const line = lines[i]?.trim() ?? "";
|
|
13814
|
+
if (!line) continue;
|
|
13815
|
+
let json;
|
|
13816
|
+
try {
|
|
13817
|
+
json = JSON.parse(line);
|
|
13818
|
+
} catch (e) {
|
|
13819
|
+
issues.push({
|
|
13820
|
+
kind: "invalid-json",
|
|
13821
|
+
line: i + 1,
|
|
13822
|
+
message: e instanceof Error ? e.message : "parse error"
|
|
13823
|
+
});
|
|
13824
|
+
return issues;
|
|
13825
|
+
}
|
|
13826
|
+
const parsed = eventLineSchema.safeParse(json);
|
|
13827
|
+
if (!parsed.success) {
|
|
13828
|
+
issues.push({
|
|
13829
|
+
kind: "invalid-event",
|
|
13830
|
+
line: i + 1,
|
|
13831
|
+
message: parsed.error.message
|
|
13832
|
+
});
|
|
13833
|
+
return issues;
|
|
13834
|
+
}
|
|
13922
13835
|
}
|
|
13923
|
-
|
|
13924
|
-
const n = normalizeGithubLogin(v);
|
|
13925
|
-
if (n === "") delete row.assignee;
|
|
13926
|
-
else row.assignee = n;
|
|
13836
|
+
return issues;
|
|
13927
13837
|
};
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13838
|
+
|
|
13839
|
+
// src/git/create-and-checkout-branch.ts
|
|
13840
|
+
var createAndCheckoutBranch = async (opts) => {
|
|
13841
|
+
await opts.runGit(opts.repoRoot, [
|
|
13842
|
+
"switch",
|
|
13843
|
+
"-c",
|
|
13844
|
+
opts.branchName,
|
|
13845
|
+
opts.startPoint
|
|
13846
|
+
]);
|
|
13937
13847
|
};
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
}
|
|
13945
|
-
if (typeof v !== "string") return;
|
|
13946
|
-
const t = v.trim();
|
|
13947
|
-
row.storyId = t === "" ? null : t;
|
|
13848
|
+
|
|
13849
|
+
// src/git/data-worktree-session.ts
|
|
13850
|
+
var import_promises3 = require("node:fs/promises");
|
|
13851
|
+
var import_node_path3 = require("node:path");
|
|
13852
|
+
var ensureDir = async (path) => {
|
|
13853
|
+
await (0, import_promises3.mkdir)(path, { recursive: true });
|
|
13948
13854
|
};
|
|
13949
|
-
var
|
|
13950
|
-
|
|
13951
|
-
|
|
13855
|
+
var defaultPathExists = async (path) => {
|
|
13856
|
+
try {
|
|
13857
|
+
await (0, import_promises3.access)(path);
|
|
13858
|
+
return true;
|
|
13859
|
+
} catch {
|
|
13860
|
+
return false;
|
|
13952
13861
|
}
|
|
13953
|
-
return normalizeTicketBranchListFromPayloadValue(payload["branches"]);
|
|
13954
|
-
};
|
|
13955
|
-
var applyTicketBranchesFromUpdatePayload = (row, payload) => {
|
|
13956
|
-
if (!Object.prototype.hasOwnProperty.call(payload, "branches")) return;
|
|
13957
|
-
const v = payload["branches"];
|
|
13958
|
-
if (!Array.isArray(v)) return;
|
|
13959
|
-
row.linkedBranches = normalizeTicketBranchListFromPayloadValue(v);
|
|
13960
13862
|
};
|
|
13961
|
-
var
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13863
|
+
var parseDataBranchWorktreeFromPorcelain = (stdout, dataBranch) => {
|
|
13864
|
+
const wantRef = `refs/heads/${dataBranch}`;
|
|
13865
|
+
const blocks = stdout.split(/\n\n+/).map((b) => b.trim()).filter(Boolean);
|
|
13866
|
+
for (const block of blocks) {
|
|
13867
|
+
const lines = block.split("\n");
|
|
13868
|
+
let worktreePath;
|
|
13869
|
+
let branch;
|
|
13870
|
+
for (const line of lines) {
|
|
13871
|
+
if (line.startsWith("worktree ")) {
|
|
13872
|
+
worktreePath = line.slice("worktree ".length);
|
|
13873
|
+
} else if (line.startsWith("branch ")) {
|
|
13874
|
+
branch = line.slice("branch ".length);
|
|
13875
|
+
}
|
|
13966
13876
|
}
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
if (typeof pr === "string") {
|
|
13970
|
-
row.priority = pr;
|
|
13971
|
-
}
|
|
13972
|
-
const sz = readTicketSizePatch(payload);
|
|
13973
|
-
if (typeof sz === "string") {
|
|
13974
|
-
row.size = sz;
|
|
13975
|
-
}
|
|
13976
|
-
const est = readTicketEstimatePatch(payload);
|
|
13977
|
-
if (typeof est === "number") {
|
|
13978
|
-
row.estimate = est;
|
|
13979
|
-
}
|
|
13980
|
-
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
13981
|
-
if (typeof sw === "string") {
|
|
13982
|
-
row.startWorkAt = sw;
|
|
13983
|
-
}
|
|
13984
|
-
const tf = readTicketIsoInstantPatch(payload, "targetFinishAt");
|
|
13985
|
-
if (typeof tf === "string") {
|
|
13986
|
-
row.targetFinishAt = tf;
|
|
13987
|
-
}
|
|
13988
|
-
if (Object.prototype.hasOwnProperty.call(payload, "dependsOn")) {
|
|
13989
|
-
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
13990
|
-
if (v !== void 0 && v.length > 0) {
|
|
13991
|
-
row.dependsOn = v;
|
|
13877
|
+
if (worktreePath !== void 0 && branch === wantRef) {
|
|
13878
|
+
return worktreePath;
|
|
13992
13879
|
}
|
|
13993
13880
|
}
|
|
13881
|
+
return void 0;
|
|
13994
13882
|
};
|
|
13995
|
-
var
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
if (pr === null) {
|
|
14012
|
-
delete row.priority;
|
|
14013
|
-
} else if (typeof pr === "string") {
|
|
14014
|
-
row.priority = pr;
|
|
14015
|
-
}
|
|
14016
|
-
const sz = readTicketSizePatch(payload);
|
|
14017
|
-
if (sz === null) {
|
|
14018
|
-
delete row.size;
|
|
14019
|
-
} else if (typeof sz === "string") {
|
|
14020
|
-
row.size = sz;
|
|
14021
|
-
}
|
|
14022
|
-
const est = readTicketEstimatePatch(payload);
|
|
14023
|
-
if (est === null) {
|
|
14024
|
-
delete row.estimate;
|
|
14025
|
-
} else if (typeof est === "number") {
|
|
14026
|
-
row.estimate = est;
|
|
14027
|
-
}
|
|
14028
|
-
const sw = readTicketIsoInstantPatch(payload, "startWorkAt");
|
|
14029
|
-
if (sw === null) {
|
|
14030
|
-
delete row.startWorkAt;
|
|
14031
|
-
} else if (typeof sw === "string") {
|
|
14032
|
-
row.startWorkAt = sw;
|
|
13883
|
+
var openDataBranchWorktree = async (opts) => {
|
|
13884
|
+
const pathExists = opts.pathExists ?? defaultPathExists;
|
|
13885
|
+
const { stdout: listOut } = await opts.runGit(opts.repoRoot, [
|
|
13886
|
+
"worktree",
|
|
13887
|
+
"list",
|
|
13888
|
+
"--porcelain"
|
|
13889
|
+
]);
|
|
13890
|
+
const listedPath = parseDataBranchWorktreeFromPorcelain(
|
|
13891
|
+
listOut,
|
|
13892
|
+
opts.dataBranch
|
|
13893
|
+
);
|
|
13894
|
+
if (listedPath !== void 0 && await pathExists(listedPath)) {
|
|
13895
|
+
const dispose2 = async () => {
|
|
13896
|
+
return;
|
|
13897
|
+
};
|
|
13898
|
+
return { worktreePath: listedPath, dispose: dispose2 };
|
|
14033
13899
|
}
|
|
14034
|
-
const
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
13900
|
+
const worktreePath = (0, import_node_path3.join)(
|
|
13901
|
+
opts.tmpBase,
|
|
13902
|
+
`hyper-pm-worktree-${ulid().toLowerCase()}`
|
|
13903
|
+
);
|
|
13904
|
+
await ensureDir(opts.tmpBase);
|
|
13905
|
+
try {
|
|
13906
|
+
await opts.runGit(opts.repoRoot, [
|
|
13907
|
+
"worktree",
|
|
13908
|
+
"add",
|
|
13909
|
+
worktreePath,
|
|
13910
|
+
opts.dataBranch
|
|
13911
|
+
]);
|
|
13912
|
+
} catch (err) {
|
|
13913
|
+
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13914
|
+
});
|
|
13915
|
+
throw err;
|
|
14039
13916
|
}
|
|
14040
|
-
|
|
14041
|
-
if (
|
|
14042
|
-
|
|
14043
|
-
} else {
|
|
14044
|
-
const v = parseTicketDependsOnFromPayloadValue(payload["dependsOn"]);
|
|
14045
|
-
if (v !== void 0) {
|
|
14046
|
-
if (v.length === 0) {
|
|
14047
|
-
delete row.dependsOn;
|
|
14048
|
-
} else {
|
|
14049
|
-
row.dependsOn = v;
|
|
14050
|
-
}
|
|
14051
|
-
}
|
|
13917
|
+
const dispose = async () => {
|
|
13918
|
+
if (opts.keepWorktree) {
|
|
13919
|
+
return;
|
|
14052
13920
|
}
|
|
14053
|
-
|
|
14054
|
-
};
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
row.updatedBy = evt.actor;
|
|
14060
|
-
};
|
|
14061
|
-
var applyLastUpdate = (row, evt) => {
|
|
14062
|
-
row.updatedAt = evt.ts;
|
|
14063
|
-
row.updatedBy = evt.actor;
|
|
13921
|
+
await opts.runGit(opts.repoRoot, ["worktree", "remove", "--force", worktreePath]).catch(() => {
|
|
13922
|
+
});
|
|
13923
|
+
await (0, import_promises3.rm)(worktreePath, { recursive: true, force: true }).catch(() => {
|
|
13924
|
+
});
|
|
13925
|
+
};
|
|
13926
|
+
return { worktreePath, dispose };
|
|
14064
13927
|
};
|
|
14065
|
-
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
return true;
|
|
13928
|
+
|
|
13929
|
+
// src/git/find-git-root.ts
|
|
13930
|
+
var findGitRoot = async (cwd, deps) => {
|
|
13931
|
+
const { stdout } = await deps.runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
13932
|
+
return stdout;
|
|
14071
13933
|
};
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
13934
|
+
|
|
13935
|
+
// src/git/init-orphan-data-branch.ts
|
|
13936
|
+
var import_promises4 = require("node:fs/promises");
|
|
13937
|
+
var import_node_path4 = require("node:path");
|
|
13938
|
+
var initOrphanDataBranchInWorktree = async (opts) => {
|
|
13939
|
+
const { stdout: tip } = await opts.runGit(opts.repoRoot, [
|
|
13940
|
+
"rev-parse",
|
|
13941
|
+
"HEAD"
|
|
13942
|
+
]);
|
|
13943
|
+
const tipCommit = tip.trim();
|
|
13944
|
+
await opts.runGit(opts.repoRoot, [
|
|
13945
|
+
"worktree",
|
|
13946
|
+
"add",
|
|
13947
|
+
opts.worktreePath,
|
|
13948
|
+
tipCommit
|
|
13949
|
+
]);
|
|
13950
|
+
await opts.runGit(opts.worktreePath, [
|
|
13951
|
+
"checkout",
|
|
13952
|
+
"--orphan",
|
|
13953
|
+
opts.dataBranch
|
|
13954
|
+
]);
|
|
13955
|
+
await opts.runGit(opts.worktreePath, ["rm", "-rf", "."]).catch(() => {
|
|
14079
13956
|
});
|
|
14080
|
-
|
|
13957
|
+
const marker = (0, import_node_path4.join)(opts.worktreePath, "README.hyper-pm.md");
|
|
13958
|
+
await (0, import_promises4.writeFile)(
|
|
13959
|
+
marker,
|
|
13960
|
+
"# hyper-pm data branch\n\nAppend-only events live under `events/`.\n",
|
|
13961
|
+
"utf8"
|
|
13962
|
+
);
|
|
13963
|
+
await opts.runGit(opts.worktreePath, ["add", "."]);
|
|
13964
|
+
await opts.runGit(opts.worktreePath, [
|
|
13965
|
+
"commit",
|
|
13966
|
+
"-m",
|
|
13967
|
+
"init hyper-pm data branch"
|
|
13968
|
+
]);
|
|
14081
13969
|
};
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14085
|
-
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
13970
|
+
|
|
13971
|
+
// src/git/pick-unique-local-branch-name.ts
|
|
13972
|
+
var DEFAULT_MAX_SUFFIX = 1e3;
|
|
13973
|
+
var localBranchRefExists = async (repoRoot, name, git) => {
|
|
13974
|
+
try {
|
|
13975
|
+
await git(repoRoot, ["show-ref", "--verify", `refs/heads/${name}`]);
|
|
13976
|
+
return true;
|
|
13977
|
+
} catch {
|
|
13978
|
+
return false;
|
|
14091
13979
|
}
|
|
14092
|
-
return void 0;
|
|
14093
13980
|
};
|
|
14094
|
-
var
|
|
14095
|
-
|
|
14096
|
-
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
body: String(evt.payload["body"] ?? ""),
|
|
14103
|
-
status,
|
|
14104
|
-
statusChangedAt: evt.ts,
|
|
14105
|
-
statusChangedBy: evt.actor,
|
|
14106
|
-
createdAt: "",
|
|
14107
|
-
createdBy: "",
|
|
14108
|
-
updatedAt: "",
|
|
14109
|
-
updatedBy: ""
|
|
14110
|
-
};
|
|
14111
|
-
applyCreatedAudit(row, evt);
|
|
14112
|
-
projection.epics.set(id, row);
|
|
14113
|
-
break;
|
|
13981
|
+
var pickUniqueLocalBranchName = async (opts) => {
|
|
13982
|
+
const max = opts.maxSuffix ?? DEFAULT_MAX_SUFFIX;
|
|
13983
|
+
const { preferredBase, repoRoot, runGit: git } = opts;
|
|
13984
|
+
for (let n = 1; n <= max; n += 1) {
|
|
13985
|
+
const raw = n === 1 ? preferredBase : `${preferredBase}-${n}`;
|
|
13986
|
+
const norm = normalizeTicketBranchName(raw);
|
|
13987
|
+
if (norm === void 0) {
|
|
13988
|
+
continue;
|
|
14114
13989
|
}
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
const cur = projection.epics.get(id);
|
|
14118
|
-
if (!cur) break;
|
|
14119
|
-
if (evt.payload["title"] !== void 0) {
|
|
14120
|
-
cur.title = String(evt.payload["title"]);
|
|
14121
|
-
}
|
|
14122
|
-
if (evt.payload["body"] !== void 0) {
|
|
14123
|
-
cur.body = String(evt.payload["body"]);
|
|
14124
|
-
}
|
|
14125
|
-
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
14126
|
-
if (nextStatus !== void 0) {
|
|
14127
|
-
applyStatusIfChanged(cur, evt, nextStatus);
|
|
14128
|
-
}
|
|
14129
|
-
applyLastUpdate(cur, evt);
|
|
14130
|
-
break;
|
|
13990
|
+
if (!await localBranchRefExists(repoRoot, norm, git)) {
|
|
13991
|
+
return { branch: norm, preferred: preferredBase };
|
|
14131
13992
|
}
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
13993
|
+
}
|
|
13994
|
+
throw new Error(
|
|
13995
|
+
`Could not allocate a free local branch name from ${JSON.stringify(preferredBase)} (tried suffixes up to -${String(max)})`
|
|
13996
|
+
);
|
|
13997
|
+
};
|
|
13998
|
+
|
|
13999
|
+
// src/git/resolve-integration-start-point.ts
|
|
14000
|
+
var assertGitRefResolvable = async (repoRoot, ref, git) => {
|
|
14001
|
+
try {
|
|
14002
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", ref]);
|
|
14003
|
+
} catch {
|
|
14004
|
+
throw new Error(`Invalid or ambiguous --from ref: ${ref}`);
|
|
14005
|
+
}
|
|
14006
|
+
};
|
|
14007
|
+
var resolveIntegrationStartPoint = async (repoRoot, remote, git) => {
|
|
14008
|
+
const symRef = `refs/remotes/${remote}/HEAD`;
|
|
14009
|
+
try {
|
|
14010
|
+
const { stdout } = await git(repoRoot, ["symbolic-ref", "-q", symRef]);
|
|
14011
|
+
const target = stdout.trim();
|
|
14012
|
+
if (target !== "") {
|
|
14013
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", target]);
|
|
14014
|
+
return target;
|
|
14140
14015
|
}
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
body: String(evt.payload["body"] ?? ""),
|
|
14149
|
-
status,
|
|
14150
|
-
statusChangedAt: evt.ts,
|
|
14151
|
-
statusChangedBy: evt.actor,
|
|
14152
|
-
createdAt: "",
|
|
14153
|
-
createdBy: "",
|
|
14154
|
-
updatedAt: "",
|
|
14155
|
-
updatedBy: ""
|
|
14156
|
-
};
|
|
14157
|
-
applyCreatedAudit(row, evt);
|
|
14158
|
-
projection.stories.set(id, row);
|
|
14159
|
-
break;
|
|
14160
|
-
}
|
|
14161
|
-
case "StoryUpdated": {
|
|
14162
|
-
const id = String(evt.payload["id"]);
|
|
14163
|
-
const cur = projection.stories.get(id);
|
|
14164
|
-
if (!cur) break;
|
|
14165
|
-
if (evt.payload["title"] !== void 0) {
|
|
14166
|
-
cur.title = String(evt.payload["title"]);
|
|
14167
|
-
}
|
|
14168
|
-
if (evt.payload["body"] !== void 0) {
|
|
14169
|
-
cur.body = String(evt.payload["body"]);
|
|
14170
|
-
}
|
|
14171
|
-
const nextStatus = parseWorkItemStatus(evt.payload["status"]);
|
|
14172
|
-
if (nextStatus !== void 0) {
|
|
14173
|
-
applyStatusIfChanged(cur, evt, nextStatus);
|
|
14174
|
-
}
|
|
14175
|
-
applyLastUpdate(cur, evt);
|
|
14176
|
-
break;
|
|
14016
|
+
} catch {
|
|
14017
|
+
}
|
|
14018
|
+
for (const head of ["refs/heads/main", "refs/heads/master"]) {
|
|
14019
|
+
try {
|
|
14020
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", head]);
|
|
14021
|
+
return head;
|
|
14022
|
+
} catch {
|
|
14177
14023
|
}
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14024
|
+
}
|
|
14025
|
+
try {
|
|
14026
|
+
await git(repoRoot, ["rev-parse", "-q", "--verify", "HEAD"]);
|
|
14027
|
+
return "HEAD";
|
|
14028
|
+
} catch {
|
|
14029
|
+
}
|
|
14030
|
+
throw new Error(
|
|
14031
|
+
"Could not resolve a default branch to branch from; pass --from <ref> (e.g. main or origin/main)."
|
|
14032
|
+
);
|
|
14033
|
+
};
|
|
14034
|
+
|
|
14035
|
+
// src/git/list-repo-commit-authors.ts
|
|
14036
|
+
var listRepoCommitAuthors = async (repoRoot, git) => {
|
|
14037
|
+
try {
|
|
14038
|
+
const { stdout } = await git(repoRoot, [
|
|
14039
|
+
"-c",
|
|
14040
|
+
"log.showSignature=false",
|
|
14041
|
+
"log",
|
|
14042
|
+
"--all",
|
|
14043
|
+
"--format=%an%x1f%ae"
|
|
14044
|
+
]);
|
|
14045
|
+
if (stdout === "") return [];
|
|
14046
|
+
const lines = stdout.split("\n").filter((l) => l.length > 0);
|
|
14047
|
+
const seenEmail = /* @__PURE__ */ new Set();
|
|
14048
|
+
const out = [];
|
|
14049
|
+
for (const line of lines) {
|
|
14050
|
+
const sep2 = line.indexOf("");
|
|
14051
|
+
if (sep2 <= 0) continue;
|
|
14052
|
+
const name = line.slice(0, sep2).trim();
|
|
14053
|
+
const email = line.slice(sep2 + 1).trim();
|
|
14054
|
+
if (email === "") continue;
|
|
14055
|
+
const key = email.toLowerCase();
|
|
14056
|
+
if (seenEmail.has(key)) continue;
|
|
14057
|
+
seenEmail.add(key);
|
|
14058
|
+
const loginGuess = guessGithubLoginFromContact(name, email);
|
|
14059
|
+
out.push(
|
|
14060
|
+
loginGuess !== void 0 ? { name, email, loginGuess } : { name, email }
|
|
14061
|
+
);
|
|
14186
14062
|
}
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
|
|
14193
|
-
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
applyTicketPlanningFieldsFromCreatePayload(row, evt.payload);
|
|
14210
|
-
projection.tickets.set(id, row);
|
|
14211
|
-
break;
|
|
14063
|
+
return out;
|
|
14064
|
+
} catch {
|
|
14065
|
+
return [];
|
|
14066
|
+
}
|
|
14067
|
+
};
|
|
14068
|
+
|
|
14069
|
+
// src/git/parse-github-owner-repo-from-remote-url.ts
|
|
14070
|
+
var parseGithubOwnerRepoFromRemoteUrl = (rawUrl) => {
|
|
14071
|
+
const trimmed = rawUrl.trim();
|
|
14072
|
+
if (!trimmed) {
|
|
14073
|
+
return void 0;
|
|
14074
|
+
}
|
|
14075
|
+
const scpMatch = /^git@github\.com:(?<path>.+)$/i.exec(trimmed);
|
|
14076
|
+
if (scpMatch?.groups?.path) {
|
|
14077
|
+
return slugFromGithubPath(scpMatch.groups.path);
|
|
14078
|
+
}
|
|
14079
|
+
try {
|
|
14080
|
+
const withScheme = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
|
|
14081
|
+
const u = new URL(withScheme);
|
|
14082
|
+
const host = u.hostname.toLowerCase();
|
|
14083
|
+
if (host !== "github.com" && host !== "www.github.com") {
|
|
14084
|
+
return void 0;
|
|
14212
14085
|
}
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14086
|
+
return slugFromGithubPath(u.pathname);
|
|
14087
|
+
} catch {
|
|
14088
|
+
return void 0;
|
|
14089
|
+
}
|
|
14090
|
+
};
|
|
14091
|
+
var slugFromGithubPath = (path) => {
|
|
14092
|
+
const segments = path.replace(/^\/+/, "").split("/").filter((s) => s.length > 0).map((s) => s.replace(/\.git$/i, ""));
|
|
14093
|
+
if (segments.length < 2) {
|
|
14094
|
+
return void 0;
|
|
14095
|
+
}
|
|
14096
|
+
const owner = segments[0];
|
|
14097
|
+
const repo = segments[1];
|
|
14098
|
+
if (!owner || !repo) {
|
|
14099
|
+
return void 0;
|
|
14100
|
+
}
|
|
14101
|
+
return `${owner}/${repo}`;
|
|
14102
|
+
};
|
|
14103
|
+
|
|
14104
|
+
// src/git/try-read-github-owner-repo-slug-from-git.ts
|
|
14105
|
+
var tryReadGithubOwnerRepoSlugFromGit = async (params) => {
|
|
14106
|
+
try {
|
|
14107
|
+
const { stdout } = await params.runGit(params.repoRoot, [
|
|
14108
|
+
"remote",
|
|
14109
|
+
"get-url",
|
|
14110
|
+
params.remote
|
|
14111
|
+
]);
|
|
14112
|
+
return parseGithubOwnerRepoFromRemoteUrl(stdout);
|
|
14113
|
+
} catch {
|
|
14114
|
+
return void 0;
|
|
14115
|
+
}
|
|
14116
|
+
};
|
|
14117
|
+
|
|
14118
|
+
// src/git/resolve-effective-git-author-for-data-commit.ts
|
|
14119
|
+
var defaultDataCommitName = "hyper-pm";
|
|
14120
|
+
var defaultDataCommitEmail = "hyper-pm@users.noreply.github.com";
|
|
14121
|
+
var tryReadGitConfigUserName = async (cwd, runGit2) => {
|
|
14122
|
+
try {
|
|
14123
|
+
const { stdout } = await runGit2(cwd, ["config", "--get", "user.name"]);
|
|
14124
|
+
return stdout.trim();
|
|
14125
|
+
} catch {
|
|
14126
|
+
return "";
|
|
14127
|
+
}
|
|
14128
|
+
};
|
|
14129
|
+
var tryReadGitConfigUserEmail = async (cwd, runGit2) => {
|
|
14130
|
+
try {
|
|
14131
|
+
const { stdout } = await runGit2(cwd, ["config", "--get", "user.email"]);
|
|
14132
|
+
return stdout.trim();
|
|
14133
|
+
} catch {
|
|
14134
|
+
return "";
|
|
14135
|
+
}
|
|
14136
|
+
};
|
|
14137
|
+
var resolveEffectiveGitAuthorForDataCommit = async (cwd, runGit2, authorEnv) => {
|
|
14138
|
+
const fromGitName = await tryReadGitConfigUserName(cwd, runGit2);
|
|
14139
|
+
const fromGitEmail = await tryReadGitConfigUserEmail(cwd, runGit2);
|
|
14140
|
+
const name = fromGitName || authorEnv.HYPER_PM_GIT_USER_NAME?.trim() || authorEnv.GIT_AUTHOR_NAME?.trim() || defaultDataCommitName;
|
|
14141
|
+
const email = fromGitEmail || authorEnv.HYPER_PM_GIT_USER_EMAIL?.trim() || authorEnv.GIT_AUTHOR_EMAIL?.trim() || defaultDataCommitEmail;
|
|
14142
|
+
return { name, email };
|
|
14143
|
+
};
|
|
14144
|
+
|
|
14145
|
+
// src/run/commit-data.ts
|
|
14146
|
+
var maxActorSuffixLen = 60;
|
|
14147
|
+
var formatDataBranchCommitMessage = (base, actorSuffix) => {
|
|
14148
|
+
const raw = actorSuffix?.trim();
|
|
14149
|
+
if (!raw) {
|
|
14150
|
+
return base;
|
|
14151
|
+
}
|
|
14152
|
+
const collapsed = raw.replace(/\s+/g, " ");
|
|
14153
|
+
const suffix = collapsed.length > maxActorSuffixLen ? `${collapsed.slice(0, maxActorSuffixLen - 1)}\u2026` : collapsed;
|
|
14154
|
+
return `${base} (${suffix})`;
|
|
14155
|
+
};
|
|
14156
|
+
var commitDataWorktreeIfNeeded = async (worktreePath, message, runGit2, opts) => {
|
|
14157
|
+
const { stdout } = await runGit2(worktreePath, ["status", "--porcelain"]);
|
|
14158
|
+
if (!stdout.trim()) return;
|
|
14159
|
+
await runGit2(worktreePath, ["add", "."]);
|
|
14160
|
+
const authorEnv = opts?.authorEnv ?? env;
|
|
14161
|
+
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
14162
|
+
worktreePath,
|
|
14163
|
+
runGit2,
|
|
14164
|
+
authorEnv
|
|
14165
|
+
);
|
|
14166
|
+
await runGit2(worktreePath, [
|
|
14167
|
+
"-c",
|
|
14168
|
+
`user.name=${name}`,
|
|
14169
|
+
"-c",
|
|
14170
|
+
`user.email=${email}`,
|
|
14171
|
+
"commit",
|
|
14172
|
+
"-m",
|
|
14173
|
+
message
|
|
14174
|
+
]);
|
|
14175
|
+
};
|
|
14176
|
+
|
|
14177
|
+
// src/run/push-data-branch.ts
|
|
14178
|
+
var firstLineFromUnknown = (err) => {
|
|
14179
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
14180
|
+
const line = raw.trim().split("\n")[0]?.trim() ?? raw.trim();
|
|
14181
|
+
return line.length > 0 ? line : "git error";
|
|
14182
|
+
};
|
|
14183
|
+
var tryPushDataBranchToRemote = async (worktreePath, remote, branch, runGit2) => {
|
|
14184
|
+
try {
|
|
14185
|
+
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
14186
|
+
} catch (e) {
|
|
14187
|
+
return {
|
|
14188
|
+
status: "skipped_no_remote",
|
|
14189
|
+
detail: firstLineFromUnknown(e)
|
|
14190
|
+
};
|
|
14191
|
+
}
|
|
14192
|
+
try {
|
|
14193
|
+
await runGit2(worktreePath, ["push", "-u", remote, branch]);
|
|
14194
|
+
return { status: "pushed" };
|
|
14195
|
+
} catch (e) {
|
|
14196
|
+
return {
|
|
14197
|
+
status: "failed",
|
|
14198
|
+
detail: firstLineFromUnknown(e)
|
|
14199
|
+
};
|
|
14200
|
+
}
|
|
14201
|
+
};
|
|
14202
|
+
|
|
14203
|
+
// src/run/sync-remote-data-branch.ts
|
|
14204
|
+
var SyncRemoteDataBranchMergeError = class extends Error {
|
|
14205
|
+
/** @param message - Human-readable reason (stderr excerpt or generic text). */
|
|
14206
|
+
constructor(message) {
|
|
14207
|
+
super(message);
|
|
14208
|
+
this.name = "SyncRemoteDataBranchMergeError";
|
|
14209
|
+
}
|
|
14210
|
+
};
|
|
14211
|
+
var remoteTrackingRef = (remote, dataBranch) => `refs/remotes/${remote}/${dataBranch}`;
|
|
14212
|
+
var mergeRefSpecifier = (remote, dataBranch) => `${remote}/${dataBranch}`;
|
|
14213
|
+
var isLikelyNonFastForwardPushFailure = (detail) => {
|
|
14214
|
+
if (detail === void 0) return false;
|
|
14215
|
+
const d = detail.toLowerCase();
|
|
14216
|
+
return d.includes("non-fast-forward") || d.includes("failed to push");
|
|
14217
|
+
};
|
|
14218
|
+
var classifyMergeOutput = (combined) => {
|
|
14219
|
+
const c = combined.toLowerCase();
|
|
14220
|
+
if (c.includes("already up to date")) {
|
|
14221
|
+
return "up_to_date";
|
|
14222
|
+
}
|
|
14223
|
+
if (c.includes("fast-forward")) {
|
|
14224
|
+
return "fast_forward";
|
|
14225
|
+
}
|
|
14226
|
+
return "merge_commit";
|
|
14227
|
+
};
|
|
14228
|
+
var refExists = async (cwd, ref, runGit2) => {
|
|
14229
|
+
try {
|
|
14230
|
+
await runGit2(cwd, ["show-ref", "--verify", "--quiet", ref]);
|
|
14231
|
+
return true;
|
|
14232
|
+
} catch {
|
|
14233
|
+
return false;
|
|
14234
|
+
}
|
|
14235
|
+
};
|
|
14236
|
+
var fetchRemoteDataBranch = async (worktreePath, remote, dataBranch, runGit2) => {
|
|
14237
|
+
try {
|
|
14238
|
+
await runGit2(worktreePath, ["remote", "get-url", remote]);
|
|
14239
|
+
} catch {
|
|
14240
|
+
return "skipped_no_remote";
|
|
14241
|
+
}
|
|
14242
|
+
try {
|
|
14243
|
+
await runGit2(worktreePath, ["fetch", remote, dataBranch]);
|
|
14244
|
+
return "ok";
|
|
14245
|
+
} catch (e) {
|
|
14246
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14247
|
+
if (/couldn't find remote ref|could not find remote ref/i.test(msg)) {
|
|
14248
|
+
return "remote_branch_absent";
|
|
14234
14249
|
}
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14250
|
+
throw e;
|
|
14251
|
+
}
|
|
14252
|
+
};
|
|
14253
|
+
var mergeRemoteTrackingIntoHead = async (worktreePath, remote, dataBranch, runGit2, authorEnv = env) => {
|
|
14254
|
+
const spec = mergeRefSpecifier(remote, dataBranch);
|
|
14255
|
+
const { name, email } = await resolveEffectiveGitAuthorForDataCommit(
|
|
14256
|
+
worktreePath,
|
|
14257
|
+
runGit2,
|
|
14258
|
+
authorEnv
|
|
14259
|
+
);
|
|
14260
|
+
try {
|
|
14261
|
+
const { stdout, stderr } = await runGit2(worktreePath, [
|
|
14262
|
+
"-c",
|
|
14263
|
+
`user.name=${name}`,
|
|
14264
|
+
"-c",
|
|
14265
|
+
`user.email=${email}`,
|
|
14266
|
+
"merge",
|
|
14267
|
+
"--no-edit",
|
|
14268
|
+
spec
|
|
14269
|
+
]);
|
|
14270
|
+
return classifyMergeOutput(`${stdout}
|
|
14271
|
+
${stderr}`);
|
|
14272
|
+
} catch (e) {
|
|
14273
|
+
await runGit2(worktreePath, ["merge", "--abort"]).catch(() => {
|
|
14274
|
+
});
|
|
14275
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14276
|
+
throw new SyncRemoteDataBranchMergeError(
|
|
14277
|
+
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}`
|
|
14278
|
+
);
|
|
14279
|
+
}
|
|
14280
|
+
};
|
|
14281
|
+
var runRemoteDataBranchGitSync = async (worktreePath, remote, dataBranch, runGit2, skipPush, deps = {}) => {
|
|
14282
|
+
const tryPushFn = deps.tryPush ?? tryPushDataBranchToRemote;
|
|
14283
|
+
const maxPushAttempts = deps.maxPushAttempts ?? 3;
|
|
14284
|
+
const authorEnv = deps.authorEnv ?? env;
|
|
14285
|
+
let dataBranchFetch = await fetchRemoteDataBranch(worktreePath, remote, dataBranch, runGit2);
|
|
14286
|
+
let dataBranchMerge = dataBranchFetch === "skipped_no_remote" ? "skipped_no_remote" : dataBranchFetch === "remote_branch_absent" ? "skipped_missing_remote_branch" : "up_to_date";
|
|
14287
|
+
if (dataBranchFetch === "ok") {
|
|
14288
|
+
const tracking = remoteTrackingRef(remote, dataBranch);
|
|
14289
|
+
const exists = await refExists(worktreePath, tracking, runGit2);
|
|
14290
|
+
if (!exists) {
|
|
14291
|
+
dataBranchMerge = "skipped_missing_remote_branch";
|
|
14292
|
+
} else {
|
|
14293
|
+
dataBranchMerge = await mergeRemoteTrackingIntoHead(
|
|
14294
|
+
worktreePath,
|
|
14295
|
+
remote,
|
|
14296
|
+
dataBranch,
|
|
14297
|
+
runGit2,
|
|
14298
|
+
authorEnv
|
|
14299
|
+
);
|
|
14243
14300
|
}
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14301
|
+
}
|
|
14302
|
+
if (skipPush) {
|
|
14303
|
+
return {
|
|
14304
|
+
dataBranchFetch,
|
|
14305
|
+
dataBranchMerge,
|
|
14306
|
+
dataBranchPush: "skipped_cli",
|
|
14307
|
+
dataBranchPushDetail: "skip-push",
|
|
14308
|
+
pushAttempts: 0
|
|
14309
|
+
};
|
|
14310
|
+
}
|
|
14311
|
+
let pushAttempts = 0;
|
|
14312
|
+
let lastPush = { status: "skipped_no_remote" };
|
|
14313
|
+
const refetchAndMerge = async () => {
|
|
14314
|
+
dataBranchFetch = await fetchRemoteDataBranch(
|
|
14315
|
+
worktreePath,
|
|
14316
|
+
remote,
|
|
14317
|
+
dataBranch,
|
|
14318
|
+
runGit2
|
|
14319
|
+
);
|
|
14320
|
+
if (dataBranchFetch !== "ok") {
|
|
14321
|
+
return;
|
|
14250
14322
|
}
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14323
|
+
const tracking = remoteTrackingRef(remote, dataBranch);
|
|
14324
|
+
const exists = await refExists(worktreePath, tracking, runGit2);
|
|
14325
|
+
if (!exists) {
|
|
14326
|
+
return;
|
|
14254
14327
|
}
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14328
|
+
dataBranchMerge = await mergeRemoteTrackingIntoHead(
|
|
14329
|
+
worktreePath,
|
|
14330
|
+
remote,
|
|
14331
|
+
dataBranch,
|
|
14332
|
+
runGit2,
|
|
14333
|
+
authorEnv
|
|
14334
|
+
);
|
|
14335
|
+
};
|
|
14336
|
+
for (let attempt = 1; attempt <= maxPushAttempts; attempt += 1) {
|
|
14337
|
+
pushAttempts = attempt;
|
|
14338
|
+
lastPush = await tryPushFn(worktreePath, remote, dataBranch, runGit2);
|
|
14339
|
+
if (lastPush.status === "pushed" || lastPush.status === "skipped_no_remote") {
|
|
14263
14340
|
break;
|
|
14264
14341
|
}
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
if (entity === "ticket") {
|
|
14269
|
-
const ticket = projection.tickets.get(entityId);
|
|
14270
|
-
if (!ticket) break;
|
|
14271
|
-
if (evt.payload["title"] !== void 0) {
|
|
14272
|
-
ticket.title = String(evt.payload["title"]);
|
|
14273
|
-
}
|
|
14274
|
-
if (evt.payload["body"] !== void 0) {
|
|
14275
|
-
ticket.body = String(evt.payload["body"]);
|
|
14276
|
-
ticket.linkedPrs = parsePrRefs(ticket.body);
|
|
14277
|
-
}
|
|
14278
|
-
const inboundStatus = resolveInboundTicketStatusFromPayload(
|
|
14279
|
-
ticket,
|
|
14280
|
-
evt.payload
|
|
14281
|
-
);
|
|
14282
|
-
if (inboundStatus !== void 0) {
|
|
14283
|
-
applyStatusIfChanged(ticket, evt, inboundStatus);
|
|
14284
|
-
}
|
|
14285
|
-
applyTicketAssigneeFromPayload(ticket, evt.payload);
|
|
14286
|
-
applyTicketPlanningFieldsFromUpdatePayload(ticket, evt.payload);
|
|
14287
|
-
applyLastUpdate(ticket, evt);
|
|
14288
|
-
}
|
|
14289
|
-
break;
|
|
14342
|
+
if (lastPush.status === "failed" && isLikelyNonFastForwardPushFailure(lastPush.detail) && attempt < maxPushAttempts) {
|
|
14343
|
+
await refetchAndMerge();
|
|
14344
|
+
continue;
|
|
14290
14345
|
}
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14346
|
+
break;
|
|
14347
|
+
}
|
|
14348
|
+
return {
|
|
14349
|
+
dataBranchFetch,
|
|
14350
|
+
dataBranchMerge,
|
|
14351
|
+
dataBranchPush: lastPush.status,
|
|
14352
|
+
...lastPush.detail !== void 0 ? { dataBranchPushDetail: lastPush.detail } : {},
|
|
14353
|
+
pushAttempts
|
|
14354
|
+
};
|
|
14355
|
+
};
|
|
14356
|
+
|
|
14357
|
+
// src/storage/append-event.ts
|
|
14358
|
+
var import_promises5 = require("node:fs/promises");
|
|
14359
|
+
var import_node_path5 = require("node:path");
|
|
14360
|
+
|
|
14361
|
+
// src/storage/event-path.ts
|
|
14362
|
+
var nextEventRelPath = (now, deps) => {
|
|
14363
|
+
const y = String(now.getUTCFullYear());
|
|
14364
|
+
const m = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
14365
|
+
const nextId = deps?.nextId ?? (() => ulid().toLowerCase());
|
|
14366
|
+
const part = `part-${nextId()}`;
|
|
14367
|
+
return `events/${y}/${m}/${part}.jsonl`;
|
|
14368
|
+
};
|
|
14369
|
+
|
|
14370
|
+
// src/storage/append-event.ts
|
|
14371
|
+
var appendEventLine = async (dataRoot, event, clock, opts) => {
|
|
14372
|
+
const rel = nextEventRelPath(clock.now(), {
|
|
14373
|
+
nextId: opts?.nextEventId
|
|
14374
|
+
});
|
|
14375
|
+
const abs = `${dataRoot.replace(/\/$/, "")}/${rel}`;
|
|
14376
|
+
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(abs), { recursive: true });
|
|
14377
|
+
await (0, import_promises5.appendFile)(abs, `${JSON.stringify(event)}
|
|
14378
|
+
`, "utf8");
|
|
14379
|
+
return rel;
|
|
14380
|
+
};
|
|
14381
|
+
|
|
14382
|
+
// src/storage/read-event-lines.ts
|
|
14383
|
+
var import_promises6 = require("node:fs/promises");
|
|
14384
|
+
var import_node_path6 = require("node:path");
|
|
14385
|
+
var listJsonlFiles = async (dir, root) => {
|
|
14386
|
+
const out = [];
|
|
14387
|
+
const entries = await (0, import_promises6.readdir)(dir, { withFileTypes: true });
|
|
14388
|
+
for (const e of entries) {
|
|
14389
|
+
const abs = (0, import_node_path6.join)(dir, e.name);
|
|
14390
|
+
if (e.isDirectory()) {
|
|
14391
|
+
out.push(...await listJsonlFiles(abs, root));
|
|
14392
|
+
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
14393
|
+
out.push((0, import_node_path6.relative)(root, abs).split("\\").join("/"));
|
|
14304
14394
|
}
|
|
14305
|
-
default:
|
|
14306
|
-
break;
|
|
14307
14395
|
}
|
|
14396
|
+
return out;
|
|
14308
14397
|
};
|
|
14309
|
-
var
|
|
14310
|
-
const
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
events.push(eventLineSchema.parse(json));
|
|
14398
|
+
var readAllEventLines = async (dataRoot) => {
|
|
14399
|
+
const eventsRoot = (0, import_node_path6.join)(dataRoot, "events");
|
|
14400
|
+
let files = [];
|
|
14401
|
+
try {
|
|
14402
|
+
files = await listJsonlFiles(eventsRoot, dataRoot);
|
|
14403
|
+
} catch {
|
|
14404
|
+
return [];
|
|
14317
14405
|
}
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14406
|
+
files.sort((a, b) => a.localeCompare(b));
|
|
14407
|
+
const lines = [];
|
|
14408
|
+
for (const rel of files) {
|
|
14409
|
+
const content = await (0, import_promises6.readFile)((0, import_node_path6.join)(dataRoot, rel), "utf8");
|
|
14410
|
+
for (const line of content.split("\n")) {
|
|
14411
|
+
if (line.trim()) lines.push(line);
|
|
14412
|
+
}
|
|
14325
14413
|
}
|
|
14326
|
-
return
|
|
14414
|
+
return lines;
|
|
14327
14415
|
};
|
|
14328
14416
|
|
|
14329
14417
|
// src/sync/collect-github-pr-activity-source-ids.ts
|
|
@@ -14883,14 +14971,15 @@ var parseCliWorkItemStatusList = (raws, deps) => {
|
|
|
14883
14971
|
}
|
|
14884
14972
|
return out;
|
|
14885
14973
|
};
|
|
14886
|
-
var buildTicketListQueryFromReadListOpts = (o, deps) => {
|
|
14974
|
+
var buildTicketListQueryFromReadListOpts = (projection, o, deps) => {
|
|
14887
14975
|
const query = {};
|
|
14888
14976
|
const statusTokens = normalizeCliStringList(o.status);
|
|
14889
14977
|
if (statusTokens.length > 0) {
|
|
14890
14978
|
query.statuses = parseCliWorkItemStatusList(statusTokens, deps);
|
|
14891
14979
|
}
|
|
14892
14980
|
if (o.epic !== void 0 && o.epic !== "") {
|
|
14893
|
-
|
|
14981
|
+
const trimmed = o.epic.trim();
|
|
14982
|
+
query.epicId = resolveEpicId(projection, trimmed) ?? trimmed;
|
|
14894
14983
|
}
|
|
14895
14984
|
const createdAfterMs = parseCliOptionalIsoMillis(
|
|
14896
14985
|
o.createdAfter,
|
|
@@ -15028,7 +15117,8 @@ var buildTicketListQueryFromReadListOpts = (o, deps) => {
|
|
|
15028
15117
|
query.targetFinishBeforeMs = targetFinishBeforeMs;
|
|
15029
15118
|
}
|
|
15030
15119
|
if (o.dependsOn !== void 0 && o.dependsOn.trim() !== "") {
|
|
15031
|
-
|
|
15120
|
+
const trimmed = o.dependsOn.trim();
|
|
15121
|
+
query.dependsOnIncludesId = resolveTicketId(projection, trimmed) ?? trimmed;
|
|
15032
15122
|
}
|
|
15033
15123
|
return Object.keys(query).length > 0 ? query : void 0;
|
|
15034
15124
|
};
|
|
@@ -15105,19 +15195,19 @@ var runCli = async (argv, deps = {
|
|
|
15105
15195
|
const g = readGlobals(this);
|
|
15106
15196
|
const o = this.opts();
|
|
15107
15197
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15198
|
+
const lines = await readAllEventLines(root);
|
|
15199
|
+
const proj = replayEvents(lines);
|
|
15108
15200
|
const id = o.id ?? ulid();
|
|
15109
15201
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15110
|
-
const
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
actor
|
|
15120
|
-
);
|
|
15202
|
+
const payload = {
|
|
15203
|
+
id,
|
|
15204
|
+
number: nextEpicNumberForCreate(proj),
|
|
15205
|
+
title: o.title,
|
|
15206
|
+
body: o.body,
|
|
15207
|
+
...status !== void 0 ? { status } : {}
|
|
15208
|
+
};
|
|
15209
|
+
assertCreatePayloadUsesExpectedHeadNumber(proj, "epic", payload);
|
|
15210
|
+
const evt = makeEvent("EpicCreated", payload, deps.clock, actor);
|
|
15121
15211
|
await appendEventLine(root, evt, deps.clock);
|
|
15122
15212
|
return evt.payload;
|
|
15123
15213
|
});
|
|
@@ -15133,18 +15223,19 @@ var runCli = async (argv, deps = {
|
|
|
15133
15223
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15134
15224
|
const lines = await readAllEventLines(root);
|
|
15135
15225
|
const proj = replayEvents(lines);
|
|
15136
|
-
const
|
|
15226
|
+
const epicId = resolveEpicId(proj, o.id) ?? o.id.trim();
|
|
15227
|
+
const cur = proj.epics.get(epicId);
|
|
15137
15228
|
if (!cur || cur.deleted) {
|
|
15138
15229
|
throw new Error(`Epic not found: ${o.id}`);
|
|
15139
15230
|
}
|
|
15140
15231
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15141
|
-
const draft = { id:
|
|
15232
|
+
const draft = { id: epicId };
|
|
15142
15233
|
if (o.title !== void 0) draft["title"] = o.title;
|
|
15143
15234
|
if (o.body !== void 0) draft["body"] = o.body;
|
|
15144
15235
|
if (status !== void 0) draft["status"] = status;
|
|
15145
15236
|
const payload = pruneEpicOrStoryUpdatePayloadAgainstRow(cur, draft);
|
|
15146
15237
|
if (isNoOpUpdatePayload(payload)) {
|
|
15147
|
-
return { id:
|
|
15238
|
+
return { id: epicId, noChanges: true };
|
|
15148
15239
|
}
|
|
15149
15240
|
const evt = makeEvent("EpicUpdated", payload, deps.clock, actor);
|
|
15150
15241
|
await appendEventLine(root, evt, deps.clock);
|
|
@@ -15155,9 +15246,12 @@ var runCli = async (argv, deps = {
|
|
|
15155
15246
|
const g = readGlobals(this);
|
|
15156
15247
|
const o = this.opts();
|
|
15157
15248
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15158
|
-
const
|
|
15249
|
+
const lines = await readAllEventLines(root);
|
|
15250
|
+
const proj = replayEvents(lines);
|
|
15251
|
+
const epicId = resolveEpicId(proj, o.id) ?? o.id.trim();
|
|
15252
|
+
const evt = makeEvent("EpicDeleted", { id: epicId }, deps.clock, actor);
|
|
15159
15253
|
await appendEventLine(root, evt, deps.clock);
|
|
15160
|
-
return { id:
|
|
15254
|
+
return { id: epicId, deleted: true };
|
|
15161
15255
|
});
|
|
15162
15256
|
});
|
|
15163
15257
|
const story = program2.command("story");
|
|
@@ -15170,24 +15264,23 @@ var runCli = async (argv, deps = {
|
|
|
15170
15264
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15171
15265
|
const lines = await readAllEventLines(root);
|
|
15172
15266
|
const proj = replayEvents(lines);
|
|
15173
|
-
const
|
|
15267
|
+
const epicId = resolveEpicId(proj, o.epic) ?? o.epic.trim();
|
|
15268
|
+
const epic2 = proj.epics.get(epicId);
|
|
15174
15269
|
if (!epic2 || epic2.deleted) {
|
|
15175
15270
|
throw new Error(`Epic not found: ${o.epic}`);
|
|
15176
15271
|
}
|
|
15177
15272
|
const id = o.id ?? ulid();
|
|
15178
15273
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15179
|
-
const
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
actor
|
|
15190
|
-
);
|
|
15274
|
+
const payload = {
|
|
15275
|
+
id,
|
|
15276
|
+
number: nextStoryNumberForCreate(proj),
|
|
15277
|
+
epicId,
|
|
15278
|
+
title: o.title,
|
|
15279
|
+
body: o.body,
|
|
15280
|
+
...status !== void 0 ? { status } : {}
|
|
15281
|
+
};
|
|
15282
|
+
assertCreatePayloadUsesExpectedHeadNumber(proj, "story", payload);
|
|
15283
|
+
const evt = makeEvent("StoryCreated", payload, deps.clock, actor);
|
|
15191
15284
|
await appendEventLine(root, evt, deps.clock);
|
|
15192
15285
|
return evt.payload;
|
|
15193
15286
|
});
|
|
@@ -15206,18 +15299,19 @@ var runCli = async (argv, deps = {
|
|
|
15206
15299
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15207
15300
|
const lines = await readAllEventLines(root);
|
|
15208
15301
|
const proj = replayEvents(lines);
|
|
15209
|
-
const
|
|
15302
|
+
const storyId = resolveStoryId(proj, o.id) ?? o.id.trim();
|
|
15303
|
+
const cur = proj.stories.get(storyId);
|
|
15210
15304
|
if (!cur || cur.deleted) {
|
|
15211
15305
|
throw new Error(`Story not found: ${o.id}`);
|
|
15212
15306
|
}
|
|
15213
15307
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15214
|
-
const draft = { id:
|
|
15308
|
+
const draft = { id: storyId };
|
|
15215
15309
|
if (o.title !== void 0) draft["title"] = o.title;
|
|
15216
15310
|
if (o.body !== void 0) draft["body"] = o.body;
|
|
15217
15311
|
if (status !== void 0) draft["status"] = status;
|
|
15218
15312
|
const payload = pruneEpicOrStoryUpdatePayloadAgainstRow(cur, draft);
|
|
15219
15313
|
if (isNoOpUpdatePayload(payload)) {
|
|
15220
|
-
return { id:
|
|
15314
|
+
return { id: storyId, noChanges: true };
|
|
15221
15315
|
}
|
|
15222
15316
|
const evt = makeEvent("StoryUpdated", payload, deps.clock, actor);
|
|
15223
15317
|
await appendEventLine(root, evt, deps.clock);
|
|
@@ -15228,9 +15322,17 @@ var runCli = async (argv, deps = {
|
|
|
15228
15322
|
const g = readGlobals(this);
|
|
15229
15323
|
const o = this.opts();
|
|
15230
15324
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15231
|
-
const
|
|
15325
|
+
const lines = await readAllEventLines(root);
|
|
15326
|
+
const proj = replayEvents(lines);
|
|
15327
|
+
const storyId = resolveStoryId(proj, o.id) ?? o.id.trim();
|
|
15328
|
+
const evt = makeEvent(
|
|
15329
|
+
"StoryDeleted",
|
|
15330
|
+
{ id: storyId },
|
|
15331
|
+
deps.clock,
|
|
15332
|
+
actor
|
|
15333
|
+
);
|
|
15232
15334
|
await appendEventLine(root, evt, deps.clock);
|
|
15233
|
-
return { id:
|
|
15335
|
+
return { id: storyId, deleted: true };
|
|
15234
15336
|
});
|
|
15235
15337
|
});
|
|
15236
15338
|
const ticket = program2.command("ticket");
|
|
@@ -15321,9 +15423,6 @@ var runCli = async (argv, deps = {
|
|
|
15321
15423
|
deps
|
|
15322
15424
|
);
|
|
15323
15425
|
const dependsOnTokensCreate = normalizeCliStringList(o.dependsOn);
|
|
15324
|
-
const dependsOnNormCreate = normalizeTicketDependsOnIds(
|
|
15325
|
-
dependsOnTokensCreate
|
|
15326
|
-
);
|
|
15327
15426
|
const planningPayload = {
|
|
15328
15427
|
...labelsPayloadCreate,
|
|
15329
15428
|
...priorityParsed !== void 0 ? { priority: priorityParsed } : {},
|
|
@@ -15337,16 +15436,21 @@ var runCli = async (argv, deps = {
|
|
|
15337
15436
|
const proj = replayEvents(lines);
|
|
15338
15437
|
const storyRaw = o.story;
|
|
15339
15438
|
const storyTrimmed = storyRaw !== void 0 && storyRaw !== "" ? storyRaw.trim() : void 0;
|
|
15439
|
+
const storyIdResolved = storyTrimmed !== void 0 ? resolveStoryId(proj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
15340
15440
|
if (storyTrimmed !== void 0) {
|
|
15341
|
-
const storyRow = proj.stories.get(
|
|
15441
|
+
const storyRow = proj.stories.get(storyIdResolved ?? "");
|
|
15342
15442
|
if (!storyRow || storyRow.deleted) {
|
|
15343
15443
|
throw new Error(`Story not found: ${storyTrimmed}`);
|
|
15344
15444
|
}
|
|
15345
15445
|
}
|
|
15346
15446
|
const id = o.id ?? ulid();
|
|
15447
|
+
const dependsOnNormCreate = resolveTicketDependsOnTokensToIds(
|
|
15448
|
+
proj,
|
|
15449
|
+
dependsOnTokensCreate
|
|
15450
|
+
);
|
|
15347
15451
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15348
15452
|
const assigneeCreate = o.assignee !== void 0 ? { assignee: normalizeGithubLogin(o.assignee) } : {};
|
|
15349
|
-
const storyPayload =
|
|
15453
|
+
const storyPayload = storyIdResolved !== void 0 ? { storyId: storyIdResolved } : {};
|
|
15350
15454
|
const branchTokens = normalizeCliStringList(o.branch);
|
|
15351
15455
|
const branchesNorm = normalizeTicketBranchListFromStrings(branchTokens);
|
|
15352
15456
|
const branchesPayload = branchesNorm.length > 0 ? { branches: branchesNorm } : {};
|
|
@@ -15359,19 +15463,26 @@ var runCli = async (argv, deps = {
|
|
|
15359
15463
|
throw new Error(dependsOnErr);
|
|
15360
15464
|
}
|
|
15361
15465
|
const dependsOnPayloadCreate = dependsOnNormCreate.length > 0 ? { dependsOn: dependsOnNormCreate } : {};
|
|
15466
|
+
const createPayload = {
|
|
15467
|
+
id,
|
|
15468
|
+
number: nextTicketNumberForCreate(proj),
|
|
15469
|
+
...storyPayload,
|
|
15470
|
+
title: o.title,
|
|
15471
|
+
body,
|
|
15472
|
+
...status !== void 0 ? { status } : {},
|
|
15473
|
+
...assigneeCreate,
|
|
15474
|
+
...branchesPayload,
|
|
15475
|
+
...dependsOnPayloadCreate,
|
|
15476
|
+
...planningPayload
|
|
15477
|
+
};
|
|
15478
|
+
assertCreatePayloadUsesExpectedHeadNumber(
|
|
15479
|
+
proj,
|
|
15480
|
+
"ticket",
|
|
15481
|
+
createPayload
|
|
15482
|
+
);
|
|
15362
15483
|
const evt = makeEvent(
|
|
15363
15484
|
"TicketCreated",
|
|
15364
|
-
|
|
15365
|
-
id,
|
|
15366
|
-
...storyPayload,
|
|
15367
|
-
title: o.title,
|
|
15368
|
-
body,
|
|
15369
|
-
...status !== void 0 ? { status } : {},
|
|
15370
|
-
...assigneeCreate,
|
|
15371
|
-
...branchesPayload,
|
|
15372
|
-
...dependsOnPayloadCreate,
|
|
15373
|
-
...planningPayload
|
|
15374
|
-
},
|
|
15485
|
+
createPayload,
|
|
15375
15486
|
deps.clock,
|
|
15376
15487
|
actor
|
|
15377
15488
|
);
|
|
@@ -15643,25 +15754,27 @@ ${body}`
|
|
|
15643
15754
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15644
15755
|
const lines = await readAllEventLines(root);
|
|
15645
15756
|
const proj = replayEvents(lines);
|
|
15757
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15758
|
+
const storyIdResolved = storyTrimmed !== void 0 ? resolveStoryId(proj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
15646
15759
|
if (storyTrimmed !== void 0) {
|
|
15647
|
-
const storyRow = proj.stories.get(
|
|
15760
|
+
const storyRow = proj.stories.get(storyIdResolved ?? "");
|
|
15648
15761
|
if (!storyRow || storyRow.deleted) {
|
|
15649
15762
|
throw new Error(`Story not found: ${storyTrimmed}`);
|
|
15650
15763
|
}
|
|
15651
15764
|
}
|
|
15652
|
-
const curTicket = proj.tickets.get(
|
|
15765
|
+
const curTicket = proj.tickets.get(ticketId);
|
|
15653
15766
|
if (curTicket === void 0 || curTicket.deleted) {
|
|
15654
15767
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15655
15768
|
}
|
|
15656
15769
|
const status = parseCliWorkItemStatus(o.status, deps);
|
|
15657
|
-
const payload = { id:
|
|
15770
|
+
const payload = { id: ticketId };
|
|
15658
15771
|
if (o.title !== void 0) payload["title"] = o.title;
|
|
15659
15772
|
if (body !== void 0) payload["body"] = body;
|
|
15660
15773
|
if (status !== void 0) payload["status"] = status;
|
|
15661
15774
|
if (o.unlinkStory) {
|
|
15662
15775
|
payload["storyId"] = null;
|
|
15663
15776
|
} else if (storyTrimmed !== void 0) {
|
|
15664
|
-
payload["storyId"] =
|
|
15777
|
+
payload["storyId"] = storyIdResolved;
|
|
15665
15778
|
}
|
|
15666
15779
|
if (o.unassign) {
|
|
15667
15780
|
payload["assignee"] = null;
|
|
@@ -15718,19 +15831,19 @@ ${body}`
|
|
|
15718
15831
|
nextDepends = [];
|
|
15719
15832
|
} else {
|
|
15720
15833
|
const removeDepSet = new Set(
|
|
15721
|
-
|
|
15834
|
+
resolveTicketDependsOnTokensToIds(proj, removeDependsOnTokens)
|
|
15722
15835
|
);
|
|
15723
15836
|
nextDepends = normalizeTicketDependsOnIds(
|
|
15724
15837
|
(curTicket.dependsOn ?? []).filter((d) => !removeDepSet.has(d))
|
|
15725
15838
|
);
|
|
15726
15839
|
nextDepends = normalizeTicketDependsOnIds([
|
|
15727
15840
|
...nextDepends,
|
|
15728
|
-
...addDependsOnTokens
|
|
15841
|
+
...resolveTicketDependsOnTokensToIds(proj, addDependsOnTokens)
|
|
15729
15842
|
]);
|
|
15730
15843
|
}
|
|
15731
15844
|
const depErr = validateTicketDependsOnForWrite({
|
|
15732
15845
|
projection: proj,
|
|
15733
|
-
fromTicketId:
|
|
15846
|
+
fromTicketId: ticketId,
|
|
15734
15847
|
nextDependsOn: nextDepends
|
|
15735
15848
|
});
|
|
15736
15849
|
if (depErr !== void 0) {
|
|
@@ -15760,7 +15873,7 @@ ${body}`
|
|
|
15760
15873
|
payload
|
|
15761
15874
|
);
|
|
15762
15875
|
if (isNoOpUpdatePayload(prunedPayload)) {
|
|
15763
|
-
return { id:
|
|
15876
|
+
return { id: ticketId, noChanges: true };
|
|
15764
15877
|
}
|
|
15765
15878
|
const evt = makeEvent(
|
|
15766
15879
|
"TicketUpdated",
|
|
@@ -15797,25 +15910,25 @@ ${body}`
|
|
|
15797
15910
|
runGit
|
|
15798
15911
|
);
|
|
15799
15912
|
}
|
|
15800
|
-
const preferred = normalizeTicketBranchName(
|
|
15801
|
-
o.branch ?? `hyper-pm/${o.id}`
|
|
15802
|
-
);
|
|
15803
|
-
if (preferred === void 0) {
|
|
15804
|
-
deps.error(
|
|
15805
|
-
"Invalid --branch or default branch name for this ticket id"
|
|
15806
|
-
);
|
|
15807
|
-
deps.exit(ExitCode.UserError);
|
|
15808
|
-
}
|
|
15809
15913
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15810
15914
|
const lines = await readAllEventLines(root);
|
|
15811
15915
|
const proj = replayEvents(lines);
|
|
15812
|
-
const
|
|
15916
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15917
|
+
const preferred = normalizeTicketBranchName(
|
|
15918
|
+
o.branch ?? `hyper-pm/${ticketId}`
|
|
15919
|
+
);
|
|
15920
|
+
if (preferred === void 0) {
|
|
15921
|
+
throw new Error(
|
|
15922
|
+
"Invalid --branch or default branch name for this ticket id"
|
|
15923
|
+
);
|
|
15924
|
+
}
|
|
15925
|
+
const curRow = proj.tickets.get(ticketId);
|
|
15813
15926
|
if (curRow === void 0 || curRow.deleted) {
|
|
15814
15927
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15815
15928
|
}
|
|
15816
15929
|
if (curRow.status === "done" || curRow.status === "cancelled") {
|
|
15817
15930
|
throw new Error(
|
|
15818
|
-
`Ticket ${
|
|
15931
|
+
`Ticket ${ticketId} is ${curRow.status}; change status before starting work`
|
|
15819
15932
|
);
|
|
15820
15933
|
}
|
|
15821
15934
|
const { branch: chosenBranch } = await pickUniqueLocalBranchName({
|
|
@@ -15836,7 +15949,7 @@ ${body}`
|
|
|
15836
15949
|
}
|
|
15837
15950
|
next = normalizeTicketBranchListFromStrings(next);
|
|
15838
15951
|
const payload = {
|
|
15839
|
-
id:
|
|
15952
|
+
id: ticketId,
|
|
15840
15953
|
status: "in_progress"
|
|
15841
15954
|
};
|
|
15842
15955
|
if (!ticketBranchListsEqual(next, curRow.linkedBranches)) {
|
|
@@ -15845,7 +15958,7 @@ ${body}`
|
|
|
15845
15958
|
const evt = makeEvent("TicketUpdated", payload, deps.clock, actor);
|
|
15846
15959
|
await appendEventLine(root, evt, deps.clock);
|
|
15847
15960
|
const result = {
|
|
15848
|
-
id:
|
|
15961
|
+
id: ticketId,
|
|
15849
15962
|
status: "in_progress",
|
|
15850
15963
|
branch: chosenBranch,
|
|
15851
15964
|
branches: next
|
|
@@ -15867,27 +15980,36 @@ ${body}`
|
|
|
15867
15980
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15868
15981
|
const lines = await readAllEventLines(root);
|
|
15869
15982
|
const proj = replayEvents(lines);
|
|
15870
|
-
const
|
|
15983
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
15984
|
+
const row = proj.tickets.get(ticketId);
|
|
15871
15985
|
if (!row || row.deleted) {
|
|
15872
15986
|
throw new Error(`Ticket not found: ${o.id}`);
|
|
15873
15987
|
}
|
|
15874
15988
|
const evt = makeEvent(
|
|
15875
15989
|
"TicketCommentAdded",
|
|
15876
|
-
{ ticketId
|
|
15990
|
+
{ ticketId, body: trimmed },
|
|
15877
15991
|
deps.clock,
|
|
15878
15992
|
actor
|
|
15879
15993
|
);
|
|
15880
15994
|
await appendEventLine(root, evt, deps.clock);
|
|
15881
|
-
return { commentId: evt.id, ticketId
|
|
15995
|
+
return { commentId: evt.id, ticketId, body: trimmed };
|
|
15882
15996
|
});
|
|
15883
15997
|
});
|
|
15884
15998
|
ticket.command("delete").requiredOption("--id <id>").action(async function() {
|
|
15885
15999
|
const g = readGlobals(this);
|
|
15886
16000
|
const o = this.opts();
|
|
15887
16001
|
await mutateDataBranch(g, deps, async (root, { actor }) => {
|
|
15888
|
-
const
|
|
16002
|
+
const lines = await readAllEventLines(root);
|
|
16003
|
+
const proj = replayEvents(lines);
|
|
16004
|
+
const ticketId = resolveTicketId(proj, o.id) ?? o.id.trim();
|
|
16005
|
+
const evt = makeEvent(
|
|
16006
|
+
"TicketDeleted",
|
|
16007
|
+
{ id: ticketId },
|
|
16008
|
+
deps.clock,
|
|
16009
|
+
actor
|
|
16010
|
+
);
|
|
15889
16011
|
await appendEventLine(root, evt, deps.clock);
|
|
15890
|
-
return { id:
|
|
16012
|
+
return { id: ticketId, deleted: true };
|
|
15891
16013
|
});
|
|
15892
16014
|
});
|
|
15893
16015
|
ticket.command("import-github").description(
|
|
@@ -15958,7 +16080,8 @@ ${body}`
|
|
|
15958
16080
|
const storyRaw = o.story;
|
|
15959
16081
|
const storyTrimmed = storyRaw !== void 0 && storyRaw !== "" ? storyRaw.trim() : void 0;
|
|
15960
16082
|
if (storyTrimmed !== void 0 && storyTrimmed !== "") {
|
|
15961
|
-
const
|
|
16083
|
+
const storyIdForImport = resolveStoryId(proj, storyTrimmed) ?? storyTrimmed;
|
|
16084
|
+
const storyRow = proj.stories.get(storyIdForImport);
|
|
15962
16085
|
if (!storyRow || storyRow.deleted) {
|
|
15963
16086
|
deps.error(`Story not found: ${storyTrimmed}`);
|
|
15964
16087
|
deps.exit(ExitCode.UserError);
|
|
@@ -16001,12 +16124,22 @@ ${body}`
|
|
|
16001
16124
|
);
|
|
16002
16125
|
} else {
|
|
16003
16126
|
const imported = [];
|
|
16127
|
+
let importProj = proj;
|
|
16128
|
+
let importLines = lines;
|
|
16129
|
+
const storyIdForPayload = storyTrimmed !== void 0 && storyTrimmed !== "" ? resolveStoryId(importProj, storyTrimmed) ?? storyTrimmed : void 0;
|
|
16004
16130
|
for (const c of candidates) {
|
|
16005
16131
|
const ticketId = ulid();
|
|
16132
|
+
const nextNum = nextTicketNumberForCreate(importProj);
|
|
16006
16133
|
const createPayload = mergeTicketImportCreatePayload(
|
|
16007
16134
|
ticketId,
|
|
16008
16135
|
c.ticketCreatedPayloadBase,
|
|
16009
|
-
|
|
16136
|
+
storyIdForPayload,
|
|
16137
|
+
nextNum
|
|
16138
|
+
);
|
|
16139
|
+
assertCreatePayloadUsesExpectedHeadNumber(
|
|
16140
|
+
importProj,
|
|
16141
|
+
"ticket",
|
|
16142
|
+
createPayload
|
|
16010
16143
|
);
|
|
16011
16144
|
const createdEvt = makeEvent(
|
|
16012
16145
|
"TicketCreated",
|
|
@@ -16027,6 +16160,8 @@ ${body}`
|
|
|
16027
16160
|
);
|
|
16028
16161
|
await appendEventLine(session.worktreePath, linkEvt, deps.clock);
|
|
16029
16162
|
imported.push({ ticketId, issueNumber: c.issueNumber });
|
|
16163
|
+
importLines = await readAllEventLines(session.worktreePath);
|
|
16164
|
+
importProj = replayEvents(importLines);
|
|
16030
16165
|
}
|
|
16031
16166
|
await commitDataWorktreeIfNeeded(
|
|
16032
16167
|
session.worktreePath,
|
|
@@ -16494,7 +16629,8 @@ var readEpic = async (g, id, deps) => {
|
|
|
16494
16629
|
formatOutput(g.format, { items: listActiveEpicSummaries(proj) })
|
|
16495
16630
|
);
|
|
16496
16631
|
} else {
|
|
16497
|
-
const
|
|
16632
|
+
const epicId = resolveEpicId(proj, id) ?? id.trim();
|
|
16633
|
+
const row = proj.epics.get(epicId);
|
|
16498
16634
|
if (!row || row.deleted) {
|
|
16499
16635
|
deps.error("Epic not found");
|
|
16500
16636
|
exitCode = ExitCode.UserError;
|
|
@@ -16529,7 +16665,8 @@ var readStory = async (g, opts, deps) => {
|
|
|
16529
16665
|
const proj = replayEvents(lines);
|
|
16530
16666
|
const { id, epicId } = opts;
|
|
16531
16667
|
if (id === void 0 || id === "") {
|
|
16532
|
-
const
|
|
16668
|
+
const epicFilterRaw = epicId !== void 0 && epicId !== "" ? epicId : void 0;
|
|
16669
|
+
const epicFilter = epicFilterRaw !== void 0 ? resolveEpicId(proj, epicFilterRaw) ?? epicFilterRaw.trim() : void 0;
|
|
16533
16670
|
if (epicFilter !== void 0) {
|
|
16534
16671
|
const epicRow = proj.epics.get(epicFilter);
|
|
16535
16672
|
if (!epicRow || epicRow.deleted) {
|
|
@@ -16550,7 +16687,8 @@ var readStory = async (g, opts, deps) => {
|
|
|
16550
16687
|
);
|
|
16551
16688
|
}
|
|
16552
16689
|
} else {
|
|
16553
|
-
const
|
|
16690
|
+
const storyId = resolveStoryId(proj, id) ?? id.trim();
|
|
16691
|
+
const row = proj.stories.get(storyId);
|
|
16554
16692
|
if (!row || row.deleted) {
|
|
16555
16693
|
deps.error("Story not found");
|
|
16556
16694
|
exitCode = ExitCode.UserError;
|
|
@@ -16594,8 +16732,8 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16594
16732
|
} = opts;
|
|
16595
16733
|
if (id === void 0 || id === "") {
|
|
16596
16734
|
const listWithoutStory = withoutStoryRaw === true;
|
|
16597
|
-
const storyFilter = storyIdRaw !== void 0 && storyIdRaw !== "" ? storyIdRaw : void 0;
|
|
16598
|
-
const epicFilter = epicIdRaw !== void 0 && epicIdRaw !== "" ? epicIdRaw : void 0;
|
|
16735
|
+
const storyFilter = storyIdRaw !== void 0 && storyIdRaw !== "" ? resolveStoryId(proj, storyIdRaw) ?? storyIdRaw.trim() : void 0;
|
|
16736
|
+
const epicFilter = epicIdRaw !== void 0 && epicIdRaw !== "" ? resolveEpicId(proj, epicIdRaw) ?? epicIdRaw.trim() : void 0;
|
|
16599
16737
|
const sortBy = tryParseTicketListSortField(sortByOpt);
|
|
16600
16738
|
const sortDir = tryParseTicketListSortDir(sortDirOpt);
|
|
16601
16739
|
if (sortBy === void 0) {
|
|
@@ -16634,6 +16772,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16634
16772
|
exitCode = ExitCode.UserError;
|
|
16635
16773
|
} else {
|
|
16636
16774
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16775
|
+
proj,
|
|
16637
16776
|
{ epic: epicFilter, ...listFlagRest },
|
|
16638
16777
|
deps
|
|
16639
16778
|
);
|
|
@@ -16654,6 +16793,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16654
16793
|
exitCode = ExitCode.UserError;
|
|
16655
16794
|
} else {
|
|
16656
16795
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16796
|
+
proj,
|
|
16657
16797
|
listFlagRest,
|
|
16658
16798
|
deps
|
|
16659
16799
|
);
|
|
@@ -16670,6 +16810,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16670
16810
|
}
|
|
16671
16811
|
} else if (listWithoutStory) {
|
|
16672
16812
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16813
|
+
proj,
|
|
16673
16814
|
{ withoutStory: true, ...listFlagRest },
|
|
16674
16815
|
deps
|
|
16675
16816
|
);
|
|
@@ -16684,6 +16825,7 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16684
16825
|
);
|
|
16685
16826
|
} else {
|
|
16686
16827
|
const listQuery = buildTicketListQueryFromReadListOpts(
|
|
16828
|
+
proj,
|
|
16687
16829
|
{ epic: epicFilter, ...listFlagRest },
|
|
16688
16830
|
deps
|
|
16689
16831
|
);
|
|
@@ -16698,7 +16840,8 @@ var readTicket = async (g, opts, deps) => {
|
|
|
16698
16840
|
);
|
|
16699
16841
|
}
|
|
16700
16842
|
} else {
|
|
16701
|
-
const
|
|
16843
|
+
const ticketId = resolveTicketId(proj, id) ?? id.trim();
|
|
16844
|
+
const row = proj.tickets.get(ticketId);
|
|
16702
16845
|
if (!row || row.deleted) {
|
|
16703
16846
|
deps.error("Ticket not found");
|
|
16704
16847
|
exitCode = ExitCode.UserError;
|