crewly 1.20.358 → 1.20.360
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/config/roles/developer/prompt.md +3 -1
- package/config/skills/registry.json +125 -1
- package/dist/backend/backend/src/constants.d.ts +189 -2
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +200 -3
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +58 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +263 -19
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/boot-pressure.d.ts +147 -0
- package/dist/backend/backend/src/services/agent/boot-pressure.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/boot-pressure.js +212 -0
- package/dist/backend/backend/src/services/agent/boot-pressure.js.map +1 -0
- package/dist/backend/backend/src/services/agent/restore-queue.d.ts +50 -1
- package/dist/backend/backend/src/services/agent/restore-queue.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/restore-queue.js +100 -5
- package/dist/backend/backend/src/services/agent/restore-queue.js.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.d.ts +11 -0
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js +28 -2
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts +10 -0
- package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/startup-briefing.service.js +65 -22
- package/dist/backend/backend/src/services/memory/startup-briefing.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/deferred-start-retry.d.ts +8 -0
- package/dist/backend/backend/src/services/messaging/deferred-start-retry.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/deferred-start-retry.js +8 -0
- package/dist/backend/backend/src/services/messaging/deferred-start-retry.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-binding.d.ts +25 -2
- package/dist/backend/backend/src/services/session/session-binding.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-binding.js +32 -4
- package/dist/backend/backend/src/services/session/session-binding.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +3 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts +27 -2
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js +105 -8
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-entries.d.ts +7 -0
- package/dist/backend/backend/src/services/wiki/wiki-log-entries.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-entries.js +10 -0
- package/dist/backend/backend/src/services/wiki/wiki-log-entries.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.d.ts +24 -0
- package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.js +75 -9
- package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts +19 -0
- package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js +23 -2
- package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.js +194 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.d.ts +239 -0
- package/dist/backend/backend/src/services/wiki/work-record.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.js +631 -0
- package/dist/backend/backend/src/services/wiki/work-record.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.d.ts +231 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.js +542 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/low-disk-guard.d.ts +92 -8
- package/dist/backend/backend/src/services/worktree/low-disk-guard.d.ts.map +1 -1
- package/dist/backend/backend/src/services/worktree/low-disk-guard.js +98 -14
- package/dist/backend/backend/src/services/worktree/low-disk-guard.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/tmp-janitor.d.ts +138 -0
- package/dist/backend/backend/src/services/worktree/tmp-janitor.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/tmp-janitor.js +199 -0
- package/dist/backend/backend/src/services/worktree/tmp-janitor.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/transcript-janitor.d.ts +154 -0
- package/dist/backend/backend/src/services/worktree/transcript-janitor.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/transcript-janitor.js +357 -0
- package/dist/backend/backend/src/services/worktree/transcript-janitor.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.js +7 -2
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-dirty.d.ts +16 -4
- package/dist/backend/backend/src/services/worktree/worktree-dirty.d.ts.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-dirty.js +21 -5
- package/dist/backend/backend/src/services/worktree/worktree-dirty.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-git.d.ts +18 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.d.ts.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-git.js +60 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts +164 -25
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js +494 -55
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-tiers.d.ts +186 -0
- package/dist/backend/backend/src/services/worktree/worktree-tiers.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-tiers.js +279 -0
- package/dist/backend/backend/src/services/worktree/worktree-tiers.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +189 -2
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +200 -3
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/boot-pressure.d.ts +147 -0
- package/dist/cli/backend/src/services/agent/boot-pressure.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/boot-pressure.js +212 -0
- package/dist/cli/backend/src/services/agent/boot-pressure.js.map +1 -0
- package/dist/cli/backend/src/services/agent/restore-queue.d.ts +50 -1
- package/dist/cli/backend/src/services/agent/restore-queue.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/restore-queue.js +100 -5
- package/dist/cli/backend/src/services/agent/restore-queue.js.map +1 -1
- package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts +10 -0
- package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/startup-briefing.service.js +65 -22
- package/dist/cli/backend/src/services/memory/startup-briefing.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +3 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-log-entries.d.ts +7 -0
- package/dist/cli/backend/src/services/wiki/wiki-log-entries.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-log-entries.js +10 -0
- package/dist/cli/backend/src/services/wiki/wiki-log-entries.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.js +194 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record.d.ts +239 -0
- package/dist/cli/backend/src/services/wiki/work-record.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record.js +631 -0
- package/dist/cli/backend/src/services/wiki/work-record.js.map +1 -0
- package/dist/cli/backend/src/services/worktree/low-disk-guard.d.ts +92 -8
- package/dist/cli/backend/src/services/worktree/low-disk-guard.d.ts.map +1 -1
- package/dist/cli/backend/src/services/worktree/low-disk-guard.js +98 -14
- package/dist/cli/backend/src/services/worktree/low-disk-guard.js.map +1 -1
- package/dist/cli/backend/src/services/worktree/worktree-git.d.ts +18 -0
- package/dist/cli/backend/src/services/worktree/worktree-git.d.ts.map +1 -1
- package/dist/cli/backend/src/services/worktree/worktree-git.js +60 -0
- package/dist/cli/backend/src/services/worktree/worktree-git.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* Low-disk guard — pure helpers for the disk janitor's free-space check.
|
|
3
3
|
*
|
|
4
4
|
* The janitor checks free space on the volume holding CREWLY_HOME every
|
|
5
|
-
* 10 minutes. Below 15 GB
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* 10 minutes. Below the low mark — max(15 GB, 8 % of the disk), because a
|
|
6
|
+
* ~1 TB Mac already misbehaves at 5–8 % free — it cleans up at once with
|
|
7
|
+
* shorter idle thresholds; if space is still short it tells the owner (at most
|
|
8
|
+
* once per 24 h, or once per 6 h and marked urgent below max(5 GB, 3 %)) what
|
|
9
|
+
* it freed, what it could not remove and why, and that it never touches the
|
|
10
|
+
* owner's own files. This file holds the decisions and the wording; the
|
|
11
|
+
* service does the I/O.
|
|
9
12
|
*
|
|
10
13
|
* @module services/worktree/low-disk-guard
|
|
11
14
|
*/
|
|
@@ -15,17 +18,35 @@ export interface StatFsLike {
|
|
|
15
18
|
bavail: number | bigint;
|
|
16
19
|
/** Block size in bytes */
|
|
17
20
|
bsize: number | bigint;
|
|
21
|
+
/** Total blocks on the volume (optional: an older probe may not report it) */
|
|
22
|
+
blocks?: number | bigint;
|
|
23
|
+
}
|
|
24
|
+
/** Free and total bytes of a volume. */
|
|
25
|
+
export interface DiskSpace {
|
|
26
|
+
/** Free bytes for unprivileged users */
|
|
27
|
+
freeBytes: number;
|
|
28
|
+
/** Total bytes, or null when the probe did not report the size */
|
|
29
|
+
totalBytes: number | null;
|
|
18
30
|
}
|
|
19
31
|
/** `fs.promises.statfs`-compatible probe. */
|
|
20
32
|
export type StatFsFn = (p: string) => Promise<StatFsLike>;
|
|
21
33
|
/** Disk level relative to the thresholds. */
|
|
22
34
|
export type DiskLevel = 'ok' | 'low' | 'critical';
|
|
23
|
-
/**
|
|
35
|
+
/** Janitor state persisted under CREWLY_HOME (notice cadence, sweep cadence, arming). */
|
|
24
36
|
export interface LowDiskNoticeState {
|
|
25
37
|
/** Last notice of any kind (ms epoch) */
|
|
26
38
|
lastNoticeAt?: number;
|
|
27
39
|
/** Last urgent notice (ms epoch) */
|
|
28
40
|
lastUrgentAt?: number;
|
|
41
|
+
/**
|
|
42
|
+
* First real pass that ran with the crewly#1354 retention code (ms epoch).
|
|
43
|
+
* Its deletes stay dry-run until RETENTION_ARM_DELAY_MS after this.
|
|
44
|
+
*/
|
|
45
|
+
retentionArmedAt?: number;
|
|
46
|
+
/** Last transcript sweep (ms epoch) */
|
|
47
|
+
lastTranscriptSweepAt?: number;
|
|
48
|
+
/** Last tmp / logs sweep (ms epoch) */
|
|
49
|
+
lastTmpSweepAt?: number;
|
|
29
50
|
}
|
|
30
51
|
/** Something the janitor looked at and left on disk. */
|
|
31
52
|
export interface KeptItem {
|
|
@@ -45,12 +66,51 @@ export interface KeptItem {
|
|
|
45
66
|
*/
|
|
46
67
|
export declare function readFreeBytes(p: string, statfs?: StatFsFn): Promise<number | null>;
|
|
47
68
|
/**
|
|
48
|
-
*
|
|
69
|
+
* Free and total bytes of the volume holding `p`.
|
|
70
|
+
*
|
|
71
|
+
* @param p - Any path on the volume
|
|
72
|
+
* @param statfs - Probe (default `fs.promises.statfs`)
|
|
73
|
+
* @returns Free and total bytes, or null when the probe failed
|
|
74
|
+
*/
|
|
75
|
+
export declare function readDiskSpace(p: string, statfs?: StatFsFn): Promise<DiskSpace | null>;
|
|
76
|
+
/**
|
|
77
|
+
* The low-disk mark for a volume: the absolute floor or a fraction of the
|
|
78
|
+
* disk, whichever is larger. A 926 GB disk gets ~74 GB, a 100 GB disk 15 GB.
|
|
79
|
+
*
|
|
80
|
+
* @param totalBytes - Disk size, or null when unknown (the floor is used)
|
|
81
|
+
* @returns Bytes below which free space counts as low
|
|
82
|
+
*/
|
|
83
|
+
export declare function lowDiskThresholdBytes(totalBytes: number | null): number;
|
|
84
|
+
/**
|
|
85
|
+
* The critical mark for a volume: max(5 GB, 3 % of the disk).
|
|
86
|
+
*
|
|
87
|
+
* @param totalBytes - Disk size, or null when unknown (the floor is used)
|
|
88
|
+
* @returns Bytes below which free space counts as critical
|
|
89
|
+
*/
|
|
90
|
+
export declare function criticalDiskThresholdBytes(totalBytes: number | null): number;
|
|
91
|
+
/**
|
|
92
|
+
* Classify free space against the volume's marks.
|
|
49
93
|
*
|
|
50
94
|
* @param freeBytes - Free bytes
|
|
51
|
-
* @
|
|
95
|
+
* @param totalBytes - Disk size (null / omitted: the absolute floors apply)
|
|
96
|
+
* @returns `critical` below the critical mark, `low` below the low mark, else `ok`
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* diskLevel(50 * GB, 926 * GB); // 'low' (mark is 8 % = 74 GB)
|
|
101
|
+
* diskLevel(50 * GB); // 'ok' (no size: 15 GB floor)
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare function diskLevel(freeBytes: number, totalBytes?: number | null): DiskLevel;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the crewly#1354 retention deletes are armed: the first real pass
|
|
107
|
+
* records the time and only logs; deletes start RETENTION_ARM_DELAY_MS later.
|
|
108
|
+
*
|
|
109
|
+
* @param state - Janitor state
|
|
110
|
+
* @param now - Current time (ms)
|
|
111
|
+
* @returns True when deletes may run
|
|
52
112
|
*/
|
|
53
|
-
export declare function
|
|
113
|
+
export declare function retentionArmed(state: LowDiskNoticeState, now: number): boolean;
|
|
54
114
|
/**
|
|
55
115
|
* Idle threshold to use, shortened in low-disk mode.
|
|
56
116
|
*
|
|
@@ -83,6 +143,26 @@ export declare function noticeToSend(level: DiskLevel, state: LowDiskNoticeState
|
|
|
83
143
|
* @returns New state
|
|
84
144
|
*/
|
|
85
145
|
export declare function recordNotice(state: LowDiskNoticeState, kind: 'urgent' | 'normal', now: number): LowDiskNoticeState;
|
|
146
|
+
/** What one pass freed, by kind (bytes), for the owner line. */
|
|
147
|
+
export interface FreedBreakdown {
|
|
148
|
+
/** Finished worktrees and scratch dirs removed */
|
|
149
|
+
worktrees: number;
|
|
150
|
+
/** node_modules / build output stripped from kept worktrees */
|
|
151
|
+
stripped: number;
|
|
152
|
+
/** Worktrees archived as a patch and removed */
|
|
153
|
+
archived: number;
|
|
154
|
+
/** Agent transcripts pruned */
|
|
155
|
+
transcripts: number;
|
|
156
|
+
/** CREWLY_HOME/tmp and logs */
|
|
157
|
+
tmp: number;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* One short line of what a pass freed, by kind; empty when nothing was.
|
|
161
|
+
*
|
|
162
|
+
* @param freed - Bytes freed per kind
|
|
163
|
+
* @returns `"freed 3.2 GB (worktrees 2.1 GB, node_modules 1.1 GB)"` or ''
|
|
164
|
+
*/
|
|
165
|
+
export declare function describeFreed(freed: FreedBreakdown): string;
|
|
86
166
|
/**
|
|
87
167
|
* Plain-English reason for a kept item.
|
|
88
168
|
*
|
|
@@ -102,6 +182,10 @@ export declare function buildLowDiskNotice(input: {
|
|
|
102
182
|
urgent: boolean;
|
|
103
183
|
freedBytes: number;
|
|
104
184
|
items: KeptItem[];
|
|
185
|
+
/** Optional breakdown of what was freed (replaces the plain "cleaned up X" line) */
|
|
186
|
+
freed?: FreedBreakdown;
|
|
187
|
+
/** Optional: total disk size, so the owner sees the mark that was crossed */
|
|
188
|
+
totalBytes?: number | null;
|
|
105
189
|
}): {
|
|
106
190
|
title: string;
|
|
107
191
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"low-disk-guard.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/low-disk-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"low-disk-guard.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/low-disk-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* Low-disk guard — pure helpers for the disk janitor's free-space check.
|
|
3
3
|
*
|
|
4
4
|
* The janitor checks free space on the volume holding CREWLY_HOME every
|
|
5
|
-
* 10 minutes. Below 15 GB
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* 10 minutes. Below the low mark — max(15 GB, 8 % of the disk), because a
|
|
6
|
+
* ~1 TB Mac already misbehaves at 5–8 % free — it cleans up at once with
|
|
7
|
+
* shorter idle thresholds; if space is still short it tells the owner (at most
|
|
8
|
+
* once per 24 h, or once per 6 h and marked urgent below max(5 GB, 3 %)) what
|
|
9
|
+
* it freed, what it could not remove and why, and that it never touches the
|
|
10
|
+
* owner's own files. This file holds the decisions and the wording; the
|
|
11
|
+
* service does the I/O.
|
|
9
12
|
*
|
|
10
13
|
* @module services/worktree/low-disk-guard
|
|
11
14
|
*/
|
|
@@ -20,30 +23,81 @@ import { formatBytes } from './worktree-janitor.git.js';
|
|
|
20
23
|
* @returns Free bytes for unprivileged users, or null when the probe failed
|
|
21
24
|
*/
|
|
22
25
|
export async function readFreeBytes(p, statfs = defaultStatFs) {
|
|
26
|
+
return (await readDiskSpace(p, statfs))?.freeBytes ?? null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Free and total bytes of the volume holding `p`.
|
|
30
|
+
*
|
|
31
|
+
* @param p - Any path on the volume
|
|
32
|
+
* @param statfs - Probe (default `fs.promises.statfs`)
|
|
33
|
+
* @returns Free and total bytes, or null when the probe failed
|
|
34
|
+
*/
|
|
35
|
+
export async function readDiskSpace(p, statfs = defaultStatFs) {
|
|
23
36
|
try {
|
|
24
37
|
const s = await statfs(p);
|
|
25
|
-
|
|
38
|
+
const bsize = Number(s.bsize);
|
|
39
|
+
const total = s.blocks === undefined ? null : Number(s.blocks) * bsize;
|
|
40
|
+
return { freeBytes: Number(s.bavail) * bsize, totalBytes: total !== null && Number.isFinite(total) && total > 0 ? total : null };
|
|
26
41
|
}
|
|
27
42
|
catch {
|
|
28
43
|
return null;
|
|
29
44
|
}
|
|
30
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The low-disk mark for a volume: the absolute floor or a fraction of the
|
|
48
|
+
* disk, whichever is larger. A 926 GB disk gets ~74 GB, a 100 GB disk 15 GB.
|
|
49
|
+
*
|
|
50
|
+
* @param totalBytes - Disk size, or null when unknown (the floor is used)
|
|
51
|
+
* @returns Bytes below which free space counts as low
|
|
52
|
+
*/
|
|
53
|
+
export function lowDiskThresholdBytes(totalBytes) {
|
|
54
|
+
const floor = WORKTREE_JANITOR_CONSTANTS.LOW_DISK_BYTES;
|
|
55
|
+
return totalBytes ? Math.max(floor, Math.round(totalBytes * WORKTREE_JANITOR_CONSTANTS.LOW_DISK_FRACTION)) : floor;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The critical mark for a volume: max(5 GB, 3 % of the disk).
|
|
59
|
+
*
|
|
60
|
+
* @param totalBytes - Disk size, or null when unknown (the floor is used)
|
|
61
|
+
* @returns Bytes below which free space counts as critical
|
|
62
|
+
*/
|
|
63
|
+
export function criticalDiskThresholdBytes(totalBytes) {
|
|
64
|
+
const floor = WORKTREE_JANITOR_CONSTANTS.CRITICAL_DISK_BYTES;
|
|
65
|
+
return totalBytes ? Math.max(floor, Math.round(totalBytes * WORKTREE_JANITOR_CONSTANTS.CRITICAL_DISK_FRACTION)) : floor;
|
|
66
|
+
}
|
|
31
67
|
async function defaultStatFs(p) {
|
|
32
68
|
return fs.promises.statfs(p);
|
|
33
69
|
}
|
|
34
70
|
/**
|
|
35
|
-
* Classify free space.
|
|
71
|
+
* Classify free space against the volume's marks.
|
|
36
72
|
*
|
|
37
73
|
* @param freeBytes - Free bytes
|
|
38
|
-
* @
|
|
74
|
+
* @param totalBytes - Disk size (null / omitted: the absolute floors apply)
|
|
75
|
+
* @returns `critical` below the critical mark, `low` below the low mark, else `ok`
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* diskLevel(50 * GB, 926 * GB); // 'low' (mark is 8 % = 74 GB)
|
|
80
|
+
* diskLevel(50 * GB); // 'ok' (no size: 15 GB floor)
|
|
81
|
+
* ```
|
|
39
82
|
*/
|
|
40
|
-
export function diskLevel(freeBytes) {
|
|
41
|
-
if (freeBytes <
|
|
83
|
+
export function diskLevel(freeBytes, totalBytes = null) {
|
|
84
|
+
if (freeBytes < criticalDiskThresholdBytes(totalBytes))
|
|
42
85
|
return 'critical';
|
|
43
|
-
if (freeBytes <
|
|
86
|
+
if (freeBytes < lowDiskThresholdBytes(totalBytes))
|
|
44
87
|
return 'low';
|
|
45
88
|
return 'ok';
|
|
46
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Whether the crewly#1354 retention deletes are armed: the first real pass
|
|
92
|
+
* records the time and only logs; deletes start RETENTION_ARM_DELAY_MS later.
|
|
93
|
+
*
|
|
94
|
+
* @param state - Janitor state
|
|
95
|
+
* @param now - Current time (ms)
|
|
96
|
+
* @returns True when deletes may run
|
|
97
|
+
*/
|
|
98
|
+
export function retentionArmed(state, now) {
|
|
99
|
+
return state.retentionArmedAt !== undefined && now - state.retentionArmedAt >= WORKTREE_JANITOR_CONSTANTS.RETENTION_ARM_DELAY_MS;
|
|
100
|
+
}
|
|
47
101
|
/**
|
|
48
102
|
* Idle threshold to use, shortened in low-disk mode.
|
|
49
103
|
*
|
|
@@ -92,6 +146,27 @@ export function noticeToSend(level, state, now) {
|
|
|
92
146
|
export function recordNotice(state, kind, now) {
|
|
93
147
|
return { ...state, lastNoticeAt: now, ...(kind === 'urgent' ? { lastUrgentAt: now } : {}) };
|
|
94
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* One short line of what a pass freed, by kind; empty when nothing was.
|
|
151
|
+
*
|
|
152
|
+
* @param freed - Bytes freed per kind
|
|
153
|
+
* @returns `"freed 3.2 GB (worktrees 2.1 GB, node_modules 1.1 GB)"` or ''
|
|
154
|
+
*/
|
|
155
|
+
export function describeFreed(freed) {
|
|
156
|
+
const parts = [];
|
|
157
|
+
if (freed.worktrees > 0)
|
|
158
|
+
parts.push(`finished worktrees ${formatBytes(freed.worktrees)}`);
|
|
159
|
+
if (freed.stripped > 0)
|
|
160
|
+
parts.push(`node_modules of idle worktrees ${formatBytes(freed.stripped)}`);
|
|
161
|
+
if (freed.archived > 0)
|
|
162
|
+
parts.push(`archived worktrees ${formatBytes(freed.archived)}`);
|
|
163
|
+
if (freed.transcripts > 0)
|
|
164
|
+
parts.push(`old agent transcripts ${formatBytes(freed.transcripts)}`);
|
|
165
|
+
if (freed.tmp > 0)
|
|
166
|
+
parts.push(`temp files and logs ${formatBytes(freed.tmp)}`);
|
|
167
|
+
const total = freed.worktrees + freed.stripped + freed.archived + freed.transcripts + freed.tmp;
|
|
168
|
+
return total > 0 ? `freed ${formatBytes(total)} (${parts.join(', ')})` : '';
|
|
169
|
+
}
|
|
95
170
|
const REASON_TEXT = {
|
|
96
171
|
dirty: 'has changes that were never committed',
|
|
97
172
|
'not-merged': 'has work that is not merged yet',
|
|
@@ -109,6 +184,10 @@ const REASON_TEXT = {
|
|
|
109
184
|
'status-failed': 'git could not read it',
|
|
110
185
|
'git-failed': 'git could not read it',
|
|
111
186
|
'remove-failed': 'deleting it failed',
|
|
187
|
+
'archive-failed': 'saving its changes as a patch failed, so it stays',
|
|
188
|
+
'contains-git': 'holds a git checkout, which only the worktree rules may remove',
|
|
189
|
+
'live-session': 'is the conversation of a running agent',
|
|
190
|
+
foreign: 'is not an agent conversation',
|
|
112
191
|
};
|
|
113
192
|
/**
|
|
114
193
|
* Plain-English reason for a kept item.
|
|
@@ -129,10 +208,14 @@ export function describeReason(reason) {
|
|
|
129
208
|
export function buildLowDiskNotice(input) {
|
|
130
209
|
const title = input.urgent ? 'URGENT: disk almost full' : 'Disk space is running low';
|
|
131
210
|
const lines = [];
|
|
132
|
-
|
|
133
|
-
lines.push(input.
|
|
134
|
-
|
|
135
|
-
|
|
211
|
+
const ofDisk = input.totalBytes ? ` of ${formatBytes(input.totalBytes)}` : '';
|
|
212
|
+
lines.push(`Only ${formatBytes(input.freeBytes)}${ofDisk} free on this machine.${input.urgent ? ' Crewly and the agents may stop working soon.' : ''}`);
|
|
213
|
+
const breakdown = input.freed ? describeFreed(input.freed) : '';
|
|
214
|
+
lines.push(breakdown
|
|
215
|
+
? `Today I ${breakdown}, but it is not enough.`
|
|
216
|
+
: input.freedBytes > 0
|
|
217
|
+
? `I cleaned up ${formatBytes(input.freedBytes)} of finished work, but it is not enough.`
|
|
218
|
+
: 'I found nothing more that is safe to delete on my own.');
|
|
136
219
|
const top = [...input.items].sort((a, b) => b.bytes - a.bytes).slice(0, WORKTREE_JANITOR_CONSTANTS.LOW_DISK_REPORT_ITEMS);
|
|
137
220
|
if (top.length > 0) {
|
|
138
221
|
lines.push('', 'Biggest things I left alone:');
|
|
@@ -143,6 +226,7 @@ export function buildLowDiskNotice(input) {
|
|
|
143
226
|
else {
|
|
144
227
|
lines.push('Please free up some space.');
|
|
145
228
|
}
|
|
229
|
+
lines.push('I only clean what agents left behind (worktrees, scratch dirs, agent transcripts, Crewly temp files and logs); your own files, downloads and app caches I never touch.');
|
|
146
230
|
return { title, message: lines.join('\n') };
|
|
147
231
|
}
|
|
148
232
|
//# sourceMappingURL=low-disk-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"low-disk-guard.js","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/low-disk-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"low-disk-guard.js","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/low-disk-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tmp and log janitor — retention for `<CREWLY_HOME>/tmp` and size caps for
|
|
3
|
+
* `<CREWLY_HOME>/logs/archive` and `logs/sessions` (crewly#1354).
|
|
4
|
+
*
|
|
5
|
+
* `~/.crewly/tmp` is where agents, skills and Crewly itself put scratch
|
|
6
|
+
* output (Slack downloads, release build dirs, previews, skill output) and
|
|
7
|
+
* nothing ever removed it (600 MB on one Mac); the log archive had a 7-day
|
|
8
|
+
* rule but no cap (600 MB) and session logs none at all (200 MB).
|
|
9
|
+
*
|
|
10
|
+
* Tmp rules: a top-level entry untouched (shallow tree mtime) for 7 days is
|
|
11
|
+
* removed. Some sub-directories are swept per child with their own age
|
|
12
|
+
* instead (`slack-files` / `slack-images` / `slack-pdfs` 30 days,
|
|
13
|
+
* `crewly-web-release` 2 days, `skill-output` 7 days) and the directory itself
|
|
14
|
+
* stays. Never removed: symlinks, anything a process or agent session has as
|
|
15
|
+
* cwd, and any entry holding a git checkout — a linked worktree in tmp
|
|
16
|
+
* belongs to the worktree rules (the service adds tmp to their discovery
|
|
17
|
+
* roots), and a clone may be the only copy of its history.
|
|
18
|
+
*
|
|
19
|
+
* Log caps: the oldest files go first until the directory fits; a file
|
|
20
|
+
* written in the last hour, or the log of a live session, is never deleted.
|
|
21
|
+
*
|
|
22
|
+
* @module services/worktree/tmp-janitor
|
|
23
|
+
*/
|
|
24
|
+
/** A place a live process or agent is working in (same shape as the janitor's BusyCwd). */
|
|
25
|
+
export interface TmpBusyCwd {
|
|
26
|
+
cwd: string;
|
|
27
|
+
source: 'agent-session' | 'process';
|
|
28
|
+
}
|
|
29
|
+
/** Why a tmp entry was removed or kept. */
|
|
30
|
+
export type TmpReason = 'old' | 'recent' | 'contains-git' | 'process-inside' | 'agent-session-inside' | 'cwd-probe-failed' | 'symlink' | 'remove-failed';
|
|
31
|
+
/** Verdict for one tmp entry. */
|
|
32
|
+
export interface TmpEntryVerdict {
|
|
33
|
+
/** Absolute path */
|
|
34
|
+
path: string;
|
|
35
|
+
/** Bytes (0 when unknown) */
|
|
36
|
+
bytes: number;
|
|
37
|
+
/** What the sweep decided */
|
|
38
|
+
decision: 'remove' | 'keep';
|
|
39
|
+
/** The deciding rule */
|
|
40
|
+
reason: TmpReason;
|
|
41
|
+
/** Ms since last touched, when known */
|
|
42
|
+
idleMs?: number;
|
|
43
|
+
/** True when deleted */
|
|
44
|
+
removed: boolean;
|
|
45
|
+
/** Error text when deletion failed */
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Result of one tmp sweep. */
|
|
49
|
+
export interface TmpSweepSummary {
|
|
50
|
+
/** The tmp root */
|
|
51
|
+
root: string;
|
|
52
|
+
/** Entries deleted */
|
|
53
|
+
removed: number;
|
|
54
|
+
/** Dry run: entries that would be deleted */
|
|
55
|
+
wouldRemove: number;
|
|
56
|
+
/** Bytes freed */
|
|
57
|
+
freedBytes: number;
|
|
58
|
+
/** Dry run: bytes that would be freed */
|
|
59
|
+
wouldFreeBytes: number;
|
|
60
|
+
/** Entries kept (`recent` ones are counted, not listed) */
|
|
61
|
+
kept: number;
|
|
62
|
+
/** Kept entries by reason */
|
|
63
|
+
keptReasons: Record<string, number>;
|
|
64
|
+
/** Verdicts (all but `recent`) */
|
|
65
|
+
entries: TmpEntryVerdict[];
|
|
66
|
+
}
|
|
67
|
+
/** Input of {@link sweepTmp}. */
|
|
68
|
+
export interface TmpSweepInput {
|
|
69
|
+
/** `<CREWLY_HOME>/tmp` */
|
|
70
|
+
root: string;
|
|
71
|
+
/** Busy cwds, or null when the probe failed (everything is then kept) */
|
|
72
|
+
busy: TmpBusyCwd[] | null;
|
|
73
|
+
/** Current time (ms) */
|
|
74
|
+
now: number;
|
|
75
|
+
/** When true, nothing is deleted */
|
|
76
|
+
dryRun: boolean;
|
|
77
|
+
/** Age for top-level entries (default TMP_MAX_AGE_MS) */
|
|
78
|
+
maxAgeMs?: number;
|
|
79
|
+
/** Per-child policies by sub-directory name (default TMP_CHILD_POLICIES) */
|
|
80
|
+
childPolicies?: Readonly<Record<string, number>>;
|
|
81
|
+
/** Size probe (default: shallow stat walk) */
|
|
82
|
+
sizeOf?: (p: string) => Promise<number | null>;
|
|
83
|
+
}
|
|
84
|
+
/** Bytes of a path by a bounded stat walk (no symlinks followed). */
|
|
85
|
+
export declare function shallowBytes(p: string, depth?: number): Promise<number>;
|
|
86
|
+
/**
|
|
87
|
+
* One sweep of the tmp root. Never throws; an unreadable root yields an
|
|
88
|
+
* empty summary.
|
|
89
|
+
*
|
|
90
|
+
* @param input - Root, busy cwds, clock, dry-run flag
|
|
91
|
+
* @returns What was removed and kept
|
|
92
|
+
*/
|
|
93
|
+
export declare function sweepTmp(input: TmpSweepInput): Promise<TmpSweepSummary>;
|
|
94
|
+
/** Input of {@link capDirectoryBytes}. */
|
|
95
|
+
export interface DirCapInput {
|
|
96
|
+
/** Directory of files to cap (not recursive) */
|
|
97
|
+
dir: string;
|
|
98
|
+
/** Allowed total bytes */
|
|
99
|
+
capBytes: number;
|
|
100
|
+
/** Current time (ms) */
|
|
101
|
+
now: number;
|
|
102
|
+
/** When true, nothing is deleted */
|
|
103
|
+
dryRun: boolean;
|
|
104
|
+
/** Files to consider (default: every regular file) */
|
|
105
|
+
filter?: (name: string) => boolean;
|
|
106
|
+
/** Files never deleted (a live session's log) */
|
|
107
|
+
protect?: (name: string) => boolean;
|
|
108
|
+
/** A file written within this long is never deleted (default LOG_CAP_MIN_AGE_MS) */
|
|
109
|
+
minAgeMs?: number;
|
|
110
|
+
}
|
|
111
|
+
/** Result of {@link capDirectoryBytes}. */
|
|
112
|
+
export interface DirCapSummary {
|
|
113
|
+
/** The directory */
|
|
114
|
+
dir: string;
|
|
115
|
+
/** Total bytes before */
|
|
116
|
+
totalBytes: number;
|
|
117
|
+
/** The cap */
|
|
118
|
+
capBytes: number;
|
|
119
|
+
/** Files deleted (oldest first) */
|
|
120
|
+
deleted: string[];
|
|
121
|
+
/** Bytes freed */
|
|
122
|
+
freedBytes: number;
|
|
123
|
+
/** Dry run: files that would be deleted */
|
|
124
|
+
wouldDelete: string[];
|
|
125
|
+
/** Dry run: bytes that would be freed */
|
|
126
|
+
wouldFreeBytes: number;
|
|
127
|
+
/** Bytes that stay over the cap because every remaining file is protected or too new */
|
|
128
|
+
overCapBytes: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Delete the oldest files of a directory until it fits the cap. Never
|
|
132
|
+
* throws; an unreadable directory yields an empty summary.
|
|
133
|
+
*
|
|
134
|
+
* @param input - Directory, cap, filters, clock, dry-run flag
|
|
135
|
+
* @returns What was deleted and what still exceeds the cap
|
|
136
|
+
*/
|
|
137
|
+
export declare function capDirectoryBytes(input: DirCapInput): Promise<DirCapSummary>;
|
|
138
|
+
//# sourceMappingURL=tmp-janitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmp-janitor.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/tmp-janitor.ts"],"names":[],"mappings":"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"}
|