@indigoai-us/hq-cli 5.345.7 → 5.345.9
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 +8 -0
- package/dist/commands/__fixtures__/make-tar.d.ts +2 -10
- package/dist/commands/__fixtures__/make-tar.js +2 -2
- package/dist/commands/agent-enroll.d.ts +2 -3
- package/dist/commands/agent-enroll.js +2 -2
- package/dist/commands/lanes-message.js +100 -75
- package/dist/commands/mcp-status.d.ts +4 -3
- package/dist/commands/reindex.d.ts +0 -6
- package/dist/commands/reindex.js +1 -1
- package/dist/commands/safe-extract.d.ts +2 -17
- package/dist/commands/safe-extract.js +2 -2
- package/dist/commands/search.d.ts +2 -1
- package/dist/lazy-commands.d.ts +0 -6
- package/dist/lazy-commands.js +1 -1
- package/dist/lib/daemon/heartbeat.d.ts +0 -4
- package/dist/lib/daemon/heartbeat.js +3 -3
- package/dist/lib/daemon/run.d.ts +1 -1
- package/dist/lib/daemon/run.js +11 -2
- package/dist/lib/daemon/supervisor.js +2 -1
- package/dist/lib/doctor/__testing__/fake-hq-tree.d.ts +8 -9
- package/dist/lib/doctor/__testing__/fake-hq-tree.js +1 -1
- package/dist/lib/doctor/checks/anywhere.d.ts +3 -4
- package/dist/lib/doctor/checks/anywhere.js +2 -2
- package/dist/lib/doctor/checks/runtime-probe.d.ts +0 -21
- package/dist/lib/doctor/checks/runtime-probe.js +4 -4
- package/dist/lib/doctor/checks/sync-health.d.ts +2 -3
- package/dist/lib/doctor/checks/sync-health.js +1 -1
- package/dist/lib/doctor/compat.d.ts +2 -1
- package/dist/lib/doctor/deep/classify.d.ts +2 -1
- package/dist/lib/doctor/fix/backup.d.ts +0 -8
- package/dist/lib/doctor/fix/backup.js +2 -2
- package/dist/lib/doctor/fixtures/discover.d.ts +2 -10
- package/dist/lib/doctor/fixtures/discover.js +1 -1
- package/dist/lib/install/claude-targets.d.ts +0 -4
- package/dist/lib/install/claude-targets.js +3 -3
- package/dist/lib/install/codex-targets.d.ts +0 -9
- package/dist/lib/install/codex-targets.js +4 -4
- package/dist/lib/lanes/autopilot.d.ts +2 -17
- package/dist/lib/lanes/autopilot.js +8 -8
- package/dist/lib/lanes/flag-keys.d.ts +2 -0
- package/dist/lib/lanes/flag-keys.js +2 -0
- package/dist/lib/lanes/keep-alive.d.ts +2 -0
- package/dist/lib/lanes/keep-alive.js +9 -0
- package/dist/lib/lanes/reconcile.js +44 -27
- package/dist/lib/lanes/tracker-report.d.ts +16 -15
- package/dist/lib/lanes/wait.d.ts +2 -5
- package/dist/lib/lanes/wait.js +3 -3
- package/dist/lib/mesh/live/report-summary.d.ts +0 -10
- package/dist/lib/mesh/live/report-summary.js +5 -5
- package/package.json +1 -1
|
@@ -22,12 +22,12 @@ import { ANSWERED_QUESTIONS_FILE, armLaneWatcher, envelopeRepairMode, isPidRecor
|
|
|
22
22
|
import { appendCappedHistory, lanesStoreRoot, parseLaneRecord, parseQuestionRecord, readLane, readQuestion, listQuestionIds, updateLane, updateQuestion, } from "./store.js";
|
|
23
23
|
import { applyThrottleDecision, decideAdmission, defaultThrottleDeps, emptyThrottleState, evaluateThrottle, isCpuCheckEnabled, readAvailableMemMb, readThrottleState, resolveCpuBusyFraction, sampleCpuBusyObservation, recordCpuBusyObservation, throttleStatePath, writeThrottleState, } from "./throttle.js";
|
|
24
24
|
import { readLanesRegistryFlag, readLanesRegistryFlagFailOff } from "./registry-flag.js";
|
|
25
|
-
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_LEAD_ADMISSION_PRIORITY_FLAG } from "./flag-keys.js";
|
|
25
|
+
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, LANE_LEAD_ADMISSION_PRIORITY_FLAG, } from "./flag-keys.js";
|
|
26
26
|
import { checkLaneDiskSpace, configuredCodexRolloutHomes, laneDiskAccount, retainCodexRollouts } from "./disk-guard.js";
|
|
27
27
|
import { laneCompanyUidSource, resolveLaneCompany } from "./lane-company.js";
|
|
28
28
|
import { appendDropboxMessage } from "./dropbox.js";
|
|
29
29
|
import { DEFAULT_RUNAWAY_SEARCH_GUARD_CONFIG, listHostProcesses, runRunawayToolGuard, RUNAWAY_TOOL_GUARD_FLAG, } from "./runaway-tool-guard.js";
|
|
30
|
-
import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS,
|
|
30
|
+
import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_GRACE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_RESUME_TEXT, queueLaneTerminalResume, LEAD_LANE_KEEP_ALIVE_INTERRUPTED_RESUME_TEXT, LEAD_LANE_KEEP_ALIVE_MAX_RESUMES, LEAD_LANE_KEEP_ALIVE_RESUME_TEXT, LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, doneKeepAliveVerdict, dueKeepAliveNextCheckMs, hasPendingKeepAliveWork, keepAliveNextCheckAtMs, keepAliveExclusion, loadRetiredLaneIds, leadLaneKeepAliveBackoffMs, undeliveredAnsweredQuestions, } from "./keep-alive.js";
|
|
31
31
|
import { providerSupportsSessionResume } from "./delivery.js";
|
|
32
32
|
import { isIsoDateTime } from "./types.js";
|
|
33
33
|
import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, loadQuotaState, readQuotaSignal, recordAccountQuota, } from "./quota.js";
|
|
@@ -1236,6 +1236,7 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1236
1236
|
const keepAliveFlagByCompany = new Map();
|
|
1237
1237
|
const blockedResumeFlagByCompany = new Map();
|
|
1238
1238
|
const immediateFirstResumeFlagByCompany = new Map();
|
|
1239
|
+
const preciseDueWakeFlagByCompany = new Map();
|
|
1239
1240
|
const supersessionLineageAwareByCompany = new Map();
|
|
1240
1241
|
await Promise.all([...keepAliveFlagCompanies.entries()].map(async ([key, company]) => {
|
|
1241
1242
|
const options = {
|
|
@@ -1246,17 +1247,19 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1246
1247
|
lane.keep_alive === true &&
|
|
1247
1248
|
laneRunsHere(lane, startDeps.host) &&
|
|
1248
1249
|
keepAliveCompanyKey(resolveLaneCompany(hqRoot, lane).company) === key);
|
|
1249
|
-
const [keepAliveEnabled, lineageAware, blockedResumeEnabled, immediateFirstResumeEnabled] = await Promise.all([
|
|
1250
|
+
const [keepAliveEnabled, lineageAware, blockedResumeEnabled, immediateFirstResumeEnabled, preciseDueWakeEnabled] = await Promise.all([
|
|
1250
1251
|
readRegistryFlag(LEAD_LANE_KEEP_ALIVE_FLAG, options),
|
|
1251
1252
|
readRegistryFlag(LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, options),
|
|
1252
1253
|
hasBlockedKeepAliveLane
|
|
1253
1254
|
? readRegistryFlag(LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, options)
|
|
1254
1255
|
: Promise.resolve(false),
|
|
1255
1256
|
readRegistryFlag(LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, options),
|
|
1257
|
+
readRegistryFlag(LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, options),
|
|
1256
1258
|
]);
|
|
1257
1259
|
keepAliveFlagByCompany.set(key, keepAliveEnabled);
|
|
1258
1260
|
blockedResumeFlagByCompany.set(key, blockedResumeEnabled);
|
|
1259
1261
|
immediateFirstResumeFlagByCompany.set(key, immediateFirstResumeEnabled);
|
|
1262
|
+
preciseDueWakeFlagByCompany.set(key, preciseDueWakeEnabled);
|
|
1260
1263
|
supersessionLineageAwareByCompany.set(key, lineageAware);
|
|
1261
1264
|
}));
|
|
1262
1265
|
const admissionThrottleDeps = startDeps.throttleDeps ?? defaultThrottleDeps(startDeps.env ?? process.env);
|
|
@@ -1278,7 +1281,7 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1278
1281
|
const freshLanes = loadLaneRecords(hqRoot, summary);
|
|
1279
1282
|
const freshQuestions = loadQuestionRecords(hqRoot, summary);
|
|
1280
1283
|
await closeInterruptedDoneStoryWorkers(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, storyCloseEnabledByCompany);
|
|
1281
|
-
const dueKeepAlivesAdmitted = await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, keepAliveFlagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, deps.terminalKeepAliveCandidate, async (laneIds) => {
|
|
1284
|
+
const dueKeepAlivesAdmitted = await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, keepAliveFlagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, preciseDueWakeFlagByCompany, deps.terminalKeepAliveCandidate, async (laneIds) => {
|
|
1282
1285
|
dueKeepAliveLaneIds = new Set(laneIds);
|
|
1283
1286
|
await admitQueued(hqRoot, loadLaneRecords(hqRoot, summary), summary, admissionDeps, now, laneIds);
|
|
1284
1287
|
});
|
|
@@ -2513,7 +2516,7 @@ function appendBlockedKeepAliveHistory(hqRoot, lane, terminalAt, at, reason, dep
|
|
|
2513
2516
|
}),
|
|
2514
2517
|
}), false);
|
|
2515
2518
|
}
|
|
2516
|
-
async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, flagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, terminalKeepAliveCandidate, admitDueCandidates) {
|
|
2519
|
+
async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, flagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, preciseDueWakeFlagByCompany, terminalKeepAliveCandidate, admitDueCandidates) {
|
|
2517
2520
|
const nowMs = now.getTime();
|
|
2518
2521
|
const nowIso = now.toISOString();
|
|
2519
2522
|
const config = loadLanesConfig(hqRoot);
|
|
@@ -2546,10 +2549,14 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2546
2549
|
continue;
|
|
2547
2550
|
const anchorMs = Date.parse(lane.last_envelope?.at ?? lane.updated_at);
|
|
2548
2551
|
const nextCheckMs = Date.parse(envelope.next_check_at ?? "");
|
|
2549
|
-
if (!Number.isFinite(anchorMs)
|
|
2552
|
+
if (!Number.isFinite(anchorMs))
|
|
2550
2553
|
continue;
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2554
|
+
const companyKey = keepAliveCompanyKey(resolveLaneCompany(hqRoot, lane).company);
|
|
2555
|
+
const preciseDueWakeEnabled = preciseDueWakeFlagByCompany.get(companyKey) === true;
|
|
2556
|
+
// This set only accelerates lanes with an explicit due next-check. Retry
|
|
2557
|
+
// backoff is decided once in the resume path and queuedDueCandidateIds.
|
|
2558
|
+
const dueNextCheckMs = dueKeepAliveNextCheckMs(nextCheckMs, nowMs, anchorMs, preciseDueWakeEnabled);
|
|
2559
|
+
if (dueNextCheckMs !== undefined &&
|
|
2553
2560
|
doneKeepAliveVerdict(lane, envelope, false, { nowMs, nextCheckAnchorMs: anchorMs }) === "eligible")
|
|
2554
2561
|
dueCandidateIds.add(lane.lane_id);
|
|
2555
2562
|
}
|
|
@@ -2939,23 +2946,13 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2939
2946
|
const storedNextMs = resetByHuman
|
|
2940
2947
|
? Number.NaN
|
|
2941
2948
|
: Date.parse(current.keep_alive_next_eligible_at ?? "");
|
|
2942
|
-
|
|
2949
|
+
let nextEligibleMs = Number.isFinite(storedNextMs)
|
|
2943
2950
|
? Math.max(attemptEligibleMs, storedNextMs)
|
|
2944
2951
|
: attemptEligibleMs;
|
|
2945
|
-
if (nowMs < nextEligibleMs) {
|
|
2946
|
-
let skipLane = current;
|
|
2947
|
-
if (resetByHuman && hasKeepAliveProgress(current)) {
|
|
2948
|
-
const clearedProgress = casLaneIf(hqRoot, current.lane_id, (latestLane) => latestLane.version === current.version &&
|
|
2949
|
-
latestLane.state === current.state &&
|
|
2950
|
-
latestLane.keep_alive === true &&
|
|
2951
|
-
latestLane.keep_alive_opted_in_at === current.keep_alive_opted_in_at, (latestLane) => clearedKeepAliveProgress(latestLane), deps.dryRun);
|
|
2952
|
-
skipLane = clearedProgress.record;
|
|
2953
|
-
}
|
|
2954
|
-
recordKeepAliveSkipEvent(hqRoot, skipLane, "backoff", skipLane.version, summary, deps, new Date(nextEligibleMs).toISOString());
|
|
2955
|
-
continue;
|
|
2956
|
-
}
|
|
2957
|
-
const nextEligibleAt = new Date(nowMs + leadLaneKeepAliveBackoffMs(immediateFirstResumeEnabled ? attempt : attempt + 1)).toISOString();
|
|
2958
2952
|
let resumeReason = "backoff";
|
|
2953
|
+
let dueNextCheckMs;
|
|
2954
|
+
const preciseDueWakeEnabled = initialState === "done" &&
|
|
2955
|
+
preciseDueWakeFlagByCompany.get(keepAliveCompanyKey(companyForLane(current))) === true;
|
|
2959
2956
|
if (initialState === "done") {
|
|
2960
2957
|
if (hasPendingKeepAliveWork(hqRoot, current, questions)) {
|
|
2961
2958
|
resumeReason = "pending_work";
|
|
@@ -2965,13 +2962,30 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2965
2962
|
const nextCheckMs = Date.parse(finalEnvelope?.next_check_at ?? "");
|
|
2966
2963
|
const anchorMs = Date.parse(current.last_envelope?.at ?? current.updated_at);
|
|
2967
2964
|
if (Number.isFinite(nextCheckMs) && Number.isFinite(anchorMs)) {
|
|
2968
|
-
const
|
|
2969
|
-
if (
|
|
2965
|
+
const eligibleNextCheckMs = dueKeepAliveNextCheckMs(nextCheckMs, nowMs, anchorMs, preciseDueWakeEnabled);
|
|
2966
|
+
if (eligibleNextCheckMs !== undefined &&
|
|
2967
|
+
(preciseDueWakeEnabled || eligibleNextCheckMs > nextEligibleMs)) {
|
|
2970
2968
|
resumeReason = "next_check_at_due";
|
|
2969
|
+
dueNextCheckMs = eligibleNextCheckMs;
|
|
2970
|
+
if (preciseDueWakeEnabled)
|
|
2971
|
+
nextEligibleMs = Math.min(nextEligibleMs, eligibleNextCheckMs);
|
|
2971
2972
|
}
|
|
2972
2973
|
}
|
|
2973
2974
|
}
|
|
2974
2975
|
}
|
|
2976
|
+
if (nowMs < nextEligibleMs) {
|
|
2977
|
+
let skipLane = current;
|
|
2978
|
+
if (resetByHuman && hasKeepAliveProgress(current)) {
|
|
2979
|
+
const clearedProgress = casLaneIf(hqRoot, current.lane_id, (latestLane) => latestLane.version === current.version &&
|
|
2980
|
+
latestLane.state === current.state &&
|
|
2981
|
+
latestLane.keep_alive === true &&
|
|
2982
|
+
latestLane.keep_alive_opted_in_at === current.keep_alive_opted_in_at, (latestLane) => clearedKeepAliveProgress(latestLane), deps.dryRun);
|
|
2983
|
+
skipLane = clearedProgress.record;
|
|
2984
|
+
}
|
|
2985
|
+
recordKeepAliveSkipEvent(hqRoot, skipLane, "backoff", skipLane.version, summary, deps, new Date(nextEligibleMs).toISOString());
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const nextEligibleAt = new Date(nowMs + leadLaneKeepAliveBackoffMs(immediateFirstResumeEnabled ? attempt : attempt + 1)).toISOString();
|
|
2975
2989
|
const queuedCount = loadLaneRecords(hqRoot, summary).filter((queuedLane) => queuedLane.state === "queued" &&
|
|
2976
2990
|
queuedLane.provider === current.provider &&
|
|
2977
2991
|
laneRunsHere(queuedLane, deps.host) &&
|
|
@@ -3233,7 +3247,8 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
3233
3247
|
}
|
|
3234
3248
|
if (!queued.changed)
|
|
3235
3249
|
continue;
|
|
3236
|
-
if (resumeReason === "next_check_at_due"
|
|
3250
|
+
if (resumeReason === "next_check_at_due" ||
|
|
3251
|
+
(preciseDueWakeEnabled && initialState === "done" && nowMs >= nextEligibleMs && dueNextCheckMs === undefined))
|
|
3237
3252
|
queuedDueCandidateIds.add(current.lane_id);
|
|
3238
3253
|
summary.resumed.push({
|
|
3239
3254
|
id: current.lane_id,
|
|
@@ -3478,11 +3493,13 @@ async function runTerminalKeepAliveCandidatePass(hqRoot, lanes, summary, deps, n
|
|
|
3478
3493
|
let keepAliveEnabled;
|
|
3479
3494
|
let lineageAware;
|
|
3480
3495
|
let immediateFirstResumeEnabled;
|
|
3496
|
+
let preciseDueWakeEnabled;
|
|
3481
3497
|
try {
|
|
3482
|
-
[keepAliveEnabled, lineageAware, immediateFirstResumeEnabled] = await Promise.all([
|
|
3498
|
+
[keepAliveEnabled, lineageAware, immediateFirstResumeEnabled, preciseDueWakeEnabled] = await Promise.all([
|
|
3483
3499
|
readFlag(LEAD_LANE_KEEP_ALIVE_FLAG, options),
|
|
3484
3500
|
readFlag(LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, options),
|
|
3485
3501
|
readFlag(LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, options),
|
|
3502
|
+
readFlag(LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, options),
|
|
3486
3503
|
]);
|
|
3487
3504
|
}
|
|
3488
3505
|
catch (err) {
|
|
@@ -3497,7 +3514,7 @@ async function runTerminalKeepAliveCandidatePass(hqRoot, lanes, summary, deps, n
|
|
|
3497
3514
|
const current = freshLanes.find((row) => row.lane_id === candidate.laneId);
|
|
3498
3515
|
if (!current || current.version !== candidate.version || current.state !== "done")
|
|
3499
3516
|
return;
|
|
3500
|
-
await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, deps, now, new Map([[keepAliveCompanyKey(company), true]]), new Map([[keepAliveCompanyKey(company), lineageAware]]), new Map(), new Map([[keepAliveCompanyKey(company), immediateFirstResumeEnabled]]), candidate);
|
|
3517
|
+
await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, deps, now, new Map([[keepAliveCompanyKey(company), true]]), new Map([[keepAliveCompanyKey(company), lineageAware]]), new Map(), new Map([[keepAliveCompanyKey(company), immediateFirstResumeEnabled]]), new Map([[keepAliveCompanyKey(company), preciseDueWakeEnabled]]), candidate);
|
|
3501
3518
|
await admitQueued(hqRoot, loadLaneRecords(hqRoot, summary), summary, deps, now, new Set([candidate.laneId]));
|
|
3502
3519
|
});
|
|
3503
3520
|
return summary;
|
|
@@ -3,12 +3,12 @@ import type { QuestionRecord } from "./types.js";
|
|
|
3
3
|
import type { TrackerRecord } from "./tracker-store.js";
|
|
4
4
|
export type ReportStoryStatus = "queued" | "in_progress" | "review" | "done" | "dropped";
|
|
5
5
|
export type ReportAudience = "owner" | "operator" | "lane";
|
|
6
|
-
|
|
6
|
+
type ApprovalState = "proposal" | "approved";
|
|
7
7
|
export interface TrackerReportRecord extends TrackerRecord {
|
|
8
8
|
/** Absolute path of the validated on-disk record; used only in errors. */
|
|
9
9
|
source_path: string;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
interface TrackerReportStory {
|
|
12
12
|
id: string;
|
|
13
13
|
title: string;
|
|
14
14
|
status: ReportStoryStatus;
|
|
@@ -24,18 +24,18 @@ export interface TrackerReportIssue {
|
|
|
24
24
|
record_id?: string;
|
|
25
25
|
question_id?: string;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
interface TrackerReportPullRequest {
|
|
28
28
|
number: string;
|
|
29
29
|
title: string;
|
|
30
30
|
merged_at: string;
|
|
31
31
|
source_path: string;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
interface TrackerReportRelease {
|
|
34
34
|
version: string;
|
|
35
35
|
released_at: string;
|
|
36
36
|
source_path: string;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
interface TrackerReportQuestion {
|
|
39
39
|
record: QuestionRecord;
|
|
40
40
|
/** Loaded through the existing company-checked question body reader. */
|
|
41
41
|
body: QuestionBody;
|
|
@@ -63,22 +63,22 @@ export interface TrackerReportInput {
|
|
|
63
63
|
since_source: "explicit" | "previous_report" | "first_run";
|
|
64
64
|
teams: readonly TrackerReportTeamInput[];
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
interface ReportTimedStory {
|
|
67
67
|
id: string;
|
|
68
68
|
title: string;
|
|
69
69
|
at: string;
|
|
70
70
|
references: string[];
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
interface ReportPullRequest {
|
|
73
73
|
number: string;
|
|
74
74
|
title: string;
|
|
75
75
|
merged_at: string;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
interface ReportRelease {
|
|
78
78
|
version: string;
|
|
79
79
|
released_at: string;
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
interface ReportKpiValue {
|
|
82
82
|
kpi_id: string;
|
|
83
83
|
name: string;
|
|
84
84
|
at: string;
|
|
@@ -86,7 +86,7 @@ export interface ReportKpiValue {
|
|
|
86
86
|
unit: string;
|
|
87
87
|
source: string;
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
interface ReportQuestion {
|
|
90
90
|
question_id: string;
|
|
91
91
|
question: string;
|
|
92
92
|
asked_at: string;
|
|
@@ -99,7 +99,7 @@ export interface ReportQuestion {
|
|
|
99
99
|
answered_by: string;
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
interface ReportBlocker {
|
|
103
103
|
id: string;
|
|
104
104
|
story_id: string;
|
|
105
105
|
what: string;
|
|
@@ -107,7 +107,7 @@ export interface ReportBlocker {
|
|
|
107
107
|
next_step: string;
|
|
108
108
|
opened_at: string;
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
interface ReportDirective {
|
|
111
111
|
id: string;
|
|
112
112
|
text: string;
|
|
113
113
|
date: string;
|
|
@@ -117,7 +117,7 @@ export interface ReportDirective {
|
|
|
117
117
|
at: string;
|
|
118
118
|
}>;
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
interface TrackerOwnerTeamReport {
|
|
121
121
|
team: string;
|
|
122
122
|
project_id: string;
|
|
123
123
|
errors: TrackerReportIssue[];
|
|
@@ -142,7 +142,7 @@ export interface TrackerOwnerReport {
|
|
|
142
142
|
since_source: TrackerReportInput["since_source"];
|
|
143
143
|
teams: TrackerOwnerTeamReport[];
|
|
144
144
|
}
|
|
145
|
-
|
|
145
|
+
interface TrackerTeamKpi {
|
|
146
146
|
id: string;
|
|
147
147
|
name: string;
|
|
148
148
|
definition: string;
|
|
@@ -162,7 +162,7 @@ export interface TrackerTeamKpi {
|
|
|
162
162
|
}>;
|
|
163
163
|
trend: "improving" | "regressing" | "flat" | "insufficient_data";
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
interface TrackerTeamOkr {
|
|
166
166
|
id: string;
|
|
167
167
|
objective: string;
|
|
168
168
|
period: string;
|
|
@@ -200,4 +200,5 @@ export declare function buildTrackerTeamPage(team: TrackerReportTeamInput, compa
|
|
|
200
200
|
export declare function renderTrackerOwnerReportText(report: TrackerOwnerReport): string;
|
|
201
201
|
/** Human-readable team page, with proposal status visible beside each objective and KPI. */
|
|
202
202
|
export declare function renderTrackerTeamPageText(page: TrackerTeamPage): string;
|
|
203
|
+
export {};
|
|
203
204
|
//# sourceMappingURL=tracker-report.d.ts.map
|
package/dist/lib/lanes/wait.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { LaneRecord, QuestionRecord } from "./types.js";
|
|
2
|
-
export declare const LANE_WAIT_POLL_INTERVAL_MS = 2000;
|
|
3
|
-
export declare const LANE_WAIT_MAX_LANES = 64;
|
|
4
2
|
export declare const LANE_WAIT_TIMEOUT_EXIT_CODE = 4;
|
|
5
3
|
export declare const LANE_WAIT_INVALID_INPUT_EXIT_CODE = 2;
|
|
6
|
-
|
|
7
|
-
export type LaneWaitChangeType = (typeof LANE_WAIT_CHANGE_TYPES)[number];
|
|
8
|
-
export type LaneWaitChange = {
|
|
4
|
+
type LaneWaitChange = {
|
|
9
5
|
type: "envelope";
|
|
10
6
|
ref: string;
|
|
11
7
|
decision: "done" | "ask" | "blocked";
|
|
@@ -36,4 +32,5 @@ export interface LaneWaitDeps {
|
|
|
36
32
|
* lock. Question records are scanned in one pass when question changes matter.
|
|
37
33
|
*/
|
|
38
34
|
export declare function runLaneWait(hqRoot: string, laneIds: readonly string[], changeTypes: readonly string[], timeoutMs: number, deps?: LaneWaitDeps): Promise<LaneWaitResult | null>;
|
|
35
|
+
export {};
|
|
39
36
|
//# sourceMappingURL=wait.d.ts.map
|
package/dist/lib/lanes/wait.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { listQuestionIds, readLane, readQuestion } from "./store.js";
|
|
2
2
|
import { LanesError } from "./errors.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const LANE_WAIT_POLL_INTERVAL_MS = 2_000;
|
|
4
|
+
const LANE_WAIT_MAX_LANES = 64;
|
|
5
5
|
export const LANE_WAIT_TIMEOUT_EXIT_CODE = 4;
|
|
6
6
|
export const LANE_WAIT_INVALID_INPUT_EXIT_CODE = 2;
|
|
7
|
-
|
|
7
|
+
const LANE_WAIT_CHANGE_TYPES = ["envelope", "question", "state"];
|
|
8
8
|
function defaultSleep(ms) {
|
|
9
9
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
10
|
}
|
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
* Built locally at the quiet trigger / SessionEnd flush. Never includes file
|
|
5
5
|
* contents. Tokens, secret-looking strings, and secrets-file paths are redacted.
|
|
6
6
|
*/
|
|
7
|
-
export declare const REPORT_SUMMARY_MAX_CHARS = 140;
|
|
8
|
-
export declare const REPORT_SUMMARY_SCHEMA_MAX = 280;
|
|
9
|
-
export declare const REPORT_TRANSCRIPT_TAIL_BYTES: number;
|
|
10
7
|
export interface SessionEndReportFields {
|
|
11
8
|
summary?: string;
|
|
12
9
|
repo?: string;
|
|
@@ -26,19 +23,12 @@ export interface BuildSessionEndReportFieldsInput {
|
|
|
26
23
|
export declare function redactReportSummary(text: string): string;
|
|
27
24
|
export declare function firstSentence(text: string, max?: number): string;
|
|
28
25
|
export declare function extractLastAssistantText(jsonl: string): string | undefined;
|
|
29
|
-
export declare function readTranscriptTail(transcriptPath: string, maxBytes?: number): string | undefined;
|
|
30
26
|
export declare function collectGitContext(cwd: string, git?: (cwd: string, args: string[]) => string | undefined): {
|
|
31
27
|
repo?: string;
|
|
32
28
|
gitBranch?: string;
|
|
33
29
|
};
|
|
34
30
|
export declare function extractPrUrls(text: string, max?: number): string[];
|
|
35
31
|
export declare function claudeTranscriptPathFor(sessionId: string, cwd: string, home?: string): string;
|
|
36
|
-
export declare function resolveTranscriptPath(input: {
|
|
37
|
-
transcriptPath?: string;
|
|
38
|
-
sessionId?: string;
|
|
39
|
-
cwd?: string;
|
|
40
|
-
home?: string;
|
|
41
|
-
}): string | undefined;
|
|
42
32
|
export declare function buildSessionEndReportFields(input: BuildSessionEndReportFieldsInput): SessionEndReportFields;
|
|
43
33
|
/** Merge report fields onto a session_end event object (no-op for other kinds). */
|
|
44
34
|
export declare function enrichSessionEndEvent(event: Record<string, unknown>, extra?: Pick<BuildSessionEndReportFieldsInput, "transcriptPath" | "home" | "git" | "readTranscript">): Record<string, unknown>;
|
|
@@ -9,9 +9,9 @@ import * as fs from "node:fs";
|
|
|
9
9
|
import * as os from "node:os";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import { SECRET_RE, SECRETS_PATH_RE } from "../../lanes/text-scan.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const REPORT_SUMMARY_MAX_CHARS = 140;
|
|
13
|
+
const REPORT_SUMMARY_SCHEMA_MAX = 280;
|
|
14
|
+
const REPORT_TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
15
15
|
const PR_URL_RE = /https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/pull\/\d+/g;
|
|
16
16
|
export function redactReportSummary(text) {
|
|
17
17
|
let out = text.replace(SECRET_RE, "[redacted]");
|
|
@@ -101,7 +101,7 @@ export function extractLastAssistantText(jsonl) {
|
|
|
101
101
|
}
|
|
102
102
|
return last;
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
function readTranscriptTail(transcriptPath, maxBytes = REPORT_TRANSCRIPT_TAIL_BYTES) {
|
|
105
105
|
try {
|
|
106
106
|
const st = fs.statSync(transcriptPath);
|
|
107
107
|
if (!st.isFile() || st.size <= 0)
|
|
@@ -171,7 +171,7 @@ export function claudeTranscriptPathFor(sessionId, cwd, home = os.homedir()) {
|
|
|
171
171
|
const encoded = cwd.startsWith("/") ? cwd.replace(/\//g, "-") : `-${cwd.replace(/\//g, "-")}`;
|
|
172
172
|
return path.join(home, ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
function resolveTranscriptPath(input) {
|
|
175
175
|
const explicit = input.transcriptPath?.trim();
|
|
176
176
|
if (explicit)
|
|
177
177
|
return explicit;
|