@indigoai-us/hq-cli 5.267.0 → 5.269.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/CHANGELOG.md +23 -0
- package/dist/command-catalog.generated.d.ts +73 -0
- package/dist/command-catalog.generated.js +94 -0
- package/dist/commands/lanes-hold.d.ts +2 -0
- package/dist/commands/lanes-hold.js +122 -310
- package/dist/commands/lanes-message.js +6 -4
- package/dist/commands/lanes-review.d.ts +10 -0
- package/dist/commands/lanes-review.js +56 -0
- package/dist/commands/lanes-shared.d.ts +1 -0
- package/dist/commands/lanes.d.ts +2 -0
- package/dist/commands/lanes.js +26 -1
- package/dist/lib/checkpoint-ontology/multi-writer.d.ts +1 -1
- package/dist/lib/checkpoint-ontology/multi-writer.js +3 -0
- package/dist/lib/lanes/blocker-freshness.js +2 -1
- package/dist/lib/lanes/keep-alive.js +49 -20
- package/dist/lib/lanes/kr-freshness.js +3 -2
- package/dist/lib/lanes/lane-company.d.ts +3 -2
- package/dist/lib/lanes/lane-company.js +21 -4
- package/dist/lib/lanes/manager-status-gate.js +5 -3
- package/dist/lib/lanes/merge-command.d.ts +14 -0
- package/dist/lib/lanes/merge-command.js +363 -0
- package/dist/lib/lanes/reviews.d.ts +38 -0
- package/dist/lib/lanes/reviews.js +395 -0
- package/dist/lib/lanes/watcher.js +4 -2
- package/package.json +1 -1
package/dist/commands/lanes.js
CHANGED
|
@@ -23,6 +23,7 @@ import { registerLaneChecksCommand } from "./lanes-checks.js";
|
|
|
23
23
|
import { registerLaneReportCommands } from "./lanes-report.js";
|
|
24
24
|
import { registerLaneTrackerImportCommand } from "./lanes-import.js";
|
|
25
25
|
import { registerLaneRepoMergeHoldCommand } from "./lanes-hold.js";
|
|
26
|
+
import { registerLaneReviewCommand } from "./lanes-review.js";
|
|
26
27
|
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
27
28
|
import { resolveLanesHqRoot } from "../lib/lanes/hq-root.js";
|
|
28
29
|
import { isSsmRunCommandProcess } from "../lib/lanes/ssm-command-context.js";
|
|
@@ -47,6 +48,7 @@ import { CompanySelectionError } from "../utils/company-selection-error.js";
|
|
|
47
48
|
import { assertNoSecretText } from "../lib/lanes/text-scan.js";
|
|
48
49
|
import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, laneMeshEventIdentity, } from "../lib/lanes/mesh-events.js";
|
|
49
50
|
import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
|
|
51
|
+
import { listLaneReviews } from "../lib/lanes/reviews.js";
|
|
50
52
|
import { effectiveAccountHome } from "../lib/lanes/account-home.js";
|
|
51
53
|
import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, aliveDirectChildren, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readLane, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
|
|
52
54
|
import { activeLaneStories, laneStories, laneStory, storyWarning, } from "../lib/lanes/stories.js";
|
|
@@ -291,6 +293,7 @@ function resolveDeps(deps = {}) {
|
|
|
291
293
|
isSsmOwnerDispatch: deps.isSsmOwnerDispatch ?? (() => isSsmRunCommandProcess()),
|
|
292
294
|
withGrantHireLocks: deps.withGrantHireLocks ?? withLaneHireLocks,
|
|
293
295
|
laneTrackerEnabled: deps.laneTrackerEnabled ?? defaultLaneTrackerEnabled,
|
|
296
|
+
mergeReviewEnabled: deps.mergeReviewEnabled,
|
|
294
297
|
trackerActor: deps.trackerActor ?? defaultTrackerActor,
|
|
295
298
|
};
|
|
296
299
|
}
|
|
@@ -4541,10 +4544,26 @@ async function runShow(ctx, laneId) {
|
|
|
4541
4544
|
env: ctx.env,
|
|
4542
4545
|
now: ctx.now().getTime(),
|
|
4543
4546
|
});
|
|
4547
|
+
const laneIsSenior = allLanes.some((item) => item.senior.kind === "lane" && item.senior.id === laneId);
|
|
4548
|
+
const now = ctx.now().getTime();
|
|
4549
|
+
const reviewListing = laneIsSenior
|
|
4550
|
+
? listLaneReviews(hqRoot, laneId)
|
|
4551
|
+
: { reviews: [], skipped: 0 };
|
|
4552
|
+
if (reviewListing.skipped > 0) {
|
|
4553
|
+
console.error(`hq lanes show: skipped ${reviewListing.skipped} invalid or unreadable review item(s)`);
|
|
4554
|
+
}
|
|
4555
|
+
const recentReviews = reviewListing.reviews
|
|
4556
|
+
.filter((item) => {
|
|
4557
|
+
const recordedAt = Date.parse(item.recorded_at);
|
|
4558
|
+
return recordedAt >= now - 24 * 60 * 60 * 1000 && recordedAt <= now;
|
|
4559
|
+
})
|
|
4560
|
+
.slice(0, 20)
|
|
4561
|
+
.map(({ repo, pr, head_sha, recorded_at }) => ({ repo, pr, head_sha, recorded_at }));
|
|
4544
4562
|
printJson({
|
|
4545
4563
|
ok: true,
|
|
4546
4564
|
action: "show",
|
|
4547
4565
|
lane,
|
|
4566
|
+
...(laneIsSenior ? { reviews: recentReviews, reviews_skipped: reviewListing.skipped } : {}),
|
|
4548
4567
|
...hire,
|
|
4549
4568
|
overdue: Boolean(lane.overdue) || isOverdue(hqRoot, lane.lane_id, ctx.now()),
|
|
4550
4569
|
stalled: Boolean(lane.stalled),
|
|
@@ -4741,7 +4760,7 @@ async function runKeepAlive(ctx, laneId, opts) {
|
|
|
4741
4760
|
const initialLane = readLane(hqRoot, laneId);
|
|
4742
4761
|
assertKeepAliveChangeAllowed(ctx, initialLane, laneId);
|
|
4743
4762
|
lineageAware = await readLanesRegistryFlag(LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, {
|
|
4744
|
-
company: initialLane.company,
|
|
4763
|
+
company: resolveLaneCompany(hqRoot, initialLane).company ?? undefined,
|
|
4745
4764
|
env: ctx.env,
|
|
4746
4765
|
});
|
|
4747
4766
|
}
|
|
@@ -6927,6 +6946,12 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
6927
6946
|
resolveCompany: ctx.resolveCompany,
|
|
6928
6947
|
now: ctx.now,
|
|
6929
6948
|
env: ctx.env,
|
|
6949
|
+
mergeReviewEnabled: ctx.mergeReviewEnabled,
|
|
6950
|
+
}, wrap);
|
|
6951
|
+
registerLaneReviewCommand(lanes, {
|
|
6952
|
+
hqRoot: ctx.hqRoot,
|
|
6953
|
+
env: ctx.env,
|
|
6954
|
+
now: ctx.now,
|
|
6930
6955
|
}, wrap);
|
|
6931
6956
|
registerOutpostPrunerCommand(lanes);
|
|
6932
6957
|
registerLaneKpisCommand(lanes, { hqRoot: ctx.hqRoot, now: ctx.now, wrap });
|
|
@@ -77,7 +77,7 @@ export interface DuplicateGroup {
|
|
|
77
77
|
/** `same_name`: equal canonical names, or one's canonical name is the other's unshared alias. `similar_name`: canonical names match once spaces are removed. */
|
|
78
78
|
reason: "same_name" | "similar_name";
|
|
79
79
|
paths: string[];
|
|
80
|
-
/** Highest `signal_count`, then earliest `first_seen`, then path. */
|
|
80
|
+
/** Highest `signal_count`, then earliest `first_seen`, then a file that is not a numbered copy (`<slug> 2.md`), then path. */
|
|
81
81
|
survivor: string;
|
|
82
82
|
}
|
|
83
83
|
export interface DuplicateReport {
|
|
@@ -285,6 +285,8 @@ export function mergeBackConflicts(hqRoot, company, now) {
|
|
|
285
285
|
}
|
|
286
286
|
return run;
|
|
287
287
|
}
|
|
288
|
+
/** A copy saved next to the original file, e.g. `hq-core 2.md`. */
|
|
289
|
+
const NUMBERED_COPY = / \d+\.md$/;
|
|
288
290
|
/** Groups of writable entities of one type whose names collide. Read-only. */
|
|
289
291
|
export function findDuplicateGroups(index) {
|
|
290
292
|
const parent = new Map();
|
|
@@ -349,6 +351,7 @@ export function findDuplicateGroups(index) {
|
|
|
349
351
|
const fb = Date.parse(eb.first_seen ?? "");
|
|
350
352
|
return (eb.signal_count - ea.signal_count ||
|
|
351
353
|
(Number.isFinite(fa) ? fa : Infinity) - (Number.isFinite(fb) ? fb : Infinity) ||
|
|
354
|
+
Number(NUMBERED_COPY.test(a)) - Number(NUMBERED_COPY.test(b)) ||
|
|
352
355
|
a.localeCompare(b));
|
|
353
356
|
});
|
|
354
357
|
out.push({
|
|
@@ -4,6 +4,7 @@ import { LanesError } from "./errors.js";
|
|
|
4
4
|
import { DEFAULT_BLOCKER_FRESHNESS_HOURS, loadLanesConfig } from "./config.js";
|
|
5
5
|
import { resolveManagerStatusTarget } from "./manager-status-gate.js";
|
|
6
6
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
7
|
+
import { resolveLaneCompany } from "./lane-company.js";
|
|
7
8
|
import { assertNoSecretText } from "./text-scan.js";
|
|
8
9
|
export const BLOCKER_FRESHNESS_FLAG = "lanes.blocker-freshness";
|
|
9
10
|
export const BLOCKER_FRESHNESS_DEFAULT_HOURS = DEFAULT_BLOCKER_FRESHNESS_HOURS;
|
|
@@ -100,7 +101,7 @@ export async function resolveBlockerFreshnessForLane(root, lane, options = {}) {
|
|
|
100
101
|
let flagEnabled;
|
|
101
102
|
try {
|
|
102
103
|
flagEnabled = await (options.readFlag ?? readLanesRegistryFlag)(BLOCKER_FRESHNESS_FLAG, {
|
|
103
|
-
company: lane.company ??
|
|
104
|
+
company: resolveLaneCompany(root, lane).company ?? undefined,
|
|
104
105
|
env: options.env,
|
|
105
106
|
});
|
|
106
107
|
}
|
|
@@ -206,20 +206,23 @@ export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESS
|
|
|
206
206
|
const companyOf = companyForLane ?? ((candidate) => candidate.company);
|
|
207
207
|
const laneCompany = companyOf(lane);
|
|
208
208
|
const lanesById = new Map(lanes.map((candidate) => [candidate.lane_id, candidate]));
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const parent = lanesById.get(parentLaneId);
|
|
217
|
-
parentLaneId = parent?.senior.kind === "lane" ? parent.senior.id : undefined;
|
|
209
|
+
lanesById.set(lane.lane_id, lane);
|
|
210
|
+
const sessionOwners = new Map();
|
|
211
|
+
for (const owner of lanesById.values()) {
|
|
212
|
+
for (const sessionId of recordedLaneSessionIds(owner)) {
|
|
213
|
+
const owners = sessionOwners.get(sessionId) ?? new Set();
|
|
214
|
+
owners.add(owner.lane_id);
|
|
215
|
+
sessionOwners.set(sessionId, owners);
|
|
218
216
|
}
|
|
219
217
|
}
|
|
218
|
+
const targetAncestorIds = lineageAware
|
|
219
|
+
? laneAncestorsFrom(lane.senior, lanesById, sessionOwners)
|
|
220
|
+
: new Set();
|
|
220
221
|
return lanes.find((candidate) => {
|
|
221
222
|
if (candidate.lane_id === lane.lane_id || Date.parse(candidate.created_at) <= createdAt)
|
|
222
223
|
return false;
|
|
224
|
+
if (candidate.state === "cancelled" || candidate.state === "killed" || candidate.state === "failed")
|
|
225
|
+
return false;
|
|
223
226
|
const candidateCompany = companyOf(candidate);
|
|
224
227
|
const sameCompany = laneCompany === null
|
|
225
228
|
? candidateCompany === null
|
|
@@ -229,17 +232,8 @@ export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESS
|
|
|
229
232
|
if (lineageAware && targetAncestorIds.has(candidate.lane_id))
|
|
230
233
|
return false;
|
|
231
234
|
// Any descendant is part of this lead's work tree, not a replacement lead.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
while (parentLaneId) {
|
|
235
|
-
if (parentLaneId === lane.lane_id)
|
|
236
|
-
return false;
|
|
237
|
-
if (visitedLaneIds.has(parentLaneId))
|
|
238
|
-
break;
|
|
239
|
-
visitedLaneIds.add(parentLaneId);
|
|
240
|
-
const parent = lanesById.get(parentLaneId);
|
|
241
|
-
parentLaneId = parent?.senior.kind === "lane" ? parent.senior.id : undefined;
|
|
242
|
-
}
|
|
235
|
+
if (laneAncestorsFrom(candidate.senior, lanesById, sessionOwners).has(lane.lane_id))
|
|
236
|
+
return false;
|
|
243
237
|
const sameLaneSenior = lane.senior.kind === "lane" &&
|
|
244
238
|
candidate.senior.kind === "lane" &&
|
|
245
239
|
candidate.senior.id === lane.senior.id;
|
|
@@ -252,6 +246,41 @@ export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESS
|
|
|
252
246
|
return sameProfile || projectLead;
|
|
253
247
|
});
|
|
254
248
|
}
|
|
249
|
+
/** Session ids durable lane records still identify as spawn/resume sessions. */
|
|
250
|
+
function recordedLaneSessionIds(lane) {
|
|
251
|
+
return [lane.provider_session_id, lane.last_resume?.session_id].filter((sessionId) => typeof sessionId === "string" && sessionId.trim().length > 0);
|
|
252
|
+
}
|
|
253
|
+
/** Follow both lane seniors and session seniors back to the lane that owns each session. */
|
|
254
|
+
function laneAncestorsFrom(senior, lanesById, sessionOwners) {
|
|
255
|
+
const laneIds = new Set();
|
|
256
|
+
const sessionIds = new Set();
|
|
257
|
+
const pending = [senior];
|
|
258
|
+
while (pending.length > 0) {
|
|
259
|
+
const current = pending.pop();
|
|
260
|
+
if (current === undefined)
|
|
261
|
+
break;
|
|
262
|
+
if (current.kind === "lane") {
|
|
263
|
+
const laneId = current.id;
|
|
264
|
+
if (typeof laneId !== "string" || laneId.trim().length === 0 || laneIds.has(laneId))
|
|
265
|
+
continue;
|
|
266
|
+
laneIds.add(laneId);
|
|
267
|
+
const parent = lanesById.get(laneId);
|
|
268
|
+
if (parent !== undefined)
|
|
269
|
+
pending.push(parent.senior);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (current.kind !== "session")
|
|
273
|
+
continue;
|
|
274
|
+
const sessionId = current.id;
|
|
275
|
+
if (typeof sessionId !== "string" || sessionId.trim().length === 0 || sessionIds.has(sessionId))
|
|
276
|
+
continue;
|
|
277
|
+
sessionIds.add(sessionId);
|
|
278
|
+
for (const ownerLaneId of sessionOwners.get(sessionId) ?? []) {
|
|
279
|
+
pending.push({ kind: "lane", id: ownerLaneId });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return laneIds;
|
|
283
|
+
}
|
|
255
284
|
export function keepAliveExclusion(lane, lanes, retiredLaneIds, lineageAware = LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED, companyForLane) {
|
|
256
285
|
if (isRetiredLaneId(lane.lane_id, retiredLaneIds))
|
|
257
286
|
return "retired";
|
|
@@ -5,6 +5,7 @@ import { DEFAULT_KR_FRESHNESS_HOURS, loadLanesConfig } from "./config.js";
|
|
|
5
5
|
import { LanesError } from "./errors.js";
|
|
6
6
|
import { resolveManagerStatusTarget } from "./manager-status-gate.js";
|
|
7
7
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
8
|
+
import { resolveLaneCompany } from "./lane-company.js";
|
|
8
9
|
import { assertNoSecretText } from "./text-scan.js";
|
|
9
10
|
export const KR_FRESHNESS_FLAG = "lanes.kr-freshness";
|
|
10
11
|
export const KR_FRESHNESS_DEFAULT_HOURS = DEFAULT_KR_FRESHNESS_HOURS;
|
|
@@ -327,7 +328,7 @@ export async function resolveKrFreshnessForLane(root, lane, options = {}) {
|
|
|
327
328
|
let flagEnabled;
|
|
328
329
|
try {
|
|
329
330
|
flagEnabled = await (options.readFlag ?? readLanesRegistryFlag)(KR_FRESHNESS_FLAG, {
|
|
330
|
-
company: lane.company ??
|
|
331
|
+
company: resolveLaneCompany(root, lane).company ?? undefined,
|
|
331
332
|
env: options.env,
|
|
332
333
|
});
|
|
333
334
|
}
|
|
@@ -378,7 +379,7 @@ export async function resolveKrFreshnessForShow(root, lane, options = {}) {
|
|
|
378
379
|
let enabled;
|
|
379
380
|
try {
|
|
380
381
|
enabled = await (options.readFlag ?? readLanesRegistryFlag)(KR_FRESHNESS_FLAG, {
|
|
381
|
-
company: lane.company ??
|
|
382
|
+
company: resolveLaneCompany(root, lane).company ?? undefined,
|
|
382
383
|
env: options.env,
|
|
383
384
|
});
|
|
384
385
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { LaneCompanyRef, LaneRecord } from "./types.js";
|
|
2
|
-
export type LaneCompanySource = "lane" | "project" | "unresolved";
|
|
2
|
+
export type LaneCompanySource = "lane" | "mesh_company" | "project" | "unresolved";
|
|
3
3
|
export interface LaneCompanyResolution {
|
|
4
4
|
company: LaneCompanyRef | null;
|
|
5
5
|
source: LaneCompanySource;
|
|
6
6
|
}
|
|
7
7
|
/** Resolve a lane's company without inferring ownership from its worker or caller. */
|
|
8
|
-
export declare function resolveLaneCompany(hqRoot: string, lane: Pick<LaneRecord, "lane_id" | "company" | "project_id">): LaneCompanyResolution;
|
|
8
|
+
export declare function resolveLaneCompany(hqRoot: string, lane: Pick<LaneRecord, "lane_id" | "company" | "mesh_company" | "project_id">): LaneCompanyResolution;
|
|
9
|
+
export declare function laneCompanyUidSource(source: LaneCompanySource): string | undefined;
|
|
9
10
|
//# sourceMappingURL=lane-company.d.ts.map
|
|
@@ -2,10 +2,15 @@ import { resolveProjectQuestionCompany } from "./questions.js";
|
|
|
2
2
|
import { LanesError } from "./errors.js";
|
|
3
3
|
/** Resolve a lane's company without inferring ownership from its worker or caller. */
|
|
4
4
|
export function resolveLaneCompany(hqRoot, lane) {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
8
|
-
return { company: { slug, uid }, source: "lane" };
|
|
5
|
+
const laneCompanySlug = typeof lane.company?.slug === "string" ? lane.company.slug.trim() : "";
|
|
6
|
+
const laneCompanyUid = typeof lane.company?.uid === "string" ? lane.company.uid.trim() : "";
|
|
7
|
+
if (laneCompanySlug && laneCompanyUid) {
|
|
8
|
+
return { company: { slug: laneCompanySlug, uid: laneCompanyUid }, source: "lane" };
|
|
9
|
+
}
|
|
10
|
+
const meshCompanySlug = typeof lane.mesh_company?.slug === "string" ? lane.mesh_company.slug.trim() : "";
|
|
11
|
+
const meshCompanyUid = typeof lane.mesh_company?.uid === "string" ? lane.mesh_company.uid.trim() : "";
|
|
12
|
+
if (meshCompanySlug && meshCompanyUid) {
|
|
13
|
+
return { company: { slug: meshCompanySlug, uid: meshCompanyUid }, source: "mesh_company" };
|
|
9
14
|
}
|
|
10
15
|
let projectCompany;
|
|
11
16
|
try {
|
|
@@ -21,4 +26,16 @@ export function resolveLaneCompany(hqRoot, lane) {
|
|
|
21
26
|
? { company: projectCompany, source: "project" }
|
|
22
27
|
: { company: null, source: "unresolved" };
|
|
23
28
|
}
|
|
29
|
+
export function laneCompanyUidSource(source) {
|
|
30
|
+
switch (source) {
|
|
31
|
+
case "lane":
|
|
32
|
+
return "lane.company.uid";
|
|
33
|
+
case "mesh_company":
|
|
34
|
+
return "lane.mesh_company.uid";
|
|
35
|
+
case "project":
|
|
36
|
+
return "project.cloud_uid";
|
|
37
|
+
case "unresolved":
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
//# sourceMappingURL=lane-company.js.map
|
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { checkCompanyPath } from "./checked-company-path.js";
|
|
4
4
|
import { LanesError } from "./errors.js";
|
|
5
|
+
import { laneCompanyUidSource, resolveLaneCompany } from "./lane-company.js";
|
|
5
6
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
6
7
|
export const MANAGER_STATUS_GATE_FLAG = "lanes.manager-status-gate";
|
|
7
8
|
function isObject(value) {
|
|
@@ -84,7 +85,7 @@ export function resolveManagerStatusTarget(root, lane) {
|
|
|
84
85
|
invalidMapping(`Matched juniors row needs a non-empty ${field}`, registry.filePath, { lane_id: lane.lane_id, field });
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
|
-
const company = lane.company?.slug ??
|
|
88
|
+
const company = resolveLaneCompany(root, lane).company?.slug ?? "";
|
|
88
89
|
const statusPath = checkCompanyPath(root, company, row.status, registry.filePath);
|
|
89
90
|
return {
|
|
90
91
|
manager: true,
|
|
@@ -96,11 +97,12 @@ export async function resolveManagerStatusGateForLane(root, lane, options = {})
|
|
|
96
97
|
const reportError = options.onError ?? ((err) => logManagerStatusGateFailure(lane, err));
|
|
97
98
|
let enabled;
|
|
98
99
|
try {
|
|
99
|
-
const
|
|
100
|
+
const resolution = resolveLaneCompany(root, lane);
|
|
101
|
+
const company = resolution.company ?? undefined;
|
|
100
102
|
enabled = await (options.readFlag ?? readLanesRegistryFlag)(MANAGER_STATUS_GATE_FLAG, {
|
|
101
103
|
company,
|
|
102
104
|
...(company ? {
|
|
103
|
-
companyUidSource:
|
|
105
|
+
companyUidSource: laneCompanyUidSource(resolution.source),
|
|
104
106
|
} : {}),
|
|
105
107
|
env: options.env,
|
|
106
108
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MergeCommandTarget {
|
|
2
|
+
kind: "pr" | "api" | "graphql" | "git";
|
|
3
|
+
repo: string | null;
|
|
4
|
+
pr: number | null;
|
|
5
|
+
pinnedHead: string | null;
|
|
6
|
+
unresolvedReason: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface MergeCommandParseResult {
|
|
9
|
+
targets: MergeCommandTarget[];
|
|
10
|
+
unresolved: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function canonicalRepo(raw: string): string;
|
|
13
|
+
export declare function parseMergeCommands(command: string): MergeCommandParseResult;
|
|
14
|
+
//# sourceMappingURL=merge-command.d.ts.map
|