@magnitudedev/pi-extension 0.0.1-alpha.1 → 0.0.1-alpha.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/README.md CHANGED
@@ -10,9 +10,16 @@ pi install npm:@magnitudedev/pi-extension
10
10
  ```
11
11
 
12
12
  On the next fresh interactive Pi launch, Magnitude asks **“Set up local models with Magnitude now?”**
13
- Yes sends this prompt to your current Pi agent and starts onboarding:
14
-
15
- > Set up local models for me with the Magnitude CLI. Install it with `npm i -g @magnitudedev/cli` (or my package manager), then run `magnitude docs onboarding` and follow the instructions.
13
+ Yes opens Magnitude's actual graphical setup in the same terminal, including its model rankings,
14
+ radar, downloads, and loading progress. It connects Pi automatically at the final step, then returns
15
+ to the same Pi conversation with the selected model active. No agent prompt or cloud credentials
16
+ are needed. If Magnitude is missing, accepting setup installs the CLI with
17
+ `npm install --global @magnitudedev/cli` before opening onboarding. Pi stays visible with its native
18
+ spinner: “Installing Magnitude…”. Installer output is suppressed; failures
19
+ show a concise diagnostic. Escape cancels preparation, and `/magnitude-setup` retries.
20
+ An existing CLI is preserved. The extension invokes `magnitude setup --host pi`; `--host` is hidden from help.
21
+ If an older CLI does not recognize that option, update it explicitly and retry; it is never silently
22
+ replaced.
16
23
 
17
24
  No or Escape leaves “You can set up local models anytime with `/magnitude-setup`.” in the conversation.
18
25
  The offer is remembered per Pi profile across restarts, reloads, and package updates. Existing
@@ -20,9 +27,9 @@ Magnitude model configurations, non-interactive modes, conversations, and startu
20
27
  alone. Run `/magnitude-setup` whenever you want to start onboarding yourself.
21
28
 
22
29
  The package includes the Magnitude usage skill; an already-loaded skill of that name takes
23
- precedence without a collision warning. `--no-skills` disables this fallback too. The CLI is not
24
- an npm dependency and is not required to load the extension. Your Pi agent needs a working model
25
- and credentials to carry out onboarding.
30
+ precedence without a collision warning. `--no-skills` disables this fallback too. No separate CLI
31
+ installation is needed. npm must be available with a writable global prefix, as for a normal npm
32
+ CLI installation. Merely loading the extension does not install software.
26
33
 
27
34
  If you already have Magnitude and a local model, connect directly:
28
35
 
@@ -49,7 +56,7 @@ latency, and token-weighted generation throughput. Pi extensions execute with yo
49
56
 
50
57
  Commands:
51
58
 
52
- - `/magnitude-setup` — ask your current agent to set up Magnitude local models
59
+ - `/magnitude-setup` — open Magnitude's graphical model setup inside Pi
53
60
  - `/load-model [model-id]` — load an installed model
54
61
  - `/stop-model` — stop the active model
55
62
 
@@ -74,3 +81,16 @@ builds and runs the checkout's inference runtime,
74
81
  and keeps the current source CLI available until Pi exits. Exiting Pi stops the development runtime
75
82
  and restores the service state that existed before launch. The launcher inherits the current
76
83
  environment; it does not start or configure tracing.
84
+
85
+ To test the first-run setup offer with no preconfigured Magnitude provider:
86
+
87
+ ```sh
88
+ bun run dev:pi --setup
89
+ ```
90
+
91
+ This installs only the checkout's package into the temporary Pi profile. Accept the setup offer,
92
+ choose a model, and return to Pi to chat. Both development modes keep connection files and skills
93
+ inside the temporary profile, and do not change login-startup registration. They share the machine's
94
+ real model storage and inference service: downloads consume disk space and selected models use
95
+ memory. The launcher restores the prior managed service after Pi exits. Ordinary installed setup
96
+ does enable login startup.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@magnitudedev/pi-extension",
3
- "version": "0.0.1-alpha.1",
3
+ "version": "0.0.1-alpha.3",
4
4
  "rpcVersion": 1,
5
- "contentFingerprint": "292fa6fd784d957591e91f9a67c2460b7cf503149b66cdfe22ecd68ab33ca87d",
5
+ "contentFingerprint": "5d348e366e4c95b29edba024aae7756e7e941695537923bd3e82b1ddc54b9566",
6
6
  "files": {
7
- "README.md": "098773e588d568025e90b7aaa716879ddb7e8e2e87492fe86042fce856f66520",
8
- "dist/magnitude.js": "968f6bf0f605a4500cab5e4852edb5f8c67d1d4dd16d0574e13f1ac922d93522",
7
+ "README.md": "c4536c32bc79ddaee7d09536f79c845c2189e8ddc721e583836eb399d9322053",
8
+ "dist/magnitude.js": "14723faa27101270992397f22fcef2ca0f8cd55753e717250f0c92f921653e07",
9
9
  "dist/skills/magnitude/SKILL.md": "37de67f0c7b831415f6298c8785b7ae97d5cfe454dc778651d96114840d2ace2"
10
10
  }
11
11
  }
package/dist/magnitude.js CHANGED
@@ -5842,19 +5842,303 @@ var registerMagnitudeCommands = (pi, sdk = clientLayer2()) => {
5842
5842
  };
5843
5843
 
5844
5844
  // extensions/onboarding.ts
5845
- import * as FileSystem from "@effect/platform/FileSystem";
5845
+ import * as FileSystem3 from "@effect/platform/FileSystem";
5846
5846
  import * as NodeFileSystem2 from "@effect/platform-node/NodeFileSystem";
5847
5847
  import { getAgentDir, parseArgs } from "@earendil-works/pi-coding-agent";
5848
- import { Effect as Effect11, Exit as Exit3, Scope as Scope4 } from "effect";
5848
+ import { Effect as Effect13, Exit as Exit4, Scope as Scope5 } from "effect";
5849
5849
  import { fileURLToPath } from "node:url";
5850
- var SETUP_PROMPT = "Set up local models for me with the Magnitude CLI. Install it with `npm i -g @magnitudedev/cli` (or my package manager), then run `magnitude docs onboarding` and follow the instructions.";
5850
+
5851
+ // extensions/setup.ts
5852
+ import * as Command2 from "@effect/platform/Command";
5853
+ import * as CommandExecutor3 from "@effect/platform/CommandExecutor";
5854
+ import * as FileSystem from "@effect/platform/FileSystem";
5855
+ import * as NodeContext from "@effect/platform-node/NodeContext";
5856
+ import { FetchHttpClient as FetchHttpClient2 } from "@effect/platform";
5857
+ import { delimiter, join } from "node:path";
5858
+ import { stripVTControlCharacters } from "node:util";
5859
+ import { Context as Context7, Effect as Effect12, Exit as Exit3, Fiber as Fiber2, Layer as Layer6, ManagedRuntime as ManagedRuntime2, Schema as Schema52, Scope as Scope4, Stream as Stream7 } from "effect";
5860
+ import { CancellableLoader } from "@earendil-works/pi-tui";
5861
+
5862
+ // ../../packages/utils/src/process/interactive-process.ts
5863
+ import { spawn } from "node:child_process";
5864
+ import { Deferred as Deferred3, Duration as Duration2, Effect as Effect11, Option as Option17, Schema as Schema51 } from "effect";
5865
+
5866
+ class InteractiveProcessFailed extends Schema51.TaggedError()("InteractiveProcessFailed", {
5867
+ operation: Schema51.Literal("spawn", "run"),
5868
+ message: Schema51.String
5869
+ }) {
5870
+ }
5871
+ var messageFrom = (cause) => cause instanceof Error ? cause.message : String(cause);
5872
+ var definedEnvironment = (environment) => Object.fromEntries(Object.entries(environment).filter((entry) => entry[1] !== undefined));
5873
+ var acquireInteractiveProcess = (input) => Effect11.gen(function* () {
5874
+ const termination = yield* Deferred3.make();
5875
+ const child = yield* Effect11.async((resume) => {
5876
+ let acquired = false;
5877
+ let handle;
5878
+ try {
5879
+ handle = spawn(input.executable, [...input.args], {
5880
+ cwd: input.workingDirectory,
5881
+ detached: false,
5882
+ env: definedEnvironment(input.environment),
5883
+ shell: false,
5884
+ stdio: "inherit"
5885
+ });
5886
+ } catch (cause) {
5887
+ resume(Effect11.fail(new InteractiveProcessFailed({
5888
+ operation: "spawn",
5889
+ message: messageFrom(cause)
5890
+ })));
5891
+ return;
5892
+ }
5893
+ const onError = (cause) => {
5894
+ const failure = new InteractiveProcessFailed({
5895
+ operation: acquired ? "run" : "spawn",
5896
+ message: messageFrom(cause)
5897
+ });
5898
+ if (acquired) {
5899
+ Deferred3.unsafeDone(termination, Effect11.fail(failure));
5900
+ } else {
5901
+ resume(Effect11.fail(failure));
5902
+ }
5903
+ };
5904
+ const onExit = (code, signal) => {
5905
+ Deferred3.unsafeDone(termination, Effect11.succeed(code === null ? { _tag: "Signaled", signal } : { _tag: "Exited", code }));
5906
+ };
5907
+ const onSpawn = () => {
5908
+ acquired = true;
5909
+ resume(Effect11.succeed(handle));
5910
+ };
5911
+ handle.once("error", onError);
5912
+ handle.once("exit", onExit);
5913
+ handle.once("spawn", onSpawn);
5914
+ return Effect11.sync(() => {
5915
+ if (!acquired) {
5916
+ handle.removeListener("error", onError);
5917
+ handle.removeListener("exit", onExit);
5918
+ handle.removeListener("spawn", onSpawn);
5919
+ if (handle.exitCode === null && handle.signalCode === null) {
5920
+ try {
5921
+ handle.kill("SIGTERM");
5922
+ } catch {}
5923
+ }
5924
+ }
5925
+ });
5926
+ });
5927
+ return { child, termination };
5928
+ });
5929
+ var FORWARDED_SIGNALS = process.platform === "win32" ? ["SIGINT", "SIGTERM", "SIGBREAK"] : ["SIGINT", "SIGTERM", "SIGHUP"];
5930
+ var awaitWithSignalForwarding = ({ child, termination }) => Effect11.acquireUseRelease(Effect11.sync(() => {
5931
+ const listeners = new Map;
5932
+ for (const signal of FORWARDED_SIGNALS) {
5933
+ const listener = () => {
5934
+ try {
5935
+ child.kill(signal);
5936
+ } catch {}
5937
+ };
5938
+ listeners.set(signal, listener);
5939
+ process.on(signal, listener);
5940
+ }
5941
+ return listeners;
5942
+ }), () => Deferred3.await(termination), (listeners) => Effect11.sync(() => {
5943
+ for (const [signal, listener] of listeners) {
5944
+ process.removeListener(signal, listener);
5945
+ }
5946
+ }));
5947
+ var terminateAndReap = ({ child, termination }) => Effect11.gen(function* () {
5948
+ if (yield* Deferred3.isDone(termination))
5949
+ return;
5950
+ yield* Effect11.sync(() => {
5951
+ try {
5952
+ child.kill("SIGTERM");
5953
+ } catch {}
5954
+ });
5955
+ const graceful = yield* Deferred3.await(termination).pipe(Effect11.ignore, Effect11.timeoutOption(Duration2.seconds(2)));
5956
+ if (Option17.isSome(graceful))
5957
+ return;
5958
+ yield* Effect11.sync(() => {
5959
+ try {
5960
+ child.kill("SIGKILL");
5961
+ } catch {}
5962
+ });
5963
+ yield* Deferred3.await(termination).pipe(Effect11.ignore, Effect11.timeout(Duration2.seconds(2)), Effect11.ignore);
5964
+ });
5965
+ var runInteractiveProcess = (input) => Effect11.acquireUseRelease(acquireInteractiveProcess(input), awaitWithSignalForwarding, terminateAndReap);
5966
+ // extensions/setup.ts
5967
+ class PiSetupFailed extends Schema52.TaggedError()("PiSetupFailed", {
5968
+ message: Schema52.String
5969
+ }) {
5970
+ }
5971
+ var failure = (message) => new PiSetupFailed({ message });
5972
+ var prepareMagnitudeCli = (cwd, setMessage = () => Effect12.void) => Effect12.gen(function* () {
5973
+ const fs = yield* FileSystem.FileSystem;
5974
+ const override = process.env.MAGNITUDE_CLI?.trim();
5975
+ const executable = override || "magnitude";
5976
+ const probe = Effect12.scoped(Effect12.gen(function* () {
5977
+ const child = yield* Command2.make(executable, "--version").pipe(Command2.start);
5978
+ const [code, , stderr] = yield* Effect12.all([
5979
+ child.exitCode,
5980
+ Stream7.runDrain(child.stdout),
5981
+ child.stderr.pipe(Stream7.decodeText(), Stream7.runFold("", (text2, part) => (text2 + part).slice(-4096)))
5982
+ ], { concurrency: "unbounded" });
5983
+ if (code !== 0)
5984
+ return yield* failure(`Magnitude could not run at ${executable} (exit ${code}). ${stripVTControlCharacters(stderr).trim().slice(-600)}${override ? " Check MAGNITUDE_CLI." : ""}`);
5985
+ }));
5986
+ yield* probe.pipe(Effect12.catchIf((error) => !override && error._tag === "SystemError" && error.reason === "NotFound", (error) => Effect12.gen(function* () {
5987
+ for (const directory of (process.env.PATH ?? "").split(delimiter)) {
5988
+ if (yield* fs.exists(join(directory || cwd, executable)))
5989
+ return yield* error;
5990
+ }
5991
+ yield* setMessage("Installing Magnitude…");
5992
+ yield* Effect12.scoped(Effect12.gen(function* () {
5993
+ const child = yield* Command2.make("npm", "install", "--global", "@magnitudedev/cli").pipe(Command2.workingDirectory(cwd), Command2.start);
5994
+ const [code, , stderr] = yield* Effect12.all([
5995
+ child.exitCode,
5996
+ Stream7.runDrain(child.stdout),
5997
+ child.stderr.pipe(Stream7.decodeText(), Stream7.runFold("", (text2, part) => (text2 + part).slice(-4096)))
5998
+ ], { concurrency: "unbounded" });
5999
+ if (code !== 0)
6000
+ return yield* failure(`Magnitude installation failed (exit ${code}). ${stripVTControlCharacters(stderr).trim().slice(-600)} Run /magnitude-setup to retry.`);
6001
+ }));
6002
+ return yield* probe;
6003
+ })), Effect12.timeout("10 minutes"), Effect12.mapError((error) => error instanceof PiSetupFailed ? error : failure(`Could not prepare Magnitude: ${String(error)}. Run /magnitude-setup to retry${override ? ", or check MAGNITUDE_CLI" : ""}.`)));
6004
+ return executable;
6005
+ });
6006
+ var withPiPreparation = (ctx, work) => Effect12.acquireUseRelease(Effect12.async((resume, signal) => {
6007
+ let closed;
6008
+ closed = ctx.ui.custom((tui, theme, _keys, done) => {
6009
+ const loader = new CancellableLoader(tui, (text2) => theme.fg("accent", text2), (text2) => theme.fg("muted", text2), "Installing Magnitude…");
6010
+ if (signal.aborted) {
6011
+ loader.dispose();
6012
+ done();
6013
+ } else
6014
+ resume(Effect12.succeed({ loader, finish: () => done(), closed: () => closed }));
6015
+ return loader;
6016
+ });
6017
+ closed.catch((error) => resume(Effect12.fail(failure(`Could not open Pi setup: ${String(error)}`))));
6018
+ }), ({ loader }) => work((message) => Effect12.sync(() => loader.setMessage(message))).pipe(Effect12.raceFirst(Effect12.async((resume) => {
6019
+ loader.onAbort = () => resume(Effect12.fail(failure("Magnitude setup cancelled. Run /magnitude-setup to retry.")));
6020
+ if (loader.signal.aborted)
6021
+ loader.onAbort();
6022
+ return Effect12.sync(() => {
6023
+ loader.onAbort = undefined;
6024
+ });
6025
+ }))), ({ loader, finish, closed }) => Effect12.sync(() => {
6026
+ loader.dispose();
6027
+ finish();
6028
+ }).pipe(Effect12.zipRight(Effect12.promise(closed))));
6029
+ var restoreHostTerminal = (tui) => tui.terminal.write("\x1B[?2026l\x1B[?1003l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?1004l" + "\x1B[?2004l\x1B[>4;0m\x1B[=0u\x1B[?1049l\x1B[0m\x1B[0 q");
6030
+ var withPiTerminal = (ctx, work) => Effect12.acquireUseRelease(Effect12.async((resume, signal) => {
6031
+ let closed;
6032
+ closed = ctx.ui.custom((tui, _theme, _keys, done) => {
6033
+ if (signal.aborted)
6034
+ done();
6035
+ else
6036
+ resume(Effect12.succeed({ tui, finish: () => done(), closed: () => closed }));
6037
+ return { render: () => [], invalidate: () => {} };
6038
+ });
6039
+ closed.catch((error) => resume(Effect12.fail(failure(`Could not open Pi setup: ${String(error)}`))));
6040
+ }), ({ tui }) => Effect12.sync(() => tui.stop()).pipe(Effect12.zipRight(work)), ({ tui, finish, closed }) => Effect12.sync(() => {
6041
+ try {
6042
+ restoreHostTerminal(tui);
6043
+ tui.start();
6044
+ tui.requestRender(true);
6045
+ } finally {
6046
+ finish();
6047
+ }
6048
+ }).pipe(Effect12.zipRight(Effect12.promise(closed))));
6049
+ var validateSetupTermination = (termination) => {
6050
+ if (termination._tag === "Signaled") {
6051
+ return termination.signal === "SIGINT" ? Effect12.succeed(false) : Effect12.fail(failure(`Magnitude setup stopped unexpectedly (${termination.signal}). Run /magnitude-setup to retry.`));
6052
+ }
6053
+ if (termination.code === 130)
6054
+ return Effect12.succeed(false);
6055
+ return termination.code === 0 ? Effect12.succeed(true) : Effect12.fail(failure(`Magnitude setup failed (exit ${termination.code}). Check the terminal error above; if setup --host pi is unsupported, update @magnitudedev/cli. Run /magnitude-setup to retry.`));
6056
+ };
6057
+ var readSetupModel = Effect12.gen(function* () {
6058
+ const client = yield* MagnitudeClient;
6059
+ const { slots } = yield* client.models.getSlots({}).pipe(Effect12.mapError((error) => failure(`Magnitude setup completed, but the selected model could not be read: ${error._tag === "RpcClientError" ? error.message : formatConnectionError(error)}. Run /reload and select it with /model.`)));
6060
+ if (slots.primary._tag !== "ConfiguredLocal")
6061
+ return yield* failure("Magnitude setup completed, but no local primary model is configured. Run /reload and select a Magnitude model with /model.");
6062
+ return slots.primary.selection.providerModelId;
6063
+ });
6064
+ var PiSetup = Context7.GenericTag("pi/PiSetup");
6065
+ var PiSetupLive = Layer6.effect(PiSetup, Effect12.gen(function* () {
6066
+ const fs = yield* FileSystem.FileSystem;
6067
+ const executor = yield* CommandExecutor3.CommandExecutor;
6068
+ return {
6069
+ run: (ctx) => Effect12.scoped(Effect12.gen(function* () {
6070
+ const executable = yield* withPiPreparation(ctx, (setMessage) => prepareMagnitudeCli(ctx.cwd, setMessage));
6071
+ const termination = yield* withPiTerminal(ctx, runInteractiveProcess({
6072
+ executable,
6073
+ args: ["setup", "--host", "pi"],
6074
+ environment: process.env,
6075
+ workingDirectory: ctx.cwd
6076
+ }));
6077
+ if (!(yield* validateSetupTermination(termination)))
6078
+ return { _tag: "Cancelled" };
6079
+ const modelId = yield* readSetupModel.pipe(Effect12.provide(MagnitudeClient.layer({ autoStart: false }).pipe(Layer6.provide(FetchHttpClient2.layer))));
6080
+ return { _tag: "Completed", modelId };
6081
+ })).pipe(Effect12.provideService(CommandExecutor3.CommandExecutor, executor), Effect12.provideService(FileSystem.FileSystem, fs), Effect12.mapError((error) => error instanceof PiSetupFailed ? error : failure(`Magnitude setup could not finish: ${String(error)}`)))
6082
+ };
6083
+ }));
6084
+ var registerMagnitudeSetup = (pi, layer4 = PiSetupLive.pipe(Layer6.provide(NodeContext.layer))) => {
6085
+ const runtime = ManagedRuntime2.make(layer4);
6086
+ const scope = Effect12.runSync(Scope4.make());
6087
+ const gate = Effect12.runSync(Effect12.makeSemaphore(1));
6088
+ const action = (ctx) => Effect12.gen(function* () {
6089
+ if (ctx.mode !== "tui")
6090
+ return yield* failure("Run /magnitude-setup in Pi's interactive terminal.");
6091
+ if (!ctx.isIdle() || ctx.hasPendingMessages())
6092
+ return yield* failure("Wait for the current task to finish, then run /magnitude-setup.");
6093
+ const setup = yield* PiSetup;
6094
+ const result = yield* setup.run(ctx);
6095
+ if (result._tag !== "Completed")
6096
+ return false;
6097
+ yield* Effect12.tryPromise({
6098
+ try: async () => {
6099
+ await ctx.modelRegistry.refresh();
6100
+ const model2 = ctx.modelRegistry.find("magnitude", result.modelId);
6101
+ if (!model2 || !await pi.setModel(model2))
6102
+ throw new Error("The selected model is not available in Pi");
6103
+ },
6104
+ catch: (error) => failure(`Magnitude setup completed, but Pi could not activate the model: ${String(error)}. Run /reload and select it with /model.`)
6105
+ });
6106
+ return true;
6107
+ });
6108
+ const run = (ctx) => runtime.runPromise(Effect12.forkIn(gate.withPermitsIfAvailable(1)(action(ctx)).pipe(Effect12.flatMap((result) => result._tag === "Some" ? Effect12.succeed(result.value) : Effect12.fail(failure("Magnitude setup is already open."))), Effect12.catchAll((error) => Effect12.sync(() => {
6109
+ ctx.ui.notify(error.message, "error");
6110
+ return false;
6111
+ }))), scope).pipe(Effect12.flatMap(Fiber2.join)));
6112
+ pi.registerCommand("magnitude-setup", {
6113
+ description: "Choose and set up a local Magnitude model",
6114
+ handler: async (_args, ctx) => {
6115
+ const reload = await run(ctx);
6116
+ if (reload) {
6117
+ try {
6118
+ await ctx.reload();
6119
+ } catch (error) {
6120
+ throw failure(`Magnitude setup completed and selected the model, but Pi could not reload its resources: ${String(error)}. Run /reload to retry.`);
6121
+ }
6122
+ }
6123
+ }
6124
+ });
6125
+ return {
6126
+ run,
6127
+ dispose: async () => {
6128
+ await Effect12.runPromise(Scope4.close(scope, Exit3.void));
6129
+ await runtime.dispose();
6130
+ }
6131
+ };
6132
+ };
6133
+
6134
+ // extensions/onboarding.ts
5851
6135
  var SETUP_QUESTION = "Set up local models with Magnitude now?";
5852
6136
  var SETUP_REMINDER = "You can set up local models anytime with `/magnitude-setup`.";
5853
- var claimSetupOffer = (agentDir) => Effect11.gen(function* () {
5854
- const fs = yield* FileSystem.FileSystem;
6137
+ var claimSetupOffer = (agentDir) => Effect13.gen(function* () {
6138
+ const fs = yield* FileSystem3.FileSystem;
5855
6139
  const directory = `${agentDir}/magnitude`;
5856
6140
  yield* fs.makeDirectory(directory, { recursive: true });
5857
- return yield* fs.writeFileString(`${directory}/setup-offered`, "", { flag: "wx" }).pipe(Effect11.as(true), Effect11.catchTag("SystemError", (error) => error.reason === "AlreadyExists" ? Effect11.succeed(false) : Effect11.fail(error)));
6141
+ return yield* fs.writeFileString(`${directory}/setup-offered`, "", { flag: "wx" }).pipe(Effect13.as(true), Effect13.catchTag("SystemError", (error) => error.reason === "AlreadyExists" ? Effect13.succeed(false) : Effect13.fail(error)));
5858
6142
  });
5859
6143
  function canOfferSetup(ctx, argv) {
5860
6144
  if (ctx.mode !== "tui" || !ctx.isIdle() || ctx.hasPendingMessages() || ctx.ui.getEditorText().trim())
@@ -5866,30 +6150,21 @@ function canOfferSetup(ctx, argv) {
5866
6150
  const args = parseArgs([...argv]);
5867
6151
  return args.messages.length === 0 && args.fileArgs.length === 0;
5868
6152
  }
5869
- var offerSetup = (pi, ctx, agentDir, signal) => Effect11.gen(function* () {
6153
+ var offerSetup = (pi, ctx, agentDir, signal, runSetup) => Effect13.gen(function* () {
5870
6154
  if (!(yield* claimSetupOffer(agentDir)) || signal.aborted)
5871
6155
  return;
5872
- const accepted = yield* Effect11.tryPromise(() => ctx.ui.confirm(SETUP_QUESTION, "", { signal }));
6156
+ const accepted = yield* Effect13.tryPromise(() => ctx.ui.confirm(SETUP_QUESTION, "", { signal }));
5873
6157
  if (signal.aborted)
5874
6158
  return;
5875
- if (accepted && ctx.isIdle() && !ctx.hasPendingMessages())
5876
- pi.sendUserMessage(SETUP_PROMPT);
5877
- else
6159
+ if (accepted && ctx.isIdle() && !ctx.hasPendingMessages()) {
6160
+ yield* Effect13.tryPromise(() => runSetup(ctx));
6161
+ } else
5878
6162
  pi.sendMessage({ customType: "magnitude-setup", content: SETUP_REMINDER, display: true });
5879
6163
  });
5880
6164
  function registerMagnitudeOnboarding(pi) {
5881
6165
  const abort = new AbortController;
5882
- const scope = Effect11.runSync(Scope4.make());
5883
- pi.registerCommand("magnitude-setup", {
5884
- description: "Set up local models with Magnitude",
5885
- handler: async (_args, ctx) => {
5886
- if (!ctx.isIdle() || ctx.hasPendingMessages()) {
5887
- ctx.ui.notify("Wait for the current task to finish, then run /magnitude-setup.", "warning");
5888
- return;
5889
- }
5890
- pi.sendUserMessage(SETUP_PROMPT);
5891
- }
5892
- });
6166
+ const scope = Effect13.runSync(Scope5.make());
6167
+ const setup = registerMagnitudeSetup(pi);
5893
6168
  pi.on("resources_discover", () => {
5894
6169
  if (parseArgs(process.argv.slice(2)).noSkills || pi.getCommands().some((command) => command.source === "skill" && command.name === "skill:magnitude"))
5895
6170
  return;
@@ -5898,24 +6173,25 @@ function registerMagnitudeOnboarding(pi) {
5898
6173
  pi.on("session_start", (event, ctx) => {
5899
6174
  if (event.reason !== "startup" || !canOfferSetup(ctx, process.argv.slice(2)))
5900
6175
  return;
5901
- Effect11.runFork(Effect11.forkIn(offerSetup(pi, ctx, getAgentDir(), abort.signal).pipe(Effect11.provide(NodeFileSystem2.layer), Effect11.catchAll(() => Effect11.sync(() => ctx.ui.notify(`Magnitude setup could not open. ${SETUP_REMINDER}`, "warning")))), scope));
6176
+ Effect13.runFork(Effect13.forkIn(offerSetup(pi, ctx, getAgentDir(), abort.signal, setup.run).pipe(Effect13.provide(NodeFileSystem2.layer), Effect13.catchAll(() => Effect13.sync(() => ctx.ui.notify(`Magnitude setup could not open. ${SETUP_REMINDER}`, "warning")))), scope));
5902
6177
  });
5903
- return () => {
6178
+ return async () => {
5904
6179
  abort.abort();
5905
- return Effect11.runPromise(Scope4.close(scope, Exit3.void));
6180
+ await Effect13.runPromise(Scope5.close(scope, Exit4.void));
6181
+ await setup.dispose();
5906
6182
  };
5907
6183
  }
5908
6184
 
5909
6185
  // extensions/observing-fetch.ts
5910
- import { Effect as Effect12, Either as Either3, Schema as Schema52 } from "effect";
6186
+ import { Effect as Effect14, Either as Either3, Schema as Schema54 } from "effect";
5911
6187
 
5912
6188
  // extensions/protocol.ts
5913
- import { Either as Either2, Schema as Schema51 } from "effect";
5914
- var ProgressChunkSchema = Schema51.Struct({ progress: MagnitudeProgressSchema });
5915
- var TimingsChunkSchema = Schema51.Struct({ timings: MagnitudeTimingsSchema });
6189
+ import { Either as Either2, Schema as Schema53 } from "effect";
6190
+ var ProgressChunkSchema = Schema53.Struct({ progress: MagnitudeProgressSchema });
6191
+ var TimingsChunkSchema = Schema53.Struct({ timings: MagnitudeTimingsSchema });
5916
6192
  var decodeMagnitudeObservation = (value) => {
5917
- const progress = Schema51.decodeUnknownEither(ProgressChunkSchema)(value);
5918
- const timings = Schema51.decodeUnknownEither(TimingsChunkSchema)(value);
6193
+ const progress = Schema53.decodeUnknownEither(ProgressChunkSchema)(value);
6194
+ const timings = Schema53.decodeUnknownEither(TimingsChunkSchema)(value);
5919
6195
  if (Either2.isLeft(progress) && Either2.isLeft(timings))
5920
6196
  return;
5921
6197
  return {
@@ -5926,7 +6202,7 @@ var decodeMagnitudeObservation = (value) => {
5926
6202
 
5927
6203
  // extensions/observing-fetch.ts
5928
6204
  var MAGNITUDE_PROGRESS_HEADER = "Magnitude-Include-Progress";
5929
- var JsonDocumentSchema = Schema52.parseJson(Schema52.Unknown);
6205
+ var JsonDocumentSchema = Schema54.parseJson(Schema54.Unknown);
5930
6206
 
5931
6207
  class SseDataParser {
5932
6208
  #buffer = "";
@@ -5973,26 +6249,26 @@ class SseDataParser {
5973
6249
  this.#dataLines = [];
5974
6250
  if (data === "[DONE]")
5975
6251
  return;
5976
- const decoded = Schema52.decodeUnknownEither(JsonDocumentSchema)(data);
6252
+ const decoded = Schema54.decodeUnknownEither(JsonDocumentSchema)(data);
5977
6253
  if (Either3.isRight(decoded))
5978
6254
  observe(decoded.right);
5979
6255
  }
5980
6256
  }
5981
- var observeResponse = (response, request, signal) => Effect12.scoped(Effect12.gen(function* () {
6257
+ var observeResponse = (response, request, signal) => Effect14.scoped(Effect14.gen(function* () {
5982
6258
  if (!response.ok || response.body === null) {
5983
6259
  yield* request.fail;
5984
6260
  return;
5985
6261
  }
5986
- const reader = yield* Effect12.acquireRelease(Effect12.sync(() => response.body.getReader()), (reader2) => Effect12.promise(() => reader2.cancel()).pipe(Effect12.interruptible, Effect12.timeout("100 millis"), Effect12.ignore, Effect12.ensuring(Effect12.sync(() => reader2.releaseLock()))));
6262
+ const reader = yield* Effect14.acquireRelease(Effect14.sync(() => response.body.getReader()), (reader2) => Effect14.promise(() => reader2.cancel()).pipe(Effect14.interruptible, Effect14.timeout("100 millis"), Effect14.ignore, Effect14.ensuring(Effect14.sync(() => reader2.releaseLock()))));
5987
6263
  if (signal.aborted) {
5988
6264
  yield* request.fail;
5989
6265
  return;
5990
6266
  }
5991
6267
  const decoder = new TextDecoder;
5992
6268
  const parser = new SseDataParser;
5993
- const drain = Effect12.gen(function* () {
6269
+ const drain = Effect14.gen(function* () {
5994
6270
  while (true) {
5995
- const result = yield* Effect12.tryPromise(() => reader.read());
6271
+ const result = yield* Effect14.tryPromise(() => reader.read());
5996
6272
  if (result.done)
5997
6273
  break;
5998
6274
  const values = [];
@@ -6005,35 +6281,35 @@ var observeResponse = (response, request, signal) => Effect12.scoped(Effect12.ge
6005
6281
  }
6006
6282
  yield* request.finish;
6007
6283
  });
6008
- const aborted = Effect12.async((resume) => {
6009
- const abort = () => resume(Effect12.interrupt);
6284
+ const aborted = Effect14.async((resume) => {
6285
+ const abort = () => resume(Effect14.interrupt);
6010
6286
  signal.addEventListener("abort", abort, { once: true });
6011
6287
  if (signal.aborted)
6012
6288
  abort();
6013
- return Effect12.sync(() => signal.removeEventListener("abort", abort));
6289
+ return Effect14.sync(() => signal.removeEventListener("abort", abort));
6014
6290
  });
6015
- yield* Effect12.raceFirst(drain, aborted).pipe(Effect12.onError(() => request.fail));
6016
- })).pipe(Effect12.catchAllCause(() => Effect12.void));
6291
+ yield* Effect14.raceFirst(drain, aborted).pipe(Effect14.onError(() => request.fail));
6292
+ })).pipe(Effect14.catchAllCause(() => Effect14.void));
6017
6293
  var makeObservingFetch = (fetchImplementation, begin, scope) => {
6018
6294
  const observingFetch = async (input, init) => {
6019
6295
  const request = new Request(input, init);
6020
6296
  request.headers.set(MAGNITUDE_PROGRESS_HEADER, "true");
6021
- const progress = Effect12.runSync(Effect12.suspend(begin).pipe(Effect12.catchAllCause(() => Effect12.succeed({
6022
- observe: () => Effect12.void,
6023
- finish: Effect12.void,
6024
- fail: Effect12.void
6297
+ const progress = Effect14.runSync(Effect14.suspend(begin).pipe(Effect14.catchAllCause(() => Effect14.succeed({
6298
+ observe: () => Effect14.void,
6299
+ finish: Effect14.void,
6300
+ fail: Effect14.void
6025
6301
  }))));
6026
6302
  try {
6027
6303
  const response = await fetchImplementation(request);
6028
6304
  try {
6029
6305
  const observation = observeResponse(response.clone(), progress, request.signal);
6030
- Effect12.runFork(Effect12.forkIn(observation, scope));
6306
+ Effect14.runFork(Effect14.forkIn(observation, scope));
6031
6307
  } catch {
6032
- Effect12.runSync(progress.fail.pipe(Effect12.catchAllCause(() => Effect12.void)));
6308
+ Effect14.runSync(progress.fail.pipe(Effect14.catchAllCause(() => Effect14.void)));
6033
6309
  }
6034
6310
  return response;
6035
6311
  } catch (error) {
6036
- Effect12.runSync(progress.fail.pipe(Effect12.catchAllCause(() => Effect12.void)));
6312
+ Effect14.runSync(progress.fail.pipe(Effect14.catchAllCause(() => Effect14.void)));
6037
6313
  throw error;
6038
6314
  }
6039
6315
  };
@@ -6044,9 +6320,9 @@ var makeObservingFetch = (fetchImplementation, begin, scope) => {
6044
6320
 
6045
6321
  // extensions/progress.ts
6046
6322
  import { Text } from "@earendil-works/pi-tui";
6047
- import { Data as Data3, Effect as Effect13, Fiber as Fiber2, Option as Option17, Queue, Schema as Schema53 } from "effect";
6323
+ import { Data as Data3, Effect as Effect15, Fiber as Fiber3, Option as Option18, Queue, Schema as Schema55 } from "effect";
6048
6324
  var MAGNITUDE_SUMMARY_WIDGET_KEY = "magnitude-inference-summary";
6049
- var RequestId = Schema53.Number.pipe(Schema53.int(), Schema53.brand("ProgressRequestId"));
6325
+ var RequestId = Schema55.Number.pipe(Schema55.int(), Schema55.brand("ProgressRequestId"));
6050
6326
 
6051
6327
  class Observing extends Data3.TaggedClass("Observing") {
6052
6328
  }
@@ -6101,31 +6377,31 @@ var formatLiveProgress = ({ progress, modelName, startedAt }, now) => {
6101
6377
  }
6102
6378
  }
6103
6379
  };
6104
- var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(function* () {
6380
+ var makeProgressTracker = (ui, now = () => performance.now()) => Effect15.gen(function* () {
6105
6381
  let state = new Idle2;
6106
6382
  let nextId = 0;
6107
6383
  let active;
6108
6384
  let latest;
6109
6385
  let nextResponseId = 0;
6110
6386
  const wake = yield* Queue.sliding(1);
6111
- const present = (f) => Effect13.sync(f).pipe(Effect13.catchAllCause(() => Effect13.void));
6387
+ const present = (f) => Effect15.sync(f).pipe(Effect15.catchAllCause(() => Effect15.void));
6112
6388
  const clearSummary = present(() => ui.setWidget(MAGNITUDE_SUMMARY_WIDGET_KEY, undefined));
6113
6389
  const resetRow = present(() => ui.setWorkingMessage());
6114
6390
  const render2 = present(() => {
6115
6391
  if (active)
6116
6392
  ui.setWorkingMessage(formatLiveProgress(active.phase, now()));
6117
6393
  });
6118
- const finalize = Effect13.gen(function* () {
6394
+ const finalize = Effect15.gen(function* () {
6119
6395
  if (state._tag !== "Settled")
6120
6396
  return;
6121
- if ([...state.run.responses.values()].some(Option17.isNone))
6397
+ if ([...state.run.responses.values()].some(Option18.isNone))
6122
6398
  return;
6123
6399
  if ([...state.run.requests.values()].some((r) => r._tag === "Observing"))
6124
6400
  return;
6125
6401
  const settled = state;
6126
6402
  state = runMachine.transition(settled, "Idle", {});
6127
6403
  const timings = [...settled.run.completed.entries()].filter(([id]) => settled.run.accepted.has(id)).sort(([a], [b]) => a - b).map(([, value]) => value);
6128
- if ([...settled.run.responses.values()].some((outcome) => !Option17.getOrElse(outcome, () => false)) || timings.length === 0) {
6404
+ if ([...settled.run.responses.values()].some((outcome) => !Option18.getOrElse(outcome, () => false)) || timings.length === 0) {
6129
6405
  yield* clearSummary;
6130
6406
  return;
6131
6407
  }
@@ -6134,7 +6410,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6134
6410
  const summary = `● ${settled.run.modelName} worked for ${duration(settled.settledAt - settled.run.startedAt)}` + ` · ${seconds(timings[0].time_to_first_token_ms)} TTFT` + (decodeMs > 0 && tokens > 0 ? ` · ${(tokens * 1000 / decodeMs).toFixed(1)} tok/s` : "");
6135
6411
  yield* present(() => ui.setWidget(MAGNITUDE_SUMMARY_WIDGET_KEY, (_tui, theme) => new Text(theme.fg("muted", summary), 0, 0)));
6136
6412
  });
6137
- const clear = Effect13.gen(function* () {
6413
+ const clear = Effect15.gen(function* () {
6138
6414
  if (state._tag === "Disposed")
6139
6415
  return;
6140
6416
  if (state._tag !== "Idle")
@@ -6144,7 +6420,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6144
6420
  yield* resetRow;
6145
6421
  yield* clearSummary;
6146
6422
  });
6147
- const startRun = (modelName) => Effect13.gen(function* () {
6423
+ const startRun = (modelName) => Effect15.gen(function* () {
6148
6424
  if (state._tag === "Disposed")
6149
6425
  return;
6150
6426
  if (state._tag === "Settled")
@@ -6154,38 +6430,38 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6154
6430
  state = runMachine.transition(state, "Working", { run: { startedAt: now(), modelName, requests: new Map, completed: new Map, responses: new Map, accepted: new Set } });
6155
6431
  yield* clearSummary;
6156
6432
  });
6157
- const timer = yield* Effect13.forever(Effect13.gen(function* () {
6433
+ const timer = yield* Effect15.forever(Effect15.gen(function* () {
6158
6434
  yield* Queue.take(wake);
6159
6435
  while (active) {
6160
- yield* Effect13.sleep("100 millis");
6436
+ yield* Effect15.sleep("100 millis");
6161
6437
  yield* render2;
6162
6438
  }
6163
- })).pipe(Effect13.forkScoped);
6164
- yield* Effect13.addFinalizer(() => Effect13.gen(function* () {
6439
+ })).pipe(Effect15.forkScoped);
6440
+ yield* Effect15.addFinalizer(() => Effect15.gen(function* () {
6165
6441
  yield* clear;
6166
6442
  if (state._tag !== "Disposed")
6167
6443
  state = runMachine.transition(state, "Disposed", {});
6168
- yield* Fiber2.interrupt(timer);
6444
+ yield* Fiber3.interrupt(timer);
6169
6445
  }));
6170
6446
  return {
6171
6447
  startRun,
6172
6448
  clear,
6173
- settleRun: Effect13.gen(function* () {
6449
+ settleRun: Effect15.gen(function* () {
6174
6450
  if (state._tag === "Working")
6175
6451
  state = runMachine.transition(state, "Settled", { settledAt: now() });
6176
6452
  yield* finalize;
6177
6453
  }),
6178
- beginResponse: (modelName) => Effect13.gen(function* () {
6454
+ beginResponse: (modelName) => Effect15.gen(function* () {
6179
6455
  yield* startRun(modelName);
6180
6456
  const run = state._tag === "Working" ? state.run : undefined;
6181
6457
  const responseId = ++nextResponseId;
6182
6458
  const requests = [];
6183
- run?.responses.set(responseId, Option17.none());
6459
+ run?.responses.set(responseId, Option18.none());
6184
6460
  const belongs = () => run !== undefined && (state._tag === "Working" || state._tag === "Settled") && state.run === run;
6185
- const end = (successful) => Effect13.gen(function* () {
6186
- if (!belongs() || Option17.isSome(run.responses.get(responseId)))
6461
+ const end = (successful) => Effect15.gen(function* () {
6462
+ if (!belongs() || Option18.isSome(run.responses.get(responseId)))
6187
6463
  return;
6188
- run.responses.set(responseId, Option17.some(successful));
6464
+ run.responses.set(responseId, Option18.some(successful));
6189
6465
  const last = requests.at(-1);
6190
6466
  if (successful && last !== undefined)
6191
6467
  run.accepted.add(last);
@@ -6204,16 +6480,16 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6204
6480
  }
6205
6481
  yield* finalize;
6206
6482
  });
6207
- const begin = Effect13.gen(function* () {
6208
- if (!belongs() || Option17.isSome(run.responses.get(responseId)))
6209
- return { observe: () => Effect13.void, finish: Effect13.void, fail: Effect13.void };
6483
+ const begin = Effect15.gen(function* () {
6484
+ if (!belongs() || Option18.isSome(run.responses.get(responseId)))
6485
+ return { observe: () => Effect15.void, finish: Effect15.void, fail: Effect15.void };
6210
6486
  const id = RequestId.make(++nextId);
6211
6487
  requests.push(id);
6212
6488
  latest = id;
6213
6489
  active = undefined;
6214
- run?.requests.set(id, new Observing({ timings: Option17.none() }));
6490
+ run?.requests.set(id, new Observing({ timings: Option18.none() }));
6215
6491
  yield* resetRow;
6216
- const close = (failed) => Effect13.gen(function* () {
6492
+ const close = (failed) => Effect15.gen(function* () {
6217
6493
  if (!belongs())
6218
6494
  return;
6219
6495
  const request = run.requests.get(id);
@@ -6223,7 +6499,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6223
6499
  run.requests.set(id, requestMachine.transition(request, "Closed", {}));
6224
6500
  else {
6225
6501
  run.requests.set(id, requestMachine.transition(request, "Observed", {}));
6226
- if (Option17.isSome(request.timings))
6502
+ if (Option18.isSome(request.timings))
6227
6503
  run.completed.set(id, request.timings.value);
6228
6504
  }
6229
6505
  if (latest === id) {
@@ -6233,14 +6509,14 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6233
6509
  yield* finalize;
6234
6510
  });
6235
6511
  return {
6236
- observe: (observation) => Effect13.gen(function* () {
6512
+ observe: (observation) => Effect15.gen(function* () {
6237
6513
  if (!belongs())
6238
6514
  return;
6239
6515
  const request = run.requests.get(id);
6240
6516
  if (request._tag !== "Observing")
6241
6517
  return;
6242
6518
  if (observation.timings)
6243
- run.requests.set(id, requestMachine.hold(request, { timings: Option17.some(observation.timings) }));
6519
+ run.requests.set(id, requestMachine.hold(request, { timings: Option18.some(observation.timings) }));
6244
6520
  if (latest !== id || !observation.progress)
6245
6521
  return;
6246
6522
  const progress = observation.progress;
@@ -6264,35 +6540,35 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(fu
6264
6540
  });
6265
6541
 
6266
6542
  // extensions/magnitude.ts
6267
- import { Effect as Effect14, Exit as Exit4, Scope as Scope6 } from "effect";
6543
+ import { Effect as Effect16, Exit as Exit5, Scope as Scope7 } from "effect";
6268
6544
  function magnitudeExtension(pi) {
6269
6545
  const completions = openAICompletionsApi();
6270
6546
  let tracker;
6271
6547
  let scope;
6272
6548
  const disposeCommands = registerMagnitudeCommands(pi);
6273
6549
  const disposeOnboarding = registerMagnitudeOnboarding(pi);
6274
- const perform = (effect) => Effect14.runSync((effect ?? Effect14.void).pipe(Effect14.catchAllCause(() => Effect14.void)));
6550
+ const perform = (effect) => Effect16.runSync((effect ?? Effect16.void).pipe(Effect16.catchAllCause(() => Effect16.void)));
6275
6551
  pi.registerProvider("magnitude", {
6276
6552
  api: "openai-completions",
6277
6553
  streamSimple: (model2, context, options) => {
6278
6554
  if (model2.api !== "openai-completions") {
6279
6555
  throw new Error(`Magnitude for Pi requires openai-completions, received ${model2.api}`);
6280
6556
  }
6281
- const response = tracker && Effect14.runSync(tracker.beginResponse(model2.name));
6557
+ const response = tracker && Effect16.runSync(tracker.beginResponse(model2.name));
6282
6558
  const stream = completions.streamSimple(model2, context, {
6283
6559
  ...options,
6284
- fetch: scope ? makeObservingFetch(options?.fetch ?? globalThis.fetch, () => response?.begin ?? Effect14.succeed({ observe: () => Effect14.void, finish: Effect14.void, fail: Effect14.void }), scope) : options?.fetch ?? globalThis.fetch
6560
+ fetch: scope ? makeObservingFetch(options?.fetch ?? globalThis.fetch, () => response?.begin ?? Effect16.succeed({ observe: () => Effect16.void, finish: Effect16.void, fail: Effect16.void }), scope) : options?.fetch ?? globalThis.fetch
6285
6561
  });
6286
6562
  if (response && scope)
6287
- Effect14.runFork(Effect14.forkIn(Effect14.tryPromise(() => stream.result()).pipe(Effect14.flatMap((message) => response.end(message.stopReason !== "error" && message.stopReason !== "aborted")), Effect14.catchAllCause(() => response.end(false))), scope));
6563
+ Effect16.runFork(Effect16.forkIn(Effect16.tryPromise(() => stream.result()).pipe(Effect16.flatMap((message) => response.end(message.stopReason !== "error" && message.stopReason !== "aborted")), Effect16.catchAllCause(() => response.end(false))), scope));
6288
6564
  return stream;
6289
6565
  }
6290
6566
  });
6291
6567
  pi.on("session_start", async (_event, ctx) => {
6292
6568
  if (scope)
6293
- await Effect14.runPromise(Scope6.close(scope, Exit4.void));
6294
- scope = Effect14.runSync(Scope6.make());
6295
- tracker = await Effect14.runPromise(makeProgressTracker(ctx.ui).pipe(Scope6.extend(scope)));
6569
+ await Effect16.runPromise(Scope7.close(scope, Exit5.void));
6570
+ scope = Effect16.runSync(Scope7.make());
6571
+ tracker = await Effect16.runPromise(makeProgressTracker(ctx.ui).pipe(Scope7.extend(scope)));
6296
6572
  });
6297
6573
  pi.on("model_select", (event) => {
6298
6574
  if (event.model.provider !== "magnitude")
@@ -6306,7 +6582,7 @@ function magnitudeExtension(pi) {
6306
6582
  pi.on("session_shutdown", async () => {
6307
6583
  await disposeOnboarding();
6308
6584
  if (scope)
6309
- await Effect14.runPromise(Scope6.close(scope, Exit4.void));
6585
+ await Effect16.runPromise(Scope7.close(scope, Exit5.void));
6310
6586
  tracker = undefined;
6311
6587
  scope = undefined;
6312
6588
  await disposeCommands();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magnitudedev/pi-extension",
3
- "version": "0.0.1-alpha.1",
3
+ "version": "0.0.1-alpha.3",
4
4
  "description": "Magnitude model controls and inference progress for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,6 +28,7 @@
28
28
  "@earendil-works/pi-tui": ">=0.83.0"
29
29
  },
30
30
  "devDependencies": {
31
+ "@magnitudedev/client-common": "workspace:*",
31
32
  "@effect/platform-bun": "^0.90.0",
32
33
  "@magnitudedev/release": "workspace:*",
33
34
  "@magnitudedev/utils": "workspace:*",