Commit Graph

35 Commits

Author SHA1 Message Date
roboomp e414585155 fix(extensions): preserved unsafe schemas during install
- Lifted legacy Type.Unsafe documents into callable omptype schemas so Optional and Object composition preserve validation and required fields.
- Ran installed extension factories against the normal throwaway loader surface before accepting a plugin install.
- Added regression coverage and documented the stronger rollback gate.

Fixes #8143
2026-08-10 07:37:28 +00:00
roboomp 1fea9b149f fix(tui): guarded stdin against custom-tool import hijack
Custom tool/extension/hook/plugin modules under ~/.claude/tools are
evaluated with live side effects during createAgentSession. A module that
attaches a stdin consumer at import time — an MCP StdioServerTransport
built at module top level, or a bare process.stdin.resume() — steals
Bun's single stdin reader, so the TUI receives exactly one data event and
goes permanently deaf after the first keypress. Under tmux the terminal's
automatic DA1 reply is that one event, so the first user keystroke is
already dead: the input-deafness reported in #5378/#5618.

Broadened the loader's withExitGuard (renamed withHostGuard) to also
snapshot and restore process.stdin around third-party module evaluation:
any data/readable/end/close/error listener the module adds is removed, and
the stream's paused and raw-mode state is restored to the pre-load
snapshot. The exit guard already fenced process.exit; stdin is the same
class of host-state hijack.

Fixes #5618
2026-07-16 19:35:43 +00:00
can1357 55ad1ff1bc Merge PR #5505: fix(plugins): refresh stale Bun git cache before reinstall (@roboomp) 2026-07-14 23:11:07 +02:00
roboomp 2439f77e70 fix(plugins): refreshed stale bun git cache before reinstall
Fetched current heads and tags into Bun's matching cached bare clone before running bun update.

Added an isolated HTTP git regression covering a moved branch with a stale cache.

Fixes #5401
2026-07-14 19:37:06 +00:00
roboomp 63adfeece5 fix(plugin): handled pinned git source replacements
- Removed the stale pinned dependency edge before invoking Bun for same-repository git source replacements so Bun does not construct a dependency loop.

- Added a regression test for the pinned-to-unpinned GitHub plugin replacement path.

Fixes #4960
2026-07-09 18:35:43 +00:00
roboomp d2be57a8f7 fix(plugins): drain subprocess pipes concurrently with proc.exited
PluginManager.install (bun install + bun update), PluginManager.uninstall,
PluginManager.#fixMissingPlugin, the legacy installer.ts install/uninstall
helpers, and generate-legacy-pi-bundled-registry.ts's formatInPlace all
called Bun.spawn with stdout/stderr piped and awaited proc.exited before
touching either stream. Once a child's output exceeded the ~64 KiB OS
pipe buffer, the child would block on write(2) while the parent blocked
on exit — a classic pipe-buffer deadlock. Even where Bun's current runtime
happens to buffer eagerly, the pattern silently leaked unbounded bytes.

Each site now starts new Response(proc.stdout).text() and stderr readers
immediately after Bun.spawn and awaits them alongside proc.exited via
Promise.all. Existing error semantics are preserved: install throws with
stderr, uninstall keeps its generic error, and formatInPlace still includes
Biome's stderr in the failure message.

Adds a regression test (plugin-install-git.test.ts) that models the
OS-pipe deadlock by holding proc.exited until both mock streams are
drained — install must read them before awaiting exit, else the test hits
its 2s Promise.race timeout.

Fixes #4230
2026-07-02 08:33:32 +00:00
roboomp 500c39aa2e fix(extensions): isolate codex hook scripts so process.exit cannot kill OMP startup
Codex discovery surfaced every `~/.codex/hooks/*.{ts,js}` file as an OMP
hook (silently defaulting untyped names to `pre:<basename>`), and
`discoverExtensionPaths` then handed those paths to `loadExtension` for
dynamic import. A standalone Codex hook script with a top-level
`process.exit(0)` terminated the host CLI cleanly — `try/catch` around
`await import()` cannot intercept a synchronous exit, so OMP died at the
`loadExtensions:start` startup marker with no error surface.

