@magnitudedev/pi-extension 0.0.1-alpha.0 → 0.0.1-alpha.1

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
@@ -3,15 +3,36 @@
3
3
  This Pi package adds Magnitude model management commands and live local-inference progress to Pi's
4
4
  built-in working row above the editor.
5
5
 
6
- Requires Pi 0.83.0 or newer and a matching Magnitude CLI. Install a local model, then run:
6
+ Requires Pi 0.83.0 or newer. Install from your terminal:
7
+
8
+ ```sh
9
+ pi install npm:@magnitudedev/pi-extension
10
+ ```
11
+
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.
16
+
17
+ No or Escape leaves “You can set up local models anytime with `/magnitude-setup`.” in the conversation.
18
+ The offer is remembered per Pi profile across restarts, reloads, and package updates. Existing
19
+ Magnitude model configurations, non-interactive modes, conversations, and startup prompts are left
20
+ alone. Run `/magnitude-setup` whenever you want to start onboarding yourself.
21
+
22
+ 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.
26
+
27
+ If you already have Magnitude and a local model, connect directly:
7
28
 
8
29
  ```sh
9
30
  magnitude connections add pi
10
31
  ```
11
32
 
12
33
  Restart Pi or run `/reload` after connecting. `PI_CODING_AGENT_DIR`, if set, is honored.
13
- Installing the package directly with `pi install` does not configure provider models,
14
- install the Magnitude CLI, start its service, or install its agent skill; the connection command
34
+ Installing the package directly does not configure provider models,
35
+ install the Magnitude CLI, or start its service; the connection command
15
36
  does all connection configuration and can be run safely after a standalone package install.
16
37
 
17
38
  The extension bundles Magnitude's private SDK. Model status, loading, and stopping use the existing
@@ -28,6 +49,7 @@ latency, and token-weighted generation throughput. Pi extensions execute with yo
28
49
 
29
50
  Commands:
30
51
 
52
+ - `/magnitude-setup` — ask your current agent to set up Magnitude local models
31
53
  - `/load-model [model-id]` — load an installed model
32
54
  - `/stop-model` — stop the active model
33
55
 
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@magnitudedev/pi-extension",
3
- "version": "0.0.1-alpha.0",
3
+ "version": "0.0.1-alpha.1",
4
4
  "rpcVersion": 1,
5
- "contentFingerprint": "0cae890db353d9f063a1298bd0f770259d18a27692c4c392fd7561c031e5792c",
5
+ "contentFingerprint": "292fa6fd784d957591e91f9a67c2460b7cf503149b66cdfe22ecd68ab33ca87d",
6
6
  "files": {
7
- "README.md": "345dccd4bee3706cb2647d10185acd0a79de61baf002f9cfce587b35376d5b19",
8
- "dist/magnitude.js": "0d59abfd9a959d5ea4a066a39bcb1cc072c957c778edcd7bd702cc5878a8403f"
7
+ "README.md": "098773e588d568025e90b7aaa716879ddb7e8e2e87492fe86042fce856f66520",
8
+ "dist/magnitude.js": "968f6bf0f605a4500cab5e4852edb5f8c67d1d4dd16d0574e13f1ac922d93522",
9
+ "dist/skills/magnitude/SKILL.md": "37de67f0c7b831415f6298c8785b7ae97d5cfe454dc778651d96114840d2ace2"
9
10
  }
10
11
  }
package/dist/magnitude.js CHANGED
@@ -3364,13 +3364,14 @@ var makeClient = (options) => Effect6.gen(function* () {
3364
3364
  yield* Deferred2.fail(active, new ConnectionClosed({}));
3365
3365
  })).pipe(Effect6.zipRight(Scope2.close(scope, Exit.void))));
3366
3366
  const unavailable = (message) => new ServiceUnavailable({ origin, message });
