Skip to content

v0.2.0: shadowing-proof package helpers, Pkg REPL console input, Create New Package command - #37

Merged
ntluong95 merged 7 commits into
mainfrom
v0.2.0/package-issues
Jul 4, 2026
Merged

ntluong95 merged 7 commits into
mainfrom
v0.2.0/package-issues

Conversation

@ntluong95

@ntluong95 ntluong95 commented Jul 4, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes three issues for the 0.2.0 release: #32, #35, and #31.

values shadowing crash in the package hooks (closes #32)

The package-pane helper script was included directly into Main, so every unqualified Base name it used resolved through the user's namespace — values = [3, 7, 2] shadowed Base.values and made the background _positron_list_packages() hook fail with a repeating "Julia package command failed" toast.

  • scripts/packages/packages.jl now defines everything inside a _PositronPackages module, so Base names always resolve to Base regardless of what the user defines in Main. This fixes the whole class of shadowing bugs (values, keys, filter, ...), not just the reported one.
  • The generated stdout-capture wrapper and the include call in src/packages.ts are Base.-qualified for the same reason (open, redirect_stdout, close, flush were equally shadowable).
  • Regression test simulates a user Main with values = [3, 7, 2, 5, 4] and runs the list hook through it.

Pkg REPL mode in the console (closes #35)

VSCodeServer binds the ] key in a LineEdit keymap that transitions the terminal REPL into Pkg.REPLMode. Positron's console is Jupyter-based and never sees raw keystrokes, so the transition happens on submission instead:

  • Submitting ] enters Pkg REPL mode. The console prompt changes to the environment-aware (@v1.12) pkg> / (MyProject) pkg> via Positron's prompt_state UI event (the same mechanism ark uses for R's browser() prompts).
  • While in the mode, every submission runs as a Pkg REPL command through Pkg.REPLMode (IJulia's version-aware bridge), with output in the console: status, add DataFrames, ?, etc.
  • back, exit, or quit returns to the julia> prompt — the Backspace/Ctrl-C keystrokes that leave the mode in a terminal can't reach a Jupyter kernel, so typed commands replace them (the entry message says so).
  • Silent background executions and the extension's package-pane calls bypass the mode; a fresh kernel resets the prompt when the UI comm opens, so a restart never leaves a stale pkg> prompt.
  • One-shot commands (] add DataFrames) still work from the julia> prompt, and check_code_complete now reports REPL special-mode lines (]..., ?foo, ;ls) as complete so the console executes them instead of treating them as invalid.

"Julia: Create New Package" command (closes #31)

New julia.createNewPackage command scaffolds a package with PkgTemplates.jl: prompts for a name (validated), a parent folder, and template options — git repository, MIT license, GitHub Actions CI, Documenter docs; tests and README are always included.

  • PkgTemplates runs in a Julia subprocess with a dedicated helper environment under the extension's global storage, so the user's own environments are never touched. First run installs PkgTemplates automatically.
  • Falls back to Pkg.generate (with a distinct success message) when PkgTemplates cannot be installed, e.g. offline.
  • A GitHub username is requested only when a selected option needs one (git remote URLs, badges), preferring git config github.user. The git option is pre-selected only when a git identity is configured.
  • Registry automation (TagBot, CompatHelper, Dependabot) is intentionally excluded from the scaffold; on success the package can be opened in a new window or added to the workspace.

Testing

  • Pkg.test("Positron"): 1001/1001 pass, including new tests for the shadowed-Main scenario, Pkg REPL mode enter/exit + completeness, the extension-internal bypass, and extract_pkg_repl_command.
  • Simulated the full mode flow in a live Julia process: enter → prompt label → status output through Pkg.REPLMode → exit.
  • tsc and esbuild bundle are clean.
  • create_package.jl exercised end-to-end for all three paths: full options (git+license+ci+docs → complete scaffold with initial commits), license-only without a username, and the offline Pkg.generate fallback.

🤖 Generated with Claude Code

ntluong95 and others added 4 commits July 4, 2026 07:52
The package-pane helper script was included directly into Main, so every
unqualified Base name it used resolved through the user's namespace. A
variable like `values = [3, 7, 2]` shadowed Base.values and made the
background _positron_list_packages() hook fail repeatedly with a
"Julia package command failed" toast.

Define the whole script inside a `_PositronPackages` module so Base names
always resolve to Base, qualify the generated stdout-capture wrapper and
the include call with `Base.`, and add a regression test that shadows
`values` in a scratch Main.

Closes #32

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Typing `]` in the console did nothing: the input parses as invalid Julia,
and IJulia maps a bare `]` to an empty Pkg command that produces no output,
so users assumed Pkg mode was broken.

- Treat single-line REPL special modes (`] add X`, `?foo`, `;ls`) as
  complete input in check_code_complete so the console executes them.
- Print guidance for a bare `]` (a modal pkg> prompt cannot exist in a
  Jupyter-based console) pointing to the supported one-line form, which
  IJulia already executes via Pkg.REPLMode.
- Extract the help-mode reply machinery into execute_positron_action and
  reuse it for the Pkg-mode guidance path.

Closes #35

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scaffolds a new package from the command palette: prompts for a name,
parent folder, and template options (git repository, MIT license, GitHub
Actions CI, Documenter docs; tests and README always included), then runs
PkgTemplates in a Julia subprocess. PkgTemplates lives in a dedicated
helper environment under the extension's global storage so user projects
are never touched, and the command falls back to Pkg.generate when
PkgTemplates cannot be installed (e.g. offline). A GitHub username is
requested only when a selected option needs one, preferring
`git config github.user`.

Closes #31

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 4, 2026 05:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares the extension for the v0.2.0 release by hardening the Julia package helper integration against user-global shadowing, improving console handling of Julia REPL “special modes” (Pkg/help/shell), and adding a new command to scaffold packages via PkgTemplates.

Changes:

  • Wrap scripts/packages/packages.jl helpers in _PositronPackages and update TypeScript to call helpers via the qualified module name; also Base-qualify generated wrapper calls to avoid Main shadowing.
  • Treat REPL special-mode one-liners (], ?, ;) as “complete” input and provide guidance output for bare ] in the Jupyter-based console.
  • Add julia.createNewPackage command to scaffold a new package using a dedicated helper environment and scripts/packages/create_package.jl, with fallback to Pkg.generate.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/runtime-manager.ts Adds a “preferred installation” selector for auxiliary tooling.
