@nteract/pi 0.1.6 → 0.1.10

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.
Files changed (2) hide show
  1. package/extensions/repl.ts +53 -22
  2. package/package.json +8 -6
@@ -16,11 +16,13 @@
16
16
  * After editing, run `/reload` in pi.
17
17
  */
18
18
 
19
- import type { ExtensionAPI, ImageContent, TextContent } from "@mariozechner/pi-coding-agent";
20
- import { highlightCode } from "@mariozechner/pi-coding-agent";
21
- import { Text, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
19
+ import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
20
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
21
+ import { highlightCode } from "@earendil-works/pi-coding-agent";
22
+ import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
22
23
  import { existsSync } from "node:fs";
23
24
  import { createRequire } from "node:module";
25
+ import { homedir } from "node:os";
24
26
  import path from "node:path";
25
27
  import { fileURLToPath } from "node:url";
26
28
  import { Type } from "typebox";
@@ -208,13 +210,26 @@ function formatStat(stats: ColumnStats | null): string {
208
210
  }
209
211
  }
210
212
 
213
+ function resolvePath(userPath: string, workingDir = process.cwd()): string {
214
+ const expanded = expandHome(userPath);
215
+ return path.isAbsolute(expanded) ? expanded : path.resolve(workingDir, expanded);
216
+ }
217
+
218
+ function expandHome(userPath: string): string {
219
+ if (userPath === "~") return homedir();
220
+ if (userPath.startsWith("~/") || userPath.startsWith("~\\")) {
221
+ return path.join(homedir(), userPath.slice(2));
222
+ }
223
+ return userPath;
224
+ }
225
+
211
226
  const SPARK_CHARS = "▁▂▃▄▅▆▇█";
212
227
 
213
228
  function sparkline(values: number[], width: number): string {
214
229
  if (values.length === 0 || width <= 0) return "";
215
230
  const min = Math.min(...values);
216
231
  const max = Math.max(...values);
217
- const bins = new Array(Math.min(width, 8)).fill(0);
232
+ const bins = Array.from({ length: Math.min(width, 8) }, () => 0);
218
233
  if (min === max) {
219
234
  return SPARK_CHARS[3].repeat(bins.length);
220
235
  }
@@ -576,6 +591,31 @@ const PYTHON_PARAMS = Type.Object({
576
591
  ),
577
592
  });
578
593
 
