@indigoai-us/hq-cli 5.311.4 → 5.312.1
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 +20 -0
- package/assets/scaffold/core/scripts/lib/work-mesh-live-hook.sh +378 -0
- package/assets/scaffold/core/scripts/lib/work-mesh-live-rebind.sh +141 -0
- package/assets/scaffold/core/scripts/migrate-policy-triggers.sh +373 -0
- package/assets/scaffold/core/scripts/register-project.sh +262 -0
- package/assets/scaffold/core/scripts/work-mesh-live-rebind.sh +59 -0
- package/dist/command-catalog.generated.d.ts +160 -0
- package/dist/command-catalog.generated.js +200 -0
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/company-rename-flag.d.ts +4 -0
- package/dist/commands/company-rename-flag.js +7 -0
- package/dist/commands/company-rename.d.ts +4 -0
- package/dist/commands/company-rename.js +90 -0
- package/dist/commands/company.js +2 -0
- package/dist/commands/core-checkpoint-stop-gate-native.js +12 -0
- package/dist/commands/core-eval-trigger-native.d.ts +4 -0
- package/dist/commands/core-eval-trigger-native.js +12 -0
- package/dist/commands/core-migrate-policy-triggers-native.d.ts +21 -0
- package/dist/commands/core-migrate-policy-triggers-native.js +378 -0
- package/dist/commands/core-native-hook-helper-commands.d.ts +4 -0
- package/dist/commands/core-native-hook-helper-commands.js +56 -0
- package/dist/commands/core-native-hook-helpers-flag.d.ts +4 -0
- package/dist/commands/core-native-hook-helpers-flag.js +7 -0
- package/dist/commands/core-register-project-native.d.ts +30 -0
- package/dist/commands/core-register-project-native.js +347 -0
- package/dist/commands/core-work-mesh-live-rebind-native.d.ts +18 -0
- package/dist/commands/core-work-mesh-live-rebind-native.js +262 -0
- package/dist/commands/core.js +7 -0
- package/dist/commands/daemon.js +22 -0
- package/dist/commands/dm.js +22 -6
- package/dist/commands/files-browse.js +16 -4
- package/dist/commands/lanes-message.js +17 -2
- package/dist/commands/lanes-shared.d.ts +1 -0
- package/dist/commands/lanes.js +96 -20
- package/dist/commands/vault-retention-flag.d.ts +3 -0
- package/dist/commands/vault-retention-flag.js +9 -0
- package/dist/commands/vault-retention.d.ts +11 -0
- package/dist/commands/vault-retention.js +69 -0
- package/dist/fast-core.js +10 -3
- package/dist/fast-scaffold.d.ts +2 -0
- package/dist/fast-scaffold.js +11 -0
- package/dist/lib/agents/model-catalog.d.ts +3 -2
- package/dist/lib/company-skill-wrapper.d.ts +0 -8
- package/dist/lib/core-utils/codex-skill-bridge.d.ts +2 -1
- package/dist/lib/core-utils/sentry-report.js +21 -4
- package/dist/lib/daemon/catalog.d.ts +2 -0
- package/dist/lib/daemon/catalog.js +13 -1
- package/dist/lib/daemon/config.d.ts +2 -0
- package/dist/lib/daemon/config.js +4 -0
- package/dist/lib/daemon/run.d.ts +2 -0
- package/dist/lib/daemon/run.js +5 -0
- package/dist/lib/deploy-api.d.ts +0 -1
- package/dist/lib/deploy-api.js +1 -1
- package/dist/lib/doctor/checks/work-context.js +9 -1
- package/dist/lib/lanes/autopilot.d.ts +38 -1
- package/dist/lib/lanes/autopilot.js +353 -5
- package/dist/lib/lanes/flag-keys.d.ts +9 -1
- package/dist/lib/lanes/flag-keys.js +9 -1
- package/dist/lib/lanes/keep-alive.d.ts +2 -0
- package/dist/lib/lanes/keep-alive.js +2 -0
- package/dist/lib/lanes/reconcile.d.ts +5 -0
- package/dist/lib/lanes/reconcile.js +57 -4
- package/dist/lib/lanes/watcher-main.js +20 -1
- package/dist/lib/lanes/watcher.d.ts +9 -0
- package/dist/lib/lanes/watcher.js +47 -1
- package/dist/lib/mesh/client.js +23 -5
- package/dist/lib/mesh/denial-codes.d.ts +5 -0
- package/dist/lib/mesh/denial-codes.js +14 -0
- package/dist/lib/mesh/live/daemon/doctor.d.ts +2 -0
- package/dist/lib/mesh/live/daemon/doctor.js +11 -1
- package/dist/lib/report-run.d.ts +3 -2
- package/dist/lib/report-templates.d.ts +0 -1
- package/dist/lib/report-templates.js +0 -3
- package/dist/lib/scaffold-cli-floor.d.ts +0 -1
- package/dist/lib/scaffold-cli-floor.js +1 -1
- package/dist/lib/search-index/embed-lock.d.ts +2 -0
- package/dist/lib/search-index/embed-lock.js +10 -1
- package/dist/lib/work-context/contract.d.ts +3 -0
- package/dist/lib/work-context/contract.schema.json +3 -1
- package/dist/lib/work-context/outbox.d.ts +14 -5
- package/dist/lib/work-context/outbox.js +48 -5
- package/dist/lib/work-context/reconcile.js +26 -5
- package/dist/main.d.ts +20 -0
- package/dist/main.js +8 -1
- package/dist/run/discover-schemas.d.ts +2 -1
- package/dist/utils/core-eval-trigger.d.ts +4 -0
- package/dist/utils/core-eval-trigger.js +88 -0
- package/dist/utils/hq-roots.d.ts +0 -2
- package/dist/utils/hq-roots.js +1 -8
- package/dist/utils/incomplete-install-error.d.ts +7 -6
- package/dist/utils/large-file-guard.d.ts +0 -10
- package/dist/utils/large-file-guard.js +1 -1
- package/dist/utils/package-root-diagnostics.d.ts +1 -1
- package/dist/utils/self-update.d.ts +2 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Usage: node watcher-main.js <lane-id>
|
|
6
6
|
* Requires HQ_ROOT in the environment.
|
|
7
7
|
*/
|
|
8
|
-
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
9
9
|
import { existsSync, realpathSync } from "node:fs";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
@@ -32,6 +32,25 @@ export function watcherMainDeps(hqRoot, laneId, env = process.env, repairDispatc
|
|
|
32
32
|
throw new Error(`recovery command exited ${result.status ?? result.signal ?? "without status"}: ${(result.stderr ?? "").trim()}`);
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
|
+
scheduleTerminalKeepAlive: async ({ laneId: scheduledLaneId, version, dueAt }) => {
|
|
36
|
+
await new Promise((resolve, reject) => {
|
|
37
|
+
const child = spawn(process.execPath, [
|
|
38
|
+
cliEntry,
|
|
39
|
+
"lanes",
|
|
40
|
+
"_keep-alive-terminal-trigger",
|
|
41
|
+
scheduledLaneId,
|
|
42
|
+
String(version),
|
|
43
|
+
dueAt,
|
|
44
|
+
], {
|
|
45
|
+
env,
|
|
46
|
+
detached: true,
|
|
47
|
+
stdio: "ignore",
|
|
48
|
+
});
|
|
49
|
+
child.once("error", reject);
|
|
50
|
+
child.once("spawn", resolve);
|
|
51
|
+
child.unref();
|
|
52
|
+
});
|
|
53
|
+
},
|
|
35
54
|
};
|
|
36
55
|
}
|
|
37
56
|
function deliverLaneSeniorMessage(cliEntry, laneId, text) {
|
|
@@ -238,6 +238,15 @@ export interface WatcherLoopDeps {
|
|
|
238
238
|
readKrFreshnessFlag?: typeof readLanesRegistryFlag;
|
|
239
239
|
/** Test seam; production reads the company-scoped hq-flags row. */
|
|
240
240
|
readEnvelopeRepairContinueFlag?: typeof readLanesRegistryFlag;
|
|
241
|
+
/** Test seam; production reads the company-scoped hq-flags row. */
|
|
242
|
+
readTerminalKeepAliveFlag?: typeof readLanesRegistryFlag;
|
|
243
|
+
/** Schedule an immediate reconcile check for the terminal lane version. */
|
|
244
|
+
scheduleTerminalKeepAlive?: (input: {
|
|
245
|
+
laneId: string;
|
|
246
|
+
version: number;
|
|
247
|
+
terminalAt: string;
|
|
248
|
+
dueAt: string;
|
|
249
|
+
}) => Promise<void>;
|
|
241
250
|
}
|
|
242
251
|
/**
|
|
243
252
|
* Wrap one mesh call. A failed emit is logged as `mesh_event_failed` with
|
|
@@ -53,7 +53,7 @@ import { laneCompanyUidSource, resolveLaneCompany } from "./lane-company.js";
|
|
|
53
53
|
import { blockerFreshnessFingerprint, resolveBlockerFreshnessForLane, } from "./blocker-freshness.js";
|
|
54
54
|
import { krFreshnessFingerprint, resolveKrFreshnessForLane, } from "./kr-freshness.js";
|
|
55
55
|
import { managerStatusWasWritten, readStatusSnapshot, resolveManagerStatusTarget, } from "./manager-status-gate.js";
|
|
56
|
-
import { queueLaneTerminalResume, queueManagerStatusGateResume } from "./keep-alive.js";
|
|
56
|
+
import { LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS, LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_TERMINAL_TRIGGER_FLAG, queueLaneTerminalResume, queueManagerStatusGateResume, } from "./keep-alive.js";
|
|
57
57
|
import { LANE_ENVELOPE_REPAIR_CONTINUE_FLAG } from "./flag-keys.js";
|
|
58
58
|
import { monitorSessionDir } from "../monitor.js";
|
|
59
59
|
import { laneRunDir, missingPidProbe, probePidRecord, readPidRecord, readProcStarttime, readSpawnManifest, envelopeRepairMode, spawnEnvelopeRepair, writePidRecord, retryLaneOnAlternateAccount, } from "./spawn.js";
|
|
@@ -1780,6 +1780,52 @@ async function runWatcherLoopOwned(hqRoot, laneId, deps) {
|
|
|
1780
1780
|
});
|
|
1781
1781
|
}
|
|
1782
1782
|
}
|
|
1783
|
+
const terminalEnvelopeNextCheckMs = effectiveEnvelope?.next_check_at === undefined
|
|
1784
|
+
? undefined
|
|
1785
|
+
: Date.parse(effectiveEnvelope.next_check_at);
|
|
1786
|
+
const hasFutureTerminalNextCheck = terminalEnvelopeNextCheckMs !== undefined &&
|
|
1787
|
+
Number.isFinite(terminalEnvelopeNextCheckMs) &&
|
|
1788
|
+
terminalEnvelopeNextCheckMs > Date.parse(tick.emit.at);
|
|
1789
|
+
if (terminalWrite.changed &&
|
|
1790
|
+
updated.keep_alive === true &&
|
|
1791
|
+
effectiveEnvelope?.decision === "done" &&
|
|
1792
|
+
effectiveEnvelope.story_complete === false &&
|
|
1793
|
+
!hasFutureTerminalNextCheck &&
|
|
1794
|
+
updated.state === "done" &&
|
|
1795
|
+
deps.scheduleTerminalKeepAlive) {
|
|
1796
|
+
try {
|
|
1797
|
+
const current = readLane(hqRoot, laneId);
|
|
1798
|
+
if (current.state === "done" && current.version === updated.version && current.keep_alive === true) {
|
|
1799
|
+
const resolution = resolveLaneCompany(hqRoot, current);
|
|
1800
|
+
const company = resolution.company;
|
|
1801
|
+
if (company) {
|
|
1802
|
+
const readFlag = deps.readTerminalKeepAliveFlag ?? readLanesRegistryFlag;
|
|
1803
|
+
const flagOptions = { company, companyUidSource: laneCompanyUidSource(resolution.source) };
|
|
1804
|
+
const [triggerEnabled, keepAliveEnabled, immediateFirstResumeEnabled] = await Promise.all([
|
|
1805
|
+
readFlag(LEAD_LANE_KEEP_ALIVE_TERMINAL_TRIGGER_FLAG, flagOptions),
|
|
1806
|
+
readFlag(LEAD_LANE_KEEP_ALIVE_FLAG, flagOptions),
|
|
1807
|
+
readFlag(LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, flagOptions),
|
|
1808
|
+
]);
|
|
1809
|
+
if (triggerEnabled && keepAliveEnabled && immediateFirstResumeEnabled) {
|
|
1810
|
+
const terminalAtMs = Date.parse(tick.emit.at);
|
|
1811
|
+
const dueAt = new Date(terminalAtMs + LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS).toISOString();
|
|
1812
|
+
logDecision({ event: "keep_alive_terminal_trigger_scheduled", at: tick.emit.at, due_at: dueAt, version: current.version });
|
|
1813
|
+
await deps.scheduleTerminalKeepAlive({
|
|
1814
|
+
laneId,
|
|
1815
|
+
version: current.version,
|
|
1816
|
+
terminalAt: tick.emit.at,
|
|
1817
|
+
dueAt,
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
catch (err) {
|
|
1824
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1825
|
+
process.stderr.write(`hq lanes watcher: terminal keep-alive trigger failed for ${laneId}: ${message}\n`);
|
|
1826
|
+
logDecision({ event: "keep_alive_terminal_trigger_failed", at: tick.emit.at, error: message });
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1783
1829
|
}
|
|
1784
1830
|
}
|
|
1785
1831
|
lastSignalMs = tick.nextLastSignalMs;
|
package/dist/lib/mesh/client.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* vault HTTP + receipt-shaped responses (US-007A / US-007B).
|
|
5
5
|
*/
|
|
6
6
|
import { listActiveMembershipCompanies, meshJson, requireToken, resolveMeshCompany, } from "./api.js";
|
|
7
|
+
import { isWorkSessionDenialCode } from "./denial-codes.js";
|
|
7
8
|
export { meshJson, requireToken, resolveMeshCompany, listActiveMembershipCompanies };
|
|
8
9
|
export async function openMeshTransport(opts) {
|
|
9
10
|
const token = await requireToken();
|
|
@@ -50,11 +51,28 @@ export function createWorkSessionDeliverer(opts) {
|
|
|
50
51
|
const message = err instanceof Error ? err.message : String(err);
|
|
51
52
|
// meshJson throws on !ok with error text; classify by leading status when present.
|
|
52
53
|
const statusMatch = /^(\d{3})\b/.exec(message);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const errorFields = err && typeof err === "object"
|
|
55
|
+
? err
|
|
56
|
+
: {};
|
|
57
|
+
const status = typeof errorFields.status === "number" &&
|
|
58
|
+
Number.isInteger(errorFields.status)
|
|
59
|
+
? errorFields.status
|
|
60
|
+
: statusMatch
|
|
61
|
+
? Number(statusMatch[1])
|
|
62
|
+
: undefined;
|
|
63
|
+
if (status === 401 || status === 403) {
|
|
64
|
+
const serverCode = isWorkSessionDenialCode(errorFields.code)
|
|
65
|
+
? errorFields.code
|
|
66
|
+
: undefined;
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
retryable: false,
|
|
70
|
+
code: "AUTH_DENIED",
|
|
71
|
+
httpStatus: status,
|
|
72
|
+
...(serverCode ? { serverCode } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (status !== undefined) {
|
|
58
76
|
if (status === 400 || status === 422) {
|
|
59
77
|
return { ok: false, retryable: false, code: "VALIDATION_FAILED" };
|
|
60
78
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Explicit 401/403 codes returned by hq-pro's work-session registration path. */
|
|
2
|
+
export declare const WORK_SESSION_DENIAL_CODES: readonly ["AUTH_REQUIRED", "AGENT_IDENTITY_UNVERIFIED", "IMPERSONATION_FORBIDDEN", "NO_PERSON_ENTITY", "INVALID_COMPANY", "WORK_REGISTRY_DISABLED"];
|
|
3
|
+
export type WorkSessionDenialCode = (typeof WORK_SESSION_DENIAL_CODES)[number];
|
|
4
|
+
export declare function isWorkSessionDenialCode(value: unknown): value is WorkSessionDenialCode;
|
|
5
|
+
//# sourceMappingURL=denial-codes.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Explicit 401/403 codes returned by hq-pro's work-session registration path. */
|
|
2
|
+
export const WORK_SESSION_DENIAL_CODES = [
|
|
3
|
+
"AUTH_REQUIRED",
|
|
4
|
+
"AGENT_IDENTITY_UNVERIFIED",
|
|
5
|
+
"IMPERSONATION_FORBIDDEN",
|
|
6
|
+
"NO_PERSON_ENTITY",
|
|
7
|
+
"INVALID_COMPANY",
|
|
8
|
+
"WORK_REGISTRY_DISABLED",
|
|
9
|
+
];
|
|
10
|
+
export function isWorkSessionDenialCode(value) {
|
|
11
|
+
return typeof value === "string" &&
|
|
12
|
+
WORK_SESSION_DENIAL_CODES.includes(value);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=denial-codes.js.map
|
|
@@ -27,6 +27,8 @@ export interface DaemonDoctorReport {
|
|
|
27
27
|
outboxDepth: number;
|
|
28
28
|
outboxQuarantined?: number;
|
|
29
29
|
outboxLastQuarantineReason?: string;
|
|
30
|
+
outboxLastQuarantineHttpStatus?: number;
|
|
31
|
+
outboxLastQuarantineServerCode?: string;
|
|
30
32
|
lastFlushAt?: string;
|
|
31
33
|
lastFlushResult?: DaemonStateFile["lastFlushResult"];
|
|
32
34
|
unhealthy: boolean;
|
|
@@ -263,6 +263,8 @@ export function collectDaemonDoctor(deps = {}) {
|
|
|
263
263
|
? {
|
|
264
264
|
outboxQuarantined: outbox.quarantined,
|
|
265
265
|
outboxLastQuarantineReason: outbox.lastQuarantineReason ?? undefined,
|
|
266
|
+
outboxLastQuarantineHttpStatus: outbox.lastQuarantineHttpStatus ?? undefined,
|
|
267
|
+
outboxLastQuarantineServerCode: outbox.lastQuarantineServerCode ?? undefined,
|
|
266
268
|
}
|
|
267
269
|
: {}),
|
|
268
270
|
lastFlushAt: state?.lastFlushAt,
|
|
@@ -310,7 +312,15 @@ export function formatDaemonDoctor(report) {
|
|
|
310
312
|
lines.push(`spool depth: ${report.spoolDepth}`, `held: ${report.heldCount}${report.heldCount > 0 ? " (needs_company; not sent as NONE)" : ""}`, `held with no local evidence: ${report.heldWithNoLocalEvidence}`, `outbox depth: ${report.outboxDepth}`);
|
|
311
313
|
}
|
|
312
314
|
if (report.outboxQuarantined !== undefined) {
|
|
313
|
-
|
|
315
|
+
const quarantineDetails = [
|
|
316
|
+
report.outboxLastQuarantineHttpStatus !== undefined
|
|
317
|
+
? `HTTP ${report.outboxLastQuarantineHttpStatus}`
|
|
318
|
+
: "",
|
|
319
|
+
report.outboxLastQuarantineServerCode ?? "",
|
|
320
|
+
]
|
|
321
|
+
.filter(Boolean)
|
|
322
|
+
.join(" ");
|
|
323
|
+
lines.push(`outbox quarantined: ${report.outboxQuarantined} (last reason=${report.outboxLastQuarantineReason ?? "unknown"}${quarantineDetails ? `; ${quarantineDetails}` : ""})`);
|
|
314
324
|
}
|
|
315
325
|
if (report.emitMode !== "legacy" && report.heldCount > 0) {
|
|
316
326
|
lines.push(`held: ${report.heldCount} (needs_company; not sent as NONE)`);
|
package/dist/lib/report-run.d.ts
CHANGED
|
@@ -8,12 +8,12 @@ export type DigestSignal = {
|
|
|
8
8
|
kind: string;
|
|
9
9
|
text: string;
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
type FocusItem = {
|
|
12
12
|
title: string;
|
|
13
13
|
project: string;
|
|
14
14
|
reason: string;
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
type ReportRunRecord = {
|
|
17
17
|
generatedAt: string;
|
|
18
18
|
inputs: {
|
|
19
19
|
template: string;
|
|
@@ -58,4 +58,5 @@ export declare function renderDailyDigest(input: {
|
|
|
58
58
|
generatedAt?: string;
|
|
59
59
|
}): DigestPage;
|
|
60
60
|
export declare function writeDigestPage(directory: string, page: DigestPage): void;
|
|
61
|
+
export {};
|
|
61
62
|
//# sourceMappingURL=report-run.d.ts.map
|
|
@@ -3,7 +3,6 @@ export type ReportTemplate = {
|
|
|
3
3
|
path: string;
|
|
4
4
|
body: string;
|
|
5
5
|
};
|
|
6
|
-
export declare function reportPackageRoot(): string;
|
|
7
6
|
export declare function listReportTemplates(root?: string): ReportTemplate[];
|
|
8
7
|
/** Verbatim runbook. Callers substitute `<reportId>` when the id is known. */
|
|
9
8
|
export declare function loadUpdateReportRunbook(root?: string): string;
|
|
@@ -3,9 +3,6 @@ import { readdirSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
6
|
-
export function reportPackageRoot() {
|
|
7
|
-
return PACKAGE_ROOT;
|
|
8
|
-
}
|
|
9
6
|
export function listReportTemplates(root = PACKAGE_ROOT) {
|
|
10
7
|
const dir = path.join(root, "templates", "reports");
|
|
11
8
|
return readdirSync(dir)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import semver from "semver";
|
|
2
|
-
|
|
2
|
+
const SCAFFOLD_CLI_UPGRADE_COMMAND = "npm install -g @indigoai-us/hq-cli@latest";
|
|
3
3
|
const MINIMUM_VERSION_RANGE = /^>=(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
4
4
|
/** Compare an installed CLI version with the scaffold's supported floor. */
|
|
5
5
|
export function compareScaffoldCliFloor(required, currentVersion) {
|
|
@@ -4,6 +4,8 @@ export type EmbedLockDependencies = {
|
|
|
4
4
|
pid: number;
|
|
5
5
|
random: () => string;
|
|
6
6
|
isProcessAlive: (pid: number) => boolean;
|
|
7
|
+
/** Test seam for a contender arriving after mkdir and before owner publication. */
|
|
8
|
+
beforeOwnerPublish?: (ownerFile: string) => void;
|
|
7
9
|
/** Test seam for simulating a competing owner replacing the atomic record. */
|
|
8
10
|
afterOwnerPublish?: (ownerFile: string) => void;
|
|
9
11
|
};
|
|
@@ -184,8 +184,13 @@ function createAndPublishLock(home, dependencies) {
|
|
|
184
184
|
// parity: the script's write_owner_record honored the same variable.
|
|
185
185
|
if (dependencies.env.QMD_FORCE_OWNER_WRITE_FAIL)
|
|
186
186
|
throw new Error('forced owner write failure');
|
|
187
|
+
dependencies.beforeOwnerPublish?.(ownerFile);
|
|
187
188
|
fs.writeFileSync(temporary, `pid=${dependencies.pid}\nts=${dependencies.now()}\nnonce=${nonce}\n`);
|
|
188
|
-
|
|
189
|
+
// renameSync replaces an existing owner on POSIX. A stale reclaim can
|
|
190
|
+
// replace this ownerless directory while this publisher is paused, so
|
|
191
|
+
// publish only if this exact generation still has no owner.
|
|
192
|
+
fs.linkSync(temporary, ownerFile);
|
|
193
|
+
fs.unlinkSync(temporary);
|
|
189
194
|
dependencies.afterOwnerPublish?.(ownerFile);
|
|
190
195
|
const verified = readOwner(directory);
|
|
191
196
|
if (!verified || verified.pid !== dependencies.pid || verified.nonce !== nonce)
|
|
@@ -196,6 +201,10 @@ function createAndPublishLock(home, dependencies) {
|
|
|
196
201
|
catch {
|
|
197
202
|
// The marker identifies only the directory this process created. Do not
|
|
198
203
|
// recursively remove the fixed lock path after a failed publication.
|
|
204
|
+
try {
|
|
205
|
+
fs.unlinkSync(temporary);
|
|
206
|
+
}
|
|
207
|
+
catch { /* absent after link or moved with a stale generation */ }
|
|
199
208
|
fs.rmSync(marker, { recursive: true, force: true });
|
|
200
209
|
removeDirectoryIfEmpty(directory);
|
|
201
210
|
return false;
|
|
@@ -61,6 +61,9 @@ export interface ContextResult {
|
|
|
61
61
|
bindingEpisodeId?: string;
|
|
62
62
|
clientOperationId: string;
|
|
63
63
|
errorCode?: string;
|
|
64
|
+
/** Sanitized HTTP denial details; raw response bodies are never included. */
|
|
65
|
+
httpStatus?: number;
|
|
66
|
+
serverCode?: string;
|
|
64
67
|
/** Why a project was chosen, or why the session is asking. Local consumers only. */
|
|
65
68
|
projectBindReason?: string;
|
|
66
69
|
/** Ranked alternatives when classification is needs_project. */
|
|
@@ -100,7 +100,9 @@
|
|
|
100
100
|
"taskId": { "type": "string", "maxLength": 128 },
|
|
101
101
|
"bindingEpisodeId": { "type": "string", "maxLength": 128 },
|
|
102
102
|
"clientOperationId": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
103
|
-
"errorCode": { "type": "string", "maxLength": 64 }
|
|
103
|
+
"errorCode": { "type": "string", "maxLength": 64 },
|
|
104
|
+
"httpStatus": { "type": "number" },
|
|
105
|
+
"serverCode": { "type": "string", "maxLength": 64 }
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { DeliveryState } from "./contract.js";
|
|
6
6
|
import { WORK_CONTEXT_CONTRACT_VERSION } from "./contract.js";
|
|
7
7
|
/** Fields allowed on a durable outbox operation (privacy allowlist). */
|
|
8
|
-
export declare const OUTBOX_ALLOWLIST: readonly ["contractVersion", "operationId", "clientOperationId", "sessionId", "harness", "companyUid", "companySlug", "projectId", "taskId", "companyConfidence", "kind", "digest", "delivery", "createdAt", "updatedAt", "attemptCount", "lastErrorCode", "receiptId", "destinationCompanyUid", "destinationCompanySlug", "nextAttemptAt"];
|
|
8
|
+
export declare const OUTBOX_ALLOWLIST: readonly ["contractVersion", "operationId", "clientOperationId", "sessionId", "harness", "companyUid", "companySlug", "projectId", "taskId", "companyConfidence", "kind", "digest", "delivery", "createdAt", "updatedAt", "attemptCount", "lastErrorCode", "lastErrorHttpStatus", "lastServerErrorCode", "receiptId", "destinationCompanyUid", "destinationCompanySlug", "nextAttemptAt"];
|
|
9
9
|
/** Base delay for outbox retry backoff (attempt 1 → 30s). */
|
|
10
10
|
export declare const OUTBOX_RETRY_BASE_MS = 30000;
|
|
11
11
|
/** Cap for outbox retry backoff (6 hours). */
|
|
@@ -34,6 +34,8 @@ export interface OutboxOperation {
|
|
|
34
34
|
updatedAt: string;
|
|
35
35
|
attemptCount: number;
|
|
36
36
|
lastErrorCode?: string;
|
|
37
|
+
lastErrorHttpStatus?: number;
|
|
38
|
+
lastServerErrorCode?: string;
|
|
37
39
|
receiptId?: string;
|
|
38
40
|
/** Destination company for kind=migrate (source is companyUid). */
|
|
39
41
|
destinationCompanyUid?: string;
|
|
@@ -88,8 +90,13 @@ export declare function markOutboxAcked(operationId: string, root: string, recei
|
|
|
88
90
|
export declare function writeAckedRegisterState(op: OutboxOperation, root: string, receiptId: string, now?: () => Date): void;
|
|
89
91
|
/** Repair older unresolved session projections from acknowledged registrations. */
|
|
90
92
|
export declare function repairAckedRegisterStates(root: string, sessionIds?: ReadonlySet<string>, now?: () => Date): number;
|
|
91
|
-
export declare function markOutboxQueued(operationId: string, root: string, errorCode: string, now?: () => Date, random?: () => number): OutboxOperation | null;
|
|
92
|
-
export declare function markOutboxQuarantined(operationId: string, root: string, errorCode: string, now?: () => Date): OutboxOperation | null;
|
|
93
|
+
export declare function markOutboxQueued(operationId: string, root: string, errorCode: string, now?: () => Date, random?: () => number, details?: OutboxErrorDetails): OutboxOperation | null;
|
|
94
|
+
export declare function markOutboxQuarantined(operationId: string, root: string, errorCode: string, now?: () => Date, details?: OutboxErrorDetails): OutboxOperation | null;
|
|
95
|
+
export interface OutboxErrorDetails {
|
|
96
|
+
httpStatus?: number;
|
|
97
|
+
serverCode?: string;
|
|
98
|
+
}
|
|
99
|
+
export declare function sanitizeOutboxErrorDetails(details?: OutboxErrorDetails): OutboxErrorDetails;
|
|
93
100
|
/**
|
|
94
101
|
* Requeue quarantined outbox operations so the daemon's replay picks them up
|
|
95
102
|
* again. Quarantine is otherwise terminal: after the work-mesh-live gap 10 fix
|
|
@@ -119,16 +126,18 @@ export interface OutboxStats {
|
|
|
119
126
|
queued: number;
|
|
120
127
|
acked: number;
|
|
121
128
|
lastQuarantineReason: string | null;
|
|
129
|
+
lastQuarantineHttpStatus: number | null;
|
|
130
|
+
lastQuarantineServerCode: string | null;
|
|
122
131
|
}
|
|
123
132
|
export declare function outboxStats(root: string): OutboxStats;
|
|
124
133
|
export type DeliverFn = (op: OutboxOperation) => Promise<{
|
|
125
134
|
ok: true;
|
|
126
135
|
receiptId: string;
|
|
127
|
-
} | {
|
|
136
|
+
} | ({
|
|
128
137
|
ok: false;
|
|
129
138
|
retryable: boolean;
|
|
130
139
|
code: string;
|
|
131
|
-
}>;
|
|
140
|
+
} & OutboxErrorDetails)>;
|
|
132
141
|
/**
|
|
133
142
|
* Replay queued (and recover lost-receipt) operations.
|
|
134
143
|
* FIFO per sessionId; bounded parallelism across sessions.
|
|
@@ -8,6 +8,7 @@ import * as path from "node:path";
|
|
|
8
8
|
import { WORK_CONTEXT_CONTRACT_VERSION } from "./contract.js";
|
|
9
9
|
import { atomicWriteJson, ensureOwnerDir } from "./atomic.js";
|
|
10
10
|
import { NotTrackingError } from "./errors.js";
|
|
11
|
+
import { isWorkSessionDenialCode } from "../mesh/denial-codes.js";
|
|
11
12
|
import { readSessionState, stripRegisterReceiptEpisodes, updateSessionState, writeAcknowledgedRegisterBinding, } from "./state.js";
|
|
12
13
|
import { isSafeWorkContextSegment, workContextOutboxDir, workContextOutboxPath, } from "./paths.js";
|
|
13
14
|
/** Fields allowed on a durable outbox operation (privacy allowlist). */
|
|
@@ -29,6 +30,8 @@ export const OUTBOX_ALLOWLIST = [
|
|
|
29
30
|
"updatedAt",
|
|
30
31
|
"attemptCount",
|
|
31
32
|
"lastErrorCode",
|
|
33
|
+
"lastErrorHttpStatus",
|
|
34
|
+
"lastServerErrorCode",
|
|
32
35
|
"receiptId",
|
|
33
36
|
"destinationCompanyUid",
|
|
34
37
|
"destinationCompanySlug",
|
|
@@ -101,6 +104,11 @@ function projectOutbox(op) {
|
|
|
101
104
|
out.companyConfidence = op.companyConfidence;
|
|
102
105
|
if (op.lastErrorCode)
|
|
103
106
|
out.lastErrorCode = op.lastErrorCode;
|
|
107
|
+
if (op.lastErrorHttpStatus !== undefined) {
|
|
108
|
+
out.lastErrorHttpStatus = op.lastErrorHttpStatus;
|
|
109
|
+
}
|
|
110
|
+
if (op.lastServerErrorCode)
|
|
111
|
+
out.lastServerErrorCode = op.lastServerErrorCode;
|
|
104
112
|
if (op.receiptId)
|
|
105
113
|
out.receiptId = op.receiptId;
|
|
106
114
|
if (op.destinationCompanyUid) {
|
|
@@ -337,12 +345,13 @@ export function repairAckedRegisterStates(root, sessionIds, now = () => new Date
|
|
|
337
345
|
}
|
|
338
346
|
return repaired;
|
|
339
347
|
}
|
|
340
|
-
export function markOutboxQueued(operationId, root, errorCode, now = () => new Date(), random = Math.random) {
|
|
348
|
+
export function markOutboxQueued(operationId, root, errorCode, now = () => new Date(), random = Math.random, details) {
|
|
341
349
|
const op = readOutboxOperation(operationId, root);
|
|
342
350
|
if (!op)
|
|
343
351
|
return null;
|
|
344
352
|
op.delivery = "queued";
|
|
345
353
|
op.lastErrorCode = errorCode;
|
|
354
|
+
applyOutboxErrorDetails(op, details);
|
|
346
355
|
op.attemptCount += 1;
|
|
347
356
|
const at = now();
|
|
348
357
|
op.updatedAt = at.toISOString();
|
|
@@ -351,17 +360,40 @@ export function markOutboxQueued(operationId, root, errorCode, now = () => new D
|
|
|
351
360
|
updateOutboxOperation(op, root);
|
|
352
361
|
return op;
|
|
353
362
|
}
|
|
354
|
-
export function markOutboxQuarantined(operationId, root, errorCode, now = () => new Date()) {
|
|
363
|
+
export function markOutboxQuarantined(operationId, root, errorCode, now = () => new Date(), details) {
|
|
355
364
|
const op = readOutboxOperation(operationId, root);
|
|
356
365
|
if (!op)
|
|
357
366
|
return null;
|
|
358
367
|
op.delivery = "quarantined";
|
|
359
368
|
op.lastErrorCode = errorCode;
|
|
369
|
+
applyOutboxErrorDetails(op, details);
|
|
360
370
|
op.attemptCount += 1;
|
|
361
371
|
op.updatedAt = now().toISOString();
|
|
362
372
|
updateOutboxOperation(op, root);
|
|
363
373
|
return op;
|
|
364
374
|
}
|
|
375
|
+
function applyOutboxErrorDetails(op, details) {
|
|
376
|
+
delete op.lastErrorHttpStatus;
|
|
377
|
+
delete op.lastServerErrorCode;
|
|
378
|
+
const safe = sanitizeOutboxErrorDetails(details);
|
|
379
|
+
if (safe.httpStatus !== undefined)
|
|
380
|
+
op.lastErrorHttpStatus = safe.httpStatus;
|
|
381
|
+
if (safe.serverCode !== undefined)
|
|
382
|
+
op.lastServerErrorCode = safe.serverCode;
|
|
383
|
+
}
|
|
384
|
+
export function sanitizeOutboxErrorDetails(details) {
|
|
385
|
+
const safe = {};
|
|
386
|
+
if (details?.httpStatus !== undefined &&
|
|
387
|
+
Number.isInteger(details.httpStatus) &&
|
|
388
|
+
details.httpStatus >= 100 &&
|
|
389
|
+
details.httpStatus <= 599) {
|
|
390
|
+
safe.httpStatus = details.httpStatus;
|
|
391
|
+
}
|
|
392
|
+
if (isWorkSessionDenialCode(details?.serverCode)) {
|
|
393
|
+
safe.serverCode = details.serverCode;
|
|
394
|
+
}
|
|
395
|
+
return safe;
|
|
396
|
+
}
|
|
365
397
|
/**
|
|
366
398
|
* Requeue quarantined outbox operations so the daemon's replay picks them up
|
|
367
399
|
* again. Quarantine is otherwise terminal: after the work-mesh-live gap 10 fix
|
|
@@ -389,6 +421,8 @@ export function requeueQuarantinedOutbox(root, opts = {}) {
|
|
|
389
421
|
op.delivery = "queued";
|
|
390
422
|
op.attemptCount = 0;
|
|
391
423
|
op.lastErrorCode = undefined;
|
|
424
|
+
op.lastErrorHttpStatus = undefined;
|
|
425
|
+
op.lastServerErrorCode = undefined;
|
|
392
426
|
op.nextAttemptAt = undefined;
|
|
393
427
|
op.updatedAt = now().toISOString();
|
|
394
428
|
updateOutboxOperation(op, root);
|
|
@@ -469,6 +503,15 @@ export function outboxStats(root) {
|
|
|
469
503
|
queued: ops.filter((o) => o.delivery === "queued").length,
|
|
470
504
|
acked: ops.filter((o) => o.delivery === "acked").length,
|
|
471
505
|
lastQuarantineReason: latestQuarantine?.lastErrorCode ?? null,
|
|
506
|
+
lastQuarantineHttpStatus: latestQuarantine &&
|
|
507
|
+
Number.isInteger(latestQuarantine.lastErrorHttpStatus) &&
|
|
508
|
+
latestQuarantine.lastErrorHttpStatus >= 100 &&
|
|
509
|
+
latestQuarantine.lastErrorHttpStatus <= 599
|
|
510
|
+
? latestQuarantine.lastErrorHttpStatus
|
|
511
|
+
: null,
|
|
512
|
+
lastQuarantineServerCode: isWorkSessionDenialCode(latestQuarantine?.lastServerErrorCode)
|
|
513
|
+
? latestQuarantine.lastServerErrorCode
|
|
514
|
+
: null,
|
|
472
515
|
};
|
|
473
516
|
}
|
|
474
517
|
function isOutboxDue(op, nowIso) {
|
|
@@ -551,18 +594,18 @@ export async function replayOutbox(root, deliver, opts = {}) {
|
|
|
551
594
|
}
|
|
552
595
|
else if (result.retryable) {
|
|
553
596
|
if (op.attemptCount + 1 >= OUTBOX_MAX_ATTEMPTS) {
|
|
554
|
-
markOutboxQuarantined(op.operationId, root, `${result.code}_MAX_ATTEMPTS`, now);
|
|
597
|
+
markOutboxQuarantined(op.operationId, root, `${result.code}_MAX_ATTEMPTS`, now, result);
|
|
555
598
|
quarantined += 1;
|
|
556
599
|
}
|
|
557
600
|
else {
|
|
558
|
-
markOutboxQueued(op.operationId, root, result.code, now, random);
|
|
601
|
+
markOutboxQueued(op.operationId, root, result.code, now, random, result);
|
|
559
602
|
queued += 1;
|
|
560
603
|
}
|
|
561
604
|
// Stop this session's FIFO on transient failure.
|
|
562
605
|
break;
|
|
563
606
|
}
|
|
564
607
|
else {
|
|
565
|
-
markOutboxQuarantined(op.operationId, root, result.code, now);
|
|
608
|
+
markOutboxQuarantined(op.operationId, root, result.code, now, result);
|
|
566
609
|
quarantined += 1;
|
|
567
610
|
break;
|
|
568
611
|
}
|
|
@@ -14,7 +14,7 @@ import { refineProjectBinding } from "./bind-best.js";
|
|
|
14
14
|
import { rebindNeedsProjectOnPrompt } from "./prompt-rebind.js";
|
|
15
15
|
import { resolveProjectTask, shouldAskAfter } from "./project.js";
|
|
16
16
|
import { deriveRemoteOwnerSlug, deriveRepoIdentityKey } from "./repo-remote.js";
|
|
17
|
-
import { enqueueOutbox, listOutboxOperations, markOutboxAcked, markOutboxQuarantined, markOutboxQueued, replayOutbox, writeAckedRegisterState, } from "./outbox.js";
|
|
17
|
+
import { enqueueOutbox, listOutboxOperations, markOutboxAcked, markOutboxQuarantined, markOutboxQueued, replayOutbox, sanitizeOutboxErrorDetails, writeAckedRegisterState, } from "./outbox.js";
|
|
18
18
|
import { mergeLocalSessionFields, isRegisterReceiptEpisodeId, readSessionState, stripRegisterReceiptEpisodes, writeSessionState, } from "./state.js";
|
|
19
19
|
function resultOf(parts) {
|
|
20
20
|
const out = {
|
|
@@ -38,6 +38,10 @@ function resultOf(parts) {
|
|
|
38
38
|
out.bindingEpisodeId = parts.bindingEpisodeId;
|
|
39
39
|
if (parts.errorCode)
|
|
40
40
|
out.errorCode = parts.errorCode;
|
|
41
|
+
if (parts.httpStatus !== undefined)
|
|
42
|
+
out.httpStatus = parts.httpStatus;
|
|
43
|
+
if (parts.serverCode)
|
|
44
|
+
out.serverCode = parts.serverCode;
|
|
41
45
|
if (parts.projectBindReason)
|
|
42
46
|
out.projectBindReason = parts.projectBindReason;
|
|
43
47
|
if (parts.projectCandidates)
|
|
@@ -974,7 +978,8 @@ export async function reconcileObservation(obs, deps) {
|
|
|
974
978
|
};
|
|
975
979
|
}
|
|
976
980
|
if (delivered.retryable) {
|
|
977
|
-
|
|
981
|
+
const details = sanitizeOutboxErrorDetails(delivered);
|
|
982
|
+
markOutboxQueued(outboxOp.operationId, deps.root, delivered.code, nowFn, undefined, details);
|
|
978
983
|
return {
|
|
979
984
|
result: resultOf({
|
|
980
985
|
kind: "queued",
|
|
@@ -986,15 +991,20 @@ export async function reconcileObservation(obs, deps) {
|
|
|
986
991
|
projectId,
|
|
987
992
|
taskId,
|
|
988
993
|
errorCode: delivered.code,
|
|
994
|
+
...details,
|
|
989
995
|
...bindResultFields,
|
|
990
996
|
}),
|
|
991
997
|
exitCode: EXIT_OK,
|
|
992
|
-
diagnostics: [
|
|
998
|
+
diagnostics: [
|
|
999
|
+
...diagnostics,
|
|
1000
|
+
`transient ${delivered.code}${formatDeliveryDetails(details)}; remains queued`,
|
|
1001
|
+
],
|
|
993
1002
|
statePath,
|
|
994
1003
|
outboxOperationId: outboxOp.operationId,
|
|
995
1004
|
};
|
|
996
1005
|
}
|
|
997
|
-
|
|
1006
|
+
const details = sanitizeOutboxErrorDetails(delivered);
|
|
1007
|
+
markOutboxQuarantined(outboxOp.operationId, deps.root, delivered.code, nowFn, details);
|
|
998
1008
|
return {
|
|
999
1009
|
result: resultOf({
|
|
1000
1010
|
kind: "error",
|
|
@@ -1007,13 +1017,24 @@ export async function reconcileObservation(obs, deps) {
|
|
|
1007
1017
|
projectId,
|
|
1008
1018
|
taskId,
|
|
1009
1019
|
errorCode: delivered.code,
|
|
1020
|
+
...details,
|
|
1010
1021
|
...bindResultFields,
|
|
1011
1022
|
}),
|
|
1012
1023
|
exitCode: EXIT_OK,
|
|
1013
|
-
diagnostics: [
|
|
1024
|
+
diagnostics: [
|
|
1025
|
+
...diagnostics,
|
|
1026
|
+
`quarantined: ${delivered.code}${formatDeliveryDetails(details)}`,
|
|
1027
|
+
],
|
|
1014
1028
|
statePath,
|
|
1015
1029
|
outboxOperationId: outboxOp.operationId,
|
|
1016
1030
|
};
|
|
1017
1031
|
}
|
|
1032
|
+
function formatDeliveryDetails(details) {
|
|
1033
|
+
const parts = [
|
|
1034
|
+
details.httpStatus !== undefined ? `HTTP ${details.httpStatus}` : "",
|
|
1035
|
+
details.serverCode ?? "",
|
|
1036
|
+
].filter(Boolean);
|
|
1037
|
+
return parts.length ? ` (${parts.join(" ")})` : "";
|
|
1038
|
+
}
|
|
1018
1039
|
export { replayOutbox };
|
|
1019
1040
|
//# sourceMappingURL=reconcile.js.map
|
package/dist/main.d.ts
CHANGED
|
@@ -12,6 +12,25 @@ import { upgradeToTeam } from "./utils/team-upgrade.js";
|
|
|
12
12
|
* finalization; command execution itself does not consume this allowance.
|
|
13
13
|
*/
|
|
14
14
|
export declare const FOREGROUND_NETWORK_BUDGET_MS = 1500;
|
|
15
|
+
/**
|
|
16
|
+
* Shared accounting for awaited foreground network work. Each lifecycle phase
|
|
17
|
+
* debits only the bounded await it performs; ordinary command runtime leaves
|
|
18
|
+
* the allowance untouched. Earlier phases reserve the finalization floor, so
|
|
19
|
+
* error flushing cannot disappear after a long command.
|
|
20
|
+
*/
|
|
21
|
+
declare class ForegroundNetworkBudget {
|
|
22
|
+
private readonly budgetMs;
|
|
23
|
+
private readonly now;
|
|
24
|
+
private consumedMs;
|
|
25
|
+
constructor(budgetMs?: number, now?: () => number);
|
|
26
|
+
timeoutFor(phaseMaximumMs: number, reservedMs?: number): number;
|
|
27
|
+
waitFor<T>(phaseMaximumMs: number, reservedMs: number, work: (timeoutMs: number) => Promise<T>): Promise<T | undefined>;
|
|
28
|
+
}
|
|
29
|
+
/** Create a shared invocation budget; exported so the time accounting is directly testable. */
|
|
30
|
+
export declare function createForegroundNetworkBudget(options?: {
|
|
31
|
+
budgetMs?: number;
|
|
32
|
+
now?: () => number;
|
|
33
|
+
}): ForegroundNetworkBudget;
|
|
15
34
|
export type StreamErrorDependencies = {
|
|
16
35
|
stderr: Pick<typeof process.stderr, "write">;
|
|
17
36
|
exit: (code: number) => void;
|
|
@@ -30,4 +49,5 @@ export type TopLevelErrorDependencies = {
|
|
|
30
49
|
};
|
|
31
50
|
/** Classify a top-level failure without making the CLI process boundary opaque to tests. */
|
|
32
51
|
export declare function handleTopLevelError(err: unknown, deps?: TopLevelErrorDependencies): Promise<void>;
|
|
52
|
+
export {};
|
|
33
53
|
//# sourceMappingURL=main.d.ts.map
|