Two-layer fix:

- `packages/coding-agent/src/extensibility/utils.ts`: new
  `withExitGuard` helper patches `process.exit` for the duration of a
  guarded callback so an exit raises `ExtensionExitError` instead of
  terminating the process; nested and concurrent guards restore correctly
  via depth counter.
- `extensibility/extensions/loader.ts`, `extensibility/hooks/loader.ts`,
  and `extensibility/plugins/manager.ts` wrap their dynamic-import sites
  in `withExitGuard` so the existing per-module `try/catch` records the
  intercepted exit as a load error and OMP keeps starting.
- `discovery/codex.ts:loadHooks` no longer treats arbitrary files as
  OMP hooks: only `pre-<tool>.{ts,js}` and `post-<tool>.{ts,js}` are
  registered. Files like `memory-bank-reminder.ts` are silently skipped
  rather than imported as extension factories.

Adds regression coverage:

- `test/extension-loader-process-exit.test.ts` — `loadExtensions` /
  `loadHooks` return errors and leave `process.exit` restored when a
  module exits at import time; sibling modules still load.
- `test/discovery/codex-hooks-discovery.test.ts` — codex provider
  registers `pre-*` / `post-*` files and drops everything else.

Fixes #3680
2026-06-27 20:38:53 +00:00
roboomp e3fb8956a2 fix(coding-agent): treated legacy scope-less marketplace entries as user
Coerced missing scope on installed_plugins.json entries to user before suppressing them, matching listClaudePluginRoots semantics, so users carrying registries written before the scope field still see marketplace plugins hidden from plugin list and doctor.

Fixes #3628
2026-06-27 05:19:03 +00:00
roboomp cf3425cc61 fix(coding-agent): suppressed package-less marketplace plugins
Derived marketplace runtime package names from plugin IDs when package.json is absent, preserving suppression for config-only marketplace installs. Added regression coverage for package-less LSP plugin installs in plugin list and doctor.

Fixes #3628
2026-06-27 05:16:54 +00:00
roboomp a4256d6507 fix(coding-agent): preserved same-name plugin links
Compared marketplace runtime entries by realpath before suppressing link-only plugin-manager entries. Added a regression where a local runtime link reuses a marketplace package name but points at a different path.

Fixes #3628
2026-06-27 05:12:57 +00:00
roboomp e36172c32c fix(coding-agent): hid marketplace plugins from npm lists
Filtered marketplace-managed runtime symlinks out of the npm plugin listing and OMP extension-package status provider while keeping marketplace installs available to the runtime loader. Added regressions for both duplicate surfaces.

Fixes #3628
2026-06-27 05:04:28 +00:00
roboomp a63da8a3a3 fix(coding-agent): made plugin install transaction atomic on validation failure
The #3063 fix introduced a second mutating step — `bun update <name>` —
that rewrites bun.lock before extension validation runs. Three failure
paths could still leave the rejected commit pinned in the lockfile or
active tree:

- Extension validation throwing after `bun update` had refreshed
  bun.lock — rollback restored package.json and node_modules/<name>
  but never touched bun.lock.
- Feature validation (`omp plugin install pkg[ghost]`) throwing
  outside the rollback block entirely.
- Runtime-config save failing after a successful install with no
  rollback path.

Snapshot bun.lock alongside package.json before `bun install` runs and
route every post-install step (resolution, update, package.json read,
feature validation, extension validation, runtime-config save) through
one outer catch that restores all three (package.json + bun.lock +
node_modules/<name> from snapshot). `#rollbackFailedInstall` now
tolerates an unresolved `actualName` for failures that throw before
the dep key is known.

Three regression tests in plugin-install-validation.test.ts pin the
new contract: bun.lock restoration after a git reinstall fails
validation, bun.lock removal when it didn't exist pre-install, and
rollback on an unknown feature request.