src/packages.ts Qualifies helper calls via _PositronPackages, Base-qualifies wrapper functions to avoid Main shadowing.
src/create-package.ts Implements the “Create New Package” command flow and subprocess runner.
src/commands.ts Registers the julia.createNewPackage command.
scripts/packages/packages.jl Moves package helper definitions into _PositronPackages module to prevent shadowing.
scripts/packages/create_package.jl Adds Julia-side scaffold script using PkgTemplates with Pkg.generate fallback.
julia/Positron/src/kernel.jl Adds REPL magic-line completeness handling and execute routing for Pkg/help behavior.
julia/Positron/test/test_kernel.jl Adds tests for REPL special modes and Pkg command extraction.
julia/Positron/test/test_package_helpers.jl Adds regression test for “shadowed Main” package helper behavior.
README.md Documents one-line Pkg commands support and the new create-package command.
package.json Bumps version to 0.2.0 and contributes/activates the new command.
package-lock.json Updates lockfile version metadata to 0.2.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/packages.ts
Comment on lines 761 to +763
`finally\n` +
`close(__positron_io)\n` +
`flush(__positron_err)\n` +
`Base.close(__positron_io)\n` +
`Base.flush(__positron_err)\n` +
ntluong95 and others added 3 commits July 4, 2026 11:32
Rework the #35 fix per review: a bare `]` now actually enters Pkg REPL
mode, forked from julia-vscode's REPL integration (VSCodeServer binds the
`]` key in a LineEdit keymap to transition the terminal REPL into
Pkg.REPLMode). A Jupyter-based console never sees raw keystrokes, so the
transition happens on submission instead:

- Submitting `]` switches the console into Pkg REPL mode; Positron's
  prompt_state UI event changes the prompt to the environment-aware
  `(@v1.12) pkg>` / `(MyProject) pkg>`.
- Every subsequent submission runs through Pkg.REPLMode (via IJulia's
  version-aware bridge) until `back`/`exit`/`quit` returns to julia>;
  the Backspace/Ctrl-C keystrokes that leave the mode in a terminal
  cannot reach the kernel, so typed commands replace them.
- Silent executions and the extension's package-pane calls bypass the
  mode, and a fresh kernel resets the prompt when the UI comm opens so
  a restart never leaves a stale pkg> prompt behind.
- One-shot `] add Foo` commands still work unchanged.

Refs #35

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xists

The kernel startup script activates the bundled julia/Positron package
first (to load Positron.jl's own dependencies), then only re-activates the
user's project if POSITRON_USER_PROJECT points to a directory with a
Project.toml/JuliaProject.toml. When neither is true - no workspace folder
open, or the folder has no project file - the kernel was left permanently
activated on the extension's own internal package, so `] status`,
`Pkg.add`, etc. silently targeted the extension's bundled dev environment
instead of the user's default global one. This is what the Pkg REPL mode
prompt surfaced as `(Positron) pkg>` instead of `(@v1.12) pkg>`.

Pkg.activate() with no arguments clears the explicit override and lets
Julia resolve the project the normal way (nearest Project.toml, else the
default global environment), exactly as if `--project` had never been
passed. Add that as the missing else branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ntluong95
ntluong95 merged commit 9b73c50 into main Jul 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants