specrails-desktop 2.11.2 → 2.11.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/package.json +1 -1
- package/server/dist/setup-manager.js +44 -12
package/package.json
CHANGED
|
@@ -620,19 +620,42 @@ async function validateCoreContract() {
|
|
|
620
620
|
}
|
|
621
621
|
// ─── SetupManager ─────────────────────────────────────────────────────────────
|
|
622
622
|
const INSTALL_LOG_BUFFER_MAX = 2000;
|
|
623
|
-
|
|
623
|
+
/**
|
|
624
|
+
* Persist the FULL install log to `~/.specrails/logs/` and return the path (or
|
|
625
|
+
* null on failure). The in-error tail is only a window; the full log carries the
|
|
626
|
+
* complete child stack — needed because a Node uncaught error prints the ORIGIN
|
|
627
|
+
* frames ABOVE the entry frames, so an 8-line tail shows only the bottom of the
|
|
628
|
+
* stack + the error object, never where it was thrown.
|
|
629
|
+
*/
|
|
630
|
+
function persistInstallLog(projectId, logBuffer) {
|
|
631
|
+
try {
|
|
632
|
+
const dir = (0, path_1.join)((0, artifact_registry_1.resolveHome)(), '.specrails', 'logs');
|
|
633
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
634
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
635
|
+
const file = (0, path_1.join)(dir, `setup-${projectId}-${stamp}.log`);
|
|
636
|
+
(0, fs_1.writeFileSync)(file, logBuffer.join('\n') + '\n', { mode: 0o600 });
|
|
637
|
+
return file;
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function formatBufferedInstallError(baseMessage, logBuffer, logPath) {
|
|
644
|
+
// Show a generous tail: a Node uncaught-exception dump is ~15-30 lines (header,
|
|
645
|
+
// stack frames, the `{errno,code,syscall,path}` object, version footer). 8 lines
|
|
646
|
+
// truncated to just the entry frames + error object, hiding the throw origin.
|
|
624
647
|
const recentLines = logBuffer
|
|
625
648
|
.map((line) => line.trim())
|
|
626
649
|
.filter(Boolean)
|
|
627
|
-
.slice(-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
'
|
|
634
|
-
|
|
635
|
-
|
|
650
|
+
.slice(-40);
|
|
651
|
+
const parts = [baseMessage];
|
|
652
|
+
if (recentLines.length > 0) {
|
|
653
|
+
parts.push('', 'Recent output:', ...recentLines.map((line) => `- ${line}`));
|
|
654
|
+
}
|
|
655
|
+
if (logPath) {
|
|
656
|
+
parts.push('', `Full log: ${logPath}`);
|
|
657
|
+
}
|
|
658
|
+
return parts.join('\n');
|
|
636
659
|
}
|
|
637
660
|
class SetupManager {
|
|
638
661
|
_broadcast;
|
|
@@ -788,12 +811,20 @@ class SetupManager {
|
|
|
788
811
|
const initArgs = hasConfig
|
|
789
812
|
? ['--yes', '--from-config', spawnConfigPath ?? configPath]
|
|
790
813
|
: ['--yes', '--root-dir', projectPath];
|
|
814
|
+
// Seed the install log with a diagnostic header capturing the EXACT spawn
|
|
815
|
+
// (node interpreter, cli entry, cwd) + relevant env. This lands in the
|
|
816
|
+
// failure report so a Windows/packaged path issue (e.g. an EISDIR on the
|
|
817
|
+
// entry realpath) is diagnosable without server-console access.
|
|
818
|
+
const diagHeader = [];
|
|
819
|
+
if (useBundledCore) {
|
|
820
|
+
diagHeader.push(`[diag] node=${(0, path_resolver_1.resolveBundledNodeExe)() ?? process.execPath}`, `[diag] cli=${(0, bundled_core_1.getBundledCoreCli)() ?? '<none>'}`, `[diag] cwd=${projectPath}`, `[diag] args=${initArgs.join(' ')}`, `[diag] SPECRAILS_BUNDLED_RUNTIMES_PATH=${process.env.SPECRAILS_BUNDLED_RUNTIMES_PATH ?? '<unset>'}`, `[diag] SPECRAILS_BUNDLED_CORE_PATH=${process.env.SPECRAILS_BUNDLED_CORE_PATH ?? '<unset>'}`);
|
|
821
|
+
}
|
|
791
822
|
// Bundled core (offline, node <cli> init) when available, else legacy npx.
|
|
792
823
|
const child = useBundledCore
|
|
793
824
|
? spawnBundledCoreInit(initArgs, projectPath)
|
|
794
825
|
: spawnCoreInit(initArgs, projectPath);
|
|
795
826
|
this._installProcesses.set(projectId, child);
|
|
796
|
-
this._installLogBuffer.set(projectId,
|
|
827
|
+
this._installLogBuffer.set(projectId, diagHeader);
|
|
797
828
|
// spawnCoreInit uses shell:false on POSIX, so a spawn failure emits 'error'
|
|
798
829
|
// (and NOT 'close') — without this handler the temp config file leaks and
|
|
799
830
|
// the unhandled 'error' event would crash the app.
|
|
@@ -867,10 +898,11 @@ class SetupManager {
|
|
|
867
898
|
}
|
|
868
899
|
else {
|
|
869
900
|
const logBuffer = this._installLogBuffer.get(projectId) ?? [];
|
|
901
|
+
const logPath = persistInstallLog(projectId, logBuffer);
|
|
870
902
|
this._broadcast({
|
|
871
903
|
type: 'setup_error',
|
|
872
904
|
projectId,
|
|
873
|
-
error: formatBufferedInstallError(`${useBundledCore ? 'bundled specrails-core' : 'npx specrails-core'} exited with code ${code ?? 'unknown'}`, logBuffer),
|
|
905
|
+
error: formatBufferedInstallError(`${useBundledCore ? 'bundled specrails-core' : 'npx specrails-core'} exited with code ${code ?? 'unknown'}`, logBuffer, logPath),
|
|
874
906
|
});
|
|
875
907
|
}
|
|
876
908
|
});
|