crewly 1.20.359 → 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 +130 -2
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +141 -3
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +37 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +103 -10
- 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 +23 -2
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.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/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.service.d.ts +23 -1
- package/dist/backend/backend/src/services/wiki/work-record.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/work-record.service.js +33 -5
- package/dist/backend/backend/src/services/wiki/work-record.service.js.map +1 -1
- 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 +130 -2
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +141 -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/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/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
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree age tiers — what the janitor does with a worktree it must keep
|
|
3
|
+
* (unmerged or dirty) once nobody has touched it for days (crewly#1354).
|
|
4
|
+
*
|
|
5
|
+
* The 1.20.159 janitor removes only worktrees whose work has landed. Every
|
|
6
|
+
* other one stayed forever with a full `node_modules` (2–3 GB each; one Mac
|
|
7
|
+
* kept 21 of them, ~15 GB). Two tiers now apply to a kept worktree that is
|
|
8
|
+
* untouched — no file, no index write, no commit newer — and has no process
|
|
9
|
+
* inside:
|
|
10
|
+
*
|
|
11
|
+
* - **strip** (idle ≥ 3 days; 1 day under low disk or once its WorkItem
|
|
12
|
+
* finished): delete its regenerable dirs (`node_modules`, `.next`, `dist`,
|
|
13
|
+
* `.turbo`, `.cache`) — never a directory git tracks anything under, never
|
|
14
|
+
* source. Reversible with `npm install` / a rebuild.
|
|
15
|
+
* - **archive** (idle ≥ 14 days): save its tracked changes (`git diff HEAD
|
|
16
|
+
* --binary`) and its untracked, non-regenerable files as one patch under
|
|
17
|
+
* `<CREWLY_HOME>/worktree-archive/<repo>/<name>-<date>.patch` (size-capped),
|
|
18
|
+
* keep its branch (its commits stay in the repo; a detached HEAD gets a
|
|
19
|
+
* `refs/crewly-archive/...` ref), then remove the worktree.
|
|
20
|
+
*
|
|
21
|
+
* The lead of the owning team is told once per worktree per tier. This file
|
|
22
|
+
* holds the decisions, the patch writer and the wording; the service wires
|
|
23
|
+
* them into its pass.
|
|
24
|
+
*
|
|
25
|
+
* @module services/worktree/worktree-tiers
|
|
26
|
+
*/
|
|
27
|
+
import * as fs from 'fs';
|
|
28
|
+
import * as path from 'path';
|
|
29
|
+
import { WORKTREE_JANITOR_CONSTANTS } from '../../constants.js';
|
|
30
|
+
import { formatBytes } from './worktree-janitor.git.js';
|
|
31
|
+
import { isRegenerablePath } from './worktree-dirty.js';
|
|
32
|
+
/** An empty tier state. */
|
|
33
|
+
export function emptyTierState() {
|
|
34
|
+
return { stripped: {}, archived: {}, finished: {} };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalise whatever was read from disk into a {@link TierState}.
|
|
38
|
+
*
|
|
39
|
+
* @param raw - Parsed JSON, or null
|
|
40
|
+
* @returns A complete state (missing maps are empty)
|
|
41
|
+
*/
|
|
42
|
+
export function normalizeTierState(raw) {
|
|
43
|
+
const out = emptyTierState();
|
|
44
|
+
if (!raw || typeof raw !== 'object')
|
|
45
|
+
return out;
|
|
46
|
+
const r = raw;
|
|
47
|
+
for (const key of ['stripped', 'archived', 'finished']) {
|
|
48
|
+
const m = r[key];
|
|
49
|
+
if (!m || typeof m !== 'object')
|
|
50
|
+
continue;
|
|
51
|
+
for (const [p, at] of Object.entries(m)) {
|
|
52
|
+
if (typeof at === 'number' && Number.isFinite(at))
|
|
53
|
+
out[key][p] = at;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Drop entries too old to matter so the state file does not grow forever.
|
|
60
|
+
* Stripped / archived records of worktrees that no longer exist are dropped
|
|
61
|
+
* too (the caller passes the paths it still sees).
|
|
62
|
+
*
|
|
63
|
+
* @param state - Tier state
|
|
64
|
+
* @param now - Current epoch ms
|
|
65
|
+
* @param existing - Worktree paths that still exist (others' strip records go)
|
|
66
|
+
* @returns A pruned copy
|
|
67
|
+
*/
|
|
68
|
+
export function pruneTierState(state, now, existing) {
|
|
69
|
+
const maxAge = WORKTREE_JANITOR_CONSTANTS.TIER_STATE_MAX_AGE_MS;
|
|
70
|
+
const out = emptyTierState();
|
|
71
|
+
for (const [p, at] of Object.entries(state.stripped))
|
|
72
|
+
if (existing.has(p))
|
|
73
|
+
out.stripped[p] = at;
|
|
74
|
+
for (const [p, at] of Object.entries(state.archived))
|
|
75
|
+
if (now - at < maxAge)
|
|
76
|
+
out.archived[p] = at;
|
|
77
|
+
for (const [p, at] of Object.entries(state.finished))
|
|
78
|
+
if (now - at < maxAge && existing.has(p))
|
|
79
|
+
out.finished[p] = at;
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* How long a worktree has been untouched, for the tier decision: the newest
|
|
84
|
+
* of its shallow tree mtime, its git-dir mtime (index / HEAD / reflog) and
|
|
85
|
+
* its newest commit. Unknown parts are ignored; all unknown = null.
|
|
86
|
+
*
|
|
87
|
+
* @param input - Current time and the three "last touched" signals (ms epoch or null)
|
|
88
|
+
* @returns Idle ms, or null when nothing is known
|
|
89
|
+
*/
|
|
90
|
+
export function tierIdleMs(input) {
|
|
91
|
+
const known = [input.treeMtimeMs, input.gitMtimeMs, input.newestCommitMs].filter((v) => typeof v === 'number' && Number.isFinite(v));
|
|
92
|
+
if (known.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
return Math.max(0, input.now - Math.max(...known));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Which tier a kept worktree has reached.
|
|
98
|
+
*
|
|
99
|
+
* @param input - Idle ms (null = unknown → none), low-disk mode, when its WorkItem finished (ms epoch or undefined)
|
|
100
|
+
* @returns `archive` at 14 days, `strip` at 3 days (1 day under low disk or after a finished WorkItem), else null
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* tierFor({ idleMs: 4 * DAY, lowDisk: false }); // 'strip'
|
|
105
|
+
* tierFor({ idleMs: 30 * HOUR, lowDisk: true }); // 'strip'
|
|
106
|
+
* tierFor({ idleMs: 30 * HOUR, lowDisk: false, finishedAt: t }); // 'strip'
|
|
107
|
+
* tierFor({ idleMs: 15 * DAY, lowDisk: false }); // 'archive'
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export function tierFor(input) {
|
|
111
|
+
if (input.idleMs === null)
|
|
112
|
+
return null;
|
|
113
|
+
if (input.idleMs >= WORKTREE_JANITOR_CONSTANTS.ARCHIVE_MIN_IDLE_MS)
|
|
114
|
+
return 'archive';
|
|
115
|
+
const stripAfter = input.lowDisk || input.finishedAt !== undefined
|
|
116
|
+
? WORKTREE_JANITOR_CONSTANTS.STRIP_MIN_IDLE_LOW_DISK_MS
|
|
117
|
+
: WORKTREE_JANITOR_CONSTANTS.STRIP_MIN_IDLE_MS;
|
|
118
|
+
return input.idleMs >= stripAfter ? 'strip' : null;
|
|
119
|
+
}
|
|
120
|
+
/** Date part of an ISO timestamp (`2026-10-17`). */
|
|
121
|
+
function dateStamp(now) {
|
|
122
|
+
return new Date(now).toISOString().slice(0, 10);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Where a worktree's archive patch goes:
|
|
126
|
+
* `<archiveRoot>/<repo basename>/<worktree basename>-<date>.patch`, with a
|
|
127
|
+
* numeric suffix when that file already exists.
|
|
128
|
+
*
|
|
129
|
+
* @param archiveRoot - `<CREWLY_HOME>/worktree-archive`
|
|
130
|
+
* @param repoMain - Main worktree of the repo
|
|
131
|
+
* @param worktreePath - The worktree
|
|
132
|
+
* @param now - Current epoch ms (for the date)
|
|
133
|
+
* @returns Absolute patch path (not created)
|
|
134
|
+
*/
|
|
135
|
+
export function archivePatchPath(archiveRoot, repoMain, worktreePath, now) {
|
|
136
|
+
const dir = path.join(archiveRoot, path.basename(repoMain));
|
|
137
|
+
const base = `${path.basename(worktreePath)}-${dateStamp(now)}`;
|
|
138
|
+
let candidate = path.join(dir, `${base}.patch`);
|
|
139
|
+
for (let i = 2; fs.existsSync(candidate) && i < 100; i++)
|
|
140
|
+
candidate = path.join(dir, `${base}-${i}.patch`);
|
|
141
|
+
return candidate;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Write a worktree's uncommitted work as one patch file: a `#` header (repo,
|
|
145
|
+
* worktree, branch, HEAD, how to apply), `git diff HEAD --binary` (tracked
|
|
146
|
+
* changes, staged or not), then one `git diff --no-index` hunk per untracked,
|
|
147
|
+
* non-regenerable file. The patch is capped at ARCHIVE_PATCH_MAX_BYTES and
|
|
148
|
+
* ARCHIVE_MAX_UNTRACKED_FILES; files that would push it over are listed in
|
|
149
|
+
* the trailer instead. `git apply --3way <file>` restores it on a checkout
|
|
150
|
+
* of the same HEAD. Throws when the tracked diff alone is over the cap or the
|
|
151
|
+
* file cannot be written (the caller then keeps the worktree).
|
|
152
|
+
*
|
|
153
|
+
* @param git - git runner
|
|
154
|
+
* @param facts - Header facts
|
|
155
|
+
* @param file - Destination (its directory is created)
|
|
156
|
+
* @param now - Current epoch ms
|
|
157
|
+
* @returns What was written
|
|
158
|
+
* @throws When git cannot read the worktree, the tracked diff exceeds the cap, or the write fails
|
|
159
|
+
*/
|
|
160
|
+
export async function writeArchivePatch(git, facts, file, now) {
|
|
161
|
+
const cap = WORKTREE_JANITOR_CONSTANTS.ARCHIVE_PATCH_MAX_BYTES;
|
|
162
|
+
const wt = facts.worktreePath;
|
|
163
|
+
const tracked = await git(['-C', wt, 'diff', '--binary', 'HEAD']);
|
|
164
|
+
if (tracked.code !== 0)
|
|
165
|
+
throw new Error(`git diff failed: ${tracked.stderr.trim().slice(0, 200)}`);
|
|
166
|
+
if (Buffer.byteLength(tracked.stdout) > cap)
|
|
167
|
+
throw new Error(`tracked changes exceed the ${formatBytes(cap)} archive cap`);
|
|
168
|
+
const others = await git(['-C', wt, 'ls-files', '--others', '--exclude-standard', '-z']);
|
|
169
|
+
if (others.code !== 0)
|
|
170
|
+
throw new Error(`git ls-files failed: ${others.stderr.trim().slice(0, 200)}`);
|
|
171
|
+
const untracked = others.stdout.split('\0').filter((p) => p !== '' && !isRegenerablePath(p));
|
|
172
|
+
const header = [
|
|
173
|
+
'# Crewly worktree archive (crewly#1354)',
|
|
174
|
+
`# repo: ${facts.repoMain}`,
|
|
175
|
+
`# worktree: ${wt}`,
|
|
176
|
+
`# branch: ${facts.branch ?? 'detached HEAD'}`,
|
|
177
|
+
`# head: ${facts.head ?? 'unknown'}`,
|
|
178
|
+
`# default: ${facts.defaultRef ?? 'none'}${facts.commitsNotOnDefault !== null ? ` (${facts.commitsNotOnDefault} commit(s) of this worktree are not on it; ${facts.branch ? 'the branch was kept' : facts.keepRef ? `kept under ${facts.keepRef}` : 'none to keep'})` : ''}`,
|
|
179
|
+
`# archived: ${new Date(now).toISOString()}`,
|
|
180
|
+
`# apply: git worktree add <dir> ${facts.head ?? '<head>'} && git -C <dir> apply --3way ${path.basename(file)}`,
|
|
181
|
+
'',
|
|
182
|
+
].join('\n');
|
|
183
|
+
const parts = [header];
|
|
184
|
+
let bytes = Buffer.byteLength(header) + Buffer.byteLength(tracked.stdout);
|
|
185
|
+
if (tracked.stdout.trim() !== '')
|
|
186
|
+
parts.push(tracked.stdout.endsWith('\n') ? tracked.stdout : `${tracked.stdout}\n`);
|
|
187
|
+
const skipped = [];
|
|
188
|
+
let written = 0;
|
|
189
|
+
for (const rel of untracked) {
|
|
190
|
+
const full = path.join(wt, rel);
|
|
191
|
+
let size = 0;
|
|
192
|
+
try {
|
|
193
|
+
const st = await fs.promises.lstat(full);
|
|
194
|
+
if (!st.isFile())
|
|
195
|
+
continue;
|
|
196
|
+
size = st.size;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (written >= WORKTREE_JANITOR_CONSTANTS.ARCHIVE_MAX_UNTRACKED_FILES || bytes + size > cap) {
|
|
202
|
+
skipped.push({ path: rel, bytes: size });
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const d = await git(['-C', wt, 'diff', '--no-index', '--binary', '--', '/dev/null', rel]);
|
|
206
|
+
// `--no-index` exits 1 when the files differ, which they always do here.
|
|
207
|
+
if (d.code !== 0 && d.code !== 1) {
|
|
208
|
+
skipped.push({ path: rel, bytes: size });
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const hunk = d.stdout.endsWith('\n') ? d.stdout : `${d.stdout}\n`;
|
|
212
|
+
const hunkBytes = Buffer.byteLength(hunk);
|
|
213
|
+
if (bytes + hunkBytes > cap) {
|
|
214
|
+
skipped.push({ path: rel, bytes: size });
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
parts.push(hunk);
|
|
218
|
+
bytes += hunkBytes;
|
|
219
|
+
written += 1;
|
|
220
|
+
}
|
|
221
|
+
if (skipped.length > 0) {
|
|
222
|
+
const trailer = ['', '# not included (over the archive cap):', ...skipped.map((s) => `# ${s.path} (${formatBytes(s.bytes)})`), ''].join('\n');
|
|
223
|
+
parts.push(trailer);
|
|
224
|
+
bytes += Buffer.byteLength(trailer);
|
|
225
|
+
}
|
|
226
|
+
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
227
|
+
await fs.promises.writeFile(file, parts.join(''), { flag: 'wx' });
|
|
228
|
+
return { file, bytes, trackedChanges: tracked.stdout.trim() !== '', untrackedFiles: written, skippedUntracked: skipped };
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Name of the ref that keeps an archived detached worktree's commits alive.
|
|
232
|
+
*
|
|
233
|
+
* @param worktreePath - The worktree
|
|
234
|
+
* @param now - Current epoch ms
|
|
235
|
+
* @returns `refs/crewly-archive/<name>-<date>`
|
|
236
|
+
*/
|
|
237
|
+
export function archiveKeepRef(worktreePath, now) {
|
|
238
|
+
const name = path.basename(worktreePath).replace(/[^A-Za-z0-9._-]+/g, '-');
|
|
239
|
+
return `${WORKTREE_JANITOR_CONSTANTS.ARCHIVE_REF_PREFIX}${name}-${dateStamp(now)}`;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The message to a lead when a worktree's regenerable dirs were stripped.
|
|
243
|
+
*
|
|
244
|
+
* @param f - Path, reason the worktree is kept, idle days, dirs, bytes
|
|
245
|
+
* @returns Message text
|
|
246
|
+
*/
|
|
247
|
+
export function buildStripNotice(f) {
|
|
248
|
+
const days = Math.floor(f.idleMs / (24 * 60 * 60 * 1000));
|
|
249
|
+
const why = f.reason === 'dirty' ? 'has uncommitted changes' : 'has work that is not merged';
|
|
250
|
+
return (`Worktree ${f.path} ${why} and nobody touched it for ${days} day${days === 1 ? '' : 's'}, so I removed its re-installable output ` +
|
|
251
|
+
`(${f.dirs.map((d) => path.relative(f.path, d) || path.basename(d)).join(', ')}; ${formatBytes(f.freedBytes)}). The source is untouched; run \`npm install\` before using it again. ` +
|
|
252
|
+
`If the work is finished, merge it and remove the worktree; after ${Math.round(WORKTREE_JANITOR_CONSTANTS.ARCHIVE_MIN_IDLE_MS / (24 * 60 * 60 * 1000))} days untouched it is saved as a patch and removed.`);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The message to a lead when a worktree was archived and removed.
|
|
256
|
+
*
|
|
257
|
+
* @param f - Path, branch, patch file, what the patch holds, idle days
|
|
258
|
+
* @returns Message text
|
|
259
|
+
*/
|
|
260
|
+
export function buildArchiveNotice(f) {
|
|
261
|
+
const days = Math.floor(f.idleMs / (24 * 60 * 60 * 1000));
|
|
262
|
+
const held = [];
|
|
263
|
+
if (f.patch.trackedChanges)
|
|
264
|
+
held.push('uncommitted changes to tracked files');
|
|
265
|
+
if (f.patch.untrackedFiles > 0)
|
|
266
|
+
held.push(`${f.patch.untrackedFiles} untracked file${f.patch.untrackedFiles === 1 ? '' : 's'}`);
|
|
267
|
+
const skipped = f.patch.skippedUntracked.length > 0 ? ` ${f.patch.skippedUntracked.length} file(s) were too large for the patch and are listed in its header.` : '';
|
|
268
|
+
const commits = f.commitsNotOnDefault && f.commitsNotOnDefault > 0
|
|
269
|
+
? f.branch
|
|
270
|
+
? ` Its ${f.commitsNotOnDefault} unmerged commit(s) are still on branch ${f.branch}.`
|
|
271
|
+
: f.keepRef
|
|
272
|
+
? ` Its ${f.commitsNotOnDefault} unmerged commit(s) are kept under ${f.keepRef}.`
|
|
273
|
+
: ''
|
|
274
|
+
: '';
|
|
275
|
+
return (`Worktree ${f.path} was untouched for ${days} days, so I archived and removed it. ` +
|
|
276
|
+
`Its ${held.length > 0 ? held.join(' and ') : 'working tree (nothing uncommitted)'} ${held.length > 0 ? 'are' : 'is'} saved in ${f.patch.file} (${formatBytes(f.patch.bytes)}).${commits}${skipped} ` +
|
|
277
|
+
'To continue: check out the branch in a new worktree and `git apply --3way` the patch.');
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=worktree-tiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-tiers.js","sourceRoot":"","sources":["../../../../../../backend/src/services/worktree/worktree-tiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAA8C,MAAM,2BAA2B,CAAC;AACpG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAkBxD,2BAA2B;AAC3B,MAAM,UAAU,cAAc;IAC7B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC9C,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IAChD,MAAM,CAAC,GAAG,GAAgD,CAAC;IAC3D,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAU,EAAE,CAAC;QACjE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,KAAK,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAA4B,CAAC,EAAE,CAAC;YACpE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACrE,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB,EAAE,GAAW,EAAE,QAA6B;IAC1F,MAAM,MAAM,GAAG,0BAA0B,CAAC,qBAAqB,CAAC;IAChE,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAChG,KAAK,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM;YAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAClG,KAAK,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACrH,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAA4G;IACtI,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAClJ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO,CAAC,KAAuE;IAC9F,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,KAAK,CAAC,MAAM,IAAI,0BAA0B,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IACrF,MAAM,UAAU,GACf,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAC9C,CAAC,CAAC,0BAA0B,CAAC,0BAA0B;QACvD,CAAC,CAAC,0BAA0B,CAAC,iBAAiB,CAAC;IACjD,OAAO,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,oDAAoD;AACpD,SAAS,SAAS,CAAC,GAAW;IAC7B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,QAAgB,EAAE,YAAoB,EAAE,GAAW;IACxG,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE,IAAI,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;QAAE,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3G,OAAO,SAAS,CAAC;AAClB,CAAC;AA4BD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAkB,EAAE,KAAyB,EAAE,IAAY,EAAE,GAAW;IAC/G,MAAM,GAAG,GAAG,0BAA0B,CAAC,uBAAuB,CAAC;IAC/D,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACnG,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAE3H,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC;IACzF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrG,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7F,MAAM,MAAM,GAAG;QACd,yCAAyC;QACzC,WAAW,KAAK,CAAC,QAAQ,EAAE;QAC3B,eAAe,EAAE,EAAE;QACnB,aAAa,KAAK,CAAC,MAAM,IAAI,eAAe,EAAE;QAC9C,WAAW,KAAK,CAAC,IAAI,IAAI,SAAS,EAAE;QACpC,cAAc,KAAK,CAAC,UAAU,IAAI,MAAM,GAAG,KAAK,CAAC,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,mBAAmB,8CAA8C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3Q,eAAe,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QAC5C,mCAAmC,KAAK,CAAC,IAAI,IAAI,QAAQ,iCAAiC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAC/G,EAAE;KACF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IAErH,MAAM,OAAO,GAA2C,EAAE,CAAC;IAC3D,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAChC,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,CAAC;YACJ,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC3B,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACR,SAAS;QACV,CAAC;QACD,IAAI,OAAO,IAAI,0BAA0B,CAAC,2BAA2B,IAAI,KAAK,GAAG,IAAI,GAAG,GAAG,EAAE,CAAC;YAC7F,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,SAAS;QACV,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1F,yEAAyE;QACzE,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,SAAS;QACV,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC;QAClE,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,SAAS;QACV,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,KAAK,IAAI,SAAS,CAAC;QACnB,OAAO,IAAI,CAAC,CAAC;IACd,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,CAAC,EAAE,EAAE,wCAAwC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChJ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AAC1H,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,GAAW;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IAC3E,OAAO,GAAG,0BAA0B,CAAC,kBAAkB,GAAG,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AACpF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAuF;IACvH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,6BAA6B,CAAC;IAC7F,OAAO,CACN,YAAY,CAAC,CAAC,IAAI,IAAI,GAAG,8BAA8B,IAAI,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,2CAA2C;QAClI,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,yEAAyE;QACrL,oEAAoE,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,mBAAmB,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,qDAAqD,CAC3M,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAkJ;IACpL,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc;QAAE,IAAI,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IAC9E,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,cAAc,kBAAkB,CAAC,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAChI,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,qEAAqE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpK,MAAM,OAAO,GACZ,CAAC,CAAC,mBAAmB,IAAI,CAAC,CAAC,mBAAmB,GAAG,CAAC;QACjD,CAAC,CAAC,CAAC,CAAC,MAAM;YACT,CAAC,CAAC,QAAQ,CAAC,CAAC,mBAAmB,2CAA2C,CAAC,CAAC,MAAM,GAAG;YACrF,CAAC,CAAC,CAAC,CAAC,OAAO;gBACV,CAAC,CAAC,QAAQ,CAAC,CAAC,mBAAmB,sCAAsC,CAAC,CAAC,OAAO,GAAG;gBACjF,CAAC,CAAC,EAAE;QACN,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,CACN,YAAY,CAAC,CAAC,IAAI,sBAAsB,IAAI,uCAAuC;QACnF,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,oCAAoC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,OAAO,GAAG,OAAO,GAAG;QACrM,uFAAuF,CACvF,CAAC;AACH,CAAC"}
|
|
@@ -2198,6 +2198,60 @@ export declare const WORK_RECORD_CONSTANTS: {
|
|
|
2198
2198
|
/** WorkItem types that are bookkeeping, never recorded. */
|
|
2199
2199
|
readonly SKIPPED_TYPES: readonly string[];
|
|
2200
2200
|
};
|
|
2201
|
+
/**
|
|
2202
|
+
* Memory-aware boot (crewly#1353). On 2026-10-17 a 16 GB Mac kernel-panicked
|
|
2203
|
+
* a minute after a Crewly restart: 10 agents restored back-to-back, then the
|
|
2204
|
+
* wiki, memory and work-record boot passes on fixed delays, while the machine
|
|
2205
|
+
* was already swapping. Pressure mode only engages after two 30 s samples,
|
|
2206
|
+
* so the boot restore reads the raw snapshot itself and the boot maintenance
|
|
2207
|
+
* passes wait for a quiet machine. Env overrides exist for the two memory
|
|
2208
|
+
* thresholds and the launch spacing.
|
|
2209
|
+
*/
|
|
2210
|
+
export declare const BOOT_PRESSURE_CONSTANTS: {
|
|
2211
|
+
/** Swap in use at or above this share counts as tight for the boot (`CREWLY_BOOT_PRESSURE_SWAP_PERCENT`). */
|
|
2212
|
+
readonly SWAP_USED_PERCENT: 80;
|
|
2213
|
+
/** Free memory below this counts as tight for the boot (`CREWLY_BOOT_PRESSURE_MIN_FREE_MB`). */
|
|
2214
|
+
readonly MIN_FREE_MB: number;
|
|
2215
|
+
/** Minimum gap between two boot launches, pressure or not, so RSS growth is visible before the next (`CREWLY_RESTORE_LAUNCH_SPACING_MS`). */
|
|
2216
|
+
readonly MIN_LAUNCH_SPACING_MS: number;
|
|
2217
|
+
/** Under pressure: how long after an agent registered its process counts as settled before the next launch. */
|
|
2218
|
+
readonly SETTLE_AFTER_READY_MS: number;
|
|
2219
|
+
/** Under pressure: how often the snapshot is re-read while a launch waits for the machine to calm down. */
|
|
2220
|
+
readonly PRESSURE_POLL_MS: number;
|
|
2221
|
+
/** A held launch is logged on the first poll and then every this many polls (once a minute at the default poll). */
|
|
2222
|
+
readonly PRESSURE_HOLD_LOG_EVERY_POLLS: 6;
|
|
2223
|
+
/** Under pressure: an owner-waiting agent waits at most this long for the machine to calm, then launches anyway. */
|
|
2224
|
+
readonly PRESSURE_HOLD_MAX_MS: number;
|
|
2225
|
+
/** Under pressure: at most this many boot launches in flight at once. */
|
|
2226
|
+
readonly PRESSURE_MAX_CONCURRENCY: 2;
|
|
2227
|
+
/** Boot maintenance passes re-check the restore queue and the snapshot this often. */
|
|
2228
|
+
readonly MAINTENANCE_POLL_MS: number;
|
|
2229
|
+
/** Boot maintenance passes give up waiting after this long and run reduced. */
|
|
2230
|
+
readonly MAINTENANCE_WAIT_MAX_MS: number;
|
|
2231
|
+
/** Work records written by the boot pass when it runs reduced (instead of CATCHUP_MAX_PER_PASS). */
|
|
2232
|
+
readonly WORK_RECORD_REDUCED_BATCH: 50;
|
|
2233
|
+
/** A vault log larger than this is rotated by streaming (tail read, header count) instead of being read whole. */
|
|
2234
|
+
readonly ROTATION_STREAM_BYTES: number;
|
|
2235
|
+
/** Bytes read from the end of a streamed log to pick the entries carried forward. */
|
|
2236
|
+
readonly ROTATION_TAIL_BYTES: number;
|
|
2237
|
+
/** Chunk size of the streaming entry count. */
|
|
2238
|
+
readonly ROTATION_CHUNK_BYTES: number;
|
|
2239
|
+
/** The owner gets one line when boot restores have been held back for longer than this. */
|
|
2240
|
+
readonly OWNER_NOTE_AFTER_MS: number;
|
|
2241
|
+
/**
|
|
2242
|
+
* Boot launches outside the restore queue (the deferred-start retry) are
|
|
2243
|
+
* held for memory at most this long after boot; afterwards the pressure
|
|
2244
|
+
* mode cap alone decides, because macOS swap stays full for hours after
|
|
2245
|
+
* the pressure is gone and a held agent is still owed something.
|
|
2246
|
+
*/
|
|
2247
|
+
readonly RETRY_HOLD_MAX_MS: number;
|
|
2248
|
+
/** Env override of SWAP_USED_PERCENT. */
|
|
2249
|
+
readonly ENV_SWAP_PERCENT: "CREWLY_BOOT_PRESSURE_SWAP_PERCENT";
|
|
2250
|
+
/** Env override of MIN_FREE_MB. */
|
|
2251
|
+
readonly ENV_MIN_FREE_MB: "CREWLY_BOOT_PRESSURE_MIN_FREE_MB";
|
|
2252
|
+
/** Env override of MIN_LAUNCH_SPACING_MS. */
|
|
2253
|
+
readonly ENV_LAUNCH_SPACING_MS: "CREWLY_RESTORE_LAUNCH_SPACING_MS";
|
|
2254
|
+
};
|
|
2201
2255
|
/**
|
|
2202
2256
|
* Startup briefing content (#1345): wiki pages, recent lessons and open
|
|
2203
2257
|
* owner threads an agent gets at registration, on top of its session memory.
|
|
@@ -2301,6 +2355,16 @@ export declare const WORKTREE_CONSTANTS: {
|
|
|
2301
2355
|
readonly INCLUDE_MAX_ENTRIES: 50;
|
|
2302
2356
|
/** Heavy directories symlinked (not copied) from the repo root when present and untracked. */
|
|
2303
2357
|
readonly DEFAULT_SHARED_DIRS: readonly string[];
|
|
2358
|
+
/**
|
|
2359
|
+
* Workspace packages' install dirs (`backend/node_modules`,
|
|
2360
|
+
* `packages/ui/node_modules`) are symlinked too when the lock file is
|
|
2361
|
+
* identical in repo and worktree (crewly#1354): searched this deep.
|
|
2362
|
+
*/
|
|
2363
|
+
readonly NESTED_INSTALL_DEPTH: 2;
|
|
2364
|
+
/** Lock files compared (first one present in the repo decides). */
|
|
2365
|
+
readonly LOCK_FILES: readonly string[];
|
|
2366
|
+
/** Directories never descended into while looking for nested install dirs. */
|
|
2367
|
+
readonly NESTED_INSTALL_SKIP_DIRS: readonly string[];
|
|
2304
2368
|
/** Marker line for the entries this feature adds to `.git/info/exclude`. */
|
|
2305
2369
|
readonly EXCLUDE_MARKER: "# crewly worktree shared paths (#814) — never commit these";
|
|
2306
2370
|
/** Timeout for local git commands (checkout of a large repo can take minutes under load). */
|
|
@@ -3135,7 +3199,7 @@ export declare const WORKTREE_JANITOR_CONSTANTS: {
|
|
|
3135
3199
|
/** Timeout of the `lsof` that finds a file's writers (ms). */
|
|
3136
3200
|
readonly RUNAWAY_LSOF_TIMEOUT_MS: 10000;
|
|
3137
3201
|
/** One line added to every agent's start prompt. */
|
|
3138
|
-
readonly PROMPT_HINT: "Disk hygiene: never let a command or script write an unbounded file. When you redirect or concatenate output (`> file`, `>> file`, `cat a b > all.md`), cap it (`| head -c 50M`, `| head -n 100000`) and never build a file from its own output. A file in your scratch dir or worktree that grows past a few GB is stopped by Crewly and the owner is alerted. Worktree hygiene: deploy only from a commit that is on main (merge first, never from a side branch); remove your worktree once its ticket is done.";
|
|
3202
|
+
readonly PROMPT_HINT: "Disk hygiene: never let a command or script write an unbounded file. When you redirect or concatenate output (`> file`, `>> file`, `cat a b > all.md`), cap it (`| head -c 50M`, `| head -n 100000`) and never build a file from its own output. A file in your scratch dir or worktree that grows past a few GB is stopped by Crewly and the owner is alerted. Worktree hygiene: deploy only from a commit that is on main (merge first, never from a side branch); remove your worktree once its ticket is done. In a new worktree, do not run `npm install` when package-lock.json is unchanged: symlink `node_modules` (root and per-package) from the main checkout instead (`ln -s <main>/node_modules node_modules`). Crewly strips node_modules from worktrees untouched for 3 days and archives untouched ones as a patch after 14 days.";
|
|
3139
3203
|
/** State file under CREWLY_HOME remembering when the owner was last told about low disk. */
|
|
3140
3204
|
readonly STATE_FILENAME: "disk-janitor-state.json";
|
|
3141
3205
|
/** File (in CREWLY_HOME) remembering which unmerged worktrees their lead was already told about. */
|
|
@@ -3174,7 +3238,11 @@ export declare const WORKTREE_JANITOR_CONSTANTS: {
|
|
|
3174
3238
|
readonly REGENERABLE_DIRS: readonly string[];
|
|
3175
3239
|
/** File suffixes treated as regenerable output (logs). */
|
|
3176
3240
|
readonly REGENERABLE_FILE_SUFFIXES: readonly string[];
|
|
3177
|
-
/**
|
|
3241
|
+
/**
|
|
3242
|
+
* Directories deleted from kept (dirty / not-merged) worktrees by the strip
|
|
3243
|
+
* tier — reinstalled by `npm install` / rebuilt by the build. A directory
|
|
3244
|
+
* git tracks anything under is never deleted (a repo that commits `dist`).
|
|
3245
|
+
*/
|
|
3178
3246
|
readonly RECLAIM_DIRS: readonly string[];
|
|
3179
3247
|
/** A kept worktree must be idle this long before its regenerable dirs are reclaimed under low disk (24 hours). */
|
|
3180
3248
|
readonly RECLAIM_MIN_IDLE_MS: number;
|
|
@@ -3200,6 +3268,66 @@ export declare const WORKTREE_JANITOR_CONSTANTS: {
|
|
|
3200
3268
|
readonly GH_PR_LIMIT: 20;
|
|
3201
3269
|
/** Max bytes of command output kept (stdout/stderr each). */
|
|
3202
3270
|
readonly MAX_OUTPUT_BYTES: number;
|
|
3271
|
+
/** A kept worktree untouched (no file, index or commit newer) for this long loses its regenerable dirs (3 days). */
|
|
3272
|
+
readonly STRIP_MIN_IDLE_MS: number;
|
|
3273
|
+
/** Under low disk, or once its WorkItem finished, the strip tier needs only this much idle (1 day). */
|
|
3274
|
+
readonly STRIP_MIN_IDLE_LOW_DISK_MS: number;
|
|
3275
|
+
/** A kept worktree untouched for this long is archived as a patch and removed (14 days). */
|
|
3276
|
+
readonly ARCHIVE_MIN_IDLE_MS: number;
|
|
3277
|
+
/** Directory under CREWLY_HOME holding archived worktree patches (`<repo>/<name>-<date>.patch`). */
|
|
3278
|
+
readonly ARCHIVE_DIR: "worktree-archive";
|
|
3279
|
+
/** Cap on one archive patch; untracked files that would push it past the cap are listed in the header instead (64 MB). */
|
|
3280
|
+
readonly ARCHIVE_PATCH_MAX_BYTES: number;
|
|
3281
|
+
/** Cap on untracked files written into one archive patch. */
|
|
3282
|
+
readonly ARCHIVE_MAX_UNTRACKED_FILES: 2000;
|
|
3283
|
+
/** Ref namespace that keeps the commits of an archived detached worktree alive (`refs/crewly-archive/<name>-<date>`). */
|
|
3284
|
+
readonly ARCHIVE_REF_PREFIX: "refs/crewly-archive/";
|
|
3285
|
+
/** How many levels below a worktree root count for its "last touched" time in the tier decision. */
|
|
3286
|
+
readonly TIER_MTIME_DEPTH: 2;
|
|
3287
|
+
/** State file under CREWLY_HOME: per-worktree strip / archive / finished-work timestamps. */
|
|
3288
|
+
readonly TIER_STATE_FILENAME: "worktree-tiers.json";
|
|
3289
|
+
/** Finished-work records (task-end hook) older than this are dropped from the state file (30 days). */
|
|
3290
|
+
readonly TIER_STATE_MAX_AGE_MS: number;
|
|
3291
|
+
/**
|
|
3292
|
+
* Every delete added in crewly#1354 (strip, archive, transcripts, tmp, logs)
|
|
3293
|
+
* is dry-run only until this long after the first real pass that saw it
|
|
3294
|
+
* (one day): the first pass logs what it would do, the next day it does it.
|
|
3295
|
+
*/
|
|
3296
|
+
readonly RETENTION_ARM_DELAY_MS: number;
|
|
3297
|
+
/** An agent transcript (and its sibling tool-results dir) untouched for this long is pruned (14 days). */
|
|
3298
|
+
readonly TRANSCRIPT_MAX_AGE_MS: number;
|
|
3299
|
+
/** The transcript sweep runs at most this often (24 hours). */
|
|
3300
|
+
readonly TRANSCRIPT_SWEEP_INTERVAL_MS: number;
|
|
3301
|
+
/** Bytes read from the head of a transcript to find Claude Code's `agentSetting` entry. */
|
|
3302
|
+
readonly TRANSCRIPT_HEAD_BYTES: number;
|
|
3303
|
+
/** Handover files newer than this are scanned for conversation ids (30 days). */
|
|
3304
|
+
readonly TRANSCRIPT_HANDOVER_SCAN_MAX_AGE_MS: number;
|
|
3305
|
+
/** Kinds that handover file names carry between the session name and the timestamp (`<session>-<kind>-<ISO>.md`). */
|
|
3306
|
+
readonly HANDOVER_KINDS: readonly string[];
|
|
3307
|
+
/** Sub-directory of a Claude home that holds per-cwd transcript folders. */
|
|
3308
|
+
readonly TRANSCRIPT_PROJECTS_DIR: "projects";
|
|
3309
|
+
/** Transcript file extension. */
|
|
3310
|
+
readonly TRANSCRIPT_EXT: ".jsonl";
|
|
3311
|
+
/** Directory under CREWLY_HOME that agents and skills use as scratch space. */
|
|
3312
|
+
readonly TMP_DIR: "tmp";
|
|
3313
|
+
/** A top-level entry of CREWLY_HOME/tmp untouched for this long is removed (7 days). */
|
|
3314
|
+
readonly TMP_MAX_AGE_MS: number;
|
|
3315
|
+
/** Sub-directories of CREWLY_HOME/tmp swept per child with their own age (ms); the directory itself stays. */
|
|
3316
|
+
readonly TMP_CHILD_POLICIES: Readonly<Record<string, number>>;
|
|
3317
|
+
/** How many levels below a tmp entry count for its "last touched" time. */
|
|
3318
|
+
readonly TMP_MTIME_DEPTH: 2;
|
|
3319
|
+
/** The tmp / logs sweep runs at most this often (6 hours). */
|
|
3320
|
+
readonly TMP_SWEEP_INTERVAL_MS: number;
|
|
3321
|
+
/** Cap on CREWLY_HOME/logs/archive; the oldest archives go first (300 MB). */
|
|
3322
|
+
readonly LOG_ARCHIVE_CAP_BYTES: number;
|
|
3323
|
+
/** Cap on CREWLY_HOME/logs/sessions; the oldest logs of sessions that are not live go first (100 MB). */
|
|
3324
|
+
readonly LOG_SESSIONS_CAP_BYTES: number;
|
|
3325
|
+
/** A log written within this long is never deleted by the cap (1 hour). */
|
|
3326
|
+
readonly LOG_CAP_MIN_AGE_MS: number;
|
|
3327
|
+
/** Low disk is free < max(LOW_DISK_BYTES, this fraction of the disk) (8 %). */
|
|
3328
|
+
readonly LOW_DISK_FRACTION: 0.08;
|
|
3329
|
+
/** Critical is free < max(CRITICAL_DISK_BYTES, this fraction of the disk) (3 %). */
|
|
3330
|
+
readonly CRITICAL_DISK_FRACTION: 0.03;
|
|
3203
3331
|
};
|
|
3204
3332
|
/**
|
|
3205
3333
|
* Constants for cron next-run computation (`getNextRunTime`).
|