3367
+ const decodeHealth = Schema47.decodeUnknown(Schema47.Union(MagnitudeHealthResponseSchema, AcnHealthResponseSchema));
3367
3368
  const probe = http.get(`${origin}/health`).pipe(Effect6.timeoutFail({
3368
3369
  duration: "2 seconds",
3369
3370
  onTimeout: () => unavailable("Magnitude service health timed out")
3370
3371
  }), Effect6.mapError((error) => error instanceof ServiceUnavailable ? error : unavailable("Magnitude service is unavailable")), Effect6.flatMap((response) => response.status !== 200 && response.status !== 503 ? Effect6.fail(new InvalidServiceResponse({
3371
3372
  origin,
3372
3373
  message: `Health returned HTTP ${response.status}`
3373
- })) : response.json.pipe(Effect6.flatMap(Schema47.decodeUnknown(MagnitudeHealthResponseSchema)), Effect6.mapError(() => new InvalidServiceResponse({
3374
+ })) : response.json.pipe(Effect6.flatMap(decodeHealth), Effect6.map((health) => ("rpcVersion" in health) ? health : { ...health, rpcVersion: 0 }), Effect6.mapError(() => new InvalidServiceResponse({
3374
3375
  origin,
3375
3376
  message: "Invalid Magnitude health response"
3376
3377
  })))));
@@ -3391,36 +3392,35 @@ var makeClient = (options) => Effect6.gen(function* () {
3391
3392
  version: health.version,
3392
3393
  rpcVersion: health.rpcVersion
3393
3394
  });
3395
+ const startService = (start2) => Effect6.scoped(Effect6.gen(function* () {
3396
+ yield* report({ _tag: "Starting", phase: "PreparingAcn" });
3397
+ yield* probe.pipe(Effect6.flatMap((health) => Option13.match(serviceProgressFromHealth(health.state), {
3398
+ onNone: () => Effect6.void,
3399
+ onSome: report
3400
+ })), Effect6.ignore, Effect6.zipRight(Effect6.sleep("250 millis")), Effect6.forever, Effect6.forkScoped);
3401
+ yield* start2.pipe(Stream4.runForEach(report));
3402
+ }));
3394
3403
  const acquire = Effect6.gen(function* () {
3395
3404
  let started = false;
3396
3405
  while (true) {
3397
- const observed = yield* Effect6.either(probe);
3398
- if (observed._tag === "Left") {
3399
- if (observed.left._tag !== "ServiceUnavailable")
3400
- return yield* observed.left;
3401
- if (!started && Option13.isSome(starter)) {
3402
- started = true;
3403
- yield* report({ _tag: "Starting", phase: "PreparingAcn" });
3404
- yield* Effect6.scoped(Effect6.gen(function* () {
3405
- yield* probe.pipe(Effect6.flatMap((health) => Option13.match(serviceProgressFromHealth(health.state), {
3406
- onNone: () => Effect6.void,
3407
- onSome: report
3408
- })), Effect6.ignore, Effect6.zipRight(Effect6.sleep("250 millis")), Effect6.forever, Effect6.forkScoped);
3409
- yield* starter.value.start.pipe(Stream4.runForEach(report));
3410
- }));
3411
- continue;
3412
- }
3413
- if (!started)
3414
- return yield* observed.left;
3415
- } else {
3416
- const health = observed.right;
3417
- const service = yield* validate(health);
3406
+ const observed = yield* Effect6.either(probe.pipe(Effect6.flatMap((health) => validate(health).pipe(Effect6.map((service) => ({ health, service }))))));
3407
+ if (observed._tag === "Right") {
3408
+ const { health, service } = observed.right;
3418
3409
  if (health.state._tag === "Ready")
3419
3410
  return service;
3420
3411
  yield* Option13.match(serviceProgressFromHealth(health.state), {
3421
3412
  onNone: () => Effect6.void,
3422
3413
  onSome: report
3423
3414
  });
3415
+ } else if (started) {
3416
+ if (observed.left._tag !== "ServiceUnavailable")
3417
+ return yield* observed.left;
3418
+ } else if (Option13.isSome(starter)) {
3419
+ started = true;
3420
+ yield* startService(starter.value.start);
3421
+ continue;
3422
+ } else {
3423
+ return yield* observed.left;
3424
3424
  }
3425
3425
  yield* Effect6.sleep("250 millis");
3426
3426
  }
@@ -5841,8 +5841,73 @@ var registerMagnitudeCommands = (pi, sdk = clientLayer2()) => {
5841
5841
  };
5842
5842
  };
5843
5843
 
5844
+ // extensions/onboarding.ts
5845
+ import * as FileSystem from "@effect/platform/FileSystem";
5846
+ import * as NodeFileSystem2 from "@effect/platform-node/NodeFileSystem";
5847
+ import { getAgentDir, parseArgs } from "@earendil-works/pi-coding-agent";
5848
+ import { Effect as Effect11, Exit as Exit3, Scope as Scope4 } from "effect";
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.";
5851
+ var SETUP_QUESTION = "Set up local models with Magnitude now?";
5852
+ 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;
5855
+ const directory = `${agentDir}/magnitude`;
5856
+ 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)));
5858
+ });
5859
+ function canOfferSetup(ctx, argv) {
5860
+ if (ctx.mode !== "tui" || !ctx.isIdle() || ctx.hasPendingMessages() || ctx.ui.getEditorText().trim())
5861
+ return false;
5862
+ if (ctx.sessionManager.getEntries().some((entry) => entry.type === "message"))
5863
+ return false;
5864
+ if (ctx.modelRegistry.getAll().some((model2) => model2.provider === "magnitude"))
5865
+ return false;
5866
+ const args = parseArgs([...argv]);
5867
+ return args.messages.length === 0 && args.fileArgs.length === 0;
5868
+ }
5869
+ var offerSetup = (pi, ctx, agentDir, signal) => Effect11.gen(function* () {
5870
+ if (!(yield* claimSetupOffer(agentDir)) || signal.aborted)
5871
+ return;
5872
+ const accepted = yield* Effect11.tryPromise(() => ctx.ui.confirm(SETUP_QUESTION, "", { signal }));
5873
+ if (signal.aborted)
5874
+ return;
5875
+ if (accepted && ctx.isIdle() && !ctx.hasPendingMessages())
5876
+ pi.sendUserMessage(SETUP_PROMPT);
5877
+ else
5878
+ pi.sendMessage({ customType: "magnitude-setup", content: SETUP_REMINDER, display: true });
5879
+ });
5880
+ function registerMagnitudeOnboarding(pi) {
5881
+ 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
+ });
5893
+ pi.on("resources_discover", () => {
5894
+ if (parseArgs(process.argv.slice(2)).noSkills || pi.getCommands().some((command) => command.source === "skill" && command.name === "skill:magnitude"))
5895
+ return;
5896
+ return { skillPaths: [fileURLToPath(new URL("./skills/magnitude/SKILL.md", import.meta.url))] };
5897
+ });
5898
+ pi.on("session_start", (event, ctx) => {
5899
+ if (event.reason !== "startup" || !canOfferSetup(ctx, process.argv.slice(2)))
5900
+ 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));
5902
+ });
5903
+ return () => {
5904
+ abort.abort();
5905
+ return Effect11.runPromise(Scope4.close(scope, Exit3.void));
5906
+ };
5907
+ }
5908
+
5844
5909
  // extensions/observing-fetch.ts