594
+ const ADD_DEPENDENCIES_PARAMS = Type.Object({
595
+ packages: Type.Array(Type.String(), {
596
+ description: "Package specs (e.g. ['matplotlib', 'pandas>=2']).",
597
+ }),
598
+ });
599
+
600
+ type AddDependenciesDetails = {
601
+ notebook_id?: string;
602
+ packages?: string[];
603
+ };
604
+
605
+ const SAVE_NOTEBOOK_PARAMS = Type.Object({
606
+ path: Type.Optional(
607
+ Type.String({
608
+ description:
609
+ "File path to save to (e.g. './analysis.ipynb'). If omitted, saves to the original location.",
610
+ }),
611
+ ),
612
+ });
613
+
614
+ type SaveNotebookDetails = {
615
+ notebook_id: string;
616
+ path?: string;
617
+ };
618
+
579
619
  export default function nteractReplExtension(pi: ExtensionAPI) {
580
620
  const bootstrap = detectBootstrap();
581
621
  if (bootstrap.kind === "missing") {
@@ -644,6 +684,7 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
644
684
  // channel auto-detect.
645
685
  session = await rn.createNotebook({
646
686
  runtime: "python",
687
+ workingDir: process.cwd(),
647
688
  peerLabel: "pi",
648
689
  description: "pi Python REPL",
649
690
  dependencies,
@@ -856,18 +897,14 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
856
897
  },
857
898
  });
858
899
 
859
- pi.registerTool({
900
+ pi.registerTool<typeof ADD_DEPENDENCIES_PARAMS, AddDependenciesDetails>({
860
901
  name: "python_add_dependencies",
861
902
  label: "Add Dependencies",
862
903
  description:
863
904
  "Install packages into the running Python environment without restarting. Accepts pip-style specs like 'matplotlib', 'numpy>=2', 'requests'. The kernel stays hot.",
864
905
  promptSnippet:
865
906
  "python_add_dependencies: install packages into the running Python session (no restart needed).",
866
- parameters: Type.Object({
867
- packages: Type.Array(Type.String(), {
868
- description: "Package specs (e.g. ['matplotlib', 'pandas>=2']).",
869
- }),
870
- }),
907
+ parameters: ADD_DEPENDENCIES_PARAMS,
871
908
  async execute(_toolCallId, params, signal) {
872
909
  if (signal?.aborted) throw new Error("aborted");
873
910
  if (!params.packages.length) {
@@ -887,28 +924,22 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
887
924
  },
888
925
  });
889
926
 
890
- pi.registerTool({
927
+ pi.registerTool<typeof SAVE_NOTEBOOK_PARAMS, SaveNotebookDetails>({
891
928
  name: "python_save_notebook",
892
929
  label: "Save Notebook",
893
930
  description:
894
931
  "Save the current Python session as an .ipynb file. If no path is given, saves to the original location (if it was opened from a file). Provide a path to save elsewhere.",
895
932
  promptSnippet: "python_save_notebook: save the current session as an .ipynb file.",
896
- parameters: Type.Object({
897
- path: Type.Optional(
898
- Type.String({
899
- description:
900
- "File path to save to (e.g. './analysis.ipynb'). If omitted, saves to the original location.",
901
- }),
902
- ),
903
- }),
933
+ parameters: SAVE_NOTEBOOK_PARAMS,
904
934
  async execute(_toolCallId, params, signal) {
905
935
  if (signal?.aborted) throw new Error("aborted");
906
936
  const sess = await ensureSession();
907
- await sess.saveNotebook(params.path);
908
- const where = params.path ?? "original location";
937
+ const savePath = params.path ? resolvePath(params.path) : undefined;
938
+ await sess.saveNotebook(savePath);
939
+ const where = savePath ?? "original location";
909
940
  return {
910
941
  content: [{ type: "text", text: `Notebook saved to ${where}` }],
911
- details: { notebook_id: sess.notebookId, path: params.path },
942
+ details: { notebook_id: sess.notebookId, path: savePath },
912
943
  };
913
944
  },
914
945
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nteract/pi",
3
- "version": "0.1.6",
3
+ "version": "0.1.10",
4
4
  "description": "Persistent notebook-backed Python REPL for Pi coding agents. Stateful execution, hot dependency sync, zero cold starts.",
5
5
  "author": "nteract contributors",
6
6
  "icon": "icon.png",
@@ -36,19 +36,21 @@
36
36
  "extensions"
37
37
  ],
38
38
  "dependencies": {
39
- "@runtimed/node": "0.2.4"
39
+ "@runtimed/node": "0.2.7"
40
40
  },
41
41
  "peerDependencies": {
42
- "@mariozechner/pi-coding-agent": "*",
43
- "@mariozechner/pi-tui": "*",
42
+ "@earendil-works/pi-ai": "*",
43
+ "@earendil-works/pi-coding-agent": "*",
44
+ "@earendil-works/pi-tui": "*",
44
45
  "typebox": "*"
45
46
  },
46
47
  "publishConfig": {
47
48
  "access": "public"
48
49
  },
49
50
  "devDependencies": {
50
- "@mariozechner/pi-coding-agent": "^0.73.0",
51
- "@mariozechner/pi-tui": "^0.73.0"
51
+ "@earendil-works/pi-ai": "^0.74.0",
52
+ "@earendil-works/pi-coding-agent": "^0.74.0",
53
+ "@earendil-works/pi-tui": "^0.74.0"
52
54
  },
53
55
  "scripts": {
54
56
  "pack:dry-run": "pnpm pack --dry-run"