@harness-engineering/core 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +135 -2
- package/dist/index.d.ts +135 -2
- package/dist/index.js +567 -36
- package/dist/index.mjs +558 -36
- package/package.json +14 -14
package/dist/index.mjs
CHANGED
|
@@ -10058,6 +10058,7 @@ var VALID_STATUSES = /* @__PURE__ */ new Set([
|
|
|
10058
10058
|
"blocked"
|
|
10059
10059
|
]);
|
|
10060
10060
|
var EM_DASH = "\u2014";
|
|
10061
|
+
var VALID_PRIORITIES = /* @__PURE__ */ new Set(["P0", "P1", "P2", "P3"]);
|
|
10061
10062
|
function parseRoadmap(markdown) {
|
|
10062
10063
|
const fmMatch = markdown.match(/^---\n([\s\S]*?)\n---/);
|
|
10063
10064
|
if (!fmMatch) {
|
|
@@ -10068,9 +10069,12 @@ function parseRoadmap(markdown) {
|
|
|
10068
10069
|
const body = markdown.slice(fmMatch[0].length);
|
|
10069
10070
|
const milestonesResult = parseMilestones(body);
|
|
10070
10071
|
if (!milestonesResult.ok) return milestonesResult;
|
|
10072
|
+
const historyResult = parseAssignmentHistory(body);
|
|
10073
|
+
if (!historyResult.ok) return historyResult;
|
|
10071
10074
|
return Ok2({
|
|
10072
10075
|
frontmatter: fmResult.value,
|
|
10073
|
-
milestones: milestonesResult.value
|
|
10076
|
+
milestones: milestonesResult.value,
|
|
10077
|
+
assignmentHistory: historyResult.value
|
|
10074
10078
|
});
|
|
10075
10079
|
}
|
|
10076
10080
|
function parseFrontmatter2(raw) {
|
|
@@ -10110,12 +10114,17 @@ function parseMilestones(body) {
|
|
|
10110
10114
|
const h2Pattern = /^## (.+)$/gm;
|
|
10111
10115
|
const h2Matches = [];
|
|
10112
10116
|
let match;
|
|
10117
|
+
let bodyEnd = body.length;
|
|
10113
10118
|
while ((match = h2Pattern.exec(body)) !== null) {
|
|
10119
|
+
if (match[1] === "Assignment History") {
|
|
10120
|
+
bodyEnd = match.index;
|
|
10121
|
+
break;
|
|
10122
|
+
}
|
|
10114
10123
|
h2Matches.push({ heading: match[1], startIndex: match.index, fullMatch: match[0] });
|
|
10115
10124
|
}
|
|
10116
10125
|
for (let i = 0; i < h2Matches.length; i++) {
|
|
10117
10126
|
const h2 = h2Matches[i];
|
|
10118
|
-
const nextStart = i + 1 < h2Matches.length ? h2Matches[i + 1].startIndex :
|
|
10127
|
+
const nextStart = i + 1 < h2Matches.length ? h2Matches[i + 1].startIndex : bodyEnd;
|
|
10119
10128
|
const sectionBody = body.slice(h2.startIndex + h2.fullMatch.length, nextStart);
|
|
10120
10129
|
const isBacklog = h2.heading === "Backlog";
|
|
10121
10130
|
const milestoneName = isBacklog ? "Backlog" : h2.heading.replace(/^Milestone:\s*/, "");
|
|
@@ -10181,15 +10190,60 @@ function parseFeatureFields(name, body) {
|
|
|
10181
10190
|
const specRaw = fieldMap.get("Spec") ?? EM_DASH;
|
|
10182
10191
|
const plans = parseListField(fieldMap, "Plans", "Plan");
|
|
10183
10192
|
const blockedBy = parseListField(fieldMap, "Blocked by", "Blockers");
|
|
10193
|
+
const assigneeRaw = fieldMap.get("Assignee") ?? EM_DASH;
|
|
10194
|
+
const priorityRaw = fieldMap.get("Priority") ?? EM_DASH;
|
|
10195
|
+
const externalIdRaw = fieldMap.get("External-ID") ?? EM_DASH;
|
|
10196
|
+
if (priorityRaw !== EM_DASH && !VALID_PRIORITIES.has(priorityRaw)) {
|
|
10197
|
+
return Err2(
|
|
10198
|
+
new Error(
|
|
10199
|
+
`Feature "${name}" has invalid priority: "${priorityRaw}". Valid priorities: ${[...VALID_PRIORITIES].join(", ")}`
|
|
10200
|
+
)
|
|
10201
|
+
);
|
|
10202
|
+
}
|
|
10184
10203
|
return Ok2({
|
|
10185
10204
|
name,
|
|
10186
10205
|
status: statusRaw,
|
|
10187
10206
|
spec: specRaw === EM_DASH ? null : specRaw,
|
|
10188
10207
|
plans,
|
|
10189
10208
|
blockedBy,
|
|
10190
|
-
summary: fieldMap.get("Summary") ?? ""
|
|
10209
|
+
summary: fieldMap.get("Summary") ?? "",
|
|
10210
|
+
assignee: assigneeRaw === EM_DASH ? null : assigneeRaw,
|
|
10211
|
+
priority: priorityRaw === EM_DASH ? null : priorityRaw,
|
|
10212
|
+
externalId: externalIdRaw === EM_DASH ? null : externalIdRaw
|
|
10191
10213
|
});
|
|
10192
10214
|
}
|
|
10215
|
+
function parseAssignmentHistory(body) {
|
|
10216
|
+
const historyMatch = body.match(/^## Assignment History\s*\n/m);
|
|
10217
|
+
if (!historyMatch || historyMatch.index === void 0) return Ok2([]);
|
|
10218
|
+
const historyStart = historyMatch.index + historyMatch[0].length;
|
|
10219
|
+
const rawHistoryBody = body.slice(historyStart);
|
|
10220
|
+
const nextH2 = rawHistoryBody.search(/^## /m);
|
|
10221
|
+
const historyBody = nextH2 === -1 ? rawHistoryBody : rawHistoryBody.slice(0, nextH2);
|
|
10222
|
+
const records = [];
|
|
10223
|
+
const lines = historyBody.split("\n");
|
|
10224
|
+
let pastHeader = false;
|
|
10225
|
+
for (const line of lines) {
|
|
10226
|
+
const trimmed = line.trim();
|
|
10227
|
+
if (!trimmed.startsWith("|")) continue;
|
|
10228
|
+
if (!pastHeader) {
|
|
10229
|
+
if (trimmed.match(/^\|[-\s|]+\|$/)) {
|
|
10230
|
+
pastHeader = true;
|
|
10231
|
+
}
|
|
10232
|
+
continue;
|
|
10233
|
+
}
|
|
10234
|
+
const cells = trimmed.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
|
|
10235
|
+
if (cells.length < 4) continue;
|
|
10236
|
+
const action = cells[2];
|
|
10237
|
+
if (!["assigned", "completed", "unassigned"].includes(action)) continue;
|
|
10238
|
+
records.push({
|
|
10239
|
+
feature: cells[0],
|
|
10240
|
+
assignee: cells[1],
|
|
10241
|
+
action,
|
|
10242
|
+
date: cells[3]
|
|
10243
|
+
});
|
|
10244
|
+
}
|
|
10245
|
+
return Ok2(records);
|
|
10246
|
+
}
|
|
10193
10247
|
|
|
10194
10248
|
// src/roadmap/serialize.ts
|
|
10195
10249
|
var EM_DASH2 = "\u2014";
|
|
@@ -10217,6 +10271,10 @@ function serializeRoadmap(roadmap) {
|
|
|
10217
10271
|
lines.push(...serializeFeature(feature));
|
|
10218
10272
|
}
|
|
10219
10273
|
}
|
|
10274
|
+
if (roadmap.assignmentHistory && roadmap.assignmentHistory.length > 0) {
|
|
10275
|
+
lines.push("");
|
|
10276
|
+
lines.push(...serializeAssignmentHistory(roadmap.assignmentHistory));
|
|
10277
|
+
}
|
|
10220
10278
|
lines.push("");
|
|
10221
10279
|
return lines.join("\n");
|
|
10222
10280
|
}
|
|
@@ -10227,7 +10285,7 @@ function serializeFeature(feature) {
|
|
|
10227
10285
|
const spec = feature.spec ?? EM_DASH2;
|
|
10228
10286
|
const plans = feature.plans.length > 0 ? feature.plans.join(", ") : EM_DASH2;
|
|
10229
10287
|
const blockedBy = feature.blockedBy.length > 0 ? feature.blockedBy.join(", ") : EM_DASH2;
|
|
10230
|
-
|
|
10288
|
+
const lines = [
|
|
10231
10289
|
`### ${feature.name}`,
|
|
10232
10290
|
"",
|
|
10233
10291
|
`- **Status:** ${feature.status}`,
|
|
@@ -10236,12 +10294,45 @@ function serializeFeature(feature) {
|
|
|
10236
10294
|
`- **Blockers:** ${blockedBy}`,
|
|
10237
10295
|
`- **Plan:** ${plans}`
|
|
10238
10296
|
];
|
|
10297
|
+
const hasExtended = feature.assignee !== null || feature.priority !== null || feature.externalId !== null;
|
|
10298
|
+
if (hasExtended) {
|
|
10299
|
+
lines.push(`- **Assignee:** ${feature.assignee ?? EM_DASH2}`);
|
|
10300
|
+
lines.push(`- **Priority:** ${feature.priority ?? EM_DASH2}`);
|
|
10301
|
+
lines.push(`- **External-ID:** ${feature.externalId ?? EM_DASH2}`);
|
|
10302
|
+
}
|
|
10303
|
+
return lines;
|
|
10304
|
+
}
|
|
10305
|
+
function serializeAssignmentHistory(records) {
|
|
10306
|
+
const lines = [
|
|
10307
|
+
"## Assignment History",
|
|
10308
|
+
"| Feature | Assignee | Action | Date |",
|
|
10309
|
+
"|---------|----------|--------|------|"
|
|
10310
|
+
];
|
|
10311
|
+
for (const record of records) {
|
|
10312
|
+
lines.push(`| ${record.feature} | ${record.assignee} | ${record.action} | ${record.date} |`);
|
|
10313
|
+
}
|
|
10314
|
+
return lines;
|
|
10239
10315
|
}
|
|
10240
10316
|
|
|
10241
10317
|
// src/roadmap/sync.ts
|
|
10242
10318
|
import * as fs19 from "fs";
|
|
10243
10319
|
import * as path19 from "path";
|
|
10244
10320
|
import { Ok as Ok3 } from "@harness-engineering/types";
|
|
10321
|
+
|
|
10322
|
+
// src/roadmap/status-rank.ts
|
|
10323
|
+
var STATUS_RANK = {
|
|
10324
|
+
backlog: 0,
|
|
10325
|
+
planned: 1,
|
|
10326
|
+
blocked: 1,
|
|
10327
|
+
// lateral to planned — sync can move to/from blocked freely
|
|
10328
|
+
"in-progress": 2,
|
|
10329
|
+
done: 3
|
|
10330
|
+
};
|
|
10331
|
+
function isRegression(from, to) {
|
|
10332
|
+
return STATUS_RANK[to] < STATUS_RANK[from];
|
|
10333
|
+
}
|
|
10334
|
+
|
|
10335
|
+
// src/roadmap/sync.ts
|
|
10245
10336
|
function inferStatus(feature, projectPath, allFeatures) {
|
|
10246
10337
|
if (feature.blockedBy.length > 0) {
|
|
10247
10338
|
const blockerNotDone = feature.blockedBy.some((blockerName) => {
|
|
@@ -10308,17 +10399,6 @@ function inferStatus(feature, projectPath, allFeatures) {
|
|
|
10308
10399
|
if (anyStarted) return "in-progress";
|
|
10309
10400
|
return null;
|
|
10310
10401
|
}
|
|
10311
|
-
var STATUS_RANK = {
|
|
10312
|
-
backlog: 0,
|
|
10313
|
-
planned: 1,
|
|
10314
|
-
blocked: 1,
|
|
10315
|
-
// lateral to planned — sync can move to/from blocked freely
|
|
10316
|
-
"in-progress": 2,
|
|
10317
|
-
done: 3
|
|
10318
|
-
};
|
|
10319
|
-
function isRegression(from, to) {
|
|
10320
|
-
return STATUS_RANK[to] < STATUS_RANK[from];
|
|
10321
|
-
}
|
|
10322
10402
|
function syncRoadmap(options) {
|
|
10323
10403
|
const { projectPath, roadmap, forceSync } = options;
|
|
10324
10404
|
const allFeatures = roadmap.milestones.flatMap((m) => m.features);
|
|
@@ -10349,6 +10429,438 @@ function applySyncChanges(roadmap, changes) {
|
|
|
10349
10429
|
roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
|
|
10350
10430
|
}
|
|
10351
10431
|
|
|
10432
|
+
// src/roadmap/tracker-sync.ts
|
|
10433
|
+
function resolveReverseStatus(externalStatus, labels, config) {
|
|
10434
|
+
const reverseMap = config.reverseStatusMap;
|
|
10435
|
+
if (!reverseMap) return null;
|
|
10436
|
+
if (reverseMap[externalStatus]) {
|
|
10437
|
+
return reverseMap[externalStatus];
|
|
10438
|
+
}
|
|
10439
|
+
const statusLabels = ["in-progress", "blocked", "planned"];
|
|
10440
|
+
const matchingLabels = labels.filter((l) => statusLabels.includes(l));
|
|
10441
|
+
if (matchingLabels.length === 1) {
|
|
10442
|
+
const compoundKey = `${externalStatus}:${matchingLabels[0]}`;
|
|
10443
|
+
if (reverseMap[compoundKey]) {
|
|
10444
|
+
return reverseMap[compoundKey];
|
|
10445
|
+
}
|
|
10446
|
+
}
|
|
10447
|
+
return null;
|
|
10448
|
+
}
|
|
10449
|
+
|
|
10450
|
+
// src/roadmap/adapters/github-issues.ts
|
|
10451
|
+
import { Ok as Ok4, Err as Err3 } from "@harness-engineering/types";
|
|
10452
|
+
function parseExternalId(externalId) {
|
|
10453
|
+
const match = externalId.match(/^github:([^/]+)\/([^#]+)#(\d+)$/);
|
|
10454
|
+
if (!match) return null;
|
|
10455
|
+
return { owner: match[1], repo: match[2], number: parseInt(match[3], 10) };
|
|
10456
|
+
}
|
|
10457
|
+
function buildExternalId(owner, repo, number) {
|
|
10458
|
+
return `github:${owner}/${repo}#${number}`;
|
|
10459
|
+
}
|
|
10460
|
+
function labelsForStatus(status, config) {
|
|
10461
|
+
const base = config.labels ?? [];
|
|
10462
|
+
const externalStatus = config.statusMap[status];
|
|
10463
|
+
if (externalStatus === "open" && status !== "backlog") {
|
|
10464
|
+
return [...base, status];
|
|
10465
|
+
}
|
|
10466
|
+
return [...base];
|
|
10467
|
+
}
|
|
10468
|
+
var GitHubIssuesSyncAdapter = class {
|
|
10469
|
+
token;
|
|
10470
|
+
config;
|
|
10471
|
+
fetchFn;
|
|
10472
|
+
apiBase;
|
|
10473
|
+
owner;
|
|
10474
|
+
repo;
|
|
10475
|
+
constructor(options) {
|
|
10476
|
+
this.token = options.token;
|
|
10477
|
+
this.config = options.config;
|
|
10478
|
+
this.fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
10479
|
+
this.apiBase = options.apiBase ?? "https://api.github.com";
|
|
10480
|
+
const repoParts = (options.config.repo ?? "").split("/");
|
|
10481
|
+
if (repoParts.length !== 2 || !repoParts[0] || !repoParts[1]) {
|
|
10482
|
+
throw new Error(`Invalid repo format: "${options.config.repo}". Expected "owner/repo".`);
|
|
10483
|
+
}
|
|
10484
|
+
this.owner = repoParts[0];
|
|
10485
|
+
this.repo = repoParts[1];
|
|
10486
|
+
}
|
|
10487
|
+
headers() {
|
|
10488
|
+
return {
|
|
10489
|
+
Authorization: `Bearer ${this.token}`,
|
|
10490
|
+
Accept: "application/vnd.github+json",
|
|
10491
|
+
"Content-Type": "application/json",
|
|
10492
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
10493
|
+
};
|
|
10494
|
+
}
|
|
10495
|
+
async createTicket(feature, milestone) {
|
|
10496
|
+
try {
|
|
10497
|
+
const labels = labelsForStatus(feature.status, this.config);
|
|
10498
|
+
const body = [
|
|
10499
|
+
feature.summary,
|
|
10500
|
+
"",
|
|
10501
|
+
`**Milestone:** ${milestone}`,
|
|
10502
|
+
feature.spec ? `**Spec:** ${feature.spec}` : ""
|
|
10503
|
+
].filter(Boolean).join("\n");
|
|
10504
|
+
const response = await this.fetchFn(
|
|
10505
|
+
`${this.apiBase}/repos/${this.owner}/${this.repo}/issues`,
|
|
10506
|
+
{
|
|
10507
|
+
method: "POST",
|
|
10508
|
+
headers: this.headers(),
|
|
10509
|
+
body: JSON.stringify({
|
|
10510
|
+
title: feature.name,
|
|
10511
|
+
body,
|
|
10512
|
+
labels
|
|
10513
|
+
})
|
|
10514
|
+
}
|
|
10515
|
+
);
|
|
10516
|
+
if (!response.ok) {
|
|
10517
|
+
const text = await response.text();
|
|
10518
|
+
return Err3(new Error(`GitHub API error ${response.status}: ${text}`));
|
|
10519
|
+
}
|
|
10520
|
+
const data = await response.json();
|
|
10521
|
+
const externalId = buildExternalId(this.owner, this.repo, data.number);
|
|
10522
|
+
return Ok4({ externalId, url: data.html_url });
|
|
10523
|
+
} catch (error) {
|
|
10524
|
+
return Err3(error instanceof Error ? error : new Error(String(error)));
|
|
10525
|
+
}
|
|
10526
|
+
}
|
|
10527
|
+
async updateTicket(externalId, changes) {
|
|
10528
|
+
try {
|
|
10529
|
+
const parsed = parseExternalId(externalId);
|
|
10530
|
+
if (!parsed) return Err3(new Error(`Invalid externalId format: "${externalId}"`));
|
|
10531
|
+
const patch = {};
|
|
10532
|
+
if (changes.name !== void 0) patch.title = changes.name;
|
|
10533
|
+
if (changes.summary !== void 0) {
|
|
10534
|
+
const body = [changes.summary, "", changes.spec ? `**Spec:** ${changes.spec}` : ""].filter(Boolean).join("\n");
|
|
10535
|
+
patch.body = body;
|
|
10536
|
+
}
|
|
10537
|
+
if (changes.status !== void 0) {
|
|
10538
|
+
const externalStatus = this.config.statusMap[changes.status];
|
|
10539
|
+
patch.state = externalStatus;
|
|
10540
|
+
patch.labels = labelsForStatus(changes.status, this.config);
|
|
10541
|
+
}
|
|
10542
|
+
const response = await this.fetchFn(
|
|
10543
|
+
`${this.apiBase}/repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}`,
|
|
10544
|
+
{
|
|
10545
|
+
method: "PATCH",
|
|
10546
|
+
headers: this.headers(),
|
|
10547
|
+
body: JSON.stringify(patch)
|
|
10548
|
+
}
|
|
10549
|
+
);
|
|
10550
|
+
if (!response.ok) {
|
|
10551
|
+
const text = await response.text();
|
|
10552
|
+
return Err3(new Error(`GitHub API error ${response.status}: ${text}`));
|
|
10553
|
+
}
|
|
10554
|
+
const data = await response.json();
|
|
10555
|
+
return Ok4({ externalId, url: data.html_url });
|
|
10556
|
+
} catch (error) {
|
|
10557
|
+
return Err3(error instanceof Error ? error : new Error(String(error)));
|
|
10558
|
+
}
|
|
10559
|
+
}
|
|
10560
|
+
async fetchTicketState(externalId) {
|
|
10561
|
+
try {
|
|
10562
|
+
const parsed = parseExternalId(externalId);
|
|
10563
|
+
if (!parsed) return Err3(new Error(`Invalid externalId format: "${externalId}"`));
|
|
10564
|
+
const response = await this.fetchFn(
|
|
10565
|
+
`${this.apiBase}/repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}`,
|
|
10566
|
+
{
|
|
10567
|
+
method: "GET",
|
|
10568
|
+
headers: this.headers()
|
|
10569
|
+
}
|
|
10570
|
+
);
|
|
10571
|
+
if (!response.ok) {
|
|
10572
|
+
const text = await response.text();
|
|
10573
|
+
return Err3(new Error(`GitHub API error ${response.status}: ${text}`));
|
|
10574
|
+
}
|
|
10575
|
+
const data = await response.json();
|
|
10576
|
+
return Ok4({
|
|
10577
|
+
externalId,
|
|
10578
|
+
status: data.state,
|
|
10579
|
+
labels: data.labels.map((l) => l.name),
|
|
10580
|
+
assignee: data.assignee ? `@${data.assignee.login}` : null
|
|
10581
|
+
});
|
|
10582
|
+
} catch (error) {
|
|
10583
|
+
return Err3(error instanceof Error ? error : new Error(String(error)));
|
|
10584
|
+
}
|
|
10585
|
+
}
|
|
10586
|
+
async fetchAllTickets() {
|
|
10587
|
+
try {
|
|
10588
|
+
const filterLabels = this.config.labels ?? [];
|
|
10589
|
+
const labelsParam = filterLabels.length > 0 ? `&labels=${filterLabels.join(",")}` : "";
|
|
10590
|
+
const tickets = [];
|
|
10591
|
+
let page = 1;
|
|
10592
|
+
const perPage = 100;
|
|
10593
|
+
while (true) {
|
|
10594
|
+
const response = await this.fetchFn(
|
|
10595
|
+
`${this.apiBase}/repos/${this.owner}/${this.repo}/issues?state=all&per_page=${perPage}&page=${page}${labelsParam}`,
|
|
10596
|
+
{
|
|
10597
|
+
method: "GET",
|
|
10598
|
+
headers: this.headers()
|
|
10599
|
+
}
|
|
10600
|
+
);
|
|
10601
|
+
if (!response.ok) {
|
|
10602
|
+
const text = await response.text();
|
|
10603
|
+
return Err3(new Error(`GitHub API error ${response.status}: ${text}`));
|
|
10604
|
+
}
|
|
10605
|
+
const data = await response.json();
|
|
10606
|
+
const issues = data.filter((d) => !d.pull_request);
|
|
10607
|
+
for (const issue of issues) {
|
|
10608
|
+
tickets.push({
|
|
10609
|
+
externalId: buildExternalId(this.owner, this.repo, issue.number),
|
|
10610
|
+
status: issue.state,
|
|
10611
|
+
labels: issue.labels.map((l) => l.name),
|
|
10612
|
+
assignee: issue.assignee ? `@${issue.assignee.login}` : null
|
|
10613
|
+
});
|
|
10614
|
+
}
|
|
10615
|
+
if (data.length < perPage) break;
|
|
10616
|
+
page++;
|
|
10617
|
+
}
|
|
10618
|
+
return Ok4(tickets);
|
|
10619
|
+
} catch (error) {
|
|
10620
|
+
return Err3(error instanceof Error ? error : new Error(String(error)));
|
|
10621
|
+
}
|
|
10622
|
+
}
|
|
10623
|
+
async assignTicket(externalId, assignee) {
|
|
10624
|
+
try {
|
|
10625
|
+
const parsed = parseExternalId(externalId);
|
|
10626
|
+
if (!parsed) return Err3(new Error(`Invalid externalId format: "${externalId}"`));
|
|
10627
|
+
const login = assignee.startsWith("@") ? assignee.slice(1) : assignee;
|
|
10628
|
+
const response = await this.fetchFn(
|
|
10629
|
+
`${this.apiBase}/repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}/assignees`,
|
|
10630
|
+
{
|
|
10631
|
+
method: "POST",
|
|
10632
|
+
headers: this.headers(),
|
|
10633
|
+
body: JSON.stringify({ assignees: [login] })
|
|
10634
|
+
}
|
|
10635
|
+
);
|
|
10636
|
+
if (!response.ok) {
|
|
10637
|
+
const text = await response.text();
|
|
10638
|
+
return Err3(new Error(`GitHub API error ${response.status}: ${text}`));
|
|
10639
|
+
}
|
|
10640
|
+
return Ok4(void 0);
|
|
10641
|
+
} catch (error) {
|
|
10642
|
+
return Err3(error instanceof Error ? error : new Error(String(error)));
|
|
10643
|
+
}
|
|
10644
|
+
}
|
|
10645
|
+
};
|
|
10646
|
+
|
|
10647
|
+
// src/roadmap/sync-engine.ts
|
|
10648
|
+
import * as fs20 from "fs";
|
|
10649
|
+
function emptySyncResult() {
|
|
10650
|
+
return { created: [], updated: [], assignmentChanges: [], errors: [] };
|
|
10651
|
+
}
|
|
10652
|
+
async function syncToExternal(roadmap, adapter, _config) {
|
|
10653
|
+
const result = emptySyncResult();
|
|
10654
|
+
for (const milestone of roadmap.milestones) {
|
|
10655
|
+
for (const feature of milestone.features) {
|
|
10656
|
+
if (!feature.externalId) {
|
|
10657
|
+
const createResult = await adapter.createTicket(feature, milestone.name);
|
|
10658
|
+
if (createResult.ok) {
|
|
10659
|
+
feature.externalId = createResult.value.externalId;
|
|
10660
|
+
result.created.push(createResult.value);
|
|
10661
|
+
} else {
|
|
10662
|
+
result.errors.push({ featureOrId: feature.name, error: createResult.error });
|
|
10663
|
+
}
|
|
10664
|
+
} else {
|
|
10665
|
+
const updateResult = await adapter.updateTicket(feature.externalId, feature);
|
|
10666
|
+
if (updateResult.ok) {
|
|
10667
|
+
result.updated.push(feature.externalId);
|
|
10668
|
+
} else {
|
|
10669
|
+
result.errors.push({ featureOrId: feature.externalId, error: updateResult.error });
|
|
10670
|
+
}
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
}
|
|
10674
|
+
return result;
|
|
10675
|
+
}
|
|
10676
|
+
async function syncFromExternal(roadmap, adapter, config, options) {
|
|
10677
|
+
const result = emptySyncResult();
|
|
10678
|
+
const forceSync = options?.forceSync ?? false;
|
|
10679
|
+
const featureByExternalId = /* @__PURE__ */ new Map();
|
|
10680
|
+
for (const milestone of roadmap.milestones) {
|
|
10681
|
+
for (const feature of milestone.features) {
|
|
10682
|
+
if (feature.externalId) {
|
|
10683
|
+
featureByExternalId.set(feature.externalId, feature);
|
|
10684
|
+
}
|
|
10685
|
+
}
|
|
10686
|
+
}
|
|
10687
|
+
if (featureByExternalId.size === 0) return result;
|
|
10688
|
+
const fetchResult = await adapter.fetchAllTickets();
|
|
10689
|
+
if (!fetchResult.ok) {
|
|
10690
|
+
result.errors.push({ featureOrId: "*", error: fetchResult.error });
|
|
10691
|
+
return result;
|
|
10692
|
+
}
|
|
10693
|
+
for (const ticketState of fetchResult.value) {
|
|
10694
|
+
const feature = featureByExternalId.get(ticketState.externalId);
|
|
10695
|
+
if (!feature) continue;
|
|
10696
|
+
if (ticketState.assignee !== feature.assignee) {
|
|
10697
|
+
result.assignmentChanges.push({
|
|
10698
|
+
feature: feature.name,
|
|
10699
|
+
from: feature.assignee,
|
|
10700
|
+
to: ticketState.assignee
|
|
10701
|
+
});
|
|
10702
|
+
feature.assignee = ticketState.assignee;
|
|
10703
|
+
}
|
|
10704
|
+
const resolvedStatus = resolveReverseStatus(ticketState.status, ticketState.labels, config);
|
|
10705
|
+
if (resolvedStatus && resolvedStatus !== feature.status) {
|
|
10706
|
+
const newStatus = resolvedStatus;
|
|
10707
|
+
if (!forceSync && isRegression(feature.status, newStatus)) {
|
|
10708
|
+
continue;
|
|
10709
|
+
}
|
|
10710
|
+
feature.status = newStatus;
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10713
|
+
return result;
|
|
10714
|
+
}
|
|
10715
|
+
var syncMutex = Promise.resolve();
|
|
10716
|
+
async function fullSync(roadmapPath, adapter, config, options) {
|
|
10717
|
+
const previousSync = syncMutex;
|
|
10718
|
+
let releaseMutex;
|
|
10719
|
+
syncMutex = new Promise((resolve5) => {
|
|
10720
|
+
releaseMutex = resolve5;
|
|
10721
|
+
});
|
|
10722
|
+
await previousSync;
|
|
10723
|
+
try {
|
|
10724
|
+
const raw = fs20.readFileSync(roadmapPath, "utf-8");
|
|
10725
|
+
const parseResult = parseRoadmap(raw);
|
|
10726
|
+
if (!parseResult.ok) {
|
|
10727
|
+
return {
|
|
10728
|
+
...emptySyncResult(),
|
|
10729
|
+
errors: [{ featureOrId: "*", error: parseResult.error }]
|
|
10730
|
+
};
|
|
10731
|
+
}
|
|
10732
|
+
const roadmap = parseResult.value;
|
|
10733
|
+
const pushResult = await syncToExternal(roadmap, adapter, config);
|
|
10734
|
+
const pullResult = await syncFromExternal(roadmap, adapter, config, options);
|
|
10735
|
+
fs20.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
|
|
10736
|
+
return {
|
|
10737
|
+
created: pushResult.created,
|
|
10738
|
+
updated: pushResult.updated,
|
|
10739
|
+
assignmentChanges: pullResult.assignmentChanges,
|
|
10740
|
+
errors: [...pushResult.errors, ...pullResult.errors]
|
|
10741
|
+
};
|
|
10742
|
+
} finally {
|
|
10743
|
+
releaseMutex();
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
|
|
10747
|
+
// src/roadmap/pilot-scoring.ts
|
|
10748
|
+
var PRIORITY_RANK = {
|
|
10749
|
+
P0: 0,
|
|
10750
|
+
P1: 1,
|
|
10751
|
+
P2: 2,
|
|
10752
|
+
P3: 3
|
|
10753
|
+
};
|
|
10754
|
+
var POSITION_WEIGHT = 0.5;
|
|
10755
|
+
var DEPENDENTS_WEIGHT = 0.3;
|
|
10756
|
+
var AFFINITY_WEIGHT = 0.2;
|
|
10757
|
+
function scoreRoadmapCandidates(roadmap, options) {
|
|
10758
|
+
const allFeatures = roadmap.milestones.flatMap((m) => m.features);
|
|
10759
|
+
const allFeatureNames = new Set(allFeatures.map((f) => f.name.toLowerCase()));
|
|
10760
|
+
const doneFeatures = new Set(
|
|
10761
|
+
allFeatures.filter((f) => f.status === "done").map((f) => f.name.toLowerCase())
|
|
10762
|
+
);
|
|
10763
|
+
const dependentsCount = /* @__PURE__ */ new Map();
|
|
10764
|
+
for (const feature of allFeatures) {
|
|
10765
|
+
for (const blocker of feature.blockedBy) {
|
|
10766
|
+
const key = blocker.toLowerCase();
|
|
10767
|
+
dependentsCount.set(key, (dependentsCount.get(key) ?? 0) + 1);
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10770
|
+
const maxDependents = Math.max(1, ...dependentsCount.values());
|
|
10771
|
+
const milestoneMap = /* @__PURE__ */ new Map();
|
|
10772
|
+
for (const ms of roadmap.milestones) {
|
|
10773
|
+
milestoneMap.set(
|
|
10774
|
+
ms.name,
|
|
10775
|
+
ms.features.map((f) => f.name.toLowerCase())
|
|
10776
|
+
);
|
|
10777
|
+
}
|
|
10778
|
+
const userCompletedFeatures = /* @__PURE__ */ new Set();
|
|
10779
|
+
if (options?.currentUser) {
|
|
10780
|
+
const user = options.currentUser.toLowerCase();
|
|
10781
|
+
for (const record of roadmap.assignmentHistory) {
|
|
10782
|
+
if (record.action === "completed" && record.assignee.toLowerCase() === user) {
|
|
10783
|
+
userCompletedFeatures.add(record.feature.toLowerCase());
|
|
10784
|
+
}
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
let totalPositions = 0;
|
|
10788
|
+
for (const ms of roadmap.milestones) {
|
|
10789
|
+
totalPositions += ms.features.length;
|
|
10790
|
+
}
|
|
10791
|
+
totalPositions = Math.max(1, totalPositions);
|
|
10792
|
+
const candidates = [];
|
|
10793
|
+
let globalPosition = 0;
|
|
10794
|
+
for (const ms of roadmap.milestones) {
|
|
10795
|
+
for (let featureIdx = 0; featureIdx < ms.features.length; featureIdx++) {
|
|
10796
|
+
const feature = ms.features[featureIdx];
|
|
10797
|
+
globalPosition++;
|
|
10798
|
+
if (feature.status !== "planned" && feature.status !== "backlog") continue;
|
|
10799
|
+
const isBlocked = feature.blockedBy.some((blocker) => {
|
|
10800
|
+
const key = blocker.toLowerCase();
|
|
10801
|
+
return allFeatureNames.has(key) && !doneFeatures.has(key);
|
|
10802
|
+
});
|
|
10803
|
+
if (isBlocked) continue;
|
|
10804
|
+
const positionScore = 1 - (globalPosition - 1) / totalPositions;
|
|
10805
|
+
const deps = dependentsCount.get(feature.name.toLowerCase()) ?? 0;
|
|
10806
|
+
const dependentsScore = deps / maxDependents;
|
|
10807
|
+
let affinityScore = 0;
|
|
10808
|
+
if (userCompletedFeatures.size > 0) {
|
|
10809
|
+
const completedBlockers = feature.blockedBy.filter(
|
|
10810
|
+
(b) => userCompletedFeatures.has(b.toLowerCase())
|
|
10811
|
+
);
|
|
10812
|
+
if (completedBlockers.length > 0) {
|
|
10813
|
+
affinityScore = 1;
|
|
10814
|
+
} else {
|
|
10815
|
+
const siblings = milestoneMap.get(ms.name) ?? [];
|
|
10816
|
+
const completedSiblings = siblings.filter((s) => userCompletedFeatures.has(s));
|
|
10817
|
+
if (completedSiblings.length > 0) {
|
|
10818
|
+
affinityScore = 0.5;
|
|
10819
|
+
}
|
|
10820
|
+
}
|
|
10821
|
+
}
|
|
10822
|
+
const weightedScore = POSITION_WEIGHT * positionScore + DEPENDENTS_WEIGHT * dependentsScore + AFFINITY_WEIGHT * affinityScore;
|
|
10823
|
+
const priorityTier = feature.priority ? PRIORITY_RANK[feature.priority] : null;
|
|
10824
|
+
candidates.push({
|
|
10825
|
+
feature,
|
|
10826
|
+
milestone: ms.name,
|
|
10827
|
+
positionScore,
|
|
10828
|
+
dependentsScore,
|
|
10829
|
+
affinityScore,
|
|
10830
|
+
weightedScore,
|
|
10831
|
+
priorityTier
|
|
10832
|
+
});
|
|
10833
|
+
}
|
|
10834
|
+
}
|
|
10835
|
+
candidates.sort((a, b) => {
|
|
10836
|
+
if (a.priorityTier !== null && b.priorityTier === null) return -1;
|
|
10837
|
+
if (a.priorityTier === null && b.priorityTier !== null) return 1;
|
|
10838
|
+
if (a.priorityTier !== null && b.priorityTier !== null) {
|
|
10839
|
+
if (a.priorityTier !== b.priorityTier) return a.priorityTier - b.priorityTier;
|
|
10840
|
+
}
|
|
10841
|
+
return b.weightedScore - a.weightedScore;
|
|
10842
|
+
});
|
|
10843
|
+
return candidates;
|
|
10844
|
+
}
|
|
10845
|
+
function assignFeature(roadmap, feature, assignee, date) {
|
|
10846
|
+
if (feature.assignee === assignee) return;
|
|
10847
|
+
if (feature.assignee !== null) {
|
|
10848
|
+
roadmap.assignmentHistory.push({
|
|
10849
|
+
feature: feature.name,
|
|
10850
|
+
assignee: feature.assignee,
|
|
10851
|
+
action: "unassigned",
|
|
10852
|
+
date
|
|
10853
|
+
});
|
|
10854
|
+
}
|
|
10855
|
+
feature.assignee = assignee;
|
|
10856
|
+
roadmap.assignmentHistory.push({
|
|
10857
|
+
feature: feature.name,
|
|
10858
|
+
assignee,
|
|
10859
|
+
action: "assigned",
|
|
10860
|
+
date
|
|
10861
|
+
});
|
|
10862
|
+
}
|
|
10863
|
+
|
|
10352
10864
|
// src/interaction/types.ts
|
|
10353
10865
|
import { z as z7 } from "zod";
|
|
10354
10866
|
var InteractionTypeSchema = z7.enum(["question", "confirmation", "transition"]);
|
|
@@ -10379,17 +10891,18 @@ var EmitInteractionInputSchema = z7.object({
|
|
|
10379
10891
|
});
|
|
10380
10892
|
|
|
10381
10893
|
// src/blueprint/scanner.ts
|
|
10382
|
-
import * as
|
|
10894
|
+
import * as fs21 from "fs/promises";
|
|
10383
10895
|
import * as path20 from "path";
|
|
10384
10896
|
var ProjectScanner = class {
|
|
10385
10897
|
constructor(rootDir) {
|
|
10386
10898
|
this.rootDir = rootDir;
|
|
10387
10899
|
}
|
|
10900
|
+
rootDir;
|
|
10388
10901
|
async scan() {
|
|
10389
10902
|
let projectName = path20.basename(this.rootDir);
|
|
10390
10903
|
try {
|
|
10391
10904
|
const pkgPath = path20.join(this.rootDir, "package.json");
|
|
10392
|
-
const pkgRaw = await
|
|
10905
|
+
const pkgRaw = await fs21.readFile(pkgPath, "utf-8");
|
|
10393
10906
|
const pkg = JSON.parse(pkgRaw);
|
|
10394
10907
|
if (pkg.name) projectName = pkg.name;
|
|
10395
10908
|
} catch {
|
|
@@ -10430,7 +10943,7 @@ var ProjectScanner = class {
|
|
|
10430
10943
|
};
|
|
10431
10944
|
|
|
10432
10945
|
// src/blueprint/generator.ts
|
|
10433
|
-
import * as
|
|
10946
|
+
import * as fs22 from "fs/promises";
|
|
10434
10947
|
import * as path21 from "path";
|
|
10435
10948
|
import * as ejs from "ejs";
|
|
10436
10949
|
|
|
@@ -10515,13 +11028,13 @@ var BlueprintGenerator = class {
|
|
|
10515
11028
|
styles: STYLES,
|
|
10516
11029
|
scripts: SCRIPTS
|
|
10517
11030
|
});
|
|
10518
|
-
await
|
|
10519
|
-
await
|
|
11031
|
+
await fs22.mkdir(options.outputDir, { recursive: true });
|
|
11032
|
+
await fs22.writeFile(path21.join(options.outputDir, "index.html"), html);
|
|
10520
11033
|
}
|
|
10521
11034
|
};
|
|
10522
11035
|
|
|
10523
11036
|
// src/update-checker.ts
|
|
10524
|
-
import * as
|
|
11037
|
+
import * as fs23 from "fs";
|
|
10525
11038
|
import * as path22 from "path";
|
|
10526
11039
|
import * as os from "os";
|
|
10527
11040
|
import { spawn } from "child_process";
|
|
@@ -10540,7 +11053,7 @@ function shouldRunCheck(state, intervalMs) {
|
|
|
10540
11053
|
}
|
|
10541
11054
|
function readCheckState() {
|
|
10542
11055
|
try {
|
|
10543
|
-
const raw =
|
|
11056
|
+
const raw = fs23.readFileSync(getStatePath(), "utf-8");
|
|
10544
11057
|
const parsed = JSON.parse(raw);
|
|
10545
11058
|
if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
|
|
10546
11059
|
const state = parsed;
|
|
@@ -11052,7 +11565,7 @@ function getModelPrice(model, dataset) {
|
|
|
11052
11565
|
}
|
|
11053
11566
|
|
|
11054
11567
|
// src/pricing/cache.ts
|
|
11055
|
-
import * as
|
|
11568
|
+
import * as fs24 from "fs/promises";
|
|
11056
11569
|
import * as path23 from "path";
|
|
11057
11570
|
|
|
11058
11571
|
// src/pricing/fallback.json
|
|
@@ -11113,7 +11626,7 @@ function getStalenessMarkerPath(projectRoot) {
|
|
|
11113
11626
|
}
|
|
11114
11627
|
async function readDiskCache(projectRoot) {
|
|
11115
11628
|
try {
|
|
11116
|
-
const raw = await
|
|
11629
|
+
const raw = await fs24.readFile(getCachePath(projectRoot), "utf-8");
|
|
11117
11630
|
return JSON.parse(raw);
|
|
11118
11631
|
} catch {
|
|
11119
11632
|
return null;
|
|
@@ -11121,8 +11634,8 @@ async function readDiskCache(projectRoot) {
|
|
|
11121
11634
|
}
|
|
11122
11635
|
async function writeDiskCache(projectRoot, data) {
|
|
11123
11636
|
const cachePath = getCachePath(projectRoot);
|
|
11124
|
-
await
|
|
11125
|
-
await
|
|
11637
|
+
await fs24.mkdir(path23.dirname(cachePath), { recursive: true });
|
|
11638
|
+
await fs24.writeFile(cachePath, JSON.stringify(data, null, 2));
|
|
11126
11639
|
}
|
|
11127
11640
|
async function fetchFromNetwork() {
|
|
11128
11641
|
try {
|
|
@@ -11149,7 +11662,7 @@ function loadFallbackDataset() {
|
|
|
11149
11662
|
async function checkAndWarnStaleness(projectRoot) {
|
|
11150
11663
|
const markerPath = getStalenessMarkerPath(projectRoot);
|
|
11151
11664
|
try {
|
|
11152
|
-
const raw = await
|
|
11665
|
+
const raw = await fs24.readFile(markerPath, "utf-8");
|
|
11153
11666
|
const marker = JSON.parse(raw);
|
|
11154
11667
|
const firstUse = new Date(marker.firstFallbackUse).getTime();
|
|
11155
11668
|
const now = Date.now();
|
|
@@ -11161,8 +11674,8 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
11161
11674
|
}
|
|
11162
11675
|
} catch {
|
|
11163
11676
|
try {
|
|
11164
|
-
await
|
|
11165
|
-
await
|
|
11677
|
+
await fs24.mkdir(path23.dirname(markerPath), { recursive: true });
|
|
11678
|
+
await fs24.writeFile(
|
|
11166
11679
|
markerPath,
|
|
11167
11680
|
JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
|
|
11168
11681
|
);
|
|
@@ -11172,7 +11685,7 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
11172
11685
|
}
|
|
11173
11686
|
async function clearStalenessMarker(projectRoot) {
|
|
11174
11687
|
try {
|
|
11175
|
-
await
|
|
11688
|
+
await fs24.unlink(getStalenessMarkerPath(projectRoot));
|
|
11176
11689
|
} catch {
|
|
11177
11690
|
}
|
|
11178
11691
|
}
|
|
@@ -11342,7 +11855,7 @@ function aggregateByDay(records) {
|
|
|
11342
11855
|
}
|
|
11343
11856
|
|
|
11344
11857
|
// src/usage/jsonl-reader.ts
|
|
11345
|
-
import * as
|
|
11858
|
+
import * as fs25 from "fs";
|
|
11346
11859
|
import * as path24 from "path";
|
|
11347
11860
|
function parseLine(line, lineNumber) {
|
|
11348
11861
|
let entry;
|
|
@@ -11385,7 +11898,7 @@ function readCostRecords(projectRoot) {
|
|
|
11385
11898
|
const costsFile = path24.join(projectRoot, ".harness", "metrics", "costs.jsonl");
|
|
11386
11899
|
let raw;
|
|
11387
11900
|
try {
|
|
11388
|
-
raw =
|
|
11901
|
+
raw = fs25.readFileSync(costsFile, "utf-8");
|
|
11389
11902
|
} catch {
|
|
11390
11903
|
return [];
|
|
11391
11904
|
}
|
|
@@ -11403,7 +11916,7 @@ function readCostRecords(projectRoot) {
|
|
|
11403
11916
|
}
|
|
11404
11917
|
|
|
11405
11918
|
// src/usage/cc-parser.ts
|
|
11406
|
-
import * as
|
|
11919
|
+
import * as fs26 from "fs";
|
|
11407
11920
|
import * as path25 from "path";
|
|
11408
11921
|
import * as os2 from "os";
|
|
11409
11922
|
function extractUsage(entry) {
|
|
@@ -11451,7 +11964,7 @@ function parseCCLine(line, filePath, lineNumber) {
|
|
|
11451
11964
|
function readCCFile(filePath) {
|
|
11452
11965
|
let raw;
|
|
11453
11966
|
try {
|
|
11454
|
-
raw =
|
|
11967
|
+
raw = fs26.readFileSync(filePath, "utf-8");
|
|
11455
11968
|
} catch {
|
|
11456
11969
|
return [];
|
|
11457
11970
|
}
|
|
@@ -11476,7 +11989,7 @@ function parseCCRecords() {
|
|
|
11476
11989
|
const projectsDir = path25.join(homeDir, ".claude", "projects");
|
|
11477
11990
|
let projectDirs;
|
|
11478
11991
|
try {
|
|
11479
|
-
projectDirs =
|
|
11992
|
+
projectDirs = fs26.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path25.join(projectsDir, d.name));
|
|
11480
11993
|
} catch {
|
|
11481
11994
|
return [];
|
|
11482
11995
|
}
|
|
@@ -11484,7 +11997,7 @@ function parseCCRecords() {
|
|
|
11484
11997
|
for (const dir of projectDirs) {
|
|
11485
11998
|
let files;
|
|
11486
11999
|
try {
|
|
11487
|
-
files =
|
|
12000
|
+
files = fs26.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path25.join(dir, f));
|
|
11488
12001
|
} catch {
|
|
11489
12002
|
continue;
|
|
11490
12003
|
}
|
|
@@ -11542,6 +12055,7 @@ export {
|
|
|
11542
12055
|
ForbiddenImportCollector,
|
|
11543
12056
|
GateConfigSchema,
|
|
11544
12057
|
GateResultSchema,
|
|
12058
|
+
GitHubIssuesSyncAdapter,
|
|
11545
12059
|
HandoffSchema,
|
|
11546
12060
|
HarnessStateSchema,
|
|
11547
12061
|
InteractionTypeSchema,
|
|
@@ -11563,6 +12077,7 @@ export {
|
|
|
11563
12077
|
RuleRegistry,
|
|
11564
12078
|
SECURITY_DESCRIPTOR,
|
|
11565
12079
|
STALENESS_WARNING_DAYS,
|
|
12080
|
+
STATUS_RANK,
|
|
11566
12081
|
SecurityConfigSchema,
|
|
11567
12082
|
SecurityScanner,
|
|
11568
12083
|
SharableBoundaryConfigSchema,
|
|
@@ -11596,6 +12111,7 @@ export {
|
|
|
11596
12111
|
archiveLearnings,
|
|
11597
12112
|
archiveSession,
|
|
11598
12113
|
archiveStream,
|
|
12114
|
+
assignFeature,
|
|
11599
12115
|
buildDependencyGraph,
|
|
11600
12116
|
buildExclusionSet,
|
|
11601
12117
|
buildSnapshot,
|
|
@@ -11660,6 +12176,7 @@ export {
|
|
|
11660
12176
|
formatGitHubSummary,
|
|
11661
12177
|
formatOutline,
|
|
11662
12178
|
formatTerminalOutput,
|
|
12179
|
+
fullSync,
|
|
11663
12180
|
generateAgentsMap,
|
|
11664
12181
|
generateSuggestions,
|
|
11665
12182
|
getActionEmitter,
|
|
@@ -11677,6 +12194,7 @@ export {
|
|
|
11677
12194
|
injectionRules,
|
|
11678
12195
|
insecureDefaultsRules,
|
|
11679
12196
|
isDuplicateFinding,
|
|
12197
|
+
isRegression,
|
|
11680
12198
|
isSmallSuggestion,
|
|
11681
12199
|
isUpdateCheckEnabled,
|
|
11682
12200
|
listActiveSessions,
|
|
@@ -11730,6 +12248,7 @@ export {
|
|
|
11730
12248
|
resetParserCache,
|
|
11731
12249
|
resolveFileToLayer,
|
|
11732
12250
|
resolveModelTier,
|
|
12251
|
+
resolveReverseStatus,
|
|
11733
12252
|
resolveRuleSeverity,
|
|
11734
12253
|
resolveSessionDir,
|
|
11735
12254
|
resolveStreamPath,
|
|
@@ -11750,6 +12269,7 @@ export {
|
|
|
11750
12269
|
saveStreamIndex,
|
|
11751
12270
|
scanForInjection,
|
|
11752
12271
|
scopeContext,
|
|
12272
|
+
scoreRoadmapCandidates,
|
|
11753
12273
|
searchSymbols,
|
|
11754
12274
|
secretRules,
|
|
11755
12275
|
serializeRoadmap,
|
|
@@ -11758,7 +12278,9 @@ export {
|
|
|
11758
12278
|
shouldRunCheck,
|
|
11759
12279
|
spawnBackgroundCheck,
|
|
11760
12280
|
syncConstraintNodes,
|
|
12281
|
+
syncFromExternal,
|
|
11761
12282
|
syncRoadmap,
|
|
12283
|
+
syncToExternal,
|
|
11762
12284
|
tagUncitedFindings,
|
|
11763
12285
|
touchStream,
|
|
11764
12286
|
trackAction,
|