@hominis/fireforge 0.13.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/dist/bin/fireforge.js +19 -5
- package/dist/src/commands/config.js +7 -1
- package/dist/src/commands/discard.js +6 -1
- package/dist/src/commands/doctor.d.ts +12 -0
- package/dist/src/commands/doctor.js +6 -1
- package/dist/src/commands/download.js +106 -7
- package/dist/src/commands/export-shared.js +7 -0
- package/dist/src/commands/export.js +5 -0
- package/dist/src/commands/furnace/apply.js +147 -47
- package/dist/src/commands/furnace/create.js +13 -2
- package/dist/src/commands/furnace/deploy.js +17 -2
- package/dist/src/commands/furnace/diff.js +3 -1
- package/dist/src/commands/furnace/init.js +25 -7
- package/dist/src/commands/furnace/list.js +15 -7
- package/dist/src/commands/furnace/override.js +47 -15
- package/dist/src/commands/furnace/remove.js +68 -20
- package/dist/src/commands/furnace/rename.js +31 -3
- package/dist/src/commands/furnace/scan.js +8 -0
- package/dist/src/commands/furnace/validate.js +70 -7
- package/dist/src/commands/import.js +65 -11
- package/dist/src/commands/re-export.js +11 -4
- package/dist/src/commands/rebase/abort.js +26 -14
- package/dist/src/commands/rebase/confirm.d.ts +15 -2
- package/dist/src/commands/rebase/confirm.js +2 -2
- package/dist/src/commands/rebase/continue.js +39 -15
- package/dist/src/commands/rebase/index.js +2 -1
- package/dist/src/commands/rebase/patch-loop.js +90 -33
- package/dist/src/commands/register.js +13 -0
- package/dist/src/commands/resolve.js +31 -10
- package/dist/src/commands/run.js +9 -44
- package/dist/src/commands/setup-support.js +25 -7
- package/dist/src/commands/status.js +59 -8
- package/dist/src/commands/test.js +13 -7
- package/dist/src/commands/token.js +11 -1
- package/dist/src/commands/watch.js +51 -1
- package/dist/src/commands/wire.js +23 -0
- package/dist/src/core/config-validate.js +15 -1
- package/dist/src/core/furnace-registration.d.ts +1 -1
- package/dist/src/core/furnace-registration.js +2 -1
- package/dist/src/core/furnace-staleness.d.ts +17 -0
- package/dist/src/core/furnace-staleness.js +58 -0
- package/dist/src/core/signal-critical.d.ts +49 -0
- package/dist/src/core/signal-critical.js +80 -0
- package/dist/src/errors/download.d.ts +1 -1
- package/dist/src/errors/download.js +6 -3
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Signal-deferred critical sections.
|
|
4
|
+
*
|
|
5
|
+
* Commands that perform a compound mutation (e.g. "apply a patch to the
|
|
6
|
+
* engine, then persist progress to a session file on disk") need to finish
|
|
7
|
+
* the pair atomically with respect to SIGINT / SIGTERM. The furnace rollback
|
|
8
|
+
* mechanism is not the right tool here: rebase-style operations intentionally
|
|
9
|
+
* leave the engine mutated and only need the on-disk bookkeeping write to
|
|
10
|
+
* complete before the process exits.
|
|
11
|
+
*
|
|
12
|
+
* `runInSignalCriticalSection(fn)` wraps a short body in a registry slot.
|
|
13
|
+
* While the body runs, the CLI entry point's SIGINT / SIGTERM handlers wait
|
|
14
|
+
* for the slot to clear before calling `process.exit`, so a signal that
|
|
15
|
+
* lands mid-body is held until the body's state write finishes.
|
|
16
|
+
*
|
|
17
|
+
* This module is a pure runtime registry — it installs no signal handlers
|
|
18
|
+
* itself. The bin entry point is responsible for awaiting
|
|
19
|
+
* `waitForActiveCriticalSections` before terminating.
|
|
20
|
+
*/
|
|
21
|
+
const activeSections = new Set();
|
|
22
|
+
/**
|
|
23
|
+
* Runs `fn` inside a signal-deferred critical section. The CLI entry point's
|
|
24
|
+
* signal handlers `await` every active section before exiting, so a SIGINT or
|
|
25
|
+
* SIGTERM that arrives during `fn` will hold exit until `fn` returns (or
|
|
26
|
+
* rejects).
|
|
27
|
+
*
|
|
28
|
+
* `fn` should be short — anything that takes longer than the bounded wait in
|
|
29
|
+
* the bin handler (`SIGNAL_CRITICAL_SECTION_TIMEOUT_MS`) will time out and
|
|
30
|
+
* the handler will exit anyway. The intent is "guard the apply + state
|
|
31
|
+
* persist pair," not "postpone exit indefinitely."
|
|
32
|
+
*/
|
|
33
|
+
export async function runInSignalCriticalSection(label, fn) {
|
|
34
|
+
let resolver = () => undefined;
|
|
35
|
+
const section = {
|
|
36
|
+
label,
|
|
37
|
+
promise: new Promise((resolve) => {
|
|
38
|
+
resolver = resolve;
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
activeSections.add(section);
|
|
42
|
+
try {
|
|
43
|
+
return await fn();
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
activeSections.delete(section);
|
|
47
|
+
resolver();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns true while any critical section is currently running. Used by the
|
|
52
|
+
* bin entry point's signal handler to decide whether to await before exit.
|
|
53
|
+
*/
|
|
54
|
+
export function hasActiveCriticalSection() {
|
|
55
|
+
return activeSections.size > 0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Waits for every active critical section to complete or for `timeoutMs` to
|
|
59
|
+
* elapse, whichever comes first. Never rejects: a section that throws still
|
|
60
|
+
* resolves from the registry's perspective because `runInSignalCriticalSection`
|
|
61
|
+
* cleans up in `finally`.
|
|
62
|
+
*/
|
|
63
|
+
export async function waitForActiveCriticalSections(timeoutMs) {
|
|
64
|
+
if (activeSections.size === 0)
|
|
65
|
+
return;
|
|
66
|
+
const snapshot = [...activeSections].map((s) => s.promise);
|
|
67
|
+
await Promise.race([
|
|
68
|
+
Promise.allSettled(snapshot).then(() => undefined),
|
|
69
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs)),
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Test-only helper: clears the critical-section registry. Production code
|
|
74
|
+
* must never call this — it voids the exit-ordering guarantee for any
|
|
75
|
+
* section still in flight.
|
|
76
|
+
*/
|
|
77
|
+
export function resetCriticalSectionsForTests() {
|
|
78
|
+
activeSections.clear();
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=signal-critical.js.map
|
|
@@ -37,6 +37,6 @@ export declare class EngineExistsError extends DownloadError {
|
|
|
37
37
|
*/
|
|
38
38
|
export declare class PartialEngineExistsError extends DownloadError {
|
|
39
39
|
readonly enginePath: string;
|
|
40
|
-
constructor(enginePath: string);
|
|
40
|
+
constructor(enginePath: string, cause?: Error);
|
|
41
41
|
get userMessage(): string;
|
|
42
42
|
}
|
|
@@ -80,16 +80,19 @@ export class EngineExistsError extends DownloadError {
|
|
|
80
80
|
*/
|
|
81
81
|
export class PartialEngineExistsError extends DownloadError {
|
|
82
82
|
enginePath;
|
|
83
|
-
constructor(enginePath) {
|
|
84
|
-
super(`Engine directory contains a partially initialized checkout: ${enginePath}
|
|
83
|
+
constructor(enginePath, cause) {
|
|
84
|
+
super(`Engine directory contains a partially initialized checkout: ${enginePath}`, undefined, cause);
|
|
85
85
|
this.enginePath = enginePath;
|
|
86
86
|
}
|
|
87
87
|
get userMessage() {
|
|
88
|
+
const causeMessage = this.cause instanceof Error && this.cause.message ? this.cause.message : undefined;
|
|
88
89
|
return (`Download Error: Firefox source exists, but the baseline git repository was not fully initialized.\n\n` +
|
|
89
90
|
`Path: ${this.enginePath}\n\n` +
|
|
91
|
+
(causeMessage ? `Underlying cause: ${causeMessage}\n\n` : '') +
|
|
90
92
|
'To fix this:\n' +
|
|
91
93
|
' 1. Re-run "fireforge download --force" to recreate the baseline repository\n' +
|
|
92
|
-
' 2. Or manually delete the engine/ directory before downloading again'
|
|
94
|
+
' 2. Or manually delete the engine/ directory before downloading again\n' +
|
|
95
|
+
' 3. Re-run with --verbose for the full underlying error and stack trace');
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
//# sourceMappingURL=download.js.map
|