Addresses review feedback on #3069.
2026-06-19 18:33:33 +00:00
roboomp 0ada5fe168 fix(coding-agent): refreshed github plugin lockfile pin on re-install
bun install <spec> respects the existing bun.lock pin when the spec is
unchanged and never re-resolves the remote ref, so re-running
`omp plugin install github:owner/repo` on an already-installed plugin
reported success while silently keeping the user on the original
resolved commit (1ms no-op, no network).

PluginManager.install now follows a git re-install with
`bun update <name>` to force re-resolution of the ref against the
upstream. First-time installs (no prior dep entry) skip the update —
the initial bun install already fetches HEAD. bun update failures
trigger the same rollback path as validation failures.

Fixes #3063
2026-06-19 18:22:57 +00:00
roboomp 4c336543d5 fix(cli): preserved linked plugin doctor state
Taught plugin doctor to treat lockfile-only plugins with node_modules entries as installed instead of orphaned.

Added coverage for plugin doctor --fix after linking a local plugin without package dependencies.

Fixes #2742
2026-06-16 05:17:24 +00:00
roboomp 7244e21b73 fix(cli): listed linked local plugins
Included lockfile-only linked plugins when building plugin list output so local symlink installs are visible after successful link operations.

Added regression coverage for plugin link followed by plugin list --json.

Fixes #2742
2026-06-16 05:02:20 +00:00
can1357 39d819e8b9 Merge PR #2237: fix(coding-agent): handle legacy plugin config settings 2026-06-15 19:46:15 +02:00
roboomp 54922241d9 fix(cli): restored git plugin upgrades by repo identity
Matched installed git dependencies by parsed host and repo path instead of the new ref so failed ref upgrades restore the prior package tree.
2026-06-11 16:46:41 +00:00
roboomp bfbbbb02af fix(cli): rejected plugins declaring missing extension entries
Surfaced manifest entries that resolve to nothing on disk at install time instead of silently skipping them through resolvePluginExtensionPaths.
2026-06-11 16:42:27 +00:00
roboomp dd5936701e fix(cli): restored plugin tree after invalid reinstall
Backed up existing npm plugin package trees before reinstall validation so failed extension loads restore the previous working package contents.
2026-06-11 16:39:39 +00:00
roboomp 9842ad8494 fix(cli): rejected unloadable npm plugin installs
Validated npm plugin extension entry points before recording installs and rolled back fresh installs that cannot resolve their extension imports.

Fixes #2312
2026-06-11 16:32:27 +00:00
roboomp 9347f8f4a4 fix(coding-agent): handled legacy plugin config settings
Normalized persisted plugin runtime config before manager and loader callers use it, so older lockfiles without a settings object can still accept plugin config writes.

Added a regression test covering setting a plugin option against a legacy lockfile.

Fixes #2236
2026-06-10 06:57:32 +00:00
can1357 9f547d8e4f refactor(mnemosyne/core): typed embedding provider outputs and tightened normalization
- Defined `EmbeddingRow` and `EmbeddingOutput` in runtime options and exported them from core embeddings.
- Updated `EmbeddingProvider`, `MnemosyneEmbeddingProvider`, and `provider` runtime option types to return `EmbeddingOutput` instead of `unknown`.
- Refactored embedding result normalization to accept typed rows and sync/async batches and coerce them into validated `Float32Array` vectors.
2026-05-31 05:32:28 +02:00
can1357 495c570ed4 fix(coding-agent): normalize hosted plugin git shorthands
Addresses review feedback on #1527.
2026-05-31 04:47:39 +02:00
oldschoola 22e564a85d feat(coding-agent): accept GitHub/git URLs in plugin install
Extends `omp plugin install` to accept git sources alongside npm specs and
marketplace refs. Bun's installer already understands git URLs; the blocker
was `PluginManager.install`'s strict npm-name validator and the assumption
that the actual package name could be derived from the spec.

