@indigoai-us/hq-cli 5.309.0 → 5.310.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 +15 -0
- package/assets/scaffold/core/scripts/hq-dm-bind.sh +585 -0
- package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +152 -0
- package/dist/command-catalog.generated.d.ts +30 -1
- package/dist/command-catalog.generated.js +37 -1
- package/dist/commands/agents.js +6 -0
- package/dist/commands/core-checkpoint-gate-setting.d.ts +0 -10
- package/dist/commands/core-checkpoint-gate-setting.js +3 -3
- package/dist/commands/core-dm-bind-native.d.ts +32 -0
- package/dist/commands/core-dm-bind-native.js +668 -0
- package/dist/commands/core-native-utilities.d.ts +2 -1
- package/dist/commands/core-native-utilities.js +4 -2
- package/dist/commands/core-ontology.d.ts +1 -9
- package/dist/commands/core-ontology.js +4 -4
- package/dist/commands/core-policy.d.ts +0 -3
- package/dist/commands/core-policy.js +3 -3
- package/dist/commands/core-work-mesh-bind-trusted-native.d.ts +32 -0
- package/dist/commands/core-work-mesh-bind-trusted-native.js +190 -0
- package/dist/commands/core.js +6 -0
- package/dist/commands/files.js +1 -1
- package/dist/commands/index-cmd.js +1 -1
- package/dist/commands/integrations-api.d.ts +9 -4
- package/dist/commands/integrations-api.js +9 -6
- package/dist/commands/integrations-manage.js +11 -3
- package/dist/commands/integrations.d.ts +8 -0
- package/dist/commands/integrations.js +83 -0
- package/dist/commands/lanes-checks.d.ts +0 -2
- package/dist/commands/lanes-checks.js +2 -2
- package/dist/commands/lanes.d.ts +0 -11
- package/dist/commands/lanes.js +6 -6
- package/dist/commands/mcp-registration.d.ts +5 -11
- package/dist/commands/mcp-registration.js +2 -6
- package/dist/lib/core-utils/sentry-report.d.ts +5 -11
- package/dist/lib/core-utils/sentry-report.js +2 -2
- package/dist/lib/db/local.d.ts +0 -5
- package/dist/lib/db/local.js +1 -1
- package/dist/lib/db/migrate.d.ts +0 -12
- package/dist/lib/db/migrate.js +5 -5
- package/dist/lib/db/sql.d.ts +0 -10
- package/dist/lib/db/sql.js +4 -8
- package/dist/lib/doctor/checks/codex-wiring.js +1 -33
- package/dist/lib/doctor/checks/grok-wiring.js +1 -34
- package/dist/lib/doctor/deep/effects.js +1 -3
- package/dist/lib/doctor/deep/sandbox.js +1 -3
- package/dist/lib/doctor/fixtures/schema.js +1 -3
- package/dist/lib/doctor/shared.d.ts +8 -0
- package/dist/lib/doctor/shared.js +38 -0
- package/dist/lib/lanes/autopilot.js +6 -4
- package/dist/lib/monitor.d.ts +2 -6
- package/dist/lib/monitor.js +5 -5
- package/dist/lib/report-publish.d.ts +1 -10
- package/dist/lib/report-publish.js +3 -9
- package/dist/lib/search-index/index.d.ts +7 -0
- package/dist/lib/search-index/index.js +21 -2
- package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +5 -0
- package/dist/lib/search-index/qmd-exit-diagnostics.js +40 -0
- package/dist/lib/service-manager/launchd.d.ts +0 -7
- package/dist/lib/service-manager/launchd.js +2 -2
- package/dist/main.js +7 -2
- package/dist/startup-registration.js +9 -1
- package/dist/utils/client-health.d.ts +0 -4
- package/dist/utils/client-health.js +2 -2
- package/dist/utils/feedback-diagnostics.d.ts +2 -1
- package/dist/utils/feedback-log-bundle.d.ts +0 -25
- package/dist/utils/feedback-log-bundle.js +5 -5
- package/dist/utils/feedback-logs.d.ts +4 -38
- package/dist/utils/feedback-logs.js +7 -7
- package/dist/utils/feedback-screenshots.d.ts +0 -1
- package/dist/utils/feedback-screenshots.js +1 -1
- package/dist/utils/install-tree-torn.d.ts +19 -13
- package/dist/utils/install-tree-torn.js +77 -2
- package/dist/utils/local-files-overview.d.ts +0 -6
- package/dist/utils/local-files-overview.js +1 -1
- package/dist/utils/qmd-model-download-error.d.ts +0 -8
- package/dist/utils/qmd-model-download-error.js +1 -1
- package/dist/utils/qmd-query-document-error.d.ts +0 -6
- package/dist/utils/qmd-query-document-error.js +1 -1
- package/dist/utils/scaffold-fast-import-guard.d.ts +0 -1
- package/dist/utils/scaffold-fast-import-guard.js +1 -1
- package/dist/utils/scaffold-sibling-references.d.ts +3 -2
- package/dist/utils/sentry-fingerprint.js +17 -0
- package/dist/utils/version-gate.d.ts +4 -0
- package/dist/utils/version-gate.js +13 -0
- package/package.json +1 -1
package/dist/lib/monitor.d.ts
CHANGED
|
@@ -4,15 +4,12 @@ export declare const MONITOR_FLAG = "monitor.enabled";
|
|
|
4
4
|
export declare const MONITOR_FLAG_DEFAULT = false;
|
|
5
5
|
export declare const MONITOR_DEFAULT_TIMEOUT_MS: number;
|
|
6
6
|
export declare const MONITOR_DEFAULT_CHECKIN_MS: number;
|
|
7
|
-
export declare const MONITOR_PROMPT_CACHE_TTL_MS: number;
|
|
8
7
|
export declare const MONITOR_BATCH_WINDOW_MS = 200;
|
|
9
8
|
export declare const MONITOR_POLL_INTERVAL_MS = 1000;
|
|
10
9
|
export declare const MONITOR_RATE_WINDOW_MS = 10000;
|
|
11
10
|
/** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
|
|
12
11
|
export declare const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
|
|
13
12
|
export declare const MONITOR_MAX_FLOOD_WINDOWS = 3;
|
|
14
|
-
export declare const MONITOR_LOCK_STALE_MS = 30000;
|
|
15
|
-
export declare const MONITOR_MAX_TIMER_DELAY_MS = 2147000000;
|
|
16
13
|
export type MonitorTarget = {
|
|
17
14
|
kind: "lane";
|
|
18
15
|
laneId: string;
|
|
@@ -38,7 +35,7 @@ export interface NearestMonitorRuntime {
|
|
|
38
35
|
export interface MonitorRuntimeIdentity extends NearestMonitorRuntime {
|
|
39
36
|
starttime: number;
|
|
40
37
|
}
|
|
41
|
-
|
|
38
|
+
interface MonitorSessionOwner {
|
|
42
39
|
pid: number;
|
|
43
40
|
starttime: number | null;
|
|
44
41
|
}
|
|
@@ -107,7 +104,6 @@ export interface MonitorCheckinResult {
|
|
|
107
104
|
/** This guard is first in monitor start so a conflicting invocation has no side effects. */
|
|
108
105
|
export declare function assertMonitorTimeoutCompatibility(persistent: boolean, timeoutProvided: boolean): void;
|
|
109
106
|
export declare function parseMonitorDuration(value: string, kind: "timeout" | "checkin"): number;
|
|
110
|
-
export declare function assertMonitorSessionId(sessionId: string): void;
|
|
111
107
|
export declare function parseMonitorTarget(value: string): MonitorTarget;
|
|
112
108
|
export declare function monitorTargetKey(target: MonitorTarget): string;
|
|
113
109
|
export declare function detectMonitorTarget(options: DetectMonitorTargetOptions): MonitorTarget;
|
|
@@ -119,7 +115,6 @@ export declare function findNearestMonitorRuntime(options: {
|
|
|
119
115
|
export declare function monitorSessionDir(hqRoot: string, provider: LaneProvider, sessionId: string): string;
|
|
120
116
|
export declare function monitorSessionHasActiveMarkers(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
121
117
|
export declare function monitorSessionHasActiveMarkerForOwner(hqRoot: string, provider: LaneProvider, sessionId: string, owner: MonitorRuntimeIdentity): boolean;
|
|
122
|
-
export declare function monitorSessionHasInboxFile(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
123
118
|
export declare function monitorSessionInboxHasEvents(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
124
119
|
export declare function monitorSessionHasWork(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
125
120
|
export declare function monitorDir(hqRoot: string, monitorId: string): string;
|
|
@@ -150,4 +145,5 @@ export declare function recordMonitorTargetDeliveryAtPath(activityPath: string,
|
|
|
150
145
|
export declare function formatElapsed(ms: number): string;
|
|
151
146
|
export declare function runMonitorCheckinTick(hqRoot: string, targetKey: string, deps: MonitorCheckinDeps): Promise<MonitorCheckinResult>;
|
|
152
147
|
export declare function readMonitorPidLiveness(pid: number | null, starttime: number | null, readStarttime?: (pid: number) => number | null): boolean;
|
|
148
|
+
export {};
|
|
153
149
|
//# sourceMappingURL=monitor.d.ts.map
|
package/dist/lib/monitor.js
CHANGED
|
@@ -9,15 +9,15 @@ export const MONITOR_FLAG = "monitor.enabled";
|
|
|
9
9
|
export const MONITOR_FLAG_DEFAULT = false;
|
|
10
10
|
export const MONITOR_DEFAULT_TIMEOUT_MS = 5 * 60_000;
|
|
11
11
|
export const MONITOR_DEFAULT_CHECKIN_MS = 55 * 60_000;
|
|
12
|
-
|
|
12
|
+
const MONITOR_PROMPT_CACHE_TTL_MS = 60 * 60_000;
|
|
13
13
|
export const MONITOR_BATCH_WINDOW_MS = 200;
|
|
14
14
|
export const MONITOR_POLL_INTERVAL_MS = 1_000;
|
|
15
15
|
export const MONITOR_RATE_WINDOW_MS = 10_000;
|
|
16
16
|
/** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
|
|
17
17
|
export const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
|
|
18
18
|
export const MONITOR_MAX_FLOOD_WINDOWS = 3;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const MONITOR_LOCK_STALE_MS = 30_000;
|
|
20
|
+
const MONITOR_MAX_TIMER_DELAY_MS = 2_147_000_000;
|
|
21
21
|
const SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
22
22
|
const SAFE_LANE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
23
23
|
const RUNTIME_ENV = {
|
|
@@ -59,7 +59,7 @@ function assertLaneTargetId(laneId) {
|
|
|
59
59
|
throw monitorError("monitor_target_invalid", `Invalid lane target ${JSON.stringify(laneId)}.`, { lane_id: laneId });
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
function assertMonitorSessionId(sessionId) {
|
|
63
63
|
if (!SESSION_ID_RE.test(sessionId)) {
|
|
64
64
|
throw monitorError("monitor_session_id_invalid", "Session ids must contain only letters, numbers, underscores, or hyphens and be 1–128 characters long.", { session_id: sessionId });
|
|
65
65
|
}
|
|
@@ -154,7 +154,7 @@ export function monitorSessionHasActiveMarkerForOwner(hqRoot, provider, sessionI
|
|
|
154
154
|
&& markerOwner.starttime === owner.starttime;
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
function monitorSessionHasInboxFile(hqRoot, provider, sessionId) {
|
|
158
158
|
return fs.existsSync(path.join(monitorSessionDir(hqRoot, provider, sessionId), "dropbox", "inbox.jsonl"));
|
|
159
159
|
}
|
|
160
160
|
export function monitorSessionInboxHasEvents(hqRoot, provider, sessionId) {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/** Mirrors the deploy skill's static-report guardrails. */
|
|
2
|
-
export declare const REPORT_SOURCE_MAX_BYTES: number;
|
|
3
|
-
export declare const REPORT_BUNDLE_MAX_BYTES: number;
|
|
4
|
-
export declare const REPORT_SOURCE_MAX_FILES = 100;
|
|
5
1
|
export declare const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
|
|
6
|
-
|
|
2
|
+
type ReportLastRun = {
|
|
7
3
|
at: string;
|
|
8
4
|
status: "running" | "succeeded" | "failed";
|
|
9
5
|
reason?: string;
|
|
@@ -175,10 +171,5 @@ type BuiltTarball = {
|
|
|
175
171
|
};
|
|
176
172
|
/** hq-deploy static payload format: index.html stays at the archive root. */
|
|
177
173
|
export declare function buildReportTarball(files: StaticFile[]): BuiltTarball;
|
|
178
|
-
/** Isolated test helper for creating a compliant report source. */
|
|
179
|
-
export declare function makeReportFixture(html: string): {
|
|
180
|
-
directory: string;
|
|
181
|
-
cleanup: () => void;
|
|
182
|
-
};
|
|
183
174
|
export {};
|
|
184
175
|
//# sourceMappingURL=report-publish.d.ts.map
|
|
@@ -13,9 +13,9 @@ import { gzipSync } from "node:zlib";
|
|
|
13
13
|
import { REPORT_PREVIEW_FILE } from "./report-snapshot.js";
|
|
14
14
|
import { loadUpdateReportRunbook } from "./report-templates.js";
|
|
15
15
|
/** Mirrors the deploy skill's static-report guardrails. */
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const REPORT_SOURCE_MAX_BYTES = 25 * 1024 * 1024;
|
|
17
|
+
const REPORT_BUNDLE_MAX_BYTES = 10 * 1024 * 1024;
|
|
18
|
+
const REPORT_SOURCE_MAX_FILES = 100;
|
|
19
19
|
export const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
|
|
20
20
|
/**
|
|
21
21
|
* Write the files exactly as they will be published, protected index.html
|
|
@@ -418,10 +418,4 @@ function writeOctal(buffer, value, offset, length) {
|
|
|
418
418
|
buffer.write(value.toString(8).padStart(length - 1, "0").slice(-length + 1), offset, length - 1, "ascii");
|
|
419
419
|
buffer[offset + length - 1] = 0;
|
|
420
420
|
}
|
|
421
|
-
/** Isolated test helper for creating a compliant report source. */
|
|
422
|
-
export function makeReportFixture(html) {
|
|
423
|
-
const directory = fs.mkdtempSync(path.join(os.tmpdir(), "hq-report-test-"));
|
|
424
|
-
fs.writeFileSync(path.join(directory, "index.html"), html);
|
|
425
|
-
return { directory, cleanup: () => fs.rmSync(directory, { recursive: true, force: true }) };
|
|
426
|
-
}
|
|
427
421
|
//# sourceMappingURL=report-publish.js.map
|
|
@@ -11,6 +11,7 @@ export type QmdProcessResult = {
|
|
|
11
11
|
*/
|
|
12
12
|
signal?: NodeJS.Signals | string | null;
|
|
13
13
|
};
|
|
14
|
+
export type QmdUpdateEntryPath = 'index-sync';
|
|
14
15
|
export type QmdProcessRunner = (bin: string, args: string[], options: {
|
|
15
16
|
cwd?: string;
|
|
16
17
|
env?: NodeJS.ProcessEnv;
|
|
@@ -113,6 +114,10 @@ export declare class QmdExitError extends Error {
|
|
|
113
114
|
readonly stdout: string;
|
|
114
115
|
readonly stderr: string;
|
|
115
116
|
name: string;
|
|
117
|
+
/** Safe route labels for telemetry; raw qmd streams remain local to the error. */
|
|
118
|
+
entryPath?: QmdUpdateEntryPath;
|
|
119
|
+
/** Present only when the invoked executable is the bundled qmd. */
|
|
120
|
+
qmdVersion?: string;
|
|
116
121
|
constructor(message: string, args: string[], status: number | null, stdout: string, stderr: string);
|
|
117
122
|
}
|
|
118
123
|
export declare class QmdCollectionMissingError extends QmdExitError {
|
|
@@ -507,6 +512,8 @@ export type ResolveQmdInvocationOptions = {
|
|
|
507
512
|
export declare function resolveQmdInvocation(options?: ResolveQmdInvocationOptions): QmdInvocation;
|
|
508
513
|
export type RunQmdOptions = {
|
|
509
514
|
bin?: string;
|
|
515
|
+
/** Source of an update failure, used only for bounded Sentry tags. */
|
|
516
|
+
entryPath?: QmdUpdateEntryPath;
|
|
510
517
|
cwd?: string;
|
|
511
518
|
env?: NodeJS.ProcessEnv;
|
|
512
519
|
runner?: QmdProcessRunner;
|
|
@@ -76,6 +76,10 @@ export class QmdExitError extends Error {
|
|
|
76
76
|
stdout;
|
|
77
77
|
stderr;
|
|
78
78
|
name = 'QmdExitError';
|
|
79
|
+
/** Safe route labels for telemetry; raw qmd streams remain local to the error. */
|
|
80
|
+
entryPath;
|
|
81
|
+
/** Present only when the invoked executable is the bundled qmd. */
|
|
82
|
+
qmdVersion;
|
|
79
83
|
constructor(message, args, status, stdout, stderr) {
|
|
80
84
|
super(message);
|
|
81
85
|
this.args = args;
|
|
@@ -1239,6 +1243,21 @@ function finishRunQmd(result, bin, args, attribution) {
|
|
|
1239
1243
|
}
|
|
1240
1244
|
throw exitError;
|
|
1241
1245
|
}
|
|
1246
|
+
function finishRunQmdWithDiagnostics(result, bin, args, options, attribution) {
|
|
1247
|
+
try {
|
|
1248
|
+
return finishRunQmd(result, bin, args, attribution);
|
|
1249
|
+
}
|
|
1250
|
+
catch (error) {
|
|
1251
|
+
if (error instanceof QmdExitError) {
|
|
1252
|
+
if (args[0] === 'update' && options.entryPath)
|
|
1253
|
+
error.entryPath = options.entryPath;
|
|
1254
|
+
const bundledBins = [packageLocalBin(), packageLocalNodeEntry()].filter((candidate) => Boolean(candidate));
|
|
1255
|
+
if (bundledBins.includes(bin))
|
|
1256
|
+
error.qmdVersion = resolveQmdVersion();
|
|
1257
|
+
}
|
|
1258
|
+
throw error;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1242
1261
|
/** Run qmd with captured output and typed failures. */
|
|
1243
1262
|
export function runQmd(args, options = {}) {
|
|
1244
1263
|
// Legacy string-bin runner seam (tests and callers that inject a fake process):
|
|
@@ -1246,7 +1265,7 @@ export function runQmd(args, options = {}) {
|
|
|
1246
1265
|
if (options.runner) {
|
|
1247
1266
|
const bin = options.bin ?? resolveQmdBin({ env: options.env });
|
|
1248
1267
|
const result = options.runner(bin, args, { cwd: options.cwd, env: options.env });
|
|
1249
|
-
return
|
|
1268
|
+
return finishRunQmdWithDiagnostics(result, bin, args, options);
|
|
1250
1269
|
}
|
|
1251
1270
|
// Default path: resolve the full invocation (shell-free Node launcher preferred)
|
|
1252
1271
|
// and spawn it through the shared Windows-aware plan. An explicit string bin is
|
|
@@ -1279,7 +1298,7 @@ export function runQmd(args, options = {}) {
|
|
|
1279
1298
|
// genuinely missing qmd — instead of blaming the launcher for all three
|
|
1280
1299
|
// (HQ-CLI-1A). `command` is the process actually spawned; `launcher` is qmd's
|
|
1281
1300
|
// file identity.
|
|
1282
|
-
return
|
|
1301
|
+
return finishRunQmdWithDiagnostics(result, launcher, args, options, {
|
|
1283
1302
|
command: invocation.command,
|
|
1284
1303
|
launcher,
|
|
1285
1304
|
cwd: options.cwd,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { QmdExitError } from "./index.js";
|
|
2
|
+
const QMD_ERROR_CODE_TOKENS = [
|
|
3
|
+
"SQLITE_BUSY",
|
|
4
|
+
"SQLITE_CORRUPT",
|
|
5
|
+
"SQLITE_FULL",
|
|
6
|
+
"ENOSPC",
|
|
7
|
+
"EACCES",
|
|
8
|
+
"EPERM",
|
|
9
|
+
"ENOENT",
|
|
10
|
+
"ECONNRESET",
|
|
11
|
+
"ETIMEDOUT",
|
|
12
|
+
];
|
|
13
|
+
const QMD_UPDATE_ENTRY_PATHS = new Set(["index-sync"]);
|
|
14
|
+
/** Bounded Sentry tags for qmd exits; never return captured streams or full argv. */
|
|
15
|
+
export function qmdExitCaptureContext(err) {
|
|
16
|
+
if (!(err instanceof QmdExitError))
|
|
17
|
+
return undefined;
|
|
18
|
+
const output = err.stderr + "\n" + err.stdout;
|
|
19
|
+
const errorCode = QMD_ERROR_CODE_TOKENS.find((token) => new RegExp("(^|[^A-Za-z0-9_])" + token + "(?=$|[^A-Za-z0-9_])").test(output)) ?? "none";
|
|
20
|
+
const firstArg = err.args[0];
|
|
21
|
+
const subcommand = typeof firstArg === "string" && /^[a-z][a-z0-9_-]{0,31}$/.test(firstArg)
|
|
22
|
+
? firstArg
|
|
23
|
+
: "unknown";
|
|
24
|
+
const exitStatus = typeof err.status === "number" && Number.isSafeInteger(err.status)
|
|
25
|
+
? String(err.status)
|
|
26
|
+
: "unknown";
|
|
27
|
+
const tags = {
|
|
28
|
+
qmd_error_code: errorCode,
|
|
29
|
+
qmd_subcommand: subcommand,
|
|
30
|
+
qmd_exit_status: exitStatus,
|
|
31
|
+
};
|
|
32
|
+
if (typeof err.qmdVersion === "string" && /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(err.qmdVersion)) {
|
|
33
|
+
tags.qmd_version = err.qmdVersion;
|
|
34
|
+
}
|
|
35
|
+
if (typeof err.entryPath === "string" && QMD_UPDATE_ENTRY_PATHS.has(err.entryPath)) {
|
|
36
|
+
tags.qmd_entry_path = err.entryPath;
|
|
37
|
+
}
|
|
38
|
+
return { tags };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=qmd-exit-diagnostics.js.map
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* touch launchctl.
|
|
8
8
|
*/
|
|
9
9
|
import { type ServiceHostPaths, type ServiceSpec } from "./types.js";
|
|
10
|
-
export declare const LAUNCHD_PATH_ENV = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin";
|
|
11
10
|
export declare function launchAgentsDir(home: string): string;
|
|
12
11
|
export declare function launchdPlistPath(home: string, spec: Pick<ServiceSpec, "label">): string;
|
|
13
12
|
export declare function renderLaunchdPlist(spec: ServiceSpec, host: ServiceHostPaths): string;
|
|
@@ -27,12 +26,6 @@ export declare const LAUNCHD_BOOTSTRAP_BACKOFF_MS: readonly number[];
|
|
|
27
26
|
export declare const LAUNCHD_BOOTSTRAP_ATTEMPTS: number;
|
|
28
27
|
export declare const defaultRunCommand: RunCommand;
|
|
29
28
|
export declare function launchdServiceTarget(plistPath: string, uid?: number): string;
|
|
30
|
-
/** launchd returns EIO (5) when bootstrap races the previous job's exit. */
|
|
31
|
-
export declare function isRetryableLaunchdBootstrap(r: {
|
|
32
|
-
status: number | null;
|
|
33
|
-
stdout: string;
|
|
34
|
-
stderr: string;
|
|
35
|
-
}): boolean;
|
|
36
29
|
/** ProgramArguments from a LaunchAgent plist. */
|
|
37
30
|
export declare function launchdPlistProgramArguments(plist: string): string[];
|
|
38
31
|
/**
|
|
@@ -10,7 +10,7 @@ import { spawnSync } from "node:child_process";
|
|
|
10
10
|
import * as os from "node:os";
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { escapeXml, } from "./types.js";
|
|
13
|
-
|
|
13
|
+
const LAUNCHD_PATH_ENV = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin";
|
|
14
14
|
export function launchAgentsDir(home) {
|
|
15
15
|
return path.join(home, "Library", "LaunchAgents");
|
|
16
16
|
}
|
|
@@ -89,7 +89,7 @@ function bootstrapErrorText(r) {
|
|
|
89
89
|
return `${r.stderr} ${r.stdout} exit ${r.status ?? ""}`;
|
|
90
90
|
}
|
|
91
91
|
/** launchd returns EIO (5) when bootstrap races the previous job's exit. */
|
|
92
|
-
|
|
92
|
+
function isRetryableLaunchdBootstrap(r) {
|
|
93
93
|
if (r.status === 0)
|
|
94
94
|
return false;
|
|
95
95
|
return /Input\/output error|\bEIO\b|Bootstrap failed: 5|Boot-strap failed: 5/i.test(bootstrapErrorText(r));
|
package/dist/main.js
CHANGED
|
@@ -24,6 +24,7 @@ import { qmdStoreUnopenableMessage } from "./utils/qmd-store-unopenable-error.js
|
|
|
24
24
|
import { qmdQueryDocumentMessage } from "./utils/qmd-query-document-error.js";
|
|
25
25
|
import { qmdModelDownloadMessage } from "./utils/qmd-model-download-error.js";
|
|
26
26
|
import { qmdWorkdirMissingMessage } from "./utils/qmd-workdir-missing-error.js";
|
|
27
|
+
import { qmdExitCaptureContext } from "./lib/search-index/qmd-exit-diagnostics.js";
|
|
27
28
|
import { hqStateWriteErrorMessage } from "./utils/hq-state-write-error.js";
|
|
28
29
|
import { checkpointStampWriteCaptureContext, checkpointStampWriteMessage, } from "./utils/checkpoint-stamp-write-error.js";
|
|
29
30
|
import { incompleteInstallMessage, incompleteInstallCaptureContext, } from "./utils/incomplete-install-error.js";
|
|
@@ -872,9 +873,13 @@ export async function handleTopLevelError(err, deps = defaultTopLevelErrorDepend
|
|
|
872
873
|
// Every other error captures bare, exactly as before.
|
|
873
874
|
const spawnContext = qmdSpawnFailureCaptureContext(err);
|
|
874
875
|
const installContext = incompleteInstallCaptureContext(err);
|
|
875
|
-
|
|
876
|
+
const qmdContext = qmdExitCaptureContext(err);
|
|
877
|
+
if (spawnContext || installContext || qmdContext) {
|
|
876
878
|
deps.sentry.captureException(err, {
|
|
877
|
-
|
|
879
|
+
...qmdContext,
|
|
880
|
+
...((spawnContext || installContext)
|
|
881
|
+
? { contexts: { ...spawnContext?.contexts, ...installContext } }
|
|
882
|
+
: {}),
|
|
878
883
|
});
|
|
879
884
|
}
|
|
880
885
|
else {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* spawns, waits, or a real install tree.
|
|
18
18
|
*/
|
|
19
19
|
import { spawnSync } from "node:child_process";
|
|
20
|
-
import { resolveRunningInstall } from "./utils/version-gate.js";
|
|
20
|
+
import { getVersionGatePhase, resolveRunningInstall } from "./utils/version-gate.js";
|
|
21
21
|
import { stringDerivedPackageRoot } from "./utils/hq-roots.js";
|
|
22
22
|
import { updateLockPath, UPDATE_LOCK_STALE_MS } from "./utils/update-lock.js";
|
|
23
23
|
import { classifyEvalThrow, classifyModuleNotFound, installRewriteInProgress, InstallTreeTornError, waitForInstallTreeSettled, } from "./utils/install-tree-torn.js";
|
|
@@ -122,6 +122,7 @@ export async function registerCommandsWithRecovery(args) {
|
|
|
122
122
|
cause: err,
|
|
123
123
|
classified,
|
|
124
124
|
packageRoot,
|
|
125
|
+
versionGatePhase: getVersionGatePhase(),
|
|
125
126
|
outcome: "guarded",
|
|
126
127
|
treeState: env[INSTALL_TREE_RECOVERY_TREE_STATE_ENV] === "stale" ? "stale" : "in_flight",
|
|
127
128
|
attempt: 2,
|
|
@@ -165,6 +166,9 @@ export async function registerCommandsWithRecovery(args) {
|
|
|
165
166
|
sawLock: result.sawLock,
|
|
166
167
|
sawRetired: result.sawRetired,
|
|
167
168
|
retiredSiblingPresent: result.retiredSiblingPresent,
|
|
169
|
+
retiredSiblingKind: result.retiredSiblingKind,
|
|
170
|
+
installTargetState: result.installTargetState,
|
|
171
|
+
updaterPidAlive: result.updaterPidAlive,
|
|
168
172
|
sawTreeChange: result.sawTreeChange,
|
|
169
173
|
lockHeldAtEnd: result.lockHeldAtEnd,
|
|
170
174
|
lockedMs: result.lockedMs,
|
|
@@ -189,6 +193,7 @@ export async function registerCommandsWithRecovery(args) {
|
|
|
189
193
|
cause: err,
|
|
190
194
|
classified,
|
|
191
195
|
packageRoot,
|
|
196
|
+
versionGatePhase: getVersionGatePhase(),
|
|
192
197
|
outcome: "reexec-failed",
|
|
193
198
|
treeState,
|
|
194
199
|
attempt: 1,
|
|
@@ -196,6 +201,9 @@ export async function registerCommandsWithRecovery(args) {
|
|
|
196
201
|
sawLock: result.sawLock,
|
|
197
202
|
sawRetired: result.sawRetired,
|
|
198
203
|
retiredSiblingPresent: result.retiredSiblingPresent,
|
|
204
|
+
retiredSiblingKind: result.retiredSiblingKind,
|
|
205
|
+
installTargetState: result.installTargetState,
|
|
206
|
+
updaterPidAlive: result.updaterPidAlive,
|
|
199
207
|
sawTreeChange: result.sawTreeChange,
|
|
200
208
|
lockTool: result.lockTool,
|
|
201
209
|
});
|
|
@@ -33,8 +33,6 @@
|
|
|
33
33
|
import { isExpiring, loadCachedTokens } from "./cognito-session.js";
|
|
34
34
|
import { type VersionInfo } from "./feedback-versions.js";
|
|
35
35
|
import { type ClientHealthArch, type ClientHealthHeartbeat, type ClientHealthLocalFilesOverview, type ClientHealthPlatform } from "./client-health-contract.js";
|
|
36
|
-
/** Same bound as CLI telemetry: a heartbeat may never stall a command. */
|
|
37
|
-
export declare const CLIENT_HEALTH_TIMEOUT_MS = 1200;
|
|
38
36
|
export declare const CLIENT_HEALTH_STATE_FILE = "cli-client-health.json";
|
|
39
37
|
/**
|
|
40
38
|
* Single-flight marker for the journal observation below. Held only for the
|
|
@@ -66,8 +64,6 @@ export declare const CLIENT_HEALTH_OBSERVATION_FILE = "cli-client-health.observa
|
|
|
66
64
|
* always re-observe — they have opened the store anyway, so it costs nothing.
|
|
67
65
|
*/
|
|
68
66
|
export declare const JOURNAL_OBSERVATION_TTL_MS: number;
|
|
69
|
-
/** An observation lock older than this is treated as abandoned. */
|
|
70
|
-
export declare const JOURNAL_OBSERVATION_LOCK_STALE_MS: number;
|
|
71
67
|
export interface CliClientHealthState {
|
|
72
68
|
/** Stable random installation identity — regenerated only if invalid. */
|
|
73
69
|
installationId: string;
|
|
@@ -40,7 +40,7 @@ import { collectVersions } from "./feedback-versions.js";
|
|
|
40
40
|
import { CLIENT_HEALTH_CONTRACT_VERSION, parseClientHealthHeartbeat, } from "./client-health-contract.js";
|
|
41
41
|
import { collectLocalFilesOverview } from "./local-files-overview.js";
|
|
42
42
|
/** Same bound as CLI telemetry: a heartbeat may never stall a command. */
|
|
43
|
-
|
|
43
|
+
const CLIENT_HEALTH_TIMEOUT_MS = 1_200;
|
|
44
44
|
export const CLIENT_HEALTH_STATE_FILE = "cli-client-health.json";
|
|
45
45
|
/**
|
|
46
46
|
* Single-flight marker for the journal observation below. Held only for the
|
|
@@ -73,7 +73,7 @@ export const CLIENT_HEALTH_OBSERVATION_FILE = "cli-client-health.observation.jso
|
|
|
73
73
|
*/
|
|
74
74
|
export const JOURNAL_OBSERVATION_TTL_MS = 15 * 60_000;
|
|
75
75
|
/** An observation lock older than this is treated as abandoned. */
|
|
76
|
-
|
|
76
|
+
const JOURNAL_OBSERVATION_LOCK_STALE_MS = 5 * 60_000;
|
|
77
77
|
/**
|
|
78
78
|
* Pre-filter mirror of the contract's SemVer shape (the contract keeps its
|
|
79
79
|
* validators private). A version failing this is DROPPED individually so one
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type VersionInfo } from "./feedback-versions.js";
|
|
2
2
|
import type { FeedbackLogsBlob } from "./feedback-logs.js";
|
|
3
|
-
|
|
3
|
+
interface GitContext {
|
|
4
4
|
branch: string | null;
|
|
5
5
|
head: string | null;
|
|
6
6
|
dirty: boolean;
|
|
@@ -37,4 +37,5 @@ export interface DiagnosticsBlob {
|
|
|
37
37
|
}
|
|
38
38
|
export declare function sanitizeArgv(argv: string[]): string[];
|
|
39
39
|
export declare function collectDiagnostics(): DiagnosticsBlob;
|
|
40
|
+
export {};
|
|
40
41
|
//# sourceMappingURL=feedback-diagnostics.d.ts.map
|
|
@@ -61,29 +61,6 @@ import { vaultApiFetch } from "./vault-api.js";
|
|
|
61
61
|
* stay in step or the CLI will build bundles the server will not accept.
|
|
62
62
|
*/
|
|
63
63
|
export declare const LOG_BUNDLE_MAX_BYTES: number;
|
|
64
|
-
/**
|
|
65
|
-
* What the presign request declares, and what the server must answer with.
|
|
66
|
-
* Mirrors `LOG_BUNDLE_FORMAT_ZIP` / `LOG_BUNDLE_ZIP_CONTENT_TYPE` in the hq-pro
|
|
67
|
-
* handler `feedback-log-bundles.ts`.
|
|
68
|
-
*/
|
|
69
|
-
export declare const LOG_BUNDLE_FORMAT = "zip";
|
|
70
|
-
export declare const LOG_BUNDLE_CONTENT_TYPE = "application/zip";
|
|
71
|
-
/**
|
|
72
|
-
* Headroom between the size we stop feeding at and the hard cap.
|
|
73
|
-
*
|
|
74
|
-
* deflate reports compressed bytes only as its internal buffer flushes, so the
|
|
75
|
-
* running total lags the bytes actually consumed. The lag is bounded by that
|
|
76
|
-
* buffer (tens of KiB); a 1 MiB margin covers it with three orders of magnitude
|
|
77
|
-
* to spare, and the final size is asserted against the real cap regardless.
|
|
78
|
-
*/
|
|
79
|
-
export declare const LOG_BUNDLE_SAFETY_MARGIN_BYTES: number;
|
|
80
|
-
/**
|
|
81
|
-
* Per-file raw ceiling. The desktop logger rotates at 32 MiB (hq-desktop-core
|
|
82
|
-
* `logfile.rs`), so this admits a full generation with headroom while stopping
|
|
83
|
-
* one pathological file from consuming the whole bundle. Files above it are
|
|
84
|
-
* read from the TAIL — the end of a log is what explains a failure.
|
|
85
|
-
*/
|
|
86
|
-
export declare const LOG_BUNDLE_MAX_FILE_RAW_BYTES: number;
|
|
87
64
|
export interface LogBundleResult {
|
|
88
65
|
/** The zipped NDJSON bytes, ready to PUT. */
|
|
89
66
|
bytes: Buffer;
|
|
@@ -150,8 +127,6 @@ export declare const ZIP32_UNCOMPRESSED_STOP_BYTES: number;
|
|
|
150
127
|
*/
|
|
151
128
|
export declare function entryCeiling(requested?: number): number;
|
|
152
129
|
export declare function crc32Fallback(buf: Buffer, seed?: number): number;
|
|
153
|
-
/** Exported for the test that proves the fallback agrees with the native one. */
|
|
154
|
-
export declare function crc32(buf: Buffer, seed?: number): number;
|
|
155
130
|
/**
|
|
156
131
|
* Bytes of ZIP framing around one entry: local header, central directory
|
|
157
132
|
* header, end-of-central-directory. The name is stored twice.
|
|
@@ -71,8 +71,8 @@ export const LOG_BUNDLE_MAX_BYTES = 50 * 1024 * 1024;
|
|
|
71
71
|
* Mirrors `LOG_BUNDLE_FORMAT_ZIP` / `LOG_BUNDLE_ZIP_CONTENT_TYPE` in the hq-pro
|
|
72
72
|
* handler `feedback-log-bundles.ts`.
|
|
73
73
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const LOG_BUNDLE_FORMAT = "zip";
|
|
75
|
+
const LOG_BUNDLE_CONTENT_TYPE = "application/zip";
|
|
76
76
|
/**
|
|
77
77
|
* Headroom between the size we stop feeding at and the hard cap.
|
|
78
78
|
*
|
|
@@ -81,14 +81,14 @@ export const LOG_BUNDLE_CONTENT_TYPE = "application/zip";
|
|
|
81
81
|
* buffer (tens of KiB); a 1 MiB margin covers it with three orders of magnitude
|
|
82
82
|
* to spare, and the final size is asserted against the real cap regardless.
|
|
83
83
|
*/
|
|
84
|
-
|
|
84
|
+
const LOG_BUNDLE_SAFETY_MARGIN_BYTES = 1024 * 1024;
|
|
85
85
|
/**
|
|
86
86
|
* Per-file raw ceiling. The desktop logger rotates at 32 MiB (hq-desktop-core
|
|
87
87
|
* `logfile.rs`), so this admits a full generation with headroom while stopping
|
|
88
88
|
* one pathological file from consuming the whole bundle. Files above it are
|
|
89
89
|
* read from the TAIL — the end of a log is what explains a failure.
|
|
90
90
|
*/
|
|
91
|
-
|
|
91
|
+
const LOG_BUNDLE_MAX_FILE_RAW_BYTES = 64 * 1024 * 1024;
|
|
92
92
|
/** Read slice size. Bounds peak memory; unrelated to the output chunking. */
|
|
93
93
|
const READ_SLICE_BYTES = 4 * 1024 * 1024;
|
|
94
94
|
/** Target raw text per emitted chunk record. Keeps NDJSON lines manageable. */
|
|
@@ -217,7 +217,7 @@ export function crc32Fallback(buf, seed = 0) {
|
|
|
217
217
|
return (~crc >>> 0) >>> 0;
|
|
218
218
|
}
|
|
219
219
|
/** Exported for the test that proves the fallback agrees with the native one. */
|
|
220
|
-
|
|
220
|
+
function crc32(buf, seed = 0) {
|
|
221
221
|
const native = zlib.crc32;
|
|
222
222
|
return typeof native === "function" ? native(buf, seed) : crc32Fallback(buf, seed);
|
|
223
223
|
}
|
|
@@ -84,13 +84,6 @@ export declare const FEEDBACK_LOGS_MIN_USEFUL_BYTES = 1024;
|
|
|
84
84
|
* evidence. The overflow count preserves the signal without the bytes.
|
|
85
85
|
*/
|
|
86
86
|
export declare const FEEDBACK_MAX_SKIPPED_ENTRIES = 25;
|
|
87
|
-
/** Subdirectory of `~/.hq` whose log files are eligible. Not recursive. */
|
|
88
|
-
export declare const FEEDBACK_LOGS_DIRNAME = "logs";
|
|
89
|
-
/**
|
|
90
|
-
* Eligible extensions inside `~/.hq/logs/`. `.jsonl` is included because the
|
|
91
|
-
* CLI's MCP registry audit trail is JSON-lines, not plain text.
|
|
92
|
-
*/
|
|
93
|
-
export declare const FEEDBACK_LOG_EXTENSIONS: readonly string[];
|
|
94
87
|
/**
|
|
95
88
|
* True for a log filename, including a ROTATED generation.
|
|
96
89
|
*
|
|
@@ -103,26 +96,6 @@ export declare const FEEDBACK_LOG_EXTENSIONS: readonly string[];
|
|
|
103
96
|
export declare function isEligibleLogName(name: string): boolean;
|
|
104
97
|
/** Per-state-file ceiling. These are status documents, not streams. */
|
|
105
98
|
export declare const FEEDBACK_STATE_MAX_FILE_BYTES: number;
|
|
106
|
-
/**
|
|
107
|
-
* Ceiling on all state snapshots combined. Deliberately a small slice of the
|
|
108
|
-
* overall budget: state is dense but finite, and the rest belongs to logs.
|
|
109
|
-
*/
|
|
110
|
-
export declare const FEEDBACK_STATE_MAX_TOTAL_BYTES: number;
|
|
111
|
-
/**
|
|
112
|
-
* State files at the `~/.hq` ROOT that are eligible, by EXACT name.
|
|
113
|
-
*
|
|
114
|
-
* The root is where `cognito-tokens.json`, `deploy-passwords.json`, and
|
|
115
|
-
* `secrets-cache/` live, so it is never globbed. Adding a name here is a
|
|
116
|
-
* deliberate act: confirm the file carries no credential before listing it.
|
|
117
|
-
*/
|
|
118
|
-
export declare const FEEDBACK_STATE_FILENAMES: readonly string[];
|
|
119
|
-
/**
|
|
120
|
-
* Per-company sync journal LOCATORS (`sync-journal.<slug>.json`) are also
|
|
121
|
-
* eligible. Matched by an exact prefix AND a `.json` suffix, which is what
|
|
122
|
-
* excludes the multi-hundred-megabyte `…json.last-good` snapshots sitting
|
|
123
|
-
* beside them. No credential file at the root carries this prefix.
|
|
124
|
-
*/
|
|
125
|
-
export declare const FEEDBACK_STATE_JOURNAL_PREFIX = "sync-journal.";
|
|
126
99
|
/**
|
|
127
100
|
* `~/.hq/locks/` — held operation locks and background-work claims.
|
|
128
101
|
*
|
|
@@ -141,8 +114,6 @@ export declare const FEEDBACK_LOCKS_DIRNAME = "locks";
|
|
|
141
114
|
* bounds that walk carries.
|
|
142
115
|
*/
|
|
143
116
|
export declare const FEEDBACK_JOBS_DIRNAME = "jobs";
|
|
144
|
-
/** Per-entry ceiling for a lock file. Their value is the name plus a little context. */
|
|
145
|
-
export declare const FEEDBACK_LOCK_MAX_FILE_BYTES = 512;
|
|
146
117
|
/**
|
|
147
118
|
* Bounds on the `jobs/` walk. Depth 3 reaches
|
|
148
119
|
* `jobs/probes/<job>/last-attempt.json`; the file cap stops a pathological
|
|
@@ -152,15 +123,9 @@ export declare const FEEDBACK_JOBS_MAX_DEPTH = 3;
|
|
|
152
123
|
export declare const FEEDBACK_JOBS_MAX_FILES = 20;
|
|
153
124
|
/** Ceiling on how many lock entries are collected. */
|
|
154
125
|
export declare const FEEDBACK_LOCKS_MAX_FILES = 20;
|
|
155
|
-
/**
|
|
156
|
-
* Log files that live at the root of `~/.hq` rather than under `logs/`.
|
|
157
|
-
* Listed explicitly — the root directory holds credentials and must never be
|
|
158
|
-
* enumerated by pattern.
|
|
159
|
-
*/
|
|
160
|
-
export declare const FEEDBACK_ROOT_LOG_FILENAMES: readonly string[];
|
|
161
126
|
/** Why a discovered log file contributed nothing to the submission. */
|
|
162
|
-
|
|
163
|
-
|
|
127
|
+
type SkipReason = "budget" | "empty" | "unreadable";
|
|
128
|
+
interface LogTail {
|
|
164
129
|
/** Path relative to `~/.hq`, e.g. `logs/hq-sync.log`. Never absolute. */
|
|
165
130
|
name: string;
|
|
166
131
|
/** Full on-disk size, even when only a tail was included. */
|
|
@@ -177,7 +142,7 @@ export interface LogTail {
|
|
|
177
142
|
tail: string;
|
|
178
143
|
}
|
|
179
144
|
/** A small JSON status document included whole (or head-truncated). */
|
|
180
|
-
|
|
145
|
+
interface StateSnapshot {
|
|
181
146
|
/** Path relative to `~/.hq`, e.g. `sync-progress.json`. Never absolute. */
|
|
182
147
|
name: string;
|
|
183
148
|
sizeBytes: number;
|
|
@@ -331,4 +296,5 @@ export interface CollectFeedbackLogsOptions {
|
|
|
331
296
|
* omit the field entirely rather than attach an empty object. Never throws.
|
|
332
297
|
*/
|
|
333
298
|
export declare function collectFeedbackLogs(opts?: CollectFeedbackLogsOptions): FeedbackLogsBlob | undefined;
|
|
299
|
+
export {};
|
|
334
300
|
//# sourceMappingURL=feedback-logs.d.ts.map
|
|
@@ -89,12 +89,12 @@ export const FEEDBACK_LOGS_MIN_USEFUL_BYTES = 1024;
|
|
|
89
89
|
*/
|
|
90
90
|
export const FEEDBACK_MAX_SKIPPED_ENTRIES = 25;
|
|
91
91
|
/** Subdirectory of `~/.hq` whose log files are eligible. Not recursive. */
|
|
92
|
-
|
|
92
|
+
const FEEDBACK_LOGS_DIRNAME = "logs";
|
|
93
93
|
/**
|
|
94
94
|
* Eligible extensions inside `~/.hq/logs/`. `.jsonl` is included because the
|
|
95
95
|
* CLI's MCP registry audit trail is JSON-lines, not plain text.
|
|
96
96
|
*/
|
|
97
|
-
|
|
97
|
+
const FEEDBACK_LOG_EXTENSIONS = [".log", ".jsonl"];
|
|
98
98
|
/**
|
|
99
99
|
* True for a log filename, including a ROTATED generation.
|
|
100
100
|
*
|
|
@@ -120,7 +120,7 @@ export const FEEDBACK_STATE_MAX_FILE_BYTES = 4 * 1024;
|
|
|
120
120
|
* Ceiling on all state snapshots combined. Deliberately a small slice of the
|
|
121
121
|
* overall budget: state is dense but finite, and the rest belongs to logs.
|
|
122
122
|
*/
|
|
123
|
-
|
|
123
|
+
const FEEDBACK_STATE_MAX_TOTAL_BYTES = 12 * 1024;
|
|
124
124
|
/**
|
|
125
125
|
* State files at the `~/.hq` ROOT that are eligible, by EXACT name.
|
|
126
126
|
*
|
|
@@ -128,7 +128,7 @@ export const FEEDBACK_STATE_MAX_TOTAL_BYTES = 12 * 1024;
|
|
|
128
128
|
* `secrets-cache/` live, so it is never globbed. Adding a name here is a
|
|
129
129
|
* deliberate act: confirm the file carries no credential before listing it.
|
|
130
130
|
*/
|
|
131
|
-
|
|
131
|
+
const FEEDBACK_STATE_FILENAMES = [
|
|
132
132
|
// In-flight sync: phase, file counts, conflict count, current file.
|
|
133
133
|
"sync-progress.json",
|
|
134
134
|
// Sync contract version the installation last wrote.
|
|
@@ -150,7 +150,7 @@ export const FEEDBACK_STATE_FILENAMES = [
|
|
|
150
150
|
* excludes the multi-hundred-megabyte `…json.last-good` snapshots sitting
|
|
151
151
|
* beside them. No credential file at the root carries this prefix.
|
|
152
152
|
*/
|
|
153
|
-
|
|
153
|
+
const FEEDBACK_STATE_JOURNAL_PREFIX = "sync-journal.";
|
|
154
154
|
/**
|
|
155
155
|
* `~/.hq/locks/` — held operation locks and background-work claims.
|
|
156
156
|
*
|
|
@@ -170,7 +170,7 @@ export const FEEDBACK_LOCKS_DIRNAME = "locks";
|
|
|
170
170
|
*/
|
|
171
171
|
export const FEEDBACK_JOBS_DIRNAME = "jobs";
|
|
172
172
|
/** Per-entry ceiling for a lock file. Their value is the name plus a little context. */
|
|
173
|
-
|
|
173
|
+
const FEEDBACK_LOCK_MAX_FILE_BYTES = 512;
|
|
174
174
|
/**
|
|
175
175
|
* Bounds on the `jobs/` walk. Depth 3 reaches
|
|
176
176
|
* `jobs/probes/<job>/last-attempt.json`; the file cap stops a pathological
|
|
@@ -185,7 +185,7 @@ export const FEEDBACK_LOCKS_MAX_FILES = 20;
|
|
|
185
185
|
* Listed explicitly — the root directory holds credentials and must never be
|
|
186
186
|
* enumerated by pattern.
|
|
187
187
|
*/
|
|
188
|
-
|
|
188
|
+
const FEEDBACK_ROOT_LOG_FILENAMES = [
|
|
189
189
|
"boot-sync.log",
|
|
190
190
|
"boot-capture.log",
|
|
191
191
|
];
|