@logicseek/hello-cc 1.0.0 → 1.0.2-dsh.3
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 +149 -0
- package/README.md +36 -0
- package/README.zh-CN.md +35 -0
- package/docs/README.md +9 -0
- package/docs/README.zh-CN.md +9 -0
- package/docs/commands.md +53 -0
- package/docs/commands.zh-CN.md +48 -0
- package/docs/dsh.md +137 -0
- package/docs/dsh.zh-CN.md +139 -0
- package/docs/guide.md +58 -0
- package/docs/guide.zh-CN.md +55 -0
- package/docs/mcp.md +9 -0
- package/docs/mcp.zh-CN.md +23 -0
- package/docs/native.md +295 -0
- package/docs/native.zh-CN.md +253 -0
- package/docs/web-handoff.zh-CN.md +53 -0
- package/lib/cli/app.mjs +27 -6
- package/lib/cli/commands/coordination.mjs +3 -1
- package/lib/cli/commands/doctor.mjs +17 -2
- package/lib/cli/commands/dsh.mjs +79 -0
- package/lib/cli/commands/gc.mjs +182 -32
- package/lib/cli/commands/hook.mjs +241 -90
- package/lib/cli/commands/lock.mjs +34 -19
- package/lib/cli/commands/mcp.mjs +28 -0
- package/lib/cli/commands/misc.mjs +15 -0
- package/lib/cli/commands/native.mjs +130 -0
- package/lib/cli/commands/peer.mjs +21 -5
- package/lib/cli/commands/run.mjs +66 -21
- package/lib/cli/commands/task.mjs +6 -3
- package/lib/cli-args.mjs +4 -0
- package/lib/coordination-state.mjs +15 -1
- package/lib/core/coordination/event-retention.mjs +14 -2
- package/lib/core/coordination/gc-plan.mjs +3 -13
- package/lib/core/coordination/locks.mjs +45 -0
- package/lib/core/coordination/results.mjs +79 -0
- package/lib/core/peers/bindings.mjs +9 -3
- package/lib/diagnostics/codex.mjs +121 -0
- package/lib/integrations/codex-interactions.mjs +114 -0
- package/lib/integrations/dsh-collaboration.mjs +170 -0
- package/lib/integrations/dsh-cordis.d.ts +19 -0
- package/lib/integrations/dsh-cordis.mjs +177 -0
- package/lib/integrations/dsh.bundle.yml +7 -0
- package/lib/integrations/dsh.mjs +287 -0
- package/lib/integrations/native/claude.mjs +451 -0
- package/lib/integrations/native/codex.mjs +242 -0
- package/lib/integrations/native/dsh-acp.mjs +343 -0
- package/lib/integrations/native/index.mjs +19 -0
- package/lib/integrations/native/interactions.mjs +53 -0
- package/lib/integrations/native/jsonrpc.mjs +185 -0
- package/lib/integrations/peers/identity.mjs +36 -10
- package/lib/integrations/peers/processes.mjs +22 -8
- package/lib/integrations/providers.mjs +6 -2
- package/lib/mcp/scope.mjs +104 -0
- package/lib/mcp/stdio.mjs +80 -0
- package/lib/mcp/tools.mjs +197 -0
- package/lib/process/identity.mjs +33 -1
- package/lib/release/release-notes.mjs +9 -0
- package/lib/runtime/buffer-directory-lease.mjs +2 -1
- package/lib/runtime/client.mjs +3 -0
- package/lib/runtime/native/client.mjs +38 -0
- package/lib/runtime/native/service.mjs +511 -0
- package/lib/runtime/native/store.mjs +121 -0
- package/lib/shared/file-lock.mjs +11 -4
- package/lib/shared/socket-lock-worker.mjs +73 -24
- package/lib/terminal/tmux.mjs +53 -23
- package/lib/ui/help.mjs +5 -2
- package/lib/web/adoption-state.mjs +55 -0
- package/lib/web/auto-attach.mjs +18 -2
- package/lib/web/buffer-gc-runtime.mjs +2 -2
- package/lib/web/codex-app-server.mjs +557 -0
- package/lib/web/codex-sessions.mjs +287 -0
- package/lib/web/control-lease.mjs +204 -0
- package/lib/web/http-routes.mjs +197 -15
- package/lib/web/http.mjs +5 -4
- package/lib/web/native-sessions.mjs +286 -0
- package/lib/web/project-contexts.mjs +8 -2
- package/lib/web/pty-sessions.mjs +60 -33
- package/lib/web/runtime-main.mjs +101 -6
- package/lib/web/session-serialize.mjs +0 -0
- package/lib/web/startup.mjs +4 -2
- package/lib/web/task-results.mjs +76 -0
- package/lib/web/tmux-sessions.mjs +92 -11
- package/lib/web/tmux-stream.mjs +2 -2
- package/lib/web/ui-codex.mjs +550 -0
- package/lib/web/ui-command-palette.mjs +119 -0
- package/lib/web/ui-handoff.mjs +102 -0
- package/lib/web/ui-history.mjs +118 -0
- package/lib/web/ui-i18n.mjs +841 -0
- package/lib/web/ui-interactions.mjs +78 -0
- package/lib/web/ui-login.mjs +101 -0
- package/lib/web/ui-native.mjs +165 -0
- package/lib/web/ui-preferences.mjs +278 -0
- package/lib/web/ui-review.mjs +132 -0
- package/lib/web/ui-template.mjs +1106 -576
- package/lib/web/ui-terminal-find.mjs +98 -0
- package/lib/web/ui-workbench.mjs +94 -0
- package/lib/web/ui-workspace.mjs +222 -0
- package/package.json +12 -4
- package/scripts/check-free-identifiers.mjs +67 -8
- package/scripts/codex-diagnostics-installed-acceptance.mjs +72 -0
- package/scripts/dsh-cordis-acceptance.mjs +200 -0
- package/scripts/dsh-installed-acceptance.mjs +247 -0
- package/scripts/dsh-official-acceptance.mjs +180 -0
- package/scripts/dsh-web-startup-acceptance.mjs +87 -0
- package/scripts/github-release.mjs +3 -1
- package/scripts/native-live-acceptance.mjs +369 -0
- package/scripts/regression.mjs +338 -187
- package/scripts/web-handoff-installed-acceptance.mjs +98 -0
- package/scripts/web-native-interaction-acceptance.mjs +204 -0
- package/scripts/web-native-model-acceptance.mjs +138 -0
- package/docs/architecture-split-review.md +0 -217
- package/docs/current-state-review-2026-08.md +0 -341
- package/docs/defect-review-2026-07.md +0 -382
- package/docs/layout-split-stack-audit.md +0 -298
- package/docs/superpowers/plans/2026-08-03-runtime-safety-plan.md +0 -294
- package/docs/superpowers/plans/2026-08-03-v1-data-identity-plan.md +0 -400
- package/docs/superpowers/plans/2026-08-03-v1-release-verification-plan.md +0 -284
- package/docs/superpowers/plans/2026-08-03-web-api-hardening-plan.md +0 -303
- package/docs/superpowers/plans/2026-08-04-runtime-buffer-gc-two-phase.md +0 -71
- package/docs/superpowers/specs/2026-08-03-runtime-safety-design.md +0 -117
- package/docs/superpowers/specs/2026-08-03-v1-data-identity-design.md +0 -120
- package/docs/superpowers/specs/2026-08-03-v1-release-verification-design.md +0 -117
- package/docs/superpowers/specs/2026-08-03-web-api-hardening-design.md +0 -104
package/lib/cli/commands/gc.mjs
CHANGED
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
} from '../../runtime/buffer-gc.mjs';
|
|
40
40
|
import { applyClockSafeBufferPlan } from '../../runtime/buffer-gc-protocol.mjs';
|
|
41
41
|
|
|
42
|
+
export const RUNTIME_BUFFER_GC_TIMEOUT_MS = 30_000;
|
|
43
|
+
|
|
42
44
|
export function createGcCommands(deps) {
|
|
43
45
|
const {
|
|
44
46
|
connect, now, helpGc,
|
|
@@ -109,7 +111,8 @@ function observeGcClockSafety(ctx, db, {
|
|
|
109
111
|
observedAt,
|
|
110
112
|
historyCategories,
|
|
111
113
|
includeStalePeers,
|
|
112
|
-
historySnapshot
|
|
114
|
+
historySnapshot,
|
|
115
|
+
bufferPathGuard = null
|
|
113
116
|
}) {
|
|
114
117
|
try {
|
|
115
118
|
return runOptimisticEvidenceMutation(db, {
|
|
@@ -124,10 +127,13 @@ function observeGcClockSafety(ctx, db, {
|
|
|
124
127
|
}),
|
|
125
128
|
observe: (subject) => observeGcEvidence(ctx, subject),
|
|
126
129
|
same: (left, right) => JSON.stringify(left) === JSON.stringify(right),
|
|
127
|
-
beforeMutate: (subject, evidenceByOwner) =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
beforeMutate: (subject, evidenceByOwner) => {
|
|
131
|
+
if (bufferPathGuard) assertBufferDirectoryPathUnchanged(bufferPathGuard);
|
|
132
|
+
return observeClockSafetyInTransactionOrThrow(
|
|
133
|
+
db,
|
|
134
|
+
gcClockSafetyOptions(subject, evidenceByOwner, olderThanDays)
|
|
135
|
+
);
|
|
136
|
+
},
|
|
131
137
|
changedMessage: 'GC subjects changed while clock evidence was being observed; retry',
|
|
132
138
|
mutate: (subject, evidenceByOwner, observation) => ({
|
|
133
139
|
...observation,
|
|
@@ -192,6 +198,128 @@ function previewGcClockSafety(ctx, db, options) {
|
|
|
192
198
|
}
|
|
193
199
|
}
|
|
194
200
|
|
|
201
|
+
function bufferDirectoryPathForbidden(message, directory) {
|
|
202
|
+
return new CliError('PROJECT_PATH_FORBIDDEN', `${message}: ${directory}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function assertBufferDirectoryPathUnchanged(captured) {
|
|
206
|
+
let resolvedRoot;
|
|
207
|
+
try {
|
|
208
|
+
resolvedRoot = fs.realpathSync.native(captured.requestedRoot);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
211
|
+
throw bufferDirectoryPathForbidden(
|
|
212
|
+
'Project root changed during buffer GC',
|
|
213
|
+
captured.requestedRoot
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (resolvedRoot !== captured.canonicalRoot) {
|
|
217
|
+
throw bufferDirectoryPathForbidden(
|
|
218
|
+
'Project root changed during buffer GC',
|
|
219
|
+
captured.requestedRoot
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
for (const component of captured.components) {
|
|
223
|
+
let current;
|
|
224
|
+
try {
|
|
225
|
+
current = fs.lstatSync(component.path);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
228
|
+
throw bufferDirectoryPathForbidden(
|
|
229
|
+
'Buffer directory path changed during lease acquisition',
|
|
230
|
+
captured.directory
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
if (current.isSymbolicLink() || !current.isDirectory() ||
|
|
234
|
+
current.dev !== component.stat.dev || current.ino !== component.stat.ino) {
|
|
235
|
+
throw bufferDirectoryPathForbidden(
|
|
236
|
+
'Buffer directory path changed during lease acquisition',
|
|
237
|
+
captured.directory
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (!captured.exists) {
|
|
242
|
+
try {
|
|
243
|
+
fs.lstatSync(captured.directory);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
if (error?.code === 'ENOENT') return;
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
throw bufferDirectoryPathForbidden(
|
|
249
|
+
'Buffer directory path changed during lease acquisition',
|
|
250
|
+
captured.directory
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function captureRequiredBufferDirectoryComponent(component, description) {
|
|
256
|
+
const stat = fs.lstatSync(component);
|
|
257
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
258
|
+
throw bufferDirectoryPathForbidden(`${description} must be a real directory`, component);
|
|
259
|
+
}
|
|
260
|
+
return { path: component, stat };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function captureOptionalBufferDirectory(root, directoryName) {
|
|
264
|
+
const requestedRoot = path.resolve(root);
|
|
265
|
+
const canonicalRoot = fs.realpathSync.native(requestedRoot);
|
|
266
|
+
const stateDirectory = path.join(canonicalRoot, '.hello-cc');
|
|
267
|
+
const directory = path.join(stateDirectory, directoryName);
|
|
268
|
+
const components = [
|
|
269
|
+
captureRequiredBufferDirectoryComponent(canonicalRoot, 'Project root'),
|
|
270
|
+
captureRequiredBufferDirectoryComponent(stateDirectory, 'Project state directory')
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
let stat;
|
|
274
|
+
try {
|
|
275
|
+
stat = fs.lstatSync(directory);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (error?.code === 'ENOENT') {
|
|
278
|
+
const captured = {
|
|
279
|
+
requestedRoot,
|
|
280
|
+
canonicalRoot,
|
|
281
|
+
directory,
|
|
282
|
+
components,
|
|
283
|
+
exists: false
|
|
284
|
+
};
|
|
285
|
+
assertBufferDirectoryPathUnchanged(captured);
|
|
286
|
+
return captured;
|
|
287
|
+
}
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
291
|
+
throw bufferDirectoryPathForbidden('Buffer directory must be a real directory', directory);
|
|
292
|
+
}
|
|
293
|
+
components.push({ path: directory, stat });
|
|
294
|
+
return { requestedRoot, canonicalRoot, directory, components, exists: true };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function collectGuardedBufferEvidence(collector, captured) {
|
|
298
|
+
const evidence = collector(captured.directory);
|
|
299
|
+
assertBufferDirectoryPathUnchanged(captured);
|
|
300
|
+
return evidence;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function withOptionalBufferDirectoryLease(captured, callback) {
|
|
304
|
+
assertBufferDirectoryPathUnchanged(captured);
|
|
305
|
+
if (!captured.exists) return null;
|
|
306
|
+
return withBufferDirectoryLease(captured.directory, (leasedDirectory) => {
|
|
307
|
+
const assertDirectoryUnchanged = () => {
|
|
308
|
+
assertBufferDirectoryPathUnchanged(captured);
|
|
309
|
+
if (fs.realpathSync.native(captured.directory) !== leasedDirectory) {
|
|
310
|
+
throw bufferDirectoryPathForbidden(
|
|
311
|
+
'Buffer directory path changed during lease acquisition',
|
|
312
|
+
captured.directory
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
assertDirectoryUnchanged();
|
|
317
|
+
const result = callback(leasedDirectory, assertDirectoryUnchanged);
|
|
318
|
+
assertDirectoryUnchanged();
|
|
319
|
+
return result;
|
|
320
|
+
}, { createParent: false });
|
|
321
|
+
}
|
|
322
|
+
|
|
195
323
|
function runGc(ctx, db, {
|
|
196
324
|
olderThanDays = 7,
|
|
197
325
|
dryRun = false,
|
|
@@ -203,6 +331,9 @@ function runGc(ctx, db, {
|
|
|
203
331
|
history = false,
|
|
204
332
|
observedAt = null
|
|
205
333
|
} = {}) {
|
|
334
|
+
const bufferPathGuard = skipBufferFiles
|
|
335
|
+
? null
|
|
336
|
+
: captureOptionalBufferDirectory(ctx.root, BUFS_DIR_NAME);
|
|
206
337
|
const auto = scope === 'auto';
|
|
207
338
|
const historyCategories = auto ? ['events'] : ['events', 'tasks', 'messages', 'handoffs'];
|
|
208
339
|
const applyHistory = auto || history;
|
|
@@ -213,16 +344,19 @@ function runGc(ctx, db, {
|
|
|
213
344
|
: gcNow * 1000 - (auto ? Math.min(olderThanDays, 7) : olderThanDays) * 86400000;
|
|
214
345
|
const bufferRetentionSec = (auto ? Math.min(olderThanDays, 7) : olderThanDays) * 86400;
|
|
215
346
|
const preparedBufferEvidence = !skipBufferFiles && collectBufferEvidenceNow
|
|
216
|
-
? collectBufferEvidenceNow
|
|
347
|
+
? collectGuardedBufferEvidence(collectBufferEvidenceNow, bufferPathGuard)
|
|
217
348
|
: null;
|
|
218
|
-
const bufferGcCutoffs =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
349
|
+
const bufferGcCutoffs = skipBufferFiles
|
|
350
|
+
? []
|
|
351
|
+
: bufferDirectoryPaths(bufferPathGuard.directory).flatMap((file) => {
|
|
352
|
+
try {
|
|
353
|
+
const stat = fs.lstatSync(file);
|
|
354
|
+
return [Math.max(0, Math.floor(stat.mtimeMs / 1000) + bufferRetentionSec)];
|
|
355
|
+
} catch {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
if (bufferPathGuard) assertBufferDirectoryPathUnchanged(bufferPathGuard);
|
|
226
360
|
bufferGcCutoffs.push(...(preparedBufferEvidence?.gcCutoffs || []));
|
|
227
361
|
const historySnapshot = createHistoryGcSnapshot(db, gcNow - retentionSec, {
|
|
228
362
|
categories: historyCategories,
|
|
@@ -245,7 +379,8 @@ function runGc(ctx, db, {
|
|
|
245
379
|
bufferGcCutoffs,
|
|
246
380
|
historyCategories,
|
|
247
381
|
gcNow,
|
|
248
|
-
historySnapshot
|
|
382
|
+
historySnapshot,
|
|
383
|
+
bufferPathGuard
|
|
249
384
|
}),
|
|
250
385
|
'History GC run'
|
|
251
386
|
);
|
|
@@ -266,6 +401,7 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
266
401
|
historyCategories,
|
|
267
402
|
gcNow,
|
|
268
403
|
historySnapshot,
|
|
404
|
+
bufferPathGuard = null,
|
|
269
405
|
clockObservation: preparedClockObservation = null,
|
|
270
406
|
forceDefer = false
|
|
271
407
|
}) {
|
|
@@ -275,17 +411,23 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
275
411
|
observedAt: gcNow,
|
|
276
412
|
historyCategories,
|
|
277
413
|
includeStalePeers: !auto,
|
|
278
|
-
historySnapshot
|
|
414
|
+
historySnapshot,
|
|
415
|
+
bufferPathGuard
|
|
279
416
|
});
|
|
280
417
|
const graceActive = forceDefer || clockGraceSuppressed(gcNow, clockObservation.graceUntil);
|
|
281
418
|
let databaseGraceActive = graceActive;
|
|
282
419
|
const beforeDatabaseMutate = () => {
|
|
420
|
+
if (bufferPathGuard) assertBufferDirectoryPathUnchanged(bufferPathGuard);
|
|
283
421
|
if (databaseGraceActive) return false;
|
|
284
422
|
try {
|
|
285
423
|
const observedAt = now();
|
|
286
424
|
const allowed = !clockGraceSuppressed(observedAt, readClockGraceUntil(db));
|
|
287
|
-
if (!allowed)
|
|
288
|
-
|
|
425
|
+
if (!allowed) {
|
|
426
|
+
databaseGraceActive = true;
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
if (bufferPathGuard) assertBufferDirectoryPathUnchanged(bufferPathGuard);
|
|
430
|
+
return true;
|
|
289
431
|
} catch (error) {
|
|
290
432
|
if (error instanceof CliError) throw error;
|
|
291
433
|
throw clockSafetyUnavailable(error);
|
|
@@ -325,14 +467,16 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
325
467
|
const bufCutoffMs = Number.isFinite(bufferCutoffMs)
|
|
326
468
|
? bufferCutoffMs
|
|
327
469
|
: gcNow * 1000 - (auto ? Math.min(olderThanDays, 7) : olderThanDays) * 86400000;
|
|
328
|
-
const bufsDir = path.join(ctx.root, '.hello-cc', BUFS_DIR_NAME);
|
|
329
470
|
if (!graceActive && !skipBufferFiles) {
|
|
330
|
-
const bufferResult =
|
|
471
|
+
const bufferResult = withOptionalBufferDirectoryLease(bufferPathGuard, (
|
|
472
|
+
leasedBufsDir,
|
|
473
|
+
assertDirectoryUnchanged
|
|
474
|
+
) => {
|
|
331
475
|
const currentEvidence = collectBufferEvidenceNow
|
|
332
|
-
? collectBufferEvidenceNow
|
|
476
|
+
? collectGuardedBufferEvidence(collectBufferEvidenceNow, bufferPathGuard)
|
|
333
477
|
: preparedBufferEvidence || { protectedPaths: protectedBuffers, unknownPaths: new Set(), gcCutoffs: [] };
|
|
334
478
|
const currentPlan = planBufferFiles({
|
|
335
|
-
directories: [
|
|
479
|
+
directories: [leasedBufsDir],
|
|
336
480
|
cutoffMs: bufCutoffMs,
|
|
337
481
|
protectedPaths: currentEvidence.protectedPaths,
|
|
338
482
|
unknownPaths: currentEvidence.unknownPaths,
|
|
@@ -341,12 +485,16 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
341
485
|
...(currentEvidence.gcCutoffs || [])
|
|
342
486
|
]
|
|
343
487
|
});
|
|
488
|
+
assertDirectoryUnchanged();
|
|
344
489
|
const currentObservedAt = now();
|
|
345
|
-
const currentObservation = tx(db, () =>
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
490
|
+
const currentObservation = tx(db, () => {
|
|
491
|
+
assertDirectoryUnchanged();
|
|
492
|
+
return observeClockSafetyInTransaction(db, {
|
|
493
|
+
operation: 'gc',
|
|
494
|
+
gcCutoffs: bufferPlanGcCutoffs(currentPlan, bufferRetentionSec),
|
|
495
|
+
nowSec: currentObservedAt
|
|
496
|
+
});
|
|
497
|
+
});
|
|
350
498
|
if (clockGraceSuppressed(currentObservedAt, currentObservation.graceUntil)) {
|
|
351
499
|
databaseGraceActive = true;
|
|
352
500
|
return deferBufferPlan(currentPlan);
|
|
@@ -360,9 +508,11 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
360
508
|
}
|
|
361
509
|
return applyBufferPlan(currentPlan);
|
|
362
510
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
511
|
+
if (bufferResult !== null) {
|
|
512
|
+
results.buf_files = bufferResult.deleted;
|
|
513
|
+
results.protected_buf_files = bufferResult.protected;
|
|
514
|
+
results.deferred_buf_files = bufferResult.deferred;
|
|
515
|
+
}
|
|
366
516
|
}
|
|
367
517
|
|
|
368
518
|
// A clock jump can make every lock look expired at once. Preserve those rows
|
|
@@ -589,7 +739,7 @@ async function prepareManualBufferGc(ctx, db, { retentionSec, dryRun }) {
|
|
|
589
739
|
phase: 'prepare',
|
|
590
740
|
retentionSec,
|
|
591
741
|
dryRun
|
|
592
|
-
}, runtime, { timeoutMs:
|
|
742
|
+
}, runtime, { timeoutMs: RUNTIME_BUFFER_GC_TIMEOUT_MS });
|
|
593
743
|
return {
|
|
594
744
|
mode: 'runtime',
|
|
595
745
|
runtime,
|
|
@@ -668,7 +818,7 @@ async function applyManualBufferGc(ctx, db, prepared, { dryRun, graceActive }) {
|
|
|
668
818
|
const applied = await runtimeRequest(ctx, 'POST', '/api/runtime/gc-buffers', {
|
|
669
819
|
phase: 'apply',
|
|
670
820
|
token: prepared.token
|
|
671
|
-
}, prepared.runtime, { timeoutMs:
|
|
821
|
+
}, prepared.runtime, { timeoutMs: RUNTIME_BUFFER_GC_TIMEOUT_MS });
|
|
672
822
|
const counts = requireBufferGcResult(applied);
|
|
673
823
|
if (typeof applied?.complete !== 'boolean' || typeof applied?.graceActive !== 'boolean') {
|
|
674
824
|
throw new CliError('RUNTIME_BAD_RESPONSE', 'Runtime buffer GC returned invalid completion state');
|