- `git-url.ts`: `parseGitUrl` now recognizes npm-style namespaced shorthand
  (`github:user/repo`, `gitlab:`, `bitbucket:`, `codeberg:`, `sourcehut:` /
  `srht:`), with optional `#ref` and `.git` suffix. Exposes `isGitSpec` as
  `parseGitUrl(s) !== null`. Existing protocol-URL and `git:` shorthand paths
  are untouched.
- `manager.ts`: `install()` branches on `isGitSpec`. Git specs go through a
  separate `validateGitSpec` (shell-metachar rejection only — `/`, `:`, `@`,
  `#`, `+` are legal) and the real package name is discovered by snapshotting
  `plugins/package.json` deps before `bun install` and diffing afterwards.
  Falls back to value-match on force-reinstall where the key already exists.
- Help text in `plugin-cli` documents the new sources and adds a github:
  example.

Smoke tested end-to-end on Windows with both forms against the test repo:
  PluginManager.install('github:oldschoola/omp-insights')
  PluginManager.install('https://github.com/oldschoola/omp-insights')
both resolve `@oldschoola/omp-insights@1.2.3` and write a correct lock entry.
Shell-injection probe (`github:foo/bar; rm -rf /`) is rejected.
2026-05-31 04:46:08 +02:00
can1357 b8e82008e3 feat(coding-agent): added extension filtering and granular capability identification
- Added `toExtensionId()` method to all capability types for granular extension identification and disabling.
- Added `disabledExtensions` and `includeDisabled` options to LoadOptions for filtering disabled capabilities by extension ID.
- Added plugin manifest support for `extensions` entry points with automatic discovery from installed plugins.
- Fixed skill loading to properly respect disabled skill names from custom directories.
- Improved cross-platform path handling by using `path.basename()` instead of string splitting in context file and state manager.
- Refactored capability index loading to validate source metadata and filter disabled extensions before processing.
2026-03-15 17:26:46 +01:00
can1357 a83175c94c refactor: migrated imports to unified package root and consolidated skill discovery logic
- Consolidated @oh-my-pi/pi-utils subpath imports into single package root import across 100+ files.
- Moved tryParseJson utility from local web scrapers module to @oh-my-pi/pi-utils package for centralized JSON parsing.
- Renamed loadSkillsFromDir to scanSkillsFromDir and refactored skill discovery to use fs.promises.readdir instead of glob-based approach.
- Replaced custom parseJSON with tryParseJson across discovery modules for consistent error handling.
- Removed emitCustomToolSessionEvent method and cleanupSshResources function, consolidating shutdown logic into dispose method.
- Updated glob pattern construction to use GlobBuilder with literal_separator(true) for improved path handling.
2026-02-23 20:59:17 +01:00
can1357 d1e16d2101 refactor: implemented $PWD > cwd to prevent macOS symlink resolution
- Replaced all direct `process.cwd()` calls with `getProjectDir()` utility function across 40+ files to centralize project directory resolution logic.
- Added `getProjectDir()` and `setProjectDir()` functions to `@oh-my-pi/pi-utils/dirs` module to provide abstracted project directory management.
- Made `SessionManager.list()` method asynchronous to support asynchronous session discovery operations.
- Updated default working directory resolution throughout codebase to use `getProjectDir()` instead of `process.cwd()` for improved project directory detection.
2026-02-13 23:40:02 +01:00
can1357 fcd7ff4f84 refactor(dirs): centralized directory path utilities into @oh-my-pi/pi-utils/dirs module
- Extracted directory path utilities from multiple packages into a centralized '@oh-my-pi/pi-utils/dirs' module.
- Moved 30+ path helper functions (getAgentDir, getConfigRootDir, getPluginsDir, getMCPConfigPath, etc.) from scattered locations into a single shared utility module.
- Consolidated APP_NAME, CONFIG_DIR_NAME, and VERSION constants into the centralized dirs module for reuse across packages.
- Updated 70+ import statements across packages/ai, packages/coding-agent, packages/stats, and packages/tui to use the new centralized module.
- Removed local path construction logic and replaced with utility function calls for improved maintainability and consistency.
- Deleted packages/coding-agent/src/extensibility/plugins/paths.ts as its functions were moved to the centralized dirs module.
2026-02-13 15:06:05 +01:00
can1357 acf8ab5225 style: stylistic changes 2026-02-10 07:39:39 +01:00
can1357 7233c4c8af fix: added windowsHide option to child process spawn calls
- Added `windowsHide: true` option to all child process spawn calls to prevent console windows from appearing on Windows systems.
2026-01-31 01:35:10 +01:00
can1357 48b6bb0986 refactor(utils): extracted process management utilities into dedicated procmgr module
- Extracted process management utilities from coding-agent shell module into dedicated procmgr module in utils package.
- Migrated shell configuration retrieval to SettingsManager class with new getGlobalShellConfig() static method.
- Replaced custom killProcessTree() implementation with new terminate() function supporting graceful shutdown with timeout and AbortSignal.
- Updated ptree.ChildProcess to use generic type parameter for input stream masking and delegated process termination to procmgr.terminate().
- Centralized process management across coding-agent modules to use SettingsManager and procmgr utilities instead of standalone shell functions.
2026-01-29 15:07:06 +01:00
can1357 779ca4872b style(deps): migrated from Prettier to Biome and updated formatting rules
- Removed Prettier configuration files (.prettierignore and .prettierrc) and migrated formatting to Biome.
- Updated Biome configuration from version 2.3.11 to 2.3.12 and changed arrowParentheses rule from 'always' to 'asNeeded'.
- Pinned @biomejs/biome dependency to exact version 2.3.12 in package.json and bun.lock.
- Applied consistent arrow function formatting across 489 files by removing unnecessary parentheses around single parameters.
- Removed blank lines after comment blocks and reorganized imports for consistency across the codebase.
2026-01-24 04:20:19 +01:00
can1357 51d39e7eea refactor(imports): migrated node module imports to namespace imports
- Converted named imports from node modules (fs, path, os) to namespace imports across all packages.
- Extended extension loader error handling with isEacces and hasFsCode type guards.
2026-01-24 03:37:59 +01:00
can1357 e22d123009 refactor(fs): migrated remaining sync file operations to async
- Converted readdirSync, readFileSync, and statSync to async readdir, readFile, stat across skills and agent discovery.
- Made scanDirectoryForSkills async and refactored custom directory scanning to use Promise.all for concurrent processing.
- Updated agent discovery to use fs/promises for async file reading and refactored helper patterns.
- Added AgentParsingError exception class for better error handling during agent parsing.
- Added filesystem error type guards (isEnoent, isEacces, isPerm, etc.) to pi-utils for safe error checking.
- Added color manipulation utilities to pi-utils for accessibility features.
- Added color-blind mode setting to settings manager.
- Migrated plugins, settings, and config modules from sync to async file operations.
- Updated error handling to use new pi-utils type guards for type-safe checking.
2026-01-24 03:18:03 +01:00
can1357 cb5bbbf382 refactor(coding-agent): flattened directory structure, eliminated core/ folder
- Eliminated core/ directory (252 files, 23 subdirs → distributed)
- Reduced max nesting from 9 levels to 5 levels
- Promoted tool subdirs to top level: exa/, lsp/, patch/, task/, web/
- Merged web-scrapers/ + web-search/ into web/{scrapers,search}/
- Flattened modes/interactive/ to modes/
- Split execution/ into: ipy/ (python), exec/ (bash), ssh/
- Renamed ipy/python-*.ts to ipy/*.ts (executor, kernel, etc.)
- Flattened cursor/exec-bridge.ts to cursor.ts
- Created logical groupings: config/, session/, extensibility/, export/
- Updated all imports across 500+ files
2026-01-23 12:24:47 +01:00