feat(packaging): root package.json + committed dist for native bun/npm git+install#11
Merged
Merged
Conversation
…install
Enables bun/npm consumers to install amplifier-agent-client-ts via native
git URL syntax:
bun add github:microsoft/amplifier-agent#main
Pattern: a minimal shipping-only package.json at the repo root points
(via 'main', 'types', 'exports') at wrappers/typescript/dist/. The
wrappers/typescript/package.json remains the dev manifest with scripts,
devDependencies, and tsconfig — unchanged.
Trade-off: wrappers/typescript/dist/ is now committed to the repo
(~108KB, 20 files). The CI workflow added in #10 already builds the
wrapper on every push; a follow-up can add an auto-commit step so dist
stays current without manual rebuild discipline. For now, the
'wrapper-v*' tag workflow gives consumers stable pinnable refs.
Why this pattern (vs alternatives):
- npm publish: requires registry account, name commitment, token for
consumers in some flows. Deferred until POC graduates.
- gitpkg.vercel.app subdir proxy: third-party service, currently
disabled (HTTP 402 DEPLOYMENT_DISABLED).
- Dist branch (separate refs): requires force-push CI; this is simpler.
- Separate repo for wrapper: needs new repo + code-sync overhead.
Consumer install path (in any project's package.json):
"amplifier-agent-client-ts": "github:microsoft/amplifier-agent#main"
bun/npm clones the repo, finds package.json at root, the 'files' field
restricts to wrappers/typescript/dist/, the 'exports' field resolves
the entry point. No tokens, no proxies, no registries.
Co-Authored-By: Amplifier <amplifier@microsoft.com>
Updates /package.json exports from string form:
"exports": { ".": "./wrappers/typescript/dist/index.js" }
to conditional form with explicit types resolution:
"exports": {
".": {
"types": "./wrappers/typescript/dist/index.d.ts",
"import": "./wrappers/typescript/dist/index.js"
}
}
Modern TypeScript (with moduleResolution: bundler/nodenext) follows the
exports field and looks for a 'types' condition before falling back to
the top-level 'types' field. The string-form exports left only 'import'
resolvable, so consumer projects (e.g. NanoClaw's agent-runner) saw
'McpServerConfig' as 'any' or unresolved, surfacing as TS2339 errors
like 'Property transport does not exist on type McpServerConfig'.
Verified locally: NC's bun run typecheck went from 5 errors to 0 after
this change.
Order matters in conditional exports: 'types' MUST appear FIRST so TS
checks it before module conditions. This follows the TypeScript handbook
guidance for the exports field.
Co-Authored-By: Amplifier <amplifier@microsoft.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a root
package.jsonand commitswrappers/typescript/dist/so consumers can install the TypeScript wrapper via native bun/npm git URL syntax — no proxy, no registry, no tokens.That's it. bun/npm clones the repo, finds
package.jsonat the root, thefilesfield restricts the install towrappers/typescript/dist/, and theexportsfield resolves the entry point.Why this pattern
The TypeScript wrapper lives at
wrappers/typescript/— a subdirectory of this repo. npm and bun don't natively support subdirectory paths in git URLs, so consumers can't directly install fromgithub:microsoft/amplifier-agentwithout help. Prior approaches:npm publishto PyPI/npm registrygitpkg.vercel.appsubdir proxyDEPLOYMENT_DISABLED; we hit this directlymicrosoft/amplifier-agent-client-tsA root
package.jsonthat references the built wrapper via relative paths works natively because bun/npm find the manifest at the repo root, and thefilesfield limits what ends up innode_modules/.What's in this PR
1.
/package.json(NEW, root)A minimal shipping-only manifest:
{ "name": "amplifier-agent-client-ts", "version": "0.3.0", "type": "module", "exports": { ".": "./wrappers/typescript/dist/index.js" }, "types": "./wrappers/typescript/dist/index.d.ts", "files": ["wrappers/typescript/dist"], "engines": { "node": ">=20" }, "license": "MIT", "repository": { "type": "git", "url": "...", "directory": "wrappers/typescript" } }No
dependencies, nodevDependencies, noscripts. The actual dev manifest stays atwrappers/typescript/package.json(unchanged) — that's where build/test/lint commands live.2.
wrappers/typescript/dist/(NEW, 20 files, ~108KB)Built TypeScript output, freshly regenerated from current source (Mode A only — no stale Mode B
display.{js,d.ts},jsonrpc.*,l14.*leftovers).3.
.gitignore(MODIFIED)Added
!wrappers/typescript/dist/to negate the repo-widedist/rule (which exists for Pythonuv buildoutput).4.
wrappers/typescript/.gitignore(MODIFIED)Removed local
dist/rule (now handled by root .gitignore's negation).Trade-off: committing built artifacts
This breaks the convention "don't commit build output." For git+install patterns this is the well-understood compromise — without committed dist/, consumers would need a
preparescript that builds on install, requiring TypeScript + bun on their side and adding ~5 sec per install. Committing dist/ instead trades ~108KB of repo size for instant, build-free consumer installs.The existing
ci.ymlworkflow already builds the wrapper on every push. A follow-up PR can add an auto-commit step that commits the freshly-builtdist/so it stays current without manual rebuild discipline. For now, the workflow verifies the wrapper builds correctly; engineers updatingwrappers/typescript/src/need to runbun run buildand include the dist/ changes in their PR.Verification
uv tool install "amplifier-agent @ git+https://github.com/microsoft/amplifier-agent@main"(Python side) confirmed working in the prior local probe. The TS side will be testable once this PR's branch is reachable viagithub:microsoft/amplifier-agent#feat/root-package-json-git-install.filesfield semantics:bun addandnpm installfrom git honor thefilesfield — onlywrappers/typescript/dist/ends up in consumer'snode_modules/amplifier-agent-client-ts/, not the entire 200MB+ amplifier-agent repo. Consumer import paths resolve viaexportsfield to./wrappers/typescript/dist/index.js.Test plan
package.jsonshouldn't affect any of thesebun add github:microsoft/amplifier-agent#feat/root-package-json-git-install(or after merge:#main)import { spawnAgent } from 'amplifier-agent-client-ts'resolves to the simplified Mode ADisplayEventshapenode_modules/amplifier-agent-client-ts/contains onlywrappers/typescript/dist/+package.json(no Python sources, no docs)Follow-up work
wrappers/typescript/dist/on changes towrappers/typescript/src/. Eliminates the "remember to rebuild" requirement.npm publishagainst this same root would work.