Skip to content

feat(packaging): ship wrapper-first Next.js npm integration#20

Merged
dcramer merged 21 commits intomainfrom
feat/npm-deployable-package
Mar 4, 2026
Merged

feat(packaging): ship wrapper-first Next.js npm integration#20
dcramer merged 21 commits intomainfrom
feat/npm-deployable-package

Conversation

@dcramer
Copy link
Copy Markdown
Member

@dcramer dcramer commented Feb 28, 2026

Make Junior deployable as an npm dependency using standard Next.js wrappers.

The previous package approach depended on CLI-generated shim files and custom build commands. This change moves to a wrapper-first integration so consumers keep normal Next.js dev/build/start scripts while importing Junior runtime surfaces directly.

Key changes:

  • Add importable runtime surfaces for app layout, catch-all API routing, instrumentation, and Next.js config composition
  • Introduce withJunior() to merge required serverExternalPackages and outputFileTracingIncludes for /api/**, with optional Sentry wrapping
  • Keep runtime handlers centralized under src/handlers/* and reuse them from app routes and package exports
  • Update packaging/build outputs (tsup, exports map, files, peer dependency layout) so published artifacts are consumable from external Next.js apps
  • Move default bot content to root-level data/, skills/, and plugins/ conventions for scaffolded and consuming repos
  • Update README/setup guidance to the wrapper model (app/api/[...path]/route.js, next.config.mjs, instrumentation.js, optional app/layout.js)
  • Preserve existing outputFileTracingIncludes["/api/**"] entries when applying Junior config instead of overwriting consumer-defined values
  • Restore webhook route parity by matching only single-segment platforms (e.g. /api/webhooks/slack) and returning 404 for multi-segment paths

This keeps deployment ergonomics aligned with normal Next.js behavior while preserving the runtime/data loading guarantees Junior needs in production.

Refs GH-9

Comment thread src/handlers/router.ts Outdated
@dcramer dcramer marked this pull request as ready for review February 28, 2026 20:54
Comment thread bin/junior.mjs Outdated
dcramer and others added 6 commits March 3, 2026 21:37
Extract route handlers, layout, instrumentation, and Next.js config
into importable modules under src/ so consumers can install junior as
a package and deploy without touching Next.js internals. The CLI now
supports init/dev/build/start subcommands with automatic shim generation.

- Extract webhook and health handlers to src/handlers/
- Add catch-all router for consumer shim (single route file)
- Add withJunior() config helper for Next.js setup
- Default JUNIOR_HOME to process.cwd() instead of throwing
- Add tsup build tooling to produce dist/ with resolved @/ aliases
- Add package exports, files, and peerDependencies
- Update CLI with init, dev, build, start subcommands

Refs GH-9
Co-Authored-By: Claude <noreply@anthropic.com>
Move SOUL.md and skills from src/ to the jr-sentry/ home directory so
the project structure matches the npm package model where bot content
lives in a separate home directory.

- Move src/chat/SOUL.md → jr-sentry/SOUL.md
- Move src/junior/skills/ → jr-sentry/skills/
- Add jr-sentry/config.toml
- Update config.ts to read from loadHomeConfig() via home module
- Rename routerModelId → fastModelId across bot, tools, and tests
- Update prompt.ts and skills.ts to use soulPath()/skillsDir()
- Update check-skills.mjs to resolve from JUNIOR_HOME
- Add Slack thread id normalization to chat-background-patch.ts

Co-Authored-By: Claude <noreply@anthropic.com>
Rebase preserved main's Slack thread normalization behavior where\nmissing raw fields return the original thread id instead of throwing.\nUpdate the legacy test to assert that behavior so test expectations\nmatch current runtime behavior.

Regenerate pnpm-lock.yaml to reflect the current dependency layout\nafter the npm-deployable packaging and home-directory cutover.

Co-Authored-By: GPT-5 <noreply@openai.com>
Ensure the npm deployable path behaves correctly after the rebase.
withJunior now wraps async/sync Next config factories, the catch-all
router accepts generated and legacy API route forms, and runtime
references use fastModelId consistently after config field renames.
Also allow JUNIOR_HOME overrides in local dev and add regression tests
for router and config composition behavior.

Co-Authored-By: GPT-5 <noreply@openai.com>
Stop mutating consumer apps during dev/build and treat integration as
explicit Next.js wrappers. junior init now scaffolds wrapper files once
(route, config, instrumentation, layout) and uses standard next scripts
with JUNIOR_HOME set.

Also defer loading chat bot runtime in webhook handlers so builds do not
fail when Slack secrets are unavailable at compile time.

Co-Authored-By: GPT-5 <noreply@openai.com>
Next.js 16 route segment config no longer accepts re-exported runtime.
Declare runtime in app route files and only re-export handlers so
root builds remain valid under Turbopack.

Co-Authored-By: GPT-5 <noreply@openai.com>
Comment thread packages/junior/src/next-config.ts
Comment thread packages/junior/src/handlers/router.ts
dcramer added 2 commits March 3, 2026 22:46
Remove config.toml and JUNIOR_HOME-driven home resolution in favor of\nroot-level data/, skills/, and plugins/ directories so installs work as\nstandard Next.js apps without custom startup wrappers.\n\nAlign CLI init output, runtime discovery, tracing includes, skill/plugin\nchecks, tests, and docs with the new single-model package flow.\n\nCo-Authored-By: GPT-5 Codex <noreply@openai.com>
Document .js/.mjs wrapper filenames for manual integration so the setup\nworks with default Next.js TypeScript configuration without module\nresolution changes.\n\nCo-Authored-By: GPT-5 Codex <noreply@openai.com>
@dcramer dcramer changed the title feat: Make junior deployable as an npm dependency feat(packaging): ship wrapper-first Next.js npm integration Mar 4, 2026
Merge existing /api/** output tracing entries in withJunior so consumer

config values are preserved instead of replaced.

Restrict webhook catch-all routing to a single platform segment so

multi-segment paths correctly return 404, matching the original route

behavior.

Add regression tests for both behaviors.

Refs GH-9

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread package.json
Comment thread .env.test Outdated
Reinstate the @chat-adapter/slack patch so file_share subtype events

are not discarded by the adapter.

Also remove the unused JUNIOR_HOME entry from .env.test now that

home resolution is convention-based and no longer env-driven.

Refs GH-9

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread src/chat/config.ts Outdated
Use AI_MODEL as the intermediate fallback for fastModelId when

AI_FAST_MODEL is unset, restoring prior behavior and keeping config

selection consistent with web-search model resolution.

Add regression tests for fallback precedence.

Refs GH-9

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread src/next-config.ts Outdated
Avoid duplicate entries in serverExternalPackages when consumers

already include Junior's default packages.

Add regression coverage for dedup behavior.

Refs GH-9

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread tsup.config.ts Outdated
Keep  external in the package build while declaring it in\n so npm consumers install it. This avoids runtime\nmodule resolution failures when bundled output references the module.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread packages/junior/tsup.config.ts
Comment thread src/handlers/health.ts Outdated
Keep workflow libraries external in tsup to match package runtime dependencies and avoid duplicate bundled/runtime copies. Remove unused runtime exports from handler modules because runtime is defined by route files in consumers.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread tests/handlers-webhooks-lazy-load.test.ts Outdated
Handler modules no longer export runtime; runtime is defined on Next.js route files. Update the lazy-load test to assert only the exported webhook handler function.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread package.json Outdated
dcramer and others added 2 commits March 4, 2026 09:59
Set up a pnpm workspace with an in-repo jr-sentry consumer project so we can validate package behavior in a production-like integration path. Use workspace linking for junior and document the local smoke workflow.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Drop  from runtime dependencies and tsup externals since the package no longer imports it. This keeps consumer installs minimal while preserving current bundle behavior.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread src/next-config.ts Outdated
Move the publishable junior package to packages/junior and move the
smoke-test consumer app to packages/jr-sentry.

Keep root developer ergonomics by proxying dev/build/test scripts from
the workspace root, and preserve patched dependency wiring at root.

Update test env loading to include workspace-root env files so root test
behavior stays stable after the package cwd move.

Fix Sentry config loading in ESM by using createRequire instead of a
global require call.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Comment thread packages/jr-sentry/next.config.mjs
Drop SENTRY_ORG, SENTRY_PROJECT, and SENTRY_AUTH_TOKEN from
consumer and scaffold env templates because withJunior() defaults to
sentry disabled in those generated configs.

This keeps setup docs aligned with actual behavior and avoids dead
configuration for new consumers.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Set the package Next build to webpack and pin turbopack root to the
workspace root for the in-repo app config.

This avoids workspace root inference failures seen after relocating the
package to packages/junior and keeps root build commands working for PR
validation and deployment checks.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Comment thread packages/junior/src/handlers/router.ts
Add oauth callback routing for GET /api/oauth/callback/:provider in
junior/handler so package consumers can complete OAuth flows when using
the catch-all API route.

Introduce a dedicated oauth-callback handler wrapper and extend router
tests for both normal and legacy api-prefixed path forms.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

start: "next start"
},
dependencies: {
junior: "latest",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Scaffolded dependency uses unpinned "latest" version specifier

Medium Severity

The junior init scaffold sets "junior": "latest" in the generated package.json, while all other dependencies use caret ranges (e.g. "next": "^16.0.0"). The "latest" tag always resolves to the newest published version at install time and isn't bounded by semver range, so a future major release with breaking changes would silently break newly scaffolded (or re-installed) projects. Using a caret range based on the current version (or reading it from the package's own package.json) would be more consistent and safer.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we'll fix later

@dcramer dcramer merged commit fb61a78 into main Mar 4, 2026
5 checks passed
@dcramer dcramer deleted the feat/npm-deployable-package branch March 4, 2026 18:55
Sign up for free to 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