@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
74 lines • 2.77 kB
JavaScript
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
/**
* A {@link Workspace} wrapper that owns its lifecycle and provides a
* canonical handle for callers that want a single owner per workspace.
*
* In Python this class pins the workspace to its own asyncio event
* loop in a background thread, isolating it from the caller's loop.
* Node.js has a single event loop per thread, so there's no
* cross-loop handoff to perform; TS `call()` simply awaits the
* supplied promise on the current loop. Callers who need true OS-
* thread isolation should place the workspace inside a Worker and
* communicate via message-passing.
*
* What this class DOES provide in TS:
* - A clear owner: the runner is responsible for closing the workspace.
* - Lifecycle guardrails: `call()` rejects after `stop()`.
* - API parity with Python for code that ports over verbatim.
*
* @example
* ```ts
* const runner = new WorkspaceRunner(new Workspace({ '/': ram }))
* try {
* const result = await runner.call(runner.ws.shell('ls /'))
* } finally {
* await runner.stop()
* }
* ```
*/
export class WorkspaceRunner {
ws;
stopped = false;
stopping = null;
constructor(ws) {
this.ws = ws;
}
/**
* Await a workspace-produced promise.
*
* Rejects if the runner has been stopped. Does not block — Node's
* single event loop interleaves this call with other work as usual.
*
* @param p a promise produced from the workspace API (e.g.
* `runner.ws.shell('ls /')`).
*/
async call(p) {
if (this.stopped)
throw new Error('WorkspaceRunner is stopped');
return p;
}
/**
* Close the workspace (delete it, with `delete`) and mark the runner as
* stopped. Idempotent; concurrent calls are deduplicated.
*/
async stop(options = {}) {
if (this.stopped)
return this.stopping ?? Promise.resolve();
this.stopped = true;
this.stopping = options.delete === true ? this.ws.delete() : this.ws.close();
await this.stopping;
}
}
//# sourceMappingURL=runner.js.map