@indigoai-us/hq-cli 5.345.9 → 5.345.10
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 +3 -0
- package/dist/commands/lanes.js +52 -4
- package/dist/lib/bot/coding-tool-activity.d.ts +2 -8
- package/dist/lib/bot/coding-tool-activity.js +1 -5
- package/dist/lib/bot/setup-tool-offer.d.ts +0 -4
- package/dist/lib/bot/setup-tool-offer.js +2 -2
- package/dist/lib/checkpoint-ontology/tree.d.ts +0 -1
- package/dist/lib/checkpoint-ontology/tree.js +1 -1
- package/dist/lib/core-utils/qmd-reindex-after-sync.d.ts +0 -2
- package/dist/lib/core-utils/qmd-reindex-after-sync.js +2 -2
- package/dist/lib/daemon/convergence.d.ts +0 -2
- package/dist/lib/daemon/convergence.js +2 -2
- package/dist/lib/daemon/flag-monitor.d.ts +0 -2
- package/dist/lib/daemon/flag-monitor.js +2 -2
- package/dist/lib/daemon/legacy-sync-env.d.ts +0 -1
- package/dist/lib/daemon/legacy-sync-env.js +1 -1
- package/dist/lib/daemon/ops/memory.d.ts +0 -2
- package/dist/lib/daemon/ops/memory.js +2 -2
- package/dist/lib/daemon/supervisor.d.ts +0 -1
- package/dist/lib/daemon/supervisor.js +1 -1
- package/dist/lib/daemon/sync-runner-bundle.d.ts +2 -1
- package/dist/lib/daemon/sync-runner-bundle.js +1 -1
- package/dist/lib/daemon/sync-runner.d.ts +2 -1
- package/dist/lib/doctor/checks/runtime-probe.d.ts +2 -16
- package/dist/lib/doctor/checks/runtime-probe.js +2 -2
- package/dist/lib/doctor/fix/json-output.d.ts +0 -1
- package/dist/lib/doctor/fix/json-output.js +1 -1
- package/dist/lib/doctor/platform.d.ts +5 -4
- package/dist/lib/lanes/blocker-freshness.d.ts +0 -2
- package/dist/lib/lanes/blocker-freshness.js +2 -2
- package/dist/lib/lanes/config.d.ts +1 -5
- package/dist/lib/lanes/config.js +4 -4
- package/dist/lib/lanes/keep-alive.d.ts +0 -4
- package/dist/lib/lanes/keep-alive.js +3 -3
- package/dist/lib/lanes/kr-freshness.d.ts +2 -4
- package/dist/lib/lanes/kr-freshness.js +4 -4
- package/dist/lib/lanes/outpost-pruner-install.d.ts +0 -3
- package/dist/lib/lanes/outpost-pruner-install.js +3 -3
- package/dist/lib/lanes/reviews.d.ts +3 -4
- package/dist/lib/lanes/reviews.js +3 -3
- package/dist/lib/lanes/store.js +1 -1
- package/dist/lib/lanes/types.d.ts +1 -1
- package/dist/lib/work-context/bind-best.d.ts +0 -19
- package/dist/lib/work-context/bind-best.js +3 -3
- package/dist/lib/work-context/organize.d.ts +3 -11
- package/dist/lib/work-context/organize.js +3 -3
- package/dist/utils/pack-contributions.d.ts +1 -3
- package/dist/utils/pack-contributions.js +0 -5
- package/dist/utils/package-use-lease.d.ts +0 -7
- package/dist/utils/package-use-lease.js +1 -1
- package/dist/utils/resolve-executable.d.ts +0 -1
- package/dist/utils/resolve-executable.js +1 -1
- package/dist/utils/version-gate.d.ts +2 -2
- package/dist/utils/version-gate.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.345.10] — 2026-10-05
|
|
6
|
+
- Keep a healthy recorded Claude account for lane messages when every worker-profile-pinned account is unavailable.
|
|
7
|
+
|
|
5
8
|
## [5.345.9] — 2026-10-05
|
|
6
9
|
- Lane messages to exited sessions now queue durably when provider admission is busy, so delivery succeeds and reconcile can resume them later.
|
|
7
10
|
- Keep the current sync runner until an hq-cloud version matching the configured pin is available.
|
package/dist/commands/lanes.js
CHANGED
|
@@ -6791,18 +6791,62 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
|
|
|
6791
6791
|
(model === undefined || currentConfig.model === undefined || currentConfig.model === model ||
|
|
6792
6792
|
lane.account === recordedModelAccount))
|
|
6793
6793
|
return undefined;
|
|
6794
|
-
const
|
|
6794
|
+
const selectionInput = {
|
|
6795
6795
|
hosts: balanceHosts.snapshots,
|
|
6796
6796
|
targetHost: lane.host,
|
|
6797
6797
|
config,
|
|
6798
6798
|
quotaState: loadQuotaState(hqRoot),
|
|
6799
6799
|
recentUsageEnabled: await readClaudeAccountBalanceSignalsEnabled(ctx, lane.company ?? undefined),
|
|
6800
6800
|
now: ctx.now(),
|
|
6801
|
-
...(!repairUnavailableAccount && allowedAccounts !== undefined ? { allowedAccounts } : {}),
|
|
6802
6801
|
...(model !== undefined ? { model } : {}),
|
|
6803
6802
|
...(recordedModelAccount !== undefined ? { recordedModelAccount } : {}),
|
|
6804
6803
|
unavailableHosts: balanceHosts.unavailableHosts,
|
|
6805
|
-
}
|
|
6804
|
+
};
|
|
6805
|
+
let selected;
|
|
6806
|
+
let profilePinUnavailable = false;
|
|
6807
|
+
try {
|
|
6808
|
+
selected = selectClaudeAccount({
|
|
6809
|
+
...selectionInput,
|
|
6810
|
+
...(!repairUnavailableAccount && allowedAccounts !== undefined ? { allowedAccounts } : {}),
|
|
6811
|
+
});
|
|
6812
|
+
}
|
|
6813
|
+
catch (err) {
|
|
6814
|
+
const accountReasons = err instanceof LanesError &&
|
|
6815
|
+
err.error === "claude_account_balance_no_eligible_account" &&
|
|
6816
|
+
Array.isArray(err.details.account_reasons)
|
|
6817
|
+
? err.details.account_reasons.filter((reason) => reason !== null && typeof reason === "object" && !Array.isArray(reason))
|
|
6818
|
+
: [];
|
|
6819
|
+
const unavailablePinReasons = new Set(["disabled", "home_missing", "not_logged_in", "model_mismatch", "quota_held"]);
|
|
6820
|
+
const everyProfileAccountUnavailable = profilePin !== undefined && profilePin.length > 0 &&
|
|
6821
|
+
profilePin.every((account) => accountReasons.some((reason) => reason.account === account && typeof reason.reason === "string" && unavailablePinReasons.has(reason.reason)));
|
|
6822
|
+
if (!everyProfileAccountUnavailable || lane.account === undefined ||
|
|
6823
|
+
(lane.admission_accounts !== undefined && !lane.admission_accounts.includes(lane.account)))
|
|
6824
|
+
throw err;
|
|
6825
|
+
const recordedSelection = selectClaudeAccount({
|
|
6826
|
+
...selectionInput,
|
|
6827
|
+
allowedAccounts: [lane.account],
|
|
6828
|
+
});
|
|
6829
|
+
selected = {
|
|
6830
|
+
...recordedSelection,
|
|
6831
|
+
considered: recordedSelection.considered.map((entry) => {
|
|
6832
|
+
const pinnedReason = profilePin.includes(entry.account)
|
|
6833
|
+
? accountReasons.find((reason) => reason.account === entry.account)?.reason
|
|
6834
|
+
: undefined;
|
|
6835
|
+
return typeof pinnedReason === "string"
|
|
6836
|
+
? { ...entry, eligible: false, ineligible_reason: pinnedReason }
|
|
6837
|
+
: entry;
|
|
6838
|
+
}),
|
|
6839
|
+
skipped_accounts: [
|
|
6840
|
+
...recordedSelection.skipped_accounts.filter((entry) => !profilePin.includes(entry.account)),
|
|
6841
|
+
...profilePin.map((account) => ({
|
|
6842
|
+
account,
|
|
6843
|
+
host: lane.host,
|
|
6844
|
+
reason: String(accountReasons.find((entry) => entry.account === account)?.reason),
|
|
6845
|
+
})),
|
|
6846
|
+
],
|
|
6847
|
+
};
|
|
6848
|
+
profilePinUnavailable = true;
|
|
6849
|
+
}
|
|
6806
6850
|
const historyReason = lane.account === undefined
|
|
6807
6851
|
? "load_balance"
|
|
6808
6852
|
: currentConfig?.enabled !== true
|
|
@@ -6815,7 +6859,11 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
|
|
|
6815
6859
|
? "usage_limit"
|
|
6816
6860
|
: "load_balance";
|
|
6817
6861
|
return {
|
|
6818
|
-
selection: {
|
|
6862
|
+
selection: {
|
|
6863
|
+
...selected,
|
|
6864
|
+
...(profilePinUnavailable ? { reason: "profile_pin_unavailable" } : {}),
|
|
6865
|
+
selected_at: ctx.now().toISOString(),
|
|
6866
|
+
},
|
|
6819
6867
|
historyReason,
|
|
6820
6868
|
...(preservedModel !== undefined ? { preservedModel } : {}),
|
|
6821
6869
|
};
|
|
@@ -45,7 +45,7 @@ export interface ActivityThreshold {
|
|
|
45
45
|
* at least `minDistinctDays` calendar days, within the last `windowDays` days.
|
|
46
46
|
*/
|
|
47
47
|
export declare const SIGNIFICANT_CODING_TOOL_ACTIVITY: Readonly<ActivityThreshold>;
|
|
48
|
-
|
|
48
|
+
interface ToolActivity {
|
|
49
49
|
/** Is the desktop app installed? */
|
|
50
50
|
installed: boolean;
|
|
51
51
|
/** App sessions used within the window (0 when the app is not installed). */
|
|
@@ -79,15 +79,8 @@ export interface DetectCodingToolActivityInput {
|
|
|
79
79
|
extraHqRoots?: string[];
|
|
80
80
|
threshold?: ActivityThreshold;
|
|
81
81
|
}
|
|
82
|
-
/** The desktop apps, by bundle id, and the bundle names they ship under. */
|
|
83
|
-
export declare const DESKTOP_APPS: Readonly<Record<CodingTool, {
|
|
84
|
-
bundleId: string;
|
|
85
|
-
bundles: readonly string[];
|
|
86
|
-
}>>;
|
|
87
82
|
/** `originator` the Codex app writes into its sessions' first line. */
|
|
88
83
|
export declare const CODEX_APP_ORIGINATOR = "Codex Desktop";
|
|
89
|
-
/** Claude Code's project folder name for a working directory. */
|
|
90
|
-
export declare function claudeProjectDirName(cwd: string): string;
|
|
91
84
|
/**
|
|
92
85
|
* Is `bundleId` this Info.plist's CFBundleIdentifier? An XML plist is read by
|
|
93
86
|
* key. A binary plist has no readable key/value pairing, so it matches when the
|
|
@@ -139,4 +132,5 @@ export declare function pickCodingTool(claude: {
|
|
|
139
132
|
}, threshold?: ActivityThreshold): CodingTool | null;
|
|
140
133
|
/** Look for the Claude and Codex desktop apps and their recent sessions, and pick one to offer, if any. */
|
|
141
134
|
export declare function detectCodingToolActivity(input: DetectCodingToolActivityInput): CodingToolActivity;
|
|
135
|
+
export {};
|
|
142
136
|
//# sourceMappingURL=coding-tool-activity.d.ts.map
|
|
@@ -48,7 +48,7 @@ export const SIGNIFICANT_CODING_TOOL_ACTIVITY = Object.freeze({
|
|
|
48
48
|
minDistinctDays: 3,
|
|
49
49
|
});
|
|
50
50
|
/** The desktop apps, by bundle id, and the bundle names they ship under. */
|
|
51
|
-
|
|
51
|
+
const DESKTOP_APPS = Object.freeze({
|
|
52
52
|
claude: { bundleId: "com.anthropic.claudefordesktop", bundles: ["Claude.app"] },
|
|
53
53
|
codex: { bundleId: "com.openai.codex", bundles: ["ChatGPT.app", "Codex.app"] },
|
|
54
54
|
});
|
|
@@ -65,10 +65,6 @@ const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
65
65
|
* many days older than the window, so a resumed session is still counted.
|
|
66
66
|
*/
|
|
67
67
|
const CODEX_FOLDER_MARGIN_DAYS = 31;
|
|
68
|
-
/** Claude Code's project folder name for a working directory. */
|
|
69
|
-
export function claudeProjectDirName(cwd) {
|
|
70
|
-
return path.resolve(cwd).replace(/[^a-zA-Z0-9]/g, "-");
|
|
71
|
-
}
|
|
72
68
|
function codexHome(home, env) {
|
|
73
69
|
const override = env.CODEX_HOME?.trim();
|
|
74
70
|
return override ? override : path.join(home, ".codex");
|
|
@@ -26,10 +26,6 @@ import type { CodingTool } from "./coding-tool-activity.js";
|
|
|
26
26
|
export declare const KEEP_GOING_HERE_REPLY = "Keep going here";
|
|
27
27
|
/** The hq-block kind the desktop app draws as the two-button card. */
|
|
28
28
|
export declare const CONTINUE_IN_TOOL_BLOCK_KIND = "continueInTool";
|
|
29
|
-
/** The desktop apps' product names. */
|
|
30
|
-
export declare const CODING_TOOL_NAMES: Readonly<Record<CodingTool, string>>;
|
|
31
|
-
/** The offer's one line. */
|
|
32
|
-
export declare function setupToolOfferLine(tool: CodingTool): string;
|
|
33
29
|
/**
|
|
34
30
|
* The opening of the app's welcome, kept when the offer replaces it: its
|
|
35
31
|
* first sentence (who the bot is and what setup covers). The rest of the
|
|
@@ -26,12 +26,12 @@ export const KEEP_GOING_HERE_REPLY = "Keep going here";
|
|
|
26
26
|
/** The hq-block kind the desktop app draws as the two-button card. */
|
|
27
27
|
export const CONTINUE_IN_TOOL_BLOCK_KIND = "continueInTool";
|
|
28
28
|
/** The desktop apps' product names. */
|
|
29
|
-
|
|
29
|
+
const CODING_TOOL_NAMES = Object.freeze({
|
|
30
30
|
claude: "Claude",
|
|
31
31
|
codex: "Codex",
|
|
32
32
|
});
|
|
33
33
|
/** The offer's one line. */
|
|
34
|
-
|
|
34
|
+
function setupToolOfferLine(tool) {
|
|
35
35
|
return `Looks like you use the ${CODING_TOOL_NAMES[tool]} app. Want to continue setup there?`;
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
@@ -25,7 +25,6 @@ export interface EntityIndex {
|
|
|
25
25
|
/** Files under `ontology/entities/` that fail validation. Never written. */
|
|
26
26
|
invalid: Set<string>;
|
|
27
27
|
}
|
|
28
|
-
export declare function emptyIndex(): EntityIndex;
|
|
29
28
|
/** Add one parsed entity to the index (also used for entities created mid-run). */
|
|
30
29
|
export declare function indexEntity(index: EntityIndex, entity: IndexedEntity): void;
|
|
31
30
|
/** Record that the entity at `rel` answers to `alias`. */
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { type EmbedLockDependencies } from "../search-index/embed-lock.js";
|
|
2
2
|
import { type LoadGateDependencies } from "../search-index/load-gate.js";
|
|
3
3
|
import { type UtilityIo } from "./common.js";
|
|
4
|
-
export declare const QMD_REINDEX_STARTUP_WARNING_FLAG = "qmd.reindex-startup-warning";
|
|
5
|
-
export declare const QMD_REINDEX_STARTUP_WARNING_FLAG_FALLBACK = false;
|
|
6
4
|
export type QmdReindexOptions = UtilityIo & {
|
|
7
5
|
cwd?: string;
|
|
8
6
|
/** Test seams; default to the real search-index implementations. */
|
|
@@ -20,8 +20,8 @@ import { resolveProcessFlagGate } from "../flag-registry.js";
|
|
|
20
20
|
import { qmdReindexSingleFlightEnabled } from "../search-index/reindex-single-flight-flag.js";
|
|
21
21
|
import { isQmdNativeBindingError, QMD_NATIVE_BINDING_REMEDY, } from "../../utils/qmd-native-binding-error.js";
|
|
22
22
|
import { ioFor, line } from "./common.js";
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const QMD_REINDEX_STARTUP_WARNING_FLAG = "qmd.reindex-startup-warning";
|
|
24
|
+
const QMD_REINDEX_STARTUP_WARNING_FLAG_FALLBACK = false;
|
|
25
25
|
function qmdStartupFailureWarningsEnabled() {
|
|
26
26
|
return resolveProcessFlagGate(QMD_REINDEX_STARTUP_WARNING_FLAG, { fallback: QMD_REINDEX_STARTUP_WARNING_FLAG_FALLBACK }, () => QMD_REINDEX_STARTUP_WARNING_FLAG_FALLBACK);
|
|
27
27
|
}
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
* on disk. Policy hq-self-updater-must-verify-convergence-after-install: the
|
|
8
8
|
* caller reports a mismatch as a failure; it is never swallowed.
|
|
9
9
|
*/
|
|
10
|
-
export declare const CONVERGENCE_TIMEOUT_MS = 10000;
|
|
11
|
-
export declare const CONVERGENCE_POLL_MS = 500;
|
|
12
10
|
export interface ConvergenceResult {
|
|
13
11
|
converged: boolean;
|
|
14
12
|
expected: string;
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
11
|
import { hqdRequest } from "./protocol.js";
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const CONVERGENCE_TIMEOUT_MS = 10_000;
|
|
13
|
+
const CONVERGENCE_POLL_MS = 500;
|
|
14
14
|
/** Ping hqd over its socket and return the version it reports. */
|
|
15
15
|
export async function pingHqdVersion(socketPath, timeoutMs = 2_000) {
|
|
16
16
|
const result = (await hqdRequest("ping", {}, { socketPath, timeoutMs }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { performance } from "node:perf_hooks";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const HQ_ANYWHERE_FLAG_REFRESH_INTERVAL_MS = 30_000;
|
|
3
|
+
const HQ_ANYWHERE_FLAG_MAX_STALENESS_MS = 60_000;
|
|
4
4
|
/**
|
|
5
5
|
* Refreshes a long-running daemon's flag independently of incoming requests.
|
|
6
6
|
* A failed read keeps the last successful decision only until its 60s age limit.
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* sync limits. This module is deliberately tolerant: a bad or missing drop-in
|
|
5
5
|
* must never stop daemon planning.
|
|
6
6
|
*/
|
|
7
|
-
export declare const LEGACY_SYNC_DROPIN_DIR = "/etc/systemd/system/outpost-sync.service.d";
|
|
8
7
|
/** Read simple KEY=VALUE and quoted "KEY=VALUE" Environment directives. */
|
|
9
8
|
export declare function readLegacySyncEnv(platform: NodeJS.Platform, directory?: string): Record<string, string>;
|
|
10
9
|
//# sourceMappingURL=legacy-sync-env.d.ts.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
|
|
9
|
+
const LEGACY_SYNC_DROPIN_DIR = "/etc/systemd/system/outpost-sync.service.d";
|
|
10
10
|
function assignments(text, into) {
|
|
11
11
|
let inService = false;
|
|
12
12
|
for (const rawLine of text.split(/\r?\n/)) {
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
* memory.get / memory.put ops (hq-anywhere US-009): session-scoped notes
|
|
3
3
|
* persisted at workspace/sessions/<sid>/hqd-memory.json under HQ_ROOT.
|
|
4
4
|
*/
|
|
5
|
-
export declare const MEMORY_FILE = "hqd-memory.json";
|
|
6
5
|
export declare class MemoryOpError extends Error {
|
|
7
6
|
readonly code: string;
|
|
8
7
|
constructor(code: string, message: string);
|
|
9
8
|
}
|
|
10
|
-
export declare function memoryPath(hqRoot: string, sessionId: string): string;
|
|
11
9
|
export declare function memoryPut(hqRoot: string, sessionId: string, key: string, value: unknown, now?: Date): {
|
|
12
10
|
key: string;
|
|
13
11
|
updatedAt: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
const SESSION_RE = /^[A-Za-z0-9._-]+$/;
|
|
8
|
-
|
|
8
|
+
const MEMORY_FILE = "hqd-memory.json";
|
|
9
9
|
const MAX_VALUE_BYTES = 256 * 1024;
|
|
10
10
|
export class MemoryOpError extends Error {
|
|
11
11
|
code;
|
|
@@ -15,7 +15,7 @@ export class MemoryOpError extends Error {
|
|
|
15
15
|
this.name = "MemoryOpError";
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function memoryPath(hqRoot, sessionId) {
|
|
19
19
|
if (!SESSION_RE.test(sessionId) || sessionId === "." || sessionId === "..") {
|
|
20
20
|
throw new MemoryOpError("bad_args", "sessionId may only contain letters, digits, '.', '_' and '-'");
|
|
21
21
|
}
|
|
@@ -26,7 +26,6 @@ import type { MachineType } from "./machine-type.js";
|
|
|
26
26
|
import type { ControlRequest } from "./requests.js";
|
|
27
27
|
import { syncPassResult } from "./sync-runner.js";
|
|
28
28
|
export declare const STOP_ESCALATION_MS = 10000;
|
|
29
|
-
export declare const CLI_UPDATE_SYNC_IDLE_MAX_MS: number;
|
|
30
29
|
export declare const CLI_UPDATE_SYNC_IDLE_KILL_GRACE_MS = 60000;
|
|
31
30
|
/** After a handoff, how long a replaced unit must stay up before the next one is replaced. */
|
|
32
31
|
export declare const HANDOFF_STAGGER_MS = 15000;
|
|
@@ -27,7 +27,7 @@ const BACKOFF_BASE_MS = 1_000;
|
|
|
27
27
|
const BACKOFF_MAX_MS = 60_000;
|
|
28
28
|
const HEALTHY_RUN_MS = 60_000;
|
|
29
29
|
export const STOP_ESCALATION_MS = 10_000;
|
|
30
|
-
|
|
30
|
+
const CLI_UPDATE_SYNC_IDLE_MAX_MS = 10 * 60_000;
|
|
31
31
|
export const CLI_UPDATE_SYNC_IDLE_KILL_GRACE_MS = 60_000;
|
|
32
32
|
const MESH_OWNER_RECHECK_MS = 15_000;
|
|
33
33
|
const MESH_OWNER_LOG_INTERVAL_MS = 10 * 60_000;
|
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
export declare const SYNC_RUNNER_BUNDLE_RUNNER_FILE = "bin/sync-runner.js";
|
|
4
4
|
export declare const SYNC_RUNNER_BUNDLE_METADATA_FILE = "package.json";
|
|
5
5
|
export declare const SYNC_RUNNER_BUNDLE_DIRECTORY = "hq-cloud-sync-runner";
|
|
6
|
-
|
|
6
|
+
declare const SYNC_RUNNER_BUNDLE_FORMAT_VERSION = 1;
|
|
7
7
|
/** Root directory where validated sync-runner bundles are selected. */
|
|
8
8
|
export declare function syncRunnerBundleStageRoot(daemonRoot: string): string;
|
|
9
9
|
/** package.json contract that the hq-cli build step emits beside the bundled bin directory. */
|
|
@@ -41,4 +41,5 @@ export declare function stagedSyncRunnerVersion(runnerPath: string): string;
|
|
|
41
41
|
* Only a completed, fsynced directory is returned; temp siblings are ignored.
|
|
42
42
|
*/
|
|
43
43
|
export declare function stageSyncRunnerBundle(options: StageSyncRunnerBundleOptions): StagedSyncRunnerBundle;
|
|
44
|
+
export {};
|
|
44
45
|
//# sourceMappingURL=sync-runner-bundle.d.ts.map
|
|
@@ -8,7 +8,7 @@ import { ensurePrivateDir } from "./paths.js";
|
|
|
8
8
|
export const SYNC_RUNNER_BUNDLE_RUNNER_FILE = "bin/sync-runner.js";
|
|
9
9
|
export const SYNC_RUNNER_BUNDLE_METADATA_FILE = "package.json";
|
|
10
10
|
export const SYNC_RUNNER_BUNDLE_DIRECTORY = "hq-cloud-sync-runner";
|
|
11
|
-
|
|
11
|
+
const SYNC_RUNNER_BUNDLE_FORMAT_VERSION = 1;
|
|
12
12
|
/** Root directory where validated sync-runner bundles are selected. */
|
|
13
13
|
export function syncRunnerBundleStageRoot(daemonRoot) {
|
|
14
14
|
return path.join(daemonRoot, "bundles", "sync-runner");
|
|
@@ -24,7 +24,7 @@ export type SyncRunnerProcessList = {
|
|
|
24
24
|
ok: false;
|
|
25
25
|
error: string;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
interface ProcessListCommandResult {
|
|
28
28
|
status: number | null;
|
|
29
29
|
stdout: string;
|
|
30
30
|
stderr: string;
|
|
@@ -57,4 +57,5 @@ export declare function syncPassResult(event: Record<string, unknown>, completed
|
|
|
57
57
|
export declare function syncHeartbeatTimeoutMs(env: NodeJS.ProcessEnv): number;
|
|
58
58
|
/** Preserve an explicit NODE_OPTIONS heap setting; otherwise apply the desktop runner's default/override. */
|
|
59
59
|
export declare function syncRunnerNodeOptions(env: NodeJS.ProcessEnv): string | undefined;
|
|
60
|
+
export {};
|
|
60
61
|
//# sourceMappingURL=sync-runner.d.ts.map
|
|
@@ -48,7 +48,7 @@ export declare const RUNTIME_PROBE_PREFIX = "hooks.runtime";
|
|
|
48
48
|
*/
|
|
49
49
|
export declare const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trigger-state";
|
|
50
50
|
/** Whether the ledger was found. Mirrors the script's `present`/`missing`. */
|
|
51
|
-
|
|
51
|
+
type LedgerState = "present" | "missing";
|
|
52
52
|
/** Options for {@link reproduceCheckHqHooks}. */
|
|
53
53
|
export interface ReproduceOptions {
|
|
54
54
|
/** Absolute HQ tree root to inspect. */
|
|
@@ -113,13 +113,6 @@ export declare function isAgentsV2Runtime(hqRoot: string, env?: NodeJS.ProcessEn
|
|
|
113
113
|
* `HQ_FLEET_CONFIG_FILE`.
|
|
114
114
|
*/
|
|
115
115
|
export declare const HQ_FLEET_CONFIG_ENV = "HQ_FLEET_CONFIG_FILE";
|
|
116
|
-
/**
|
|
117
|
-
* The agents-v2 runtime (hq-fleet) config whose `hooks:` block wires the on-box
|
|
118
|
-
* adapter into every lifecycle event — the env override, else `~/.hq-fleet/config.yaml`
|
|
119
|
-
* (where `provision/render-config.sh` renders it). Mirrors the shell's
|
|
120
|
-
* `HQ_FLEET_CONFIG_FILE="${HQ_FLEET_CONFIG_FILE:-$HOME/.hq-fleet/config.yaml}"`.
|
|
121
|
-
*/
|
|
122
|
-
export declare function resolveHqFleetConfigPath(env?: NodeJS.ProcessEnv): string;
|
|
123
116
|
/**
|
|
124
117
|
* Whether the agents-v2 runtime actually wires the on-box hook adapter.
|
|
125
118
|
*
|
|
@@ -138,14 +131,6 @@ export declare function resolveHqFleetConfigPath(env?: NodeJS.ProcessEnv): strin
|
|
|
138
131
|
* `hq_runtime_config_wires_v2_adapter` in `check-hq-hooks.sh`.
|
|
139
132
|
*/
|
|
140
133
|
export declare function runtimeConfigWiresV2Adapter(hqRoot: string, env?: NodeJS.ProcessEnv): boolean;
|
|
141
|
-
/**
|
|
142
|
-
* Whether a policy-trigger ledger evidencing a live agents-v2 turn is present:
|
|
143
|
-
* the exact session's ledger when a session id is given (session identity
|
|
144
|
-
* implies freshness), otherwise any ledger modified within the freshness window
|
|
145
|
-
* so a long-dead tree cannot self-attest off a stale file. Mirrors
|
|
146
|
-
* `hq_v2_ledger_present`.
|
|
147
|
-
*/
|
|
148
|
-
export declare function v2LedgerPresent(opts: AgentsV2AttestationOptions): boolean;
|
|
149
134
|
/**
|
|
150
135
|
* All three agents-v2 self-attestation conditions. Used only to GRANT PASS to a
|
|
151
136
|
* hq-fleet box that host detection leaves platform-unknown; never to withhold it.
|
|
@@ -158,4 +143,5 @@ export declare function agentsV2Attested(opts: AgentsV2AttestationOptions): bool
|
|
|
158
143
|
* the per-platform status rationale.
|
|
159
144
|
*/
|
|
160
145
|
export declare function checkRuntimeProbe(context: CheckContext): CheckResult[];
|
|
146
|
+
export {};
|
|
161
147
|
//# sourceMappingURL=runtime-probe.d.ts.map
|
|
@@ -172,7 +172,7 @@ export const HQ_FLEET_CONFIG_ENV = "HQ_FLEET_CONFIG_FILE";
|
|
|
172
172
|
* (where `provision/render-config.sh` renders it). Mirrors the shell's
|
|
173
173
|
* `HQ_FLEET_CONFIG_FILE="${HQ_FLEET_CONFIG_FILE:-$HOME/.hq-fleet/config.yaml}"`.
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
function resolveHqFleetConfigPath(env = process.env) {
|
|
176
176
|
const override = env[HQ_FLEET_CONFIG_ENV]?.trim();
|
|
177
177
|
if (override)
|
|
178
178
|
return override;
|
|
@@ -215,7 +215,7 @@ export function runtimeConfigWiresV2Adapter(hqRoot, env = process.env) {
|
|
|
215
215
|
* so a long-dead tree cannot self-attest off a stale file. Mirrors
|
|
216
216
|
* `hq_v2_ledger_present`.
|
|
217
217
|
*/
|
|
218
|
-
|
|
218
|
+
function v2LedgerPresent(opts) {
|
|
219
219
|
const env = opts.env ?? process.env;
|
|
220
220
|
const dir = path.join(opts.hqRoot, ...POLICY_TRIGGER_LEDGER_RELPATH.split("/"));
|
|
221
221
|
if (!isDir(dir))
|
|
@@ -58,7 +58,7 @@ export type Platform = (typeof PLATFORMS)[number];
|
|
|
58
58
|
* The platforms a signal can positively point at. `unknown` is never the target
|
|
59
59
|
* of a signal — it is the verdict when no platform is positively established.
|
|
60
60
|
*/
|
|
61
|
-
|
|
61
|
+
type DetectablePlatform = Exclude<Platform, "unknown">;
|
|
62
62
|
/**
|
|
63
63
|
* How dispositive a signal is:
|
|
64
64
|
* - `strong`: on its own, identifies a specific platform (e.g.
|
|
@@ -66,7 +66,7 @@ export type DetectablePlatform = Exclude<Platform, "unknown">;
|
|
|
66
66
|
* - `weak`: corroborating but not variant-specific (e.g. `CLAUDECODE=1`, which
|
|
67
67
|
* is shared by the CLI, app, and SDK).
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
type SignalStrength = "strong" | "weak";
|
|
70
70
|
/** One observed signal and the platform it points at. */
|
|
71
71
|
export interface PlatformEvidence {
|
|
72
72
|
/** Stable machine key for the signal, e.g. `env.CLAUDE_CODE_ENTRYPOINT`. */
|
|
@@ -97,7 +97,7 @@ export interface AncestorProcess {
|
|
|
97
97
|
command: string;
|
|
98
98
|
}
|
|
99
99
|
/** Reads this process's ancestor chain, nearest parent first. Injectable. */
|
|
100
|
-
|
|
100
|
+
type AncestryReader = () => AncestorProcess[];
|
|
101
101
|
/** Options for {@link detectPlatform}. All are injectable so runs are testable. */
|
|
102
102
|
export interface DetectPlatformOptions {
|
|
103
103
|
/** Environment to read. Default: `process.env`. */
|
|
@@ -147,7 +147,7 @@ export declare function ancestryEvidence(ancestors: AncestorProcess[]): Platform
|
|
|
147
147
|
* spawned, so a test can both feed a synthetic table and assert that the only
|
|
148
148
|
* command ever requested is `ps` — never an agent binary.
|
|
149
149
|
*/
|
|
150
|
-
|
|
150
|
+
type ProcessSpawner = (command: string, args: readonly string[]) => string | null;
|
|
151
151
|
/** Options for {@link readProcessAncestry}. */
|
|
152
152
|
export interface ReadAncestryOptions {
|
|
153
153
|
/** Process to start from. Default: `process.pid`. */
|
|
@@ -215,4 +215,5 @@ export declare function unknownPlatformCheckStatus(): DoctorStatus;
|
|
|
215
215
|
* can drop in.
|
|
216
216
|
*/
|
|
217
217
|
export declare function formatPlatformLines(detection: PlatformDetection): string[];
|
|
218
|
+
export {};
|
|
218
219
|
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -2,8 +2,6 @@ import { type ManagerStatusTarget } from "./manager-status-gate.js";
|
|
|
2
2
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
3
3
|
import type { LaneRecord } from "./types.js";
|
|
4
4
|
export declare const BLOCKER_FRESHNESS_FLAG = "lanes.blocker-freshness";
|
|
5
|
-
export declare const BLOCKER_FRESHNESS_DEFAULT_HOURS = 4;
|
|
6
|
-
export declare const BLOCKER_FRESHNESS_FUTURE_GRACE_MS: number;
|
|
7
5
|
export interface StaleBlocker {
|
|
8
6
|
key: string;
|
|
9
7
|
label: string;
|
|
@@ -7,8 +7,8 @@ import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
|
7
7
|
import { resolveLaneCompany } from "./lane-company.js";
|
|
8
8
|
import { assertNoSecretText } from "./text-scan.js";
|
|
9
9
|
export const BLOCKER_FRESHNESS_FLAG = "lanes.blocker-freshness";
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const BLOCKER_FRESHNESS_DEFAULT_HOURS = DEFAULT_BLOCKER_FRESHNESS_HOURS;
|
|
11
|
+
const BLOCKER_FRESHNESS_FUTURE_GRACE_MS = 5 * 60 * 1000;
|
|
12
12
|
const TERMINAL_BLOCKER_STATUSES = new Set([
|
|
13
13
|
"closed",
|
|
14
14
|
"resolved",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* that resolve to the same home are refused (identity-keyed-cap rule).
|
|
8
8
|
*/
|
|
9
9
|
import * as fs from "node:fs";
|
|
10
|
-
import { type AccountConfig, type LaneProvider, type LanesConfig, type RunawaySearchGuardConfig, type LivenessWindows, type ProviderConfig
|
|
10
|
+
import { type AccountConfig, type LaneProvider, type LanesConfig, type RunawaySearchGuardConfig, type LivenessWindows, type ProviderConfig } from "./types.js";
|
|
11
11
|
export declare const LANES_CONFIG_REL: string;
|
|
12
12
|
export declare const DEFAULT_MAX_QUEUED = 3;
|
|
13
13
|
export declare const DEFAULT_CPU_BUSY_PAUSE = 0.85;
|
|
@@ -43,10 +43,6 @@ export declare const DEFAULT_SESSION_QUESTION_TIMEOUT_SECS: number;
|
|
|
43
43
|
export declare const DEFAULT_BLOCKER_FRESHNESS_HOURS = 4;
|
|
44
44
|
/** Manager key results must be re-measured within six hours by default. */
|
|
45
45
|
export declare const DEFAULT_KR_FRESHNESS_HOURS = 6;
|
|
46
|
-
export declare const DEFAULT_LOW_DISK_MIN_FREE_BYTES: number;
|
|
47
|
-
export declare const DEFAULT_CODEX_ROLLOUT_COMPRESS_AFTER_HOURS = 24;
|
|
48
|
-
export declare const DEFAULT_CODEX_ROLLOUT_DELETE_AFTER_DAYS = 7;
|
|
49
|
-
export declare const DEFAULT_TRACKER_CHECKS: TrackerChecksConfig;
|
|
50
46
|
export declare const DEFAULT_RUNAWAY_SEARCH_GUARD_CONFIG: RunawaySearchGuardConfig;
|
|
51
47
|
export declare const DEFAULT_LIVENESS_WINDOWS: LivenessWindows;
|
|
52
48
|
export declare const DEFAULT_PROVIDER_MAX_RUNNING: Record<LaneProvider, number>;
|
package/dist/lib/lanes/config.js
CHANGED
|
@@ -47,10 +47,10 @@ export const DEFAULT_SESSION_QUESTION_TIMEOUT_SECS = 10 * 60;
|
|
|
47
47
|
export const DEFAULT_BLOCKER_FRESHNESS_HOURS = 4;
|
|
48
48
|
/** Manager key results must be re-measured within six hours by default. */
|
|
49
49
|
export const DEFAULT_KR_FRESHNESS_HOURS = 6;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
const DEFAULT_LOW_DISK_MIN_FREE_BYTES = 5 * 1024 ** 3;
|
|
51
|
+
const DEFAULT_CODEX_ROLLOUT_COMPRESS_AFTER_HOURS = 24;
|
|
52
|
+
const DEFAULT_CODEX_ROLLOUT_DELETE_AFTER_DAYS = 7;
|
|
53
|
+
const DEFAULT_TRACKER_CHECKS = {
|
|
54
54
|
owner_question_surface_ms: 10 * 60 * 1000,
|
|
55
55
|
open_question_age_ms: 2 * 60 * 60 * 1000,
|
|
56
56
|
status_stale_ms: 90 * 60 * 1000,
|
|
@@ -16,7 +16,6 @@ export declare const LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED = false;
|
|
|
16
16
|
export declare const LANE_RUNNING_SUPERSEDED_MESSAGE_DELIVERY_FLAG = "lanes.running-superseded-message-delivery";
|
|
17
17
|
export declare const LEAD_LANE_KEEP_ALIVE_MAX_RESUMES = 24;
|
|
18
18
|
export declare const LEAD_LANE_KEEP_ALIVE_BASE_BACKOFF_MS: number;
|
|
19
|
-
export declare const LEAD_LANE_KEEP_ALIVE_MAX_BACKOFF_MS: number;
|
|
20
19
|
export type KeepAliveLane = Pick<LaneRecord, "lane_id" | "created_at" | "senior" | "company" | "project_id"> & Partial<Pick<LaneRecord, "mesh_company" | "worker_profile" | "hire_grant" | "provider_session_id" | "last_resume" | "state">>;
|
|
21
20
|
export interface LaneTerminalResumeResult {
|
|
22
21
|
lane: LaneRecord;
|
|
@@ -57,11 +56,8 @@ export declare function canResumeDoneKeepAliveLane(lane: Pick<LaneRecord, "keep_
|
|
|
57
56
|
export declare function hasPendingKeepAliveWork(hqRoot: string, lane: Pick<LaneRecord, "lane_id" | "company" | "pending_resume">, questionRecords?: readonly QuestionRecord[]): boolean;
|
|
58
57
|
/** Undelivered answers that belong to this lane and company. */
|
|
59
58
|
export declare function undeliveredAnsweredQuestions(lane: Pick<LaneRecord, "lane_id" | "company">, questions: readonly QuestionRecord[]): QuestionRecord[];
|
|
60
|
-
export declare function retiredLaneRegistryPath(hqRoot: string): string;
|
|
61
59
|
/** Missing registry means no retired lanes; every present invalid file fails closed. */
|
|
62
60
|
export declare function loadRetiredLaneIds(hqRoot: string): ReadonlySet<string>;
|
|
63
|
-
/** IDs may be stored bare or with an owner-host suffix after an underscore. */
|
|
64
|
-
export declare function isRetiredLaneId(laneId: string, retiredLaneIds: ReadonlySet<string>): boolean;
|
|
65
61
|
export declare function keepAliveSupersededBy<T extends KeepAliveLane>(lane: T, lanes: readonly T[], lineageAware?: boolean, companyForLane?: (lane: T) => T["company"]): T | undefined;
|
|
66
62
|
export declare function keepAliveExclusion<T extends KeepAliveLane>(lane: T, lanes: readonly T[], retiredLaneIds: ReadonlySet<string>, lineageAware?: boolean, companyForLane?: (lane: T) => T["company"]): "retired" | "superseded" | undefined;
|
|
67
63
|
export declare function leadLaneKeepAliveBackoffMs(attempt: number): number;
|
|
@@ -21,7 +21,7 @@ export const LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED = false;
|
|
|
21
21
|
export const LANE_RUNNING_SUPERSEDED_MESSAGE_DELIVERY_FLAG = "lanes.running-superseded-message-delivery";
|
|
22
22
|
export const LEAD_LANE_KEEP_ALIVE_MAX_RESUMES = 24;
|
|
23
23
|
export const LEAD_LANE_KEEP_ALIVE_BASE_BACKOFF_MS = 5 * 60 * 1000;
|
|
24
|
-
|
|
24
|
+
const LEAD_LANE_KEEP_ALIVE_MAX_BACKOFF_MS = 60 * 60 * 1000;
|
|
25
25
|
/** Shared resume transition for terminal gate follow-ups. */
|
|
26
26
|
export function queueLaneTerminalResume(current, at, resumeText, options = {}) {
|
|
27
27
|
if (options.mergeExisting && current.pending_resume !== undefined) {
|
|
@@ -182,7 +182,7 @@ function readKeepAliveQuestionRecords(hqRoot) {
|
|
|
182
182
|
}
|
|
183
183
|
return questions;
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
function retiredLaneRegistryPath(hqRoot) {
|
|
186
186
|
return path.join(hqRoot, "workspace", "lane-briefs", "juniors.json");
|
|
187
187
|
}
|
|
188
188
|
/** Missing registry means no retired lanes; every present invalid file fails closed. */
|
|
@@ -233,7 +233,7 @@ function invalidRetiredList(filePath, message) {
|
|
|
233
233
|
return new LanesError("keep_alive_retired_list_invalid", `Invalid retired lane list ${filePath}: ${message}`, { path: filePath });
|
|
234
234
|
}
|
|
235
235
|
/** IDs may be stored bare or with an owner-host suffix after an underscore. */
|
|
236
|
-
|
|
236
|
+
function isRetiredLaneId(laneId, retiredLaneIds) {
|
|
237
237
|
for (const retiredId of retiredLaneIds) {
|
|
238
238
|
if (retiredId === laneId ||
|
|
239
239
|
retiredId.startsWith(`${laneId}_`) ||
|
|
@@ -2,9 +2,7 @@ import { type ManagerStatusTarget } from "./manager-status-gate.js";
|
|
|
2
2
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
3
3
|
import type { LaneRecord } from "./types.js";
|
|
4
4
|
export declare const KR_FRESHNESS_FLAG = "lanes.kr-freshness";
|
|
5
|
-
|
|
6
|
-
export declare const KR_FRESHNESS_LEDGER_REL: string;
|
|
7
|
-
export declare const KR_FRESHNESS_LEDGER_SCHEMA = "kr-freshness-ledger.v1";
|
|
5
|
+
declare const KR_FRESHNESS_LEDGER_SCHEMA = "kr-freshness-ledger.v1";
|
|
8
6
|
export type KrFreshnessVerdict = "moving" | "flat" | "stalled";
|
|
9
7
|
export interface KrFreshnessKpi {
|
|
10
8
|
name: string;
|
|
@@ -52,7 +50,6 @@ export interface KrFreshnessStatusKpi {
|
|
|
52
50
|
entryMeasuredAt: string | null;
|
|
53
51
|
}
|
|
54
52
|
export declare function readKrFreshnessStatus(statusPath: string): KrFreshnessStatusKpi[];
|
|
55
|
-
export declare function krFreshnessLedgerPath(root: string, laneId: string): string;
|
|
56
53
|
export declare function readKrFreshnessLedger(root: string, laneId: string): KrFreshnessLedger | null;
|
|
57
54
|
export declare function writeKrFreshnessLedger(root: string, ledger: KrFreshnessLedger): void;
|
|
58
55
|
export declare function updateKrFreshnessLedger(laneId: string, prior: KrFreshnessLedger | null, statusKpis: readonly KrFreshnessStatusKpi[], now: number): KrFreshnessLedger;
|
|
@@ -72,4 +69,5 @@ export declare function readKrFreshnessReport(root: string, laneId: string, now:
|
|
|
72
69
|
kr_freshness_hours: number;
|
|
73
70
|
kpis: KrFreshnessView[];
|
|
74
71
|
};
|
|
72
|
+
export {};
|
|
75
73
|
//# sourceMappingURL=kr-freshness.d.ts.map
|
|
@@ -8,9 +8,9 @@ import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
|
8
8
|
import { resolveLaneCompany } from "./lane-company.js";
|
|
9
9
|
import { assertNoSecretText } from "./text-scan.js";
|
|
10
10
|
export const KR_FRESHNESS_FLAG = "lanes.kr-freshness";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const KR_FRESHNESS_DEFAULT_HOURS = DEFAULT_KR_FRESHNESS_HOURS;
|
|
12
|
+
const KR_FRESHNESS_LEDGER_REL = path.join("workspace", "lanes", "kpi-ledger");
|
|
13
|
+
const KR_FRESHNESS_LEDGER_SCHEMA = "kr-freshness-ledger.v1";
|
|
14
14
|
const MAX_STATUS_BYTES = 1024 * 1024;
|
|
15
15
|
const MAX_LEDGER_BYTES = 1024 * 1024;
|
|
16
16
|
const MAX_KPIS = 1000;
|
|
@@ -190,7 +190,7 @@ export function readKrFreshnessStatus(statusPath) {
|
|
|
190
190
|
}
|
|
191
191
|
return [...found.values()];
|
|
192
192
|
}
|
|
193
|
-
|
|
193
|
+
function krFreshnessLedgerPath(root, laneId) {
|
|
194
194
|
return ledgerFilePath(root, laneId);
|
|
195
195
|
}
|
|
196
196
|
export function readKrFreshnessLedger(root, laneId) {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
export declare const OUTPOST_PRUNER_PRESSURE_SERVICE = "hq-outpost-worktree-pruner-pressure.service";
|
|
2
1
|
export declare const OUTPOST_PRUNER_PRESSURE_TIMER = "hq-outpost-worktree-pruner-pressure.timer";
|
|
3
|
-
export declare const OUTPOST_PRUNER_DAILY_SERVICE = "hq-outpost-worktree-pruner-daily.service";
|
|
4
2
|
export declare const OUTPOST_PRUNER_DAILY_TIMER = "hq-outpost-worktree-pruner-daily.timer";
|
|
5
|
-
export declare const OUTPOST_PRUNER_MIN_AGE_DAYS = 14;
|
|
6
3
|
export interface OutpostPrunerInstallOptions {
|
|
7
4
|
systemdRoot: string;
|
|
8
5
|
hqRoot: string;
|
|
@@ -4,11 +4,11 @@ import * as path from "node:path";
|
|
|
4
4
|
import { resolveHqBinary, resolveNodeBinary } from "../mesh/live/daemon/install.js";
|
|
5
5
|
import { SYSTEMD_PATH_ENV } from "../service-manager/systemd.js";
|
|
6
6
|
import { resolveFlagRegistryEndpoint } from "../flag-registry-endpoint.js";
|
|
7
|
-
|
|
7
|
+
const OUTPOST_PRUNER_PRESSURE_SERVICE = "hq-outpost-worktree-pruner-pressure.service";
|
|
8
8
|
export const OUTPOST_PRUNER_PRESSURE_TIMER = "hq-outpost-worktree-pruner-pressure.timer";
|
|
9
|
-
|
|
9
|
+
const OUTPOST_PRUNER_DAILY_SERVICE = "hq-outpost-worktree-pruner-daily.service";
|
|
10
10
|
export const OUTPOST_PRUNER_DAILY_TIMER = "hq-outpost-worktree-pruner-daily.timer";
|
|
11
|
-
|
|
11
|
+
const OUTPOST_PRUNER_MIN_AGE_DAYS = 14;
|
|
12
12
|
function shellQuote(value) {
|
|
13
13
|
return /^[A-Za-z0-9_./:-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
14
14
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const LANE_REVIEW_HISTORY_CAP = 50;
|
|
4
|
-
export interface LaneReviewHistoryEntry {
|
|
1
|
+
declare const LANE_REVIEW_SCHEMA_VERSION = "hq-lanes-review.v1";
|
|
2
|
+
interface LaneReviewHistoryEntry {
|
|
5
3
|
repo: string;
|
|
6
4
|
pr: number;
|
|
7
5
|
head_sha: string;
|
|
@@ -34,4 +32,5 @@ export declare function parseLaneReviewPr(raw: string | number): number;
|
|
|
34
32
|
export declare function readLaneReview(hqRoot: string, repo: string, pr: number): LaneReview | null;
|
|
35
33
|
export declare function listLaneReviews(hqRoot: string, reviewerLane?: string): LaneReviewListing;
|
|
36
34
|
export declare function recordLaneReview(hqRoot: string, input: RecordLaneReviewInput): Promise<LaneReview>;
|
|
35
|
+
export {};
|
|
37
36
|
//# sourceMappingURL=reviews.d.ts.map
|
|
@@ -3,9 +3,9 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { assertNoSecretText } from "./text-scan.js";
|
|
5
5
|
import { LanesError } from "./errors.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const LANE_REVIEWS_REL = path.join("workspace", "lanes", "reviews");
|
|
7
|
+
const LANE_REVIEW_SCHEMA_VERSION = "hq-lanes-review.v1";
|
|
8
|
+
const LANE_REVIEW_HISTORY_CAP = 50;
|
|
9
9
|
const REVIEW_LOCK_WAIT_MS = 5_000;
|
|
10
10
|
const REVIEW_LOCK_STALE_MS = 5 * 60_000;
|
|
11
11
|
function fail(error, message, details = {}) {
|
package/dist/lib/lanes/store.js
CHANGED
|
@@ -987,7 +987,7 @@ function parseLaneAccountSelection(value, filePath) {
|
|
|
987
987
|
throw failure("account");
|
|
988
988
|
if (selection.signal !== "usage" && selection.signal !== "recent_usage" && selection.signal !== "lane_count" && selection.signal !== "explicit")
|
|
989
989
|
throw failure("signal");
|
|
990
|
-
if (selection.reason !== "least_loaded" && selection.reason !== "explicit")
|
|
990
|
+
if (selection.reason !== "least_loaded" && selection.reason !== "explicit" && selection.reason !== "profile_pin_unavailable")
|
|
991
991
|
throw failure("reason");
|
|
992
992
|
if (typeof selection.selected_at !== "string" || !Number.isFinite(Date.parse(selection.selected_at)))
|
|
993
993
|
throw failure("selected_at");
|
|
@@ -284,7 +284,7 @@ export interface LaneAccountSelectionConsidered {
|
|
|
284
284
|
export interface LaneAccountSelection {
|
|
285
285
|
account: string;
|
|
286
286
|
signal: "usage" | "recent_usage" | "lane_count" | "explicit";
|
|
287
|
-
reason: "least_loaded" | "explicit";
|
|
287
|
+
reason: "least_loaded" | "explicit" | "profile_pin_unavailable";
|
|
288
288
|
target_host: LaneHost;
|
|
289
289
|
selected_at: string;
|
|
290
290
|
considered: LaneAccountSelectionConsidered[];
|
|
@@ -8,15 +8,6 @@ export interface BindCandidate {
|
|
|
8
8
|
title?: string;
|
|
9
9
|
score: number;
|
|
10
10
|
}
|
|
11
|
-
export interface CatalogProject {
|
|
12
|
-
projectId: string;
|
|
13
|
-
title?: string;
|
|
14
|
-
repos: string[];
|
|
15
|
-
journalMtimeMs?: number;
|
|
16
|
-
hasPrd: boolean;
|
|
17
|
-
hasBoard: boolean;
|
|
18
|
-
prdPath?: string;
|
|
19
|
-
}
|
|
20
11
|
export type RefineAction = {
|
|
21
12
|
action: "keep";
|
|
22
13
|
} | {
|
|
@@ -33,16 +24,6 @@ export type RefineAction = {
|
|
|
33
24
|
reason: string;
|
|
34
25
|
candidates: BindCandidate[];
|
|
35
26
|
};
|
|
36
|
-
export declare function scoreProject(hint: string, row: CatalogProject, repoPath: string | undefined, nowMs: number): number;
|
|
37
|
-
export declare function discoverProjects(input: {
|
|
38
|
-
hqRoot?: string;
|
|
39
|
-
companySlug?: string;
|
|
40
|
-
companyUid?: string;
|
|
41
|
-
env?: NodeJS.ProcessEnv;
|
|
42
|
-
home?: string;
|
|
43
|
-
}): CatalogProject[];
|
|
44
|
-
/** discoverProjects memoized by source directory and mtime. A hit does not rescan. */
|
|
45
|
-
export declare function discoverProjectsCached(input: Parameters<typeof discoverProjects>[0], nowMs?: number): CatalogProject[];
|
|
46
27
|
export declare function refineProjectBinding(input: {
|
|
47
28
|
hint?: string;
|
|
48
29
|
hqRoot?: string;
|
|
@@ -16,7 +16,7 @@ function tokens(value) {
|
|
|
16
16
|
.split(/[^a-z0-9]+/)
|
|
17
17
|
.filter((part) => part.length > 2);
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
function scoreProject(hint, row, repoPath, nowMs) {
|
|
20
20
|
const hintL = hint.toLowerCase();
|
|
21
21
|
const idL = row.projectId.toLowerCase();
|
|
22
22
|
let score = 0;
|
|
@@ -162,7 +162,7 @@ function listProjectDirs(parent, map) {
|
|
|
162
162
|
absorbDir(map, dir, name);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
function discoverProjects(input) {
|
|
166
166
|
const map = new Map();
|
|
167
167
|
const hqRoot = input.hqRoot?.trim();
|
|
168
168
|
const slug = input.companySlug?.trim();
|
|
@@ -223,7 +223,7 @@ function catalogStamp(input) {
|
|
|
223
223
|
}).join("|");
|
|
224
224
|
}
|
|
225
225
|
/** discoverProjects memoized by source directory and mtime. A hit does not rescan. */
|
|
226
|
-
|
|
226
|
+
function discoverProjectsCached(input, nowMs = Date.now()) {
|
|
227
227
|
const key = `${input.hqRoot ?? ""}|${input.companySlug ?? ""}|${input.companyUid ?? ""}|${input.home ?? ""}|${catalogStamp(input)}`;
|
|
228
228
|
if (catalogCache && catalogCache.key === key && nowMs - catalogCache.at < CATALOG_CACHE_TTL_MS) {
|
|
229
229
|
return catalogCache.rows;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* never invents a project or adhoc target and never repeats the ask.
|
|
8
8
|
*/
|
|
9
9
|
import { type SessionDecision, type SessionStateFile } from "./state.js";
|
|
10
|
-
|
|
10
|
+
interface OrganizeCandidate {
|
|
11
11
|
candidateId: string;
|
|
12
12
|
projectId: string;
|
|
13
13
|
taskId?: string;
|
|
@@ -22,7 +22,7 @@ export interface CandidatesResponse {
|
|
|
22
22
|
decisionExpiresAt: string;
|
|
23
23
|
candidates: OrganizeCandidate[];
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
type OrganizeDecisionKind = "bind_existing" | "create_project" | "create_task";
|
|
26
26
|
export interface OrganizeSubmitDecision {
|
|
27
27
|
kind: OrganizeDecisionKind;
|
|
28
28
|
projectId?: string;
|
|
@@ -74,15 +74,6 @@ export type PostOrganizeFn = (input: {
|
|
|
74
74
|
expectedVersion: number;
|
|
75
75
|
decisionExpiresAt?: string;
|
|
76
76
|
}) => Promise<OrganizeReceipt>;
|
|
77
|
-
/** Stable decision id for a session + expiry window. */
|
|
78
|
-
export declare function stableDecisionId(sessionId: string, decisionExpiresAt: string): string;
|
|
79
|
-
export declare function digestOrganizePayload(parts: {
|
|
80
|
-
sessionId: string;
|
|
81
|
-
companyUid: string;
|
|
82
|
-
decision: OrganizeSubmitDecision;
|
|
83
|
-
expectedVersion: number;
|
|
84
|
-
}): string;
|
|
85
|
-
export declare function stableOrganizeOperationId(sessionId: string, decision: OrganizeSubmitDecision): string;
|
|
86
77
|
/**
|
|
87
78
|
* Build a pending decision from server candidates. Soft evidence ranks on the
|
|
88
79
|
* server; the CLI never auto-binds from this list.
|
|
@@ -127,4 +118,5 @@ export declare function submitOrganizeDecision(input: {
|
|
|
127
118
|
now?: () => Date;
|
|
128
119
|
postOrganize?: PostOrganizeFn;
|
|
129
120
|
}): Promise<OrganizeSubmitResult>;
|
|
121
|
+
export {};
|
|
130
122
|
//# sourceMappingURL=organize.d.ts.map
|
|
@@ -12,7 +12,7 @@ import { NotTrackingError } from "./errors.js";
|
|
|
12
12
|
import { shouldAskAfter } from "./project.js";
|
|
13
13
|
import { mergeLocalSessionFields, readSessionState, writeSessionState, } from "./state.js";
|
|
14
14
|
/** Stable decision id for a session + expiry window. */
|
|
15
|
-
|
|
15
|
+
function stableDecisionId(sessionId, decisionExpiresAt) {
|
|
16
16
|
const h = crypto
|
|
17
17
|
.createHash("sha256")
|
|
18
18
|
.update(`dec:v1:${sessionId}:${decisionExpiresAt}`)
|
|
@@ -20,7 +20,7 @@ export function stableDecisionId(sessionId, decisionExpiresAt) {
|
|
|
20
20
|
.slice(0, 24);
|
|
21
21
|
return `dec_${h}`;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
function digestOrganizePayload(parts) {
|
|
24
24
|
const canonical = JSON.stringify({
|
|
25
25
|
v: 1,
|
|
26
26
|
sessionId: parts.sessionId,
|
|
@@ -30,7 +30,7 @@ export function digestOrganizePayload(parts) {
|
|
|
30
30
|
});
|
|
31
31
|
return crypto.createHash("sha256").update(canonical).digest("hex").slice(0, 64);
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
function stableOrganizeOperationId(sessionId, decision) {
|
|
34
34
|
const h = crypto
|
|
35
35
|
.createHash("sha256")
|
|
36
36
|
.update(`organize:v1:${sessionId}:${decision.kind}:${decision.projectId ?? ""}:${decision.taskId ?? ""}:${decision.title ?? ""}`)
|
|
@@ -37,11 +37,9 @@
|
|
|
37
37
|
* `merge` rows -- they never produce a symlink.
|
|
38
38
|
*/
|
|
39
39
|
import type { PackManifest, PackContributeKey } from '../types.js';
|
|
40
|
-
import {
|
|
40
|
+
import { type WireMode } from './contribution-table.js';
|
|
41
41
|
import { type UnregisterServerResult, type SafeWriteEnv, type AcquireLockOptions } from '../commands/mcp-registration.js';
|
|
42
42
|
export { readHqVersion, readRecommendedPackages } from './hq-core-yaml.js';
|
|
43
|
-
export type { CatalogEntry } from './hq-core-yaml.js';
|
|
44
|
-
export { CONTRIBUTION_TABLE };
|
|
45
43
|
export type { WireMode };
|
|
46
44
|
/**
|
|
47
45
|
* Where a contributes key is ROUTED (US-005). Reads the single-source table's
|
|
@@ -42,11 +42,6 @@ import * as yaml from 'js-yaml';
|
|
|
42
42
|
import { CONTRIBUTION_TABLE, payloadFor } from './contribution-table.js';
|
|
43
43
|
import { unregisterMcpServers, } from '../commands/mcp-registration.js';
|
|
44
44
|
export { readHqVersion, readRecommendedPackages } from './hq-core-yaml.js';
|
|
45
|
-
// NOTE on dependency direction: this module imports from ../commands/mcp-registration.js
|
|
46
|
-
// to un-register `wire:merge` (mcp) servers on uninstall. mcp-registration.ts imports
|
|
47
|
-
// ONLY fs/os/path/smol-toml (it does NOT import from pack-contributions.ts), so there
|
|
48
|
-
// is NO import cycle. If that ever changes, invert via a callback injected by packs.ts.
|
|
49
|
-
export { CONTRIBUTION_TABLE };
|
|
50
45
|
/**
|
|
51
46
|
* Where a contributes key is ROUTED (US-005). Reads the single-source table's
|
|
52
47
|
* `wire` field — `'symlink'` keys go through `linkFor`/`contributionLinks` (a
|
|
@@ -8,12 +8,6 @@ export interface PackageUseLease {
|
|
|
8
8
|
readonly leasePath: string;
|
|
9
9
|
release(): void;
|
|
10
10
|
}
|
|
11
|
-
export interface PackageUseLeaseRecord {
|
|
12
|
-
pid: number;
|
|
13
|
-
start_time_ms: number;
|
|
14
|
-
hq_version: string;
|
|
15
|
-
purpose?: PackageUseLeasePurpose;
|
|
16
|
-
}
|
|
17
11
|
/** Map only fixed command words to a bounded lease purpose; never persist argv values. */
|
|
18
12
|
export declare function packageUseLeasePurposeForArgv(argv: readonly string[]): PackageUseLeasePurpose;
|
|
19
13
|
export interface PackageUseLeaseHandoff {
|
|
@@ -23,7 +17,6 @@ export interface PackageUseLeaseHandoff {
|
|
|
23
17
|
}
|
|
24
18
|
export declare function npmPrefix(root: string, platform?: NodeJS.Platform): string | null;
|
|
25
19
|
export declare function packageUseLeaseDirectory(prefix: string, stateDirectory?: string): string;
|
|
26
|
-
export declare function packageUseUpdateRequestPath(prefix: string, stateDirectory?: string): string;
|
|
27
20
|
declare function waitForUpdateRequest(requestPath: string, timeoutMs: number): void;
|
|
28
21
|
export declare function acquirePackageUseLease(prefix: string, hqVersion: string, stateDirectory?: string, purpose?: PackageUseLeasePurpose): PackageUseLease;
|
|
29
22
|
/**
|
|
@@ -133,7 +133,7 @@ export function packageUseLeaseDirectory(prefix, stateDirectory = packageUseStat
|
|
|
133
133
|
const digest = createHash("sha256").update(normalizedPrefix(prefix), "utf8").digest("hex");
|
|
134
134
|
return path.join(stateDirectory, digest);
|
|
135
135
|
}
|
|
136
|
-
|
|
136
|
+
function packageUseUpdateRequestPath(prefix, stateDirectory) {
|
|
137
137
|
return path.join(packageUseLeaseDirectory(prefix, stateDirectory), UPDATE_REQUEST);
|
|
138
138
|
}
|
|
139
139
|
function waitForUpdateRequest(requestPath, timeoutMs) {
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export declare function executableCandidates(command: string, pathValue?: string, platform?: NodeJS.Platform, pathExt?: string): string[];
|
|
2
1
|
export declare function isExecutableOnPath(command: string, pathValue?: string, platform?: NodeJS.Platform, pathExt?: string): boolean;
|
|
3
2
|
//# sourceMappingURL=resolve-executable.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
|
|
3
|
+
function executableCandidates(command, pathValue = process.env.PATH ?? '', platform = process.platform, pathExt = process.env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM') {
|
|
4
4
|
const extensions = platform === 'win32'
|
|
5
5
|
? (pathExt || '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean)
|
|
6
6
|
: [''];
|
|
@@ -385,7 +385,7 @@ declare function nudgeUpdateRecommended(decision: VersionCheckResponse, install?
|
|
|
385
385
|
* (Windows) rather than trusting our own install path — the whole point is to
|
|
386
386
|
* see what the USER's next invocation resolves.
|
|
387
387
|
*/
|
|
388
|
-
|
|
388
|
+
declare function resolveHqOnPath(): string | null;
|
|
389
389
|
/**
|
|
390
390
|
* Pull the CLI version out of `hq --version` / `hq version` output.
|
|
391
391
|
*
|
|
@@ -400,7 +400,7 @@ export declare function resolveHqOnPath(): string | null;
|
|
|
400
400
|
*/
|
|
401
401
|
export declare function parseReportedCliVersion(stdout: string): string | null;
|
|
402
402
|
/** `<bin> --version` output (trimmed), or null on any failure/timeout. */
|
|
403
|
-
|
|
403
|
+
declare function probeCliVersion(bin: string): string | null;
|
|
404
404
|
/**
|
|
405
405
|
* Read-your-writes convergence check, run after an install reports success.
|
|
406
406
|
*
|
|
@@ -1129,7 +1129,7 @@ const CONVERGENCE_TIMEOUT_MS = 3_000;
|
|
|
1129
1129
|
* (Windows) rather than trusting our own install path — the whole point is to
|
|
1130
1130
|
* see what the USER's next invocation resolves.
|
|
1131
1131
|
*/
|
|
1132
|
-
|
|
1132
|
+
function resolveHqOnPath() {
|
|
1133
1133
|
try {
|
|
1134
1134
|
const probe = process.platform === "win32"
|
|
1135
1135
|
? spawnSync("where", ["hq"], {
|
|
@@ -1191,7 +1191,7 @@ export function parseReportedCliVersion(stdout) {
|
|
|
1191
1191
|
return null;
|
|
1192
1192
|
}
|
|
1193
1193
|
/** `<bin> --version` output (trimmed), or null on any failure/timeout. */
|
|
1194
|
-
|
|
1194
|
+
function probeCliVersion(bin) {
|
|
1195
1195
|
try {
|
|
1196
1196
|
const result = spawnSync(bin, ["--version"], {
|
|
1197
1197
|
encoding: "utf-8",
|