Skip to content

hy-2xeb: Install pipeline for GitHub-URL plugins (hy-gh-1) - #9

Merged
philcunliffe merged 1 commit into
integration/github-installfrom
polecat/hy-2xeb
May 21, 2026
Merged

hy-2xeb: Install pipeline for GitHub-URL plugins (hy-gh-1)#9
philcunliffe merged 1 commit into
integration/github-installfrom
polecat/hy-2xeb

Conversation

@philcunliffe

Copy link
Copy Markdown
Contributor

Summary

Implements the install pipeline for GitHub-URL plugins (hy-gh-1 / bead hy-2xeb).

New modules src/core/plugin_install/git_source.js and git_fetch.js handle git URL parsing and the clone / checkout / resolve / validate / copy pipeline, with per-stage spans (plugin.git.clone, plugin.git.checkout, plugin.git.resolve_ref, plugin.artifact.validate, plugin.artifact.copy). Lock entries now carry resolved_ref. CLI accepts --ref / --path with source_ambiguous and git_subdir_unsupported guards.

Test plan

  • npm test — 48/48 green (includes 20 new unit tests for git source resolver, entrypoint validation, symlink rejection, content hash stability)
  • Hermetic smoke plugin_install_git_url (created in this PR) — green
  • Existing smoke plugin_install_local_dir — green
  • Typecheck + lint — green
  • Telemetry produces plugin.git.* and plugin.artifact.* spans for the smoke fixture
  • Lock file shows the new git source shape; no credentials in any logged output

Parent bead: hy-2xeb → integration/github-install (epic hy-dnk9)