5845
- import { Effect as Effect11, Either as Either3, Schema as Schema52 } from "effect";
5910
+ import { Effect as Effect12, Either as Either3, Schema as Schema52 } from "effect";
5846
5911
 
5847
5912
  // extensions/protocol.ts
5848
5913
  import { Either as Either2, Schema as Schema51 } from "effect";
@@ -5913,21 +5978,21 @@ class SseDataParser {
5913
5978
  observe(decoded.right);
5914
5979
  }
5915
5980
  }
5916
- var observeResponse = (response, request, signal) => Effect11.scoped(Effect11.gen(function* () {
5981
+ var observeResponse = (response, request, signal) => Effect12.scoped(Effect12.gen(function* () {
5917
5982
  if (!response.ok || response.body === null) {
5918
5983
  yield* request.fail;
5919
5984
  return;
5920
5985
  }
5921
- const reader = yield* Effect11.acquireRelease(Effect11.sync(() => response.body.getReader()), (reader2) => Effect11.promise(() => reader2.cancel()).pipe(Effect11.interruptible, Effect11.timeout("100 millis"), Effect11.ignore, Effect11.ensuring(Effect11.sync(() => reader2.releaseLock()))));
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()))));
5922
5987
  if (signal.aborted) {
5923
5988
  yield* request.fail;
5924
5989
  return;
5925
5990
  }
5926
5991
  const decoder = new TextDecoder;
5927
5992
  const parser = new SseDataParser;
5928
- const drain = Effect11.gen(function* () {
5993
+ const drain = Effect12.gen(function* () {
5929
5994
  while (true) {
5930
- const result = yield* Effect11.tryPromise(() => reader.read());
5995
+ const result = yield* Effect12.tryPromise(() => reader.read());
5931
5996
  if (result.done)
5932
5997
  break;
5933
5998
  const values = [];
@@ -5940,35 +6005,35 @@ var observeResponse = (response, request, signal) => Effect11.scoped(Effect11.ge
5940
6005
  }
5941
6006
  yield* request.finish;
5942
6007
  });
5943
- const aborted = Effect11.async((resume) => {
5944
- const abort = () => resume(Effect11.interrupt);
6008
+ const aborted = Effect12.async((resume) => {
6009
+ const abort = () => resume(Effect12.interrupt);
5945
6010
  signal.addEventListener("abort", abort, { once: true });
5946
6011
  if (signal.aborted)
5947
6012
  abort();
5948
- return Effect11.sync(() => signal.removeEventListener("abort", abort));
6013
+ return Effect12.sync(() => signal.removeEventListener("abort", abort));
5949
6014
  });
5950
- yield* Effect11.raceFirst(drain, aborted).pipe(Effect11.onError(() => request.fail));
5951
- })).pipe(Effect11.catchAllCause(() => Effect11.void));
6015
+ yield* Effect12.raceFirst(drain, aborted).pipe(Effect12.onError(() => request.fail));
6016
+ })).pipe(Effect12.catchAllCause(() => Effect12.void));
5952
6017
  var makeObservingFetch = (fetchImplementation, begin, scope) => {
5953
6018
  const observingFetch = async (input, init) => {
5954
6019
  const request = new Request(input, init);
5955
6020
  request.headers.set(MAGNITUDE_PROGRESS_HEADER, "true");
5956
- const progress = Effect11.runSync(Effect11.suspend(begin).pipe(Effect11.catchAllCause(() => Effect11.succeed({
5957
- observe: () => Effect11.void,
5958
- finish: Effect11.void,
5959
- fail: Effect11.void
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
5960
6025
  }))));
5961
6026
  try {
5962
6027
  const response = await fetchImplementation(request);
5963
6028
  try {
5964
6029
  const observation = observeResponse(response.clone(), progress, request.signal);
5965
- Effect11.runFork(Effect11.forkIn(observation, scope));
6030
+ Effect12.runFork(Effect12.forkIn(observation, scope));
5966
6031
  } catch {
5967
- Effect11.runSync(progress.fail.pipe(Effect11.catchAllCause(() => Effect11.void)));
6032
+ Effect12.runSync(progress.fail.pipe(Effect12.catchAllCause(() => Effect12.void)));
5968
6033
  }
5969
6034
  return response;
5970
6035
  } catch (error) {
5971
- Effect11.runSync(progress.fail.pipe(Effect11.catchAllCause(() => Effect11.void)));
6036
+ Effect12.runSync(progress.fail.pipe(Effect12.catchAllCause(() => Effect12.void)));
5972
6037
  throw error;
5973
6038
  }
5974
6039
  };
@@ -5979,7 +6044,7 @@ var makeObservingFetch = (fetchImplementation, begin, scope) => {
5979
6044
 
5980
6045
  // extensions/progress.ts
5981
6046
  import { Text } from "@earendil-works/pi-tui";
5982
- import { Data as Data3, Effect as Effect12, Fiber as Fiber2, Option as Option17, Queue, Schema as Schema53 } from "effect";
6047
+ import { Data as Data3, Effect as Effect13, Fiber as Fiber2, Option as Option17, Queue, Schema as Schema53 } from "effect";
5983
6048
  var MAGNITUDE_SUMMARY_WIDGET_KEY = "magnitude-inference-summary";
5984
6049
  var RequestId = Schema53.Number.pipe(Schema53.int(), Schema53.brand("ProgressRequestId"));
5985
6050
 
@@ -6036,21 +6101,21 @@ var formatLiveProgress = ({ progress, modelName, startedAt }, now) => {
6036
6101
  }
6037
6102
  }
6038
6103
  };
6039
- var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(function* () {
6104
+ var makeProgressTracker = (ui, now = () => performance.now()) => Effect13.gen(function* () {
6040
6105
  let state = new Idle2;
6041
6106
  let nextId = 0;
6042
6107
  let active;
6043
6108
  let latest;
6044
6109
  let nextResponseId = 0;
6045
6110
  const wake = yield* Queue.sliding(1);
6046
- const present = (f) => Effect12.sync(f).pipe(Effect12.catchAllCause(() => Effect12.void));
6111
+ const present = (f) => Effect13.sync(f).pipe(Effect13.catchAllCause(() => Effect13.void));
6047
6112
  const clearSummary = present(() => ui.setWidget(MAGNITUDE_SUMMARY_WIDGET_KEY, undefined));
6048
6113
  const resetRow = present(() => ui.setWorkingMessage());
6049
6114
  const render2 = present(() => {
6050
6115
  if (active)
6051
6116
  ui.setWorkingMessage(formatLiveProgress(active.phase, now()));
6052
6117
  });
6053
- const finalize = Effect12.gen(function* () {
6118
+ const finalize = Effect13.gen(function* () {
6054
6119
  if (state._tag !== "Settled")
6055
6120
  return;
6056
6121
  if ([...state.run.responses.values()].some(Option17.isNone))
@@ -6069,7 +6134,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6069
6134
  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` : "");
6070
6135
  yield* present(() => ui.setWidget(MAGNITUDE_SUMMARY_WIDGET_KEY, (_tui, theme) => new Text(theme.fg("muted", summary), 0, 0)));
6071
6136
  });
6072
- const clear = Effect12.gen(function* () {
6137
+ const clear = Effect13.gen(function* () {
6073
6138
  if (state._tag === "Disposed")
6074
6139
  return;
6075
6140
  if (state._tag !== "Idle")
@@ -6079,7 +6144,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6079
6144
  yield* resetRow;
6080
6145
  yield* clearSummary;
6081
6146
  });
6082
- const startRun = (modelName) => Effect12.gen(function* () {
6147
+ const startRun = (modelName) => Effect13.gen(function* () {
6083
6148
  if (state._tag === "Disposed")
6084
6149
  return;
6085
6150
  if (state._tag === "Settled")
@@ -6089,14 +6154,14 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6089
6154
  state = runMachine.transition(state, "Working", { run: { startedAt: now(), modelName, requests: new Map, completed: new Map, responses: new Map, accepted: new Set } });
6090
6155
  yield* clearSummary;
6091
6156
  });
6092
- const timer = yield* Effect12.forever(Effect12.gen(function* () {
6157
+ const timer = yield* Effect13.forever(Effect13.gen(function* () {
6093
6158
  yield* Queue.take(wake);
6094
6159
  while (active) {
6095
- yield* Effect12.sleep("100 millis");
6160
+ yield* Effect13.sleep("100 millis");
6096
6161
  yield* render2;
6097
6162
  }
6098
- })).pipe(Effect12.forkScoped);
6099
- yield* Effect12.addFinalizer(() => Effect12.gen(function* () {
6163
+ })).pipe(Effect13.forkScoped);
6164
+ yield* Effect13.addFinalizer(() => Effect13.gen(function* () {
6100
6165
  yield* clear;
6101
6166
  if (state._tag !== "Disposed")
6102
6167
  state = runMachine.transition(state, "Disposed", {});
@@ -6105,19 +6170,19 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6105
6170
  return {
6106
6171
  startRun,
6107
6172
  clear,
6108
- settleRun: Effect12.gen(function* () {
6173
+ settleRun: Effect13.gen(function* () {
6109
6174
  if (state._tag === "Working")
6110
6175
  state = runMachine.transition(state, "Settled", { settledAt: now() });
6111
6176
  yield* finalize;
6112
6177
  }),
6113
- beginResponse: (modelName) => Effect12.gen(function* () {
6178
+ beginResponse: (modelName) => Effect13.gen(function* () {
6114
6179
  yield* startRun(modelName);
6115
6180
  const run = state._tag === "Working" ? state.run : undefined;
6116
6181
  const responseId = ++nextResponseId;
6117
6182
  const requests = [];
6118
6183
  run?.responses.set(responseId, Option17.none());
6119
6184
  const belongs = () => run !== undefined && (state._tag === "Working" || state._tag === "Settled") && state.run === run;
6120
- const end = (successful) => Effect12.gen(function* () {
6185
+ const end = (successful) => Effect13.gen(function* () {
6121
6186
  if (!belongs() || Option17.isSome(run.responses.get(responseId)))
6122
6187
  return;
6123
6188
  run.responses.set(responseId, Option17.some(successful));
@@ -6139,16 +6204,16 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6139
6204
  }
6140
6205
  yield* finalize;
6141
6206
  });
6142
- const begin = Effect12.gen(function* () {
6207
+ const begin = Effect13.gen(function* () {
6143
6208
  if (!belongs() || Option17.isSome(run.responses.get(responseId)))
6144
- return { observe: () => Effect12.void, finish: Effect12.void, fail: Effect12.void };
6209
+ return { observe: () => Effect13.void, finish: Effect13.void, fail: Effect13.void };
6145
6210
  const id = RequestId.make(++nextId);
6146
6211
  requests.push(id);
6147
6212
  latest = id;
6148
6213
  active = undefined;
6149
6214
  run?.requests.set(id, new Observing({ timings: Option17.none() }));
6150
6215
  yield* resetRow;
6151
- const close = (failed) => Effect12.gen(function* () {
6216
+ const close = (failed) => Effect13.gen(function* () {
6152
6217
  if (!belongs())
6153
6218
  return;
6154
6219
  const request = run.requests.get(id);
@@ -6168,7 +6233,7 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6168
6233
  yield* finalize;
6169
6234
  });
6170
6235
  return {
6171
- observe: (observation) => Effect12.gen(function* () {
6236
+ observe: (observation) => Effect13.gen(function* () {
6172
6237
  if (!belongs())
6173
6238
  return;
6174
6239
  const request = run.requests.get(id);
@@ -6199,34 +6264,35 @@ var makeProgressTracker = (ui, now = () => performance.now()) => Effect12.gen(fu
6199
6264
  });
6200
6265
 
6201
6266
  // extensions/magnitude.ts
6202
- import { Effect as Effect13, Exit as Exit3, Scope as Scope5 } from "effect";
6267
+ import { Effect as Effect14, Exit as Exit4, Scope as Scope6 } from "effect";
6203
6268
  function magnitudeExtension(pi) {
6204
6269
  const completions = openAICompletionsApi();
6205
6270
  let tracker;
6206
6271
  let scope;
6207
6272
  const disposeCommands = registerMagnitudeCommands(pi);
6208
- const perform = (effect) => Effect13.runSync((effect ?? Effect13.void).pipe(Effect13.catchAllCause(() => Effect13.void)));
6273
+ const disposeOnboarding = registerMagnitudeOnboarding(pi);
6274
+ const perform = (effect) => Effect14.runSync((effect ?? Effect14.void).pipe(Effect14.catchAllCause(() => Effect14.void)));
6209
6275
  pi.registerProvider("magnitude", {
6210
6276
  api: "openai-completions",
6211
6277
  streamSimple: (model2, context, options) => {
6212
6278
  if (model2.api !== "openai-completions") {
6213
6279
  throw new Error(`Magnitude for Pi requires openai-completions, received ${model2.api}`);
6214
6280
  }
6215
- const response = tracker && Effect13.runSync(tracker.beginResponse(model2.name));
6281
+ const response = tracker && Effect14.runSync(tracker.beginResponse(model2.name));
6216
6282
  const stream = completions.streamSimple(model2, context, {
6217
6283
  ...options,
6218
- fetch: scope ? makeObservingFetch(options?.fetch ?? globalThis.fetch, () => response?.begin ?? Effect13.succeed({ observe: () => Effect13.void, finish: Effect13.void, fail: Effect13.void }), scope) : options?.fetch ?? globalThis.fetch
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
6219
6285
  });
6220
6286
  if (response && scope)
6221
- Effect13.runFork(Effect13.forkIn(Effect13.tryPromise(() => stream.result()).pipe(Effect13.flatMap((message) => response.end(message.stopReason !== "error" && message.stopReason !== "aborted")), Effect13.catchAllCause(() => response.end(false))), 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));
6222
6288
  return stream;
6223
6289
  }
6224
6290
  });
6225
6291
  pi.on("session_start", async (_event, ctx) => {
6226
6292
  if (scope)
6227
- await Effect13.runPromise(Scope5.close(scope, Exit3.void));
6228
- scope = Effect13.runSync(Scope5.make());
6229
- tracker = await Effect13.runPromise(makeProgressTracker(ctx.ui).pipe(Scope5.extend(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)));
6230
6296
  });
6231
6297
  pi.on("model_select", (event) => {
6232
6298
  if (event.model.provider !== "magnitude")
@@ -6238,8 +6304,9 @@ function magnitudeExtension(pi) {
6238
6304
  });
6239
6305
  pi.on("agent_settled", () => perform(tracker?.settleRun));
6240
6306
  pi.on("session_shutdown", async () => {
6307
+ await disposeOnboarding();
6241
6308
  if (scope)
6242
- await Effect13.runPromise(Scope5.close(scope, Exit3.void));
6309
+ await Effect14.runPromise(Scope6.close(scope, Exit4.void));
6243
6310
  tracker = undefined;
6244
6311
  scope = undefined;
6245
6312
  await disposeCommands();
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: magnitude
3
+ description: Set up and operate Magnitude local inference through its CLI, recommend hardware-fit local models, monitor acquisition and loading, and connect an agent harness. Use for Magnitude service, model, catalog, setup, or harness requests.
4
+ ---
5
+
6
+ # Magnitude
7
+
8
+ Magnitude profiles the local machine, assesses compatible model configurations, acquires and runs
9
+ selected models, and connects them to supported agent harnesses.
10
+
11
+ For agent-guided setup, read `magnitude docs onboarding` completely and follow it. It contains the
12
+ current CLI-only workflow, model-selection evidence, progress semantics, and harness connection
13
+ rules.
14
+
15
+ For the general non-interactive command contract, read `magnitude docs cli`. Command output is
16
+ designed to be read directly by both agents and people.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magnitudedev/pi-extension",
3
- "version": "0.0.1-alpha.0",
3
+ "version": "0.0.1-alpha.1",
4
4
  "description": "Magnitude model controls and inference progress for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",