@indigoai-us/hq-cli 5.167.0 → 5.168.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 +21 -0
- package/dist/command-catalog.generated.d.ts +88 -1
- package/dist/command-catalog.generated.js +112 -1
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +79 -22
- package/dist/commands/lanes.js +2 -0
- package/dist/commands/mesh.js +13 -19
- package/dist/commands/outpost-pruner.d.ts +3 -0
- package/dist/commands/outpost-pruner.js +125 -0
- package/dist/lib/daemon/catalog.d.ts +11 -1
- package/dist/lib/daemon/catalog.js +31 -6
- package/dist/lib/daemon/install.d.ts +7 -0
- package/dist/lib/daemon/install.js +18 -2
- package/dist/lib/daemon/legacy.js +6 -1
- package/dist/lib/daemon/machine-type.d.ts +4 -1
- package/dist/lib/daemon/machine-type.js +29 -9
- package/dist/lib/daemon/migrate.js +2 -2
- package/dist/lib/daemon/remote-control.d.ts +32 -9
- package/dist/lib/daemon/remote-control.js +55 -11
- package/dist/lib/daemon/run.d.ts +6 -0
- package/dist/lib/daemon/run.js +43 -2
- package/dist/lib/daemon/tools.d.ts +52 -0
- package/dist/lib/daemon/tools.js +95 -0
- package/dist/lib/daemon/updater.d.ts +23 -15
- package/dist/lib/daemon/updater.js +97 -60
- package/dist/lib/lanes/outpost-pruner-install.d.ts +37 -0
- package/dist/lib/lanes/outpost-pruner-install.js +226 -0
- package/dist/lib/lanes/outpost-worktree-pruner-flag.d.ts +19 -0
- package/dist/lib/lanes/outpost-worktree-pruner-flag.js +76 -0
- package/dist/lib/lanes/outpost-worktree-pruner.d.ts +60 -0
- package/dist/lib/lanes/outpost-worktree-pruner.js +1135 -0
- package/dist/lib/mesh/live/session-events-client.js +3 -2
- package/dist/lib/mesh/project-board.d.ts +7 -0
- package/dist/lib/mesh/project-board.js +29 -1
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { resolveHqBinary, resolveNodeBinary } from "../mesh/live/daemon/install.js";
|
|
5
|
+
import { SYSTEMD_PATH_ENV } from "../service-manager/systemd.js";
|
|
6
|
+
export const OUTPOST_PRUNER_PRESSURE_SERVICE = "hq-outpost-worktree-pruner-pressure.service";
|
|
7
|
+
export const OUTPOST_PRUNER_PRESSURE_TIMER = "hq-outpost-worktree-pruner-pressure.timer";
|
|
8
|
+
export const OUTPOST_PRUNER_DAILY_SERVICE = "hq-outpost-worktree-pruner-daily.service";
|
|
9
|
+
export const OUTPOST_PRUNER_DAILY_TIMER = "hq-outpost-worktree-pruner-daily.timer";
|
|
10
|
+
export const OUTPOST_PRUNER_MIN_AGE_DAYS = 14;
|
|
11
|
+
function shellQuote(value) {
|
|
12
|
+
return /^[A-Za-z0-9_./:-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
13
|
+
}
|
|
14
|
+
function systemdEnvironment(name, value) {
|
|
15
|
+
if (/[\r\n\0]/.test(value))
|
|
16
|
+
throw new TypeError(`${name} contains a line break or NUL`);
|
|
17
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/%/g, "%%");
|
|
18
|
+
return `Environment="${name}=${escaped}"`;
|
|
19
|
+
}
|
|
20
|
+
function writeIfChanged(filePath, contents) {
|
|
21
|
+
try {
|
|
22
|
+
if (fs.readFileSync(filePath, "utf8") === contents)
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const code = err.code;
|
|
27
|
+
if (code !== "ENOENT")
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
31
|
+
const temporary = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
32
|
+
try {
|
|
33
|
+
fs.writeFileSync(temporary, contents, { encoding: "utf8", mode: 0o644 });
|
|
34
|
+
fs.renameSync(temporary, filePath);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
try {
|
|
38
|
+
fs.unlinkSync(temporary);
|
|
39
|
+
}
|
|
40
|
+
catch (unlinkError) {
|
|
41
|
+
if (unlinkError.code !== "ENOENT") {
|
|
42
|
+
process.stderr.write(`outpost pruner install: temporary unit cleanup failed (${unlinkError.code ?? "Error"})\n`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
function unlinkIfExists(filePath) {
|
|
50
|
+
try {
|
|
51
|
+
fs.unlinkSync(filePath);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const code = err.code;
|
|
56
|
+
if (code === "ENOENT")
|
|
57
|
+
return false;
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function runSystemctl(args, run) {
|
|
62
|
+
const result = run("systemctl", args);
|
|
63
|
+
if (result.status !== 0)
|
|
64
|
+
throw new Error(`systemctl ${args.join(" ")} failed (${result.status})`);
|
|
65
|
+
}
|
|
66
|
+
function pnpmBinaryDirs() {
|
|
67
|
+
const resolved = [];
|
|
68
|
+
for (const directory of (process.env.PATH ?? "").split(path.delimiter).filter(Boolean)) {
|
|
69
|
+
const binary = path.join(directory, "pnpm");
|
|
70
|
+
try {
|
|
71
|
+
fs.accessSync(binary, fs.constants.X_OK);
|
|
72
|
+
for (const candidate of [path.resolve(directory), path.dirname(fs.realpathSync(binary))]) {
|
|
73
|
+
if (!resolved.includes(candidate))
|
|
74
|
+
resolved.push(candidate);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Keep looking. The full interactive-shell PATH is not copied into units.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return resolved;
|
|
83
|
+
}
|
|
84
|
+
function unitPathEnv(hqBinary, nodeBinary) {
|
|
85
|
+
const dirs = [
|
|
86
|
+
...pnpmBinaryDirs(),
|
|
87
|
+
path.dirname(path.resolve(hqBinary)),
|
|
88
|
+
path.dirname(path.resolve(nodeBinary)),
|
|
89
|
+
...SYSTEMD_PATH_ENV.split(":"),
|
|
90
|
+
];
|
|
91
|
+
return [...new Set(dirs)].filter(Boolean).join(":");
|
|
92
|
+
}
|
|
93
|
+
function renderService(opts) {
|
|
94
|
+
const command = [
|
|
95
|
+
opts.nodeBinary,
|
|
96
|
+
opts.hqBinary,
|
|
97
|
+
"lanes",
|
|
98
|
+
"outpost-pruner",
|
|
99
|
+
"run",
|
|
100
|
+
"--trigger",
|
|
101
|
+
opts.trigger,
|
|
102
|
+
"--min-age-days",
|
|
103
|
+
String(OUTPOST_PRUNER_MIN_AGE_DAYS),
|
|
104
|
+
].map(shellQuote).join(" ");
|
|
105
|
+
return `[Unit]
|
|
106
|
+
Description=HQ outpost worktree pruning (${opts.trigger})
|
|
107
|
+
After=network-online.target
|
|
108
|
+
Wants=network-online.target
|
|
109
|
+
|
|
110
|
+
[Service]
|
|
111
|
+
Type=oneshot
|
|
112
|
+
ExecStart=${command}
|
|
113
|
+
WorkingDirectory=${shellQuote(opts.hqRoot)}
|
|
114
|
+
Nice=10
|
|
115
|
+
Environment=HOME=${shellQuote(opts.home)}
|
|
116
|
+
Environment=PATH=${shellQuote(opts.pathEnv)}
|
|
117
|
+
Environment=HQ_ROOT=${shellQuote(opts.hqRoot)}
|
|
118
|
+
Environment=HQ_NO_UPDATE_CHECK=1
|
|
119
|
+
${opts.flagEnvironment}
|
|
120
|
+
KillMode=process
|
|
121
|
+
|
|
122
|
+
[Install]
|
|
123
|
+
WantedBy=default.target
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
export function renderOutpostPrunerPressureTimer() {
|
|
127
|
+
return `[Unit]
|
|
128
|
+
Description=Check HQ outpost disk pressure for safe worktree cleanup
|
|
129
|
+
|
|
130
|
+
[Timer]
|
|
131
|
+
OnBootSec=2min
|
|
132
|
+
OnUnitActiveSec=5min
|
|
133
|
+
AccuracySec=30s
|
|
134
|
+
Persistent=true
|
|
135
|
+
Unit=${OUTPOST_PRUNER_PRESSURE_SERVICE}
|
|
136
|
+
|
|
137
|
+
[Install]
|
|
138
|
+
WantedBy=timers.target
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
export function renderOutpostPrunerDailyTimer() {
|
|
142
|
+
return `[Unit]
|
|
143
|
+
Description=Daily HQ outpost safe worktree cleanup
|
|
144
|
+
|
|
145
|
+
[Timer]
|
|
146
|
+
OnCalendar=*-*-* 03:10:00
|
|
147
|
+
RandomizedDelaySec=10min
|
|
148
|
+
AccuracySec=1min
|
|
149
|
+
Persistent=true
|
|
150
|
+
Unit=${OUTPOST_PRUNER_DAILY_SERVICE}
|
|
151
|
+
|
|
152
|
+
[Install]
|
|
153
|
+
WantedBy=timers.target
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
export function defaultOutpostPrunerSystemdDir(home = os.homedir()) {
|
|
157
|
+
return path.join(home, ".config", "systemd", "user");
|
|
158
|
+
}
|
|
159
|
+
export function installOutpostPrunerTimers(options) {
|
|
160
|
+
const nodeBinary = options.nodeBinary ?? resolveNodeBinary();
|
|
161
|
+
const hqBinary = options.hqBinary ?? resolveHqBinary();
|
|
162
|
+
const home = options.home ?? os.homedir();
|
|
163
|
+
const flagApiUrl = (options.flagApiUrl ?? process.env.HQ_FLAGS_API_URL ?? "").trim();
|
|
164
|
+
const companyUid = (options.companyUid ?? process.env.HQ_COMPANY_UID ?? "").trim();
|
|
165
|
+
if (!flagApiUrl || !companyUid) {
|
|
166
|
+
throw new TypeError("install requires HQ_FLAGS_API_URL and HQ_COMPANY_UID for the timer services");
|
|
167
|
+
}
|
|
168
|
+
const flagEnvironment = [
|
|
169
|
+
systemdEnvironment("HQ_FLAGS_API_URL", flagApiUrl),
|
|
170
|
+
systemdEnvironment("HQ_COMPANY_UID", companyUid),
|
|
171
|
+
].join("\n");
|
|
172
|
+
const pathEnv = unitPathEnv(hqBinary, nodeBinary);
|
|
173
|
+
const units = [
|
|
174
|
+
[OUTPOST_PRUNER_PRESSURE_SERVICE, renderService({ trigger: "pressure", nodeBinary, hqBinary, hqRoot: options.hqRoot, home, pathEnv, flagEnvironment })],
|
|
175
|
+
[OUTPOST_PRUNER_PRESSURE_TIMER, renderOutpostPrunerPressureTimer()],
|
|
176
|
+
[OUTPOST_PRUNER_DAILY_SERVICE, renderService({ trigger: "daily", nodeBinary, hqBinary, hqRoot: options.hqRoot, home, pathEnv, flagEnvironment })],
|
|
177
|
+
[OUTPOST_PRUNER_DAILY_TIMER, renderOutpostPrunerDailyTimer()],
|
|
178
|
+
];
|
|
179
|
+
let written = false;
|
|
180
|
+
for (const [name, contents] of units) {
|
|
181
|
+
written = writeIfChanged(path.join(options.systemdRoot, name), contents) || written;
|
|
182
|
+
}
|
|
183
|
+
let enabled = false;
|
|
184
|
+
if (options.enable) {
|
|
185
|
+
if (!options.runCommand)
|
|
186
|
+
throw new Error("--enable needs a systemctl runner");
|
|
187
|
+
runSystemctl(["--user", "daemon-reload"], options.runCommand);
|
|
188
|
+
runSystemctl(["--user", "enable", "--now", OUTPOST_PRUNER_PRESSURE_TIMER, OUTPOST_PRUNER_DAILY_TIMER], options.runCommand);
|
|
189
|
+
enabled = true;
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
ok: true,
|
|
193
|
+
action: "outpost-pruner.install",
|
|
194
|
+
systemd_root: options.systemdRoot,
|
|
195
|
+
units: units.map(([name]) => path.join(options.systemdRoot, name)),
|
|
196
|
+
written,
|
|
197
|
+
enabled,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export function uninstallOutpostPrunerTimers(options) {
|
|
201
|
+
if (options.disable) {
|
|
202
|
+
if (!options.runCommand)
|
|
203
|
+
throw new Error("--disable needs a systemctl runner");
|
|
204
|
+
runSystemctl(["--user", "disable", "--now", OUTPOST_PRUNER_PRESSURE_TIMER, OUTPOST_PRUNER_DAILY_TIMER], options.runCommand);
|
|
205
|
+
}
|
|
206
|
+
const units = [
|
|
207
|
+
OUTPOST_PRUNER_PRESSURE_SERVICE,
|
|
208
|
+
OUTPOST_PRUNER_PRESSURE_TIMER,
|
|
209
|
+
OUTPOST_PRUNER_DAILY_SERVICE,
|
|
210
|
+
OUTPOST_PRUNER_DAILY_TIMER,
|
|
211
|
+
];
|
|
212
|
+
let removed = false;
|
|
213
|
+
for (const name of units) {
|
|
214
|
+
removed = unlinkIfExists(path.join(options.systemdRoot, name)) || removed;
|
|
215
|
+
}
|
|
216
|
+
if (options.disable && options.runCommand)
|
|
217
|
+
runSystemctl(["--user", "daemon-reload"], options.runCommand);
|
|
218
|
+
return {
|
|
219
|
+
ok: true,
|
|
220
|
+
action: "outpost-pruner.uninstall",
|
|
221
|
+
systemd_root: options.systemdRoot,
|
|
222
|
+
units: units.map((name) => path.join(options.systemdRoot, name)),
|
|
223
|
+
removed,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=outpost-pruner-install.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createFlagClient } from "@indigoai-us/hq-flags-client";
|
|
2
|
+
export declare const OUTPOST_WORKTREE_PRUNER_FLAG = "outpost.worktree-pruner";
|
|
3
|
+
export declare const OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK = false;
|
|
4
|
+
export declare const OUTPOST_WORKTREE_PRUNER_FLAG_TIMEOUT_MS = 5000;
|
|
5
|
+
export interface OutpostPrunerFlagClient {
|
|
6
|
+
ready(): Promise<void>;
|
|
7
|
+
isEnabled(flagKey: string, options?: {
|
|
8
|
+
fallback?: boolean;
|
|
9
|
+
}): boolean;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface OutpostPrunerFlagDependencies {
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
createClient?: typeof createFlagClient;
|
|
15
|
+
getToken?: () => string | Promise<string>;
|
|
16
|
+
reportFailure?: (error: unknown) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function outpostWorktreePrunerEnabled(dependencies?: OutpostPrunerFlagDependencies): Promise<boolean>;
|
|
19
|
+
//# sourceMappingURL=outpost-worktree-pruner-flag.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { loadCachedTokens } from "@indigoai-us/hq-cloud";
|
|
2
|
+
import { createFlagClient } from "@indigoai-us/hq-flags-client";
|
|
3
|
+
export const OUTPOST_WORKTREE_PRUNER_FLAG = "outpost.worktree-pruner";
|
|
4
|
+
export const OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK = false;
|
|
5
|
+
export const OUTPOST_WORKTREE_PRUNER_FLAG_TIMEOUT_MS = 5_000;
|
|
6
|
+
/**
|
|
7
|
+
* Read the company-scoped rollout flag with bounded I/O. Missing endpoint,
|
|
8
|
+
* company identity, registry row, cached token, or registry availability all
|
|
9
|
+
* leave destructive pruning disabled.
|
|
10
|
+
*/
|
|
11
|
+
function errorClass(error) {
|
|
12
|
+
return error instanceof Error ? error.name : "UnknownError";
|
|
13
|
+
}
|
|
14
|
+
function reportFlagFailure(error) {
|
|
15
|
+
process.stderr.write(`${JSON.stringify({
|
|
16
|
+
event: "outpost.worktree_pruner.flag_read_failed",
|
|
17
|
+
flag: OUTPOST_WORKTREE_PRUNER_FLAG,
|
|
18
|
+
error: errorClass(error),
|
|
19
|
+
fallback: OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK,
|
|
20
|
+
})}\n`);
|
|
21
|
+
}
|
|
22
|
+
export async function outpostWorktreePrunerEnabled(dependencies = {}) {
|
|
23
|
+
const env = dependencies.env ?? process.env;
|
|
24
|
+
const endpoint = env.HQ_FLAGS_API_URL?.trim() || "";
|
|
25
|
+
const companyUid = env.HQ_COMPANY_UID?.trim() || "";
|
|
26
|
+
if (!endpoint || !companyUid) {
|
|
27
|
+
process.stderr.write(`${JSON.stringify({
|
|
28
|
+
event: "outpost.worktree_pruner.flag_config_missing",
|
|
29
|
+
flag: OUTPOST_WORKTREE_PRUNER_FLAG,
|
|
30
|
+
missing: [
|
|
31
|
+
...(!endpoint ? ["HQ_FLAGS_API_URL"] : []),
|
|
32
|
+
...(!companyUid ? ["HQ_COMPANY_UID"] : []),
|
|
33
|
+
],
|
|
34
|
+
fallback: OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK,
|
|
35
|
+
})}\n`);
|
|
36
|
+
return OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK;
|
|
37
|
+
}
|
|
38
|
+
const companySlug = env.HQ_COMPANY_SLUG?.trim() || "";
|
|
39
|
+
let client;
|
|
40
|
+
let enabled = OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK;
|
|
41
|
+
let failed = false;
|
|
42
|
+
let reported = false;
|
|
43
|
+
const reportFailure = (error) => {
|
|
44
|
+
failed = true;
|
|
45
|
+
if (reported)
|
|
46
|
+
return;
|
|
47
|
+
reported = true;
|
|
48
|
+
(dependencies.reportFailure ?? reportFlagFailure)(error);
|
|
49
|
+
};
|
|
50
|
+
try {
|
|
51
|
+
client = (dependencies.createClient ?? createFlagClient)({
|
|
52
|
+
endpoint,
|
|
53
|
+
companyUid,
|
|
54
|
+
...(companySlug ? { companyIdentifiers: [companySlug] } : {}),
|
|
55
|
+
getToken: dependencies.getToken ?? (() => loadCachedTokens()?.idToken ?? ""),
|
|
56
|
+
refreshIntervalMs: 0,
|
|
57
|
+
requestTimeoutMs: OUTPOST_WORKTREE_PRUNER_FLAG_TIMEOUT_MS,
|
|
58
|
+
onError: reportFailure,
|
|
59
|
+
});
|
|
60
|
+
await client.ready();
|
|
61
|
+
enabled = client.isEnabled(OUTPOST_WORKTREE_PRUNER_FLAG, {
|
|
62
|
+
fallback: OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
reportFailure(error);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
client?.close();
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
reportFailure(error);
|
|
73
|
+
}
|
|
74
|
+
return failed ? OUTPOST_WORKTREE_PRUNER_FLAG_FALLBACK : enabled;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=outpost-worktree-pruner-flag.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Safe, host-local cleanup for terminal HQ worktrees on outposts. */
|
|
2
|
+
export type PrunerTrigger = "pressure" | "daily" | "manual";
|
|
3
|
+
export interface OutpostWorktreePrunerOptions {
|
|
4
|
+
hqRoot: string;
|
|
5
|
+
trigger: PrunerTrigger;
|
|
6
|
+
dryRun: boolean;
|
|
7
|
+
featureEnabled: boolean;
|
|
8
|
+
minAgeDays: number;
|
|
9
|
+
now?: number;
|
|
10
|
+
/** Test seam. Production uses /proc. */
|
|
11
|
+
processRoot?: string;
|
|
12
|
+
/** Test seam. Production safely resolves and runs `pnpm store prune`. */
|
|
13
|
+
runPackageStorePrune?: () => PackageStorePruneResult;
|
|
14
|
+
/** Test seam for the storage threshold; production reads filesystem stats. */
|
|
15
|
+
readDiskUsedPercent?: (hqRoot: string) => number | null;
|
|
16
|
+
/** Test seam for classifying inaccessible /proc entries by owner. */
|
|
17
|
+
processUserId?: number;
|
|
18
|
+
/** Test seam for /proc reads; production uses the host filesystem. */
|
|
19
|
+
processPathReader?: ProcessPathReader;
|
|
20
|
+
}
|
|
21
|
+
export interface ProcessPathReader {
|
|
22
|
+
readdirSync(path: string): string[];
|
|
23
|
+
readlinkSync(path: string): string;
|
|
24
|
+
uid(path: string): number;
|
|
25
|
+
}
|
|
26
|
+
export interface PackageStorePruneResult {
|
|
27
|
+
attempted: boolean;
|
|
28
|
+
reason?: string;
|
|
29
|
+
bytes_freed?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface OutpostWorktreePrunerResult {
|
|
32
|
+
event: "outpost.worktree_pruner.run";
|
|
33
|
+
trigger: PrunerTrigger;
|
|
34
|
+
dry_run: boolean;
|
|
35
|
+
feature_enabled: boolean;
|
|
36
|
+
skipped?: string;
|
|
37
|
+
pressure_percent?: number;
|
|
38
|
+
min_age_days: number;
|
|
39
|
+
candidates: string[];
|
|
40
|
+
removed: Array<{
|
|
41
|
+
path: string;
|
|
42
|
+
bytes_freed: number;
|
|
43
|
+
}>;
|
|
44
|
+
kept: Array<{
|
|
45
|
+
path: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
bytes_freed: number;
|
|
49
|
+
bytes_freed_basis: "statfs_available_byte_delta";
|
|
50
|
+
package_store: PackageStorePruneResult;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Prune only registered worktrees beneath workspace/worktrees after every
|
|
54
|
+
* local, git, age, and liveness check has passed. The function never shells
|
|
55
|
+
* out to rm and never follows symlinks while estimating or checking age.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runOutpostWorktreePruner(options: OutpostWorktreePrunerOptions): OutpostWorktreePrunerResult;
|
|
58
|
+
export declare const OUTPOST_WORKTREE_PRUNER_DEFAULT_MIN_AGE_DAYS = 14;
|
|
59
|
+
export declare const OUTPOST_WORKTREE_PRUNER_PRESSURE_THRESHOLD_PERCENT = 78;
|
|
60
|
+
//# sourceMappingURL=outpost-worktree-pruner.d.ts.map
|