Extend src/core/plugin_install to support git sources. Parses GitHub URL
forms (https with optional .git/#ref, github: shorthand, git@github.com
SSH) plus generic git+/git:/ssh:/gitlab:/bitbucket:/file:// URLs through
a new pure git_source parser. Adds --ref and --path CLI flags to the
plugin install command; --ref conflicting with a URL #ref is rejected
as source_ambiguous, and --path is reserved as git_subdir_unsupported.
The fetch path clones with --filter=blob:none --no-checkout, checks out
the requested ref (or the remote's HEAD symref by default), resolves
HEAD to a commit, validates the manifest and entrypoint, refuses any
symlinks in the artifact tree, then copies into an atomic install
directory swap. Lock entries gain resolved_ref; the update probe runs
git ls-remote and flips update.available when the upstream commit moved.
Telemetry: the existing plugin.install span gains hyp_source_kind=git,
git_url_host/owner/repo/ref/resolved_ref, content_hash, and
manifest_hash. Child spans plugin.git.clone, plugin.git.checkout,
plugin.git.resolve_ref, plugin.artifact.validate, and
plugin.artifact.copy each carry status and error_kind. Git stderr is
redacted for credentials before being surfaced.
Tests cover URL parsing variants, the --ref/URL-fragment conflict, the
subdir reservation, entrypoint traversal rejection, symlink detection,
and content-hash stability. New hermetic smoke plugin_install_git_url
builds a local bare repo and exercises the install end-to-end through
the dispatcher.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@philcunliffe
philcunliffe merged commit a1a74bb into integration/github-installMay 21, 2026
6 checks passed
@philcunliffe
philcunliffe deleted the polecat/hy-2xeb branch May 21, 2026 20:10
philcunliffe added a commit that referenced this pull request May 22, 2026
* chore: seed integration/github-install for feature flow
* feat: install pipeline for GitHub-URL plugins (hy-2xeb) (#9)
Extend src/core/plugin_install to support git sources. Parses GitHub URL
forms (https with optional .git/#ref, github: shorthand, git@github.com
SSH) plus generic git+/git:/ssh:/gitlab:/bitbucket:/file:// URLs through
a new pure git_source parser. Adds --ref and --path CLI flags to the
plugin install command; --ref conflicting with a URL #ref is rejected
as source_ambiguous, and --path is reserved as git_subdir_unsupported.
The fetch path clones with --filter=blob:none --no-checkout, checks out
the requested ref (or the remote's HEAD symref by default), resolves
HEAD to a commit, validates the manifest and entrypoint, refuses any
symlinks in the artifact tree, then copies into an atomic install
directory swap. Lock entries gain resolved_ref; the update probe runs
git ls-remote and flips update.available when the upstream commit moved.
Telemetry: the existing plugin.install span gains hyp_source_kind=git,
git_url_host/owner/repo/ref/resolved_ref, content_hash, and
manifest_hash. Child spans plugin.git.clone, plugin.git.checkout,
plugin.git.resolve_ref, plugin.artifact.validate, and
plugin.artifact.copy each carry status and error_kind. Git stderr is
redacted for credentials before being surfaced.
Tests cover URL parsing variants, the --ref/URL-fragment conflict, the
subdir reservation, entrypoint traversal rejection, symlink detection,
and content-hash stability. New hermetic smoke plugin_install_git_url
builds a local bare repo and exercises the install end-to-end through
the dispatcher.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: boot integration for installed plugins (hy-jky3) (#11)
bootKernel now reads plugin-lock.json, merges bundled and installed
manifest pools, resolves dependencies across the merged set, and
activates installed third-party plugins when the config names them.
Rejects boot with `installed_shadows_bundled` when an installed
plugin tries to shadow a bundled first-party name. Adds telemetry
attributes (installed_available, installed_failed,
installed_shadow_collisions, installed_selected) and a
plugin.installed_active log per installed-and-selected plugin.
Threads installed manifest metadata into the cross-plugin config
validator via a new mergeInstalledManifestsIntoKnown helper, so
third-party plugin sections are no longer flagged plugin_unknown
and their provides/requires participate in sink-pair and
capability-ambiguity checks. Updates hyp config validate, hyp init
--from-file, and daemon status to feed the merged map in.
Adds boot-installed unit tests covering merged pool, dep resolution
over bundled+installed, shadow rejection, and config-validator
behavior, plus a hermetic plugin_boot_installed smoke that installs
a git-fixture plugin, activates it via config, runs its contributed
command, and asserts the boot telemetry surface.
* feat: update + trust UX for installed plugins (hy-qvmo) (#13)
Add a confirmation gate to `hyp plugin install` and a real update flow
to `hyp plugin update <plugin>` so remote installs no longer commit
without the user (or `--yes`) seeing what is about to land.
Install (git sources)
- New `--yes`/`-y` flag.
- Non-TTY without `--yes` rejects with `remote_install_confirmation_required`
(exit code 2).
- TTY without `--yes` prints a summary (source URL, resolved commit,
plugin name + version, permissions, entrypoint, content_hash) and
prompts `Proceed? [y/N]`. Both summary and prompt land on stderr so
stdout stays parseable.
- Local-dir installs keep their current non-interactive behavior — the
confirmation gate only fires inside `fetchGitSource`.
Update
- `hyp plugin update <plugin>` now re-clones with the same source, runs
manifest validate, and shows old vs. new resolved_ref/version/content_hash
before the artifact swap. `--yes` skips the prompt; non-TTY without
`--yes` rejects as above. On rejection the prior install is left
intact because the rename swap only fires once `beforeCommit` returns
`proceed=true`.
- The bare `hyp plugin update` (no plugin name) keeps the legacy
"refresh update_check state for every plugin" behavior so `outdated`
can still be recomputed without committing to a re-install.
Soft warnings (stderr only)
- Manifest permissions containing `network` warn about broad scope.
- Branch-shaped refs (and missing refs) warn that pinning a tag or
commit SHA gives reproducible installs.
Telemetry
- `plugin.install` and a new `plugin.update` span both carry a
`confirmation` attribute drawn from `confirmed`, `auto_yes`,
`rejected`, `non_tty_no_yes`. The `plugin.installed` log row mirrors
the attribute when it was set.
- `fetch.FetchErrorKind` / `git_fetch.GitFetchErrorKind` gain
`remote_install_confirmation_required` and `remote_install_rejected`.
Tests + smoke
- New `test/core/plugin-install-confirm.test.js` covers the pure
helpers (`decideConfirmation`, `buildWarnings`, `sourceIsUnpinnedBranch`,
`renderConfirmationSummary`) and exercises the `installPlugin` +
`updatePlugin` integration against a hermetic file:// bare repo.
- New env-gated acceptance smoke
`hypaware-core/smoke/flows/plugin_install_github_url.js` installs a
real GitHub plugin fixture at a pinned tag (opt-in via
`HYP_SMOKE_REAL_GITHUB=1`, with overridable URL/ref/name env vars).
Skips with a clear marker when the env var is unset so CI runs of
`npm run smoke` do not hit the network.
- The existing hermetic git-url and boot-installed smokes now pass
`--yes` (they run with non-TTY buffer streams) and assert
`confirmation=auto_yes` on the install span.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: review findings on integration/github-install plugin install (hy-lpo3) (#18)
Address all blocker and major findings from the dual-review on PR #6:
confirm.js — switch to node:readline/promises so the awaited
rl.question() actually returns a Promise and the interactive TTY
prompt path can return a decision instead of throwing.
update_check.js — pickLsRemoteSha now prefers the peeled `^{}` SHA
when present so annotated tags compare against entry.resolved_ref
correctly instead of producing spurious "update available" signals.
Also wraps the ls-remote spawn with a hard timeout (default 5s,
HYP_GIT_PROBE_TIMEOUT_MS-overridable, clamped) that emits a
git_probe_timeout error_kind, and the post-install path now passes
freshlyResolved=true so the probe is skipped entirely when we just
resolved the upstream ref — the span still emits with
probe_skipped=freshly_resolved for observability.
git_source.js / resolver.js / install.js — strip user:pass@ userinfo
from source.raw and source.gitUrl before they reach the lock entry,
the confirmation prompt, or the install span. Persistence and display
are always credential-free; clones rely on the user's git credential
helper. Adds redactGitUrl / redactRawSource helpers.
git_fetch.js / update_check.js — insert `--` end-of-options separator
before user-controlled positionals in `git clone`, `git checkout`,
and `git ls-remote` so a hostile URL or ref like `--upload-pack=<cmd>`
cannot be parsed as a git option (CVE-2018-17456 family). Also reject
leading-dash inputs in parseGitSource, applyGitSourceFlags, and the
CLI parser as belt-and-braces defense before the spawn boundary.
git_source.js — applyGitSourceFlags JSDoc no longer claims the subdir
value is "still recorded on the returned spec" since the function
throws unconditionally; the unreachable subdir spread is removed.
Tests cover redactGitUrl/redactRawSource, leading-dash rejection
across parser layers, peeled-tag SHA preference in pickLsRemoteSha,
and the real readline/promises behavior of buildTtyPrompt via
PassThrough streams.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: feature-launch <feature-launch@gas.city>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
philcunliffe added a commit that referenced this pull request Jul 10, 2026
…0097) (#295)
* Bounded query execution: heap-growth budget + scanColumn wiring (LLP 0097)
Realizes LLP 0054/0055/0056 kernel-side against the pinned engines
(squirreling 0.14.0 / icebird 0.8.13), closing the issue-#9 crasher class:
an unbounded ORDER BY over ai_gateway_messages now refuses in ~1s at
~1.4GB peak RSS with a typed error instead of dying at 6GB.
- sql.js: thread the abort signal into squirrelExecuteSql (LLP 0054
#signal-threading) and enforce a per-query heap-growth budget, checked
INLINE on the scan path (every 4096 rows / per column chunk) plus a
100ms interval for post-scan phases. A timer-only watchdog measurably
never fires during a hot query (event loop starved). Default 1GiB
growth, HYP_QUERY_MAX_HEAP_MB / maxHeapBytes override, typed
QueryExecutionBudgetError exported from hypaware/core/query.
- storage.js: hide internal fields by scan-level projection instead of
rebuilding every row (~5 allocations/row removed); forward scanColumn.
- union-source.js: forward scanColumn by concatenating per-partition
column streams, owning limit/offset over the merged stream (LLP 0055).
- ai-gateway dataset.js: withSchemaColumns forwards scanColumn,
null-filling a partition that physically lacks the column.
- LLP 0097 records the Phase 0 measurements (LLP 0057) and the decision;
editorial forward-refs on 0054/0057.
Measured on the production cache (202k rows / 931MB): every benched
query faster (up to -26% wall), none regressed; graph queries unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Bounded query exec: terminal budget check, signal-listener cleanup, blank-env guard (LLP 0097)
Review hardening for the heap-growth guard (dual-review of PR #295):
- Terminal budget check after collect(): the inline guard samples only
every 4096 rows / per column chunk and the interval watchdog cannot fire
during a fully synchronous run, so growth concentrated in a sub-stride
tail or in finalization could return a wrongly-successful result. One
guard.check() after materialization closes that window.
- Detach the linked upstream-signal abort listener in finally: a long-lived
signal shared across many queries would otherwise retain the per-call
controller closure.
- resolveHeapBudgetBytes: a set-but-blank HYP_QUERY_MAX_HEAP_MB (how many
config systems render an unset optional) resolved to Number('')===0 and
silently disabled the guard. Only a non-empty value now counts as an
override; blank/whitespace falls through to the measured default.
Exports resolveHeapBudgetBytes for a deterministic unit test of the env
resolution (the heap-growth path itself is not deterministically testable
in a shared process). Full suite green (2152 pass); tsc build:types clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@philcunliffe