From bf29a80c14f5293b8c9e1d1e821cabff9d77c61c Mon Sep 17 00:00:00 2001 From: EremesNG Date: Mon, 20 Jul 2026 19:34:39 -0600 Subject: [PATCH 1/2] fix(opencode): remove unused mcp-steroid configuration The `mcp-steroid` configuration was removed as it is no longer needed or referenced. Cleaning up unused configurations reduces potential clutter and simplifies maintenance. --- opencode.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/opencode.json b/opencode.json index 542aac8..cd5a04d 100644 --- a/opencode.json +++ b/opencode.json @@ -5,11 +5,6 @@ "type": "remote", "url": "http://127.0.0.1:29173/index-mcp/streamable-http", "enabled": true - }, - "mcp-steroid": { - "type": "remote", - "url": "http://127.0.0.1:6315/mcp", - "enabled": true } } } \ No newline at end of file From 55fce25c6bf56b248ede1fd743ee4090b2164e8b Mon Sep 17 00:00:00 2001 From: EremesNG Date: Mon, 20 Jul 2026 20:04:07 -0600 Subject: [PATCH 2/2] fix(setup): handle busy filesystem during setup Added handling for filesystems that are busy or inaccessible during setup. Improved diagnostics and provided actionable manual instructions, ensuring privacy-safe error messages and better user guidance. Refs: #setup --- src/setup/engine.ts | 19 ++++++++++++++----- src/setup/filesystem.ts | 13 +++++++++++-- tests/setup/rollback.test.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/setup/engine.ts b/src/setup/engine.ts index 6ce47c6..36da25f 100644 --- a/src/setup/engine.ts +++ b/src/setup/engine.ts @@ -1408,6 +1408,7 @@ function receiptFailureResult( changed: boolean, receiptPath: string | null, diagnostic: string, + manualActions?: string[], ): SetupResult { return { status: 'failed', @@ -1417,9 +1418,9 @@ function receiptFailureResult( target: paths.targetRoot, steps: [{ name: 'Apply receipt-backed setup transaction', outcome: 'failed' }], diagnostics: [diagnostic], - manual_actions: changed + manual_actions: manualActions ?? (changed ? ['Inspect the verified in-progress receipt before retrying or rolling back.'] - : ['No setup target change remains; review the failed receipt before retrying.'], + : ['No setup target change remains; review the failed receipt before retrying.']), receipt: receiptPath, }; } @@ -2027,14 +2028,22 @@ async function executeOpenCodeSetup( receiptKeyPath, receiptTrustedRoot, ); + const busyTarget = applied.filesystem.diagnostics.includes('filesystem-target-busy'); + let failureDiagnostic = 'Setup transaction failed and did not complete.'; + if (busyTarget) { + failureDiagnostic = 'OpenCode setup could not replace its managed files because OpenCode or another process keeps them busy or inaccessible.'; + } else if (applied.filesystem.remainingArtifacts.length > 0) { + failureDiagnostic = 'Setup transaction failed with an unresolved temporary filesystem artifact.'; + } return receiptFailureResult( request, paths, applied.filesystem.changed, applied.initialReceiptPersisted ? receiptPaths.receiptPath : null, - applied.filesystem.remainingArtifacts.length > 0 - ? 'Setup transaction failed with an unresolved temporary filesystem artifact.' - : 'Setup transaction failed and did not complete.', + failureDiagnostic, + busyTarget + ? ['Close every OpenCode process and retry setup; do not delete the thoth-mem plugin manually.'] + : undefined, ); } diff --git a/src/setup/filesystem.ts b/src/setup/filesystem.ts index 3728bea..7da4f7a 100644 --- a/src/setup/filesystem.ts +++ b/src/setup/filesystem.ts @@ -194,7 +194,7 @@ export async function applyAtomicFilesystemChanges( remainingArtifacts: [], diagnostics: [], }; - } catch { + } catch (error) { const remainingArtifacts = await cleanupArtifacts(activeArtifacts, options); const { restored, unrestored } = await restoreAppliedChanges(applied, options); const cleanupIncomplete = remainingArtifacts.length > 0; @@ -208,7 +208,7 @@ export async function applyAtomicFilesystemChanges( ? 'filesystem-artifact-cleanup-incomplete' : unrestored.length > 0 ? 'filesystem-apply-failed-restoration-incomplete' - : 'filesystem-apply-failed-restored', + : filesystemApplyDiagnostic(error), ); } } @@ -974,6 +974,15 @@ async function cleanupArtifacts( return [...artifacts].sort(); } +function filesystemApplyDiagnostic(error: unknown): string { + const code = error instanceof Error && 'code' in error + ? (error as NodeJS.ErrnoException).code + : undefined; + return ['EPERM', 'EBUSY', 'EACCES', 'ETXTBSY'].includes(code ?? '') + ? 'filesystem-target-busy' + : 'filesystem-apply-failed-restored'; +} + function failedResult( backups: FilesystemBackup[], restored: string[], diff --git a/tests/setup/rollback.test.ts b/tests/setup/rollback.test.ts index 04ab711..38d4ea7 100644 --- a/tests/setup/rollback.test.ts +++ b/tests/setup/rollback.test.ts @@ -1095,6 +1095,32 @@ describe('write-ahead setup receipts', () => { }); }); + it('reports a privacy-safe busy-target action when OpenCode replacement is blocked', async () => { + await withTemporaryFixture(async (fixture) => { + const privateError = 'EPERM private target path C:\\Users\\secret\\OpenCode'; + let faultInjected = false; + const result = await runSetup(fixture, fixture.request, { + ids: ['busy-target'], + filesystemFault: ({ point }) => { + if (point === 'atomic-rename' && !faultInjected) { + faultInjected = true; + throw Object.assign(new Error(privateError), { code: 'EPERM' }); + } + }, + }); + + expect(result).toMatchObject({ status: 'failed', changed: false }); + expect(faultInjected).toBe(true); + expect(result.diagnostics).toEqual([ + 'OpenCode setup could not replace its managed files because OpenCode or another process keeps them busy or inaccessible.', + ]); + expect(result.manual_actions).toEqual([ + 'Close every OpenCode process and retry setup; do not delete the thoth-mem plugin manually.', + ]); + expect(JSON.stringify(result)).not.toContain(privateError); + }); + }); + it('uses target-bound transient OpenCode journals and removes successful rollback evidence', async () => { await withTemporaryFixture(async (fixture) => { const result = await runSetup(fixture, fixture.request, { ids: ['transient-journal'] });