|
| 1 | +# Fix Packaging Bugs and Publish 0.0.2 |
| 2 | + |
| 3 | +> Driven by smoke-test findings (`docs/superpowers/plans/2026-05-01-fresh-install-smoke.md`). The 0.0.1 release is unusable end-to-end; three packages shipped raw source, one bundles vitest into runtime. |
| 4 | +
|
| 5 | +**Goal:** Land three packaging fixes, verify locally with `npm pack` + smoke-workspace install, then ship 0.0.2 to npm. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Bug summary |
| 10 | + |
| 11 | +1. **`@ngaf/a2ui`, `@ngaf/partial-json`, `@ngaf/licensing` published as source.** No explicit `nx-release-publish` target in their `project.json`; Nx defaulted to publishing the project root rather than `dist/`. |
| 12 | +2. **`@ngaf/chat` bundles vitest into runtime.** `runAgentConformance` and `runAgentWithHistoryConformance` are exported from the main public-api and `import { describe, it, expect } from 'vitest'` at module level. ng-packagr bundles vitest into the FESM file. |
| 13 | +3. **`@ngaf/render` import of `@ngaf/licensing` fails to resolve** — consequence of bug #1; fixes itself once `@ngaf/licensing` ships actual JS. |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Strategy |
| 18 | + |
| 19 | +- **Fix 1 (mechanical):** Add `nx-release-publish` target to the three TS-only libs. |
| 20 | +- **Fix 2 (entry point):** Move conformance helpers to `@ngaf/chat/testing` secondary entry point. `mockAgent` stays on the main entry (no vitest dep) for ergonomic test-fixture use without separate import. |
| 21 | +- **Verification before publish:** `npm pack` each lib, install tarballs into `~/tmp/ngaf/smoke-workspace`, confirm build passes. |
| 22 | +- **Publish 0.0.2:** standard `nx release version 0.0.2 --specifier=patch && nx release publish` flow. |
| 23 | + |
| 24 | +`@ngaf/langgraph` test helpers (`mockLangGraphAgent`) don't import vitest; leave on main entry. AG-UI's `FakeAgent` and `provideFakeAgUiAgent` are runtime utilities (not tests), no vitest dep; leave on main entry. |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +### Task 1: Add publish config to TS-only libs |
| 29 | + |
| 30 | +**Files:** `libs/a2ui/project.json`, `libs/partial-json/project.json`, `libs/licensing/project.json` |
| 31 | + |
| 32 | +For each, add: |
| 33 | +```json |
| 34 | +"nx-release-publish": { |
| 35 | + "options": { |
| 36 | + "packageRoot": "dist/{projectRoot}" |
| 37 | + } |
| 38 | +} |
| 39 | +``` |
| 40 | +to the `targets` block. |
| 41 | + |
| 42 | +- [ ] **Step 1: Edit each project.json** |
| 43 | + |
| 44 | +```bash |
| 45 | +for lib in a2ui partial-json licensing; do |
| 46 | + jq '.targets["nx-release-publish"] = { options: { packageRoot: "dist/{projectRoot}" } }' \ |
| 47 | + libs/$lib/project.json > libs/$lib/project.json.tmp \ |
| 48 | + && mv libs/$lib/project.json.tmp libs/$lib/project.json |
| 49 | +done |
| 50 | +``` |
| 51 | + |
| 52 | +- [ ] **Step 2: Verify** |
| 53 | + |
| 54 | +```bash |
| 55 | +for lib in a2ui partial-json licensing; do |
| 56 | + echo "=== $lib ===" |
| 57 | + jq '.targets["nx-release-publish"]' libs/$lib/project.json |
| 58 | +done |
| 59 | +``` |
| 60 | + |
| 61 | +Expected: each shows `{"options": {"packageRoot": "dist/{projectRoot}"}}`. |
| 62 | + |
| 63 | +--- |
| 64 | + |
| 65 | +### Task 2: Move conformance helpers to `@ngaf/chat/testing` |
| 66 | + |
| 67 | +**Files:** `libs/chat/src/lib/testing/`, `libs/chat/src/public-api.ts`, new `libs/chat/testing/` secondary entry point. |
| 68 | + |
| 69 | +ng-packagr secondary entry points are colocated subdirectories with their own `ng-package.json`. Convention: |
| 70 | + |
| 71 | +``` |
| 72 | +libs/chat/ |
| 73 | +├── ng-package.json # main entry |
| 74 | +├── src/ |
| 75 | +│ ├── public-api.ts |
| 76 | +│ └── lib/ |
| 77 | +│ └── testing/ # source files |
| 78 | +│ ├── agent-conformance.ts |
| 79 | +│ └── agent-with-history-conformance.ts |
| 80 | +└── testing/ # NEW — secondary entry |
| 81 | + ├── ng-package.json |
| 82 | + └── public-api.ts |
| 83 | +``` |
| 84 | + |
| 85 | +The secondary `testing/public-api.ts` re-exports from the source files. The main `src/public-api.ts` STOPS exporting the conformance helpers. |
| 86 | + |
| 87 | +- [ ] **Step 1: Create `libs/chat/testing/ng-package.json`** |
| 88 | + |
| 89 | +```json |
| 90 | +{ |
| 91 | + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
| 92 | + "lib": { |
| 93 | + "entryFile": "public-api.ts" |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +- [ ] **Step 2: Create `libs/chat/testing/public-api.ts`** |
| 99 | + |
| 100 | +```ts |
| 101 | +// SPDX-License-Identifier: MIT |
| 102 | +export { runAgentConformance } from '../src/lib/testing/agent-conformance'; |
| 103 | +export { runAgentWithHistoryConformance } from '../src/lib/testing/agent-with-history-conformance'; |
| 104 | +``` |
| 105 | + |
| 106 | +(Keep `mockAgent` on the main entry; it's pure factory code with no vitest dep and is ergonomically useful for component tests.) |
| 107 | + |
| 108 | +- [ ] **Step 3: Update `libs/chat/src/public-api.ts`** |
| 109 | + |
| 110 | +Remove these lines: |
| 111 | +```ts |
| 112 | +export { runAgentConformance } from './lib/testing/agent-conformance'; |
| 113 | +export { runAgentWithHistoryConformance } from './lib/testing/agent-with-history-conformance'; |
| 114 | +``` |
| 115 | + |
| 116 | +Keep: |
| 117 | +```ts |
| 118 | +export { mockAgent } from './lib/testing/mock-agent'; |
| 119 | +export type { MockAgent, MockAgentOptions } from './lib/testing/mock-agent'; |
| 120 | +``` |
| 121 | + |
| 122 | +- [ ] **Step 4: Update internal references** |
| 123 | + |
| 124 | +`libs/langgraph/src/lib/agent.conformance.spec.ts` imports `runAgentConformance` — currently from `@ngaf/chat`; should now be `@ngaf/chat/testing`. |
| 125 | + |
| 126 | +```bash |
| 127 | +rg -l "runAgentConformance|runAgentWithHistoryConformance" libs/ apps/ cockpit/ --glob '!**/dist/**' |
| 128 | +``` |
| 129 | + |
| 130 | +For each result, change `from '@ngaf/chat'` → `from '@ngaf/chat/testing'` for these specific imports. |
| 131 | + |
| 132 | +- [ ] **Step 5: Verify chat builds** |
| 133 | + |
| 134 | +```bash |
| 135 | +npx nx build chat --skip-nx-cache 2>&1 | tail -3 |
| 136 | +ls dist/libs/chat/ |
| 137 | +``` |
| 138 | + |
| 139 | +Expected: PASS. `dist/libs/chat/` contains both the main FESM and a `testing/` subdirectory with its own `package.json`/types. |
| 140 | + |
| 141 | +The published artifact will have `exports`: |
| 142 | +```json |
| 143 | +{ |
| 144 | + ".": { ... main entry ... }, |
| 145 | + "./testing": { ... testing entry ... } |
| 146 | +} |
| 147 | +``` |
| 148 | + |
| 149 | +(ng-packagr generates this automatically.) |
| 150 | + |
| 151 | +--- |
| 152 | + |
| 153 | +### Task 3: Local pack + install verification |
| 154 | + |
| 155 | +Before publishing to npm, validate the fix locally. |
| 156 | + |
| 157 | +- [ ] **Step 1: Build all 7 publishable libs** |
| 158 | + |
| 159 | +```bash |
| 160 | +npx nx run-many -t build --projects=chat,langgraph,ag-ui,render,a2ui,partial-json,licensing --skip-nx-cache 2>&1 | tail -3 |
| 161 | +``` |
| 162 | + |
| 163 | +- [ ] **Step 2: Verify each dist has proper artifacts** |
| 164 | + |
| 165 | +```bash |
| 166 | +for lib in chat langgraph ag-ui render a2ui partial-json licensing; do |
| 167 | + echo "=== $lib ===" |
| 168 | + ls dist/libs/$lib/ | head -8 |
| 169 | + echo "---" |
| 170 | + jq '{name, main, module, types, exports: (.exports // "none")}' dist/libs/$lib/package.json 2>&1 | head -10 |
| 171 | +done |
| 172 | +``` |
| 173 | + |
| 174 | +Expected for ng-packagr libs (chat/langgraph/ag-ui/render): `fesm2022/`, `types/`, `exports.{".":...}` block. |
| 175 | + |
| 176 | +Expected for tsc libs (a2ui/partial-json/licensing): compiled `.js` + `.d.ts` files, valid `main`/`module`/`types`. |
| 177 | + |
| 178 | +If any lib's `dist/` is missing or has only source: that lib's build target needs investigation. |
| 179 | + |
| 180 | +- [ ] **Step 3: Pack each as a local tarball** |
| 181 | + |
| 182 | +```bash |
| 183 | +mkdir -p ~/tmp/ngaf/local-tarballs |
| 184 | +rm -f ~/tmp/ngaf/local-tarballs/*.tgz |
| 185 | + |
| 186 | +for lib in chat langgraph ag-ui render a2ui partial-json licensing; do |
| 187 | + cd dist/libs/$lib && npm pack --pack-destination ~/tmp/ngaf/local-tarballs && cd - |
| 188 | +done |
| 189 | + |
| 190 | +ls ~/tmp/ngaf/local-tarballs/ |
| 191 | +``` |
| 192 | + |
| 193 | +Expected: 7 `.tgz` files. |
| 194 | + |
| 195 | +- [ ] **Step 4: Install local tarballs into smoke workspace** |
| 196 | + |
| 197 | +```bash |
| 198 | +cd ~/tmp/ngaf/smoke-workspace |
| 199 | +npm install \ |
| 200 | + ~/tmp/ngaf/local-tarballs/ngaf-chat-0.0.1.tgz \ |
| 201 | + ~/tmp/ngaf/local-tarballs/ngaf-ag-ui-0.0.1.tgz \ |
| 202 | + ~/tmp/ngaf/local-tarballs/ngaf-render-0.0.1.tgz \ |
| 203 | + ~/tmp/ngaf/local-tarballs/ngaf-licensing-0.0.1.tgz \ |
| 204 | + ~/tmp/ngaf/local-tarballs/ngaf-a2ui-0.0.1.tgz \ |
| 205 | + ~/tmp/ngaf/local-tarballs/ngaf-partial-json-0.0.1.tgz |
| 206 | +``` |
| 207 | + |
| 208 | +- [ ] **Step 5: Re-run the AG-UI smoke build** |
| 209 | + |
| 210 | +```bash |
| 211 | +cd ~/tmp/ngaf/smoke-workspace |
| 212 | +npx ng build ag-ui-fake 2>&1 | tail -10 |
| 213 | +``` |
| 214 | + |
| 215 | +Expected: PASS. If build still fails: capture the new error, address before publish. |
| 216 | + |
| 217 | +If the test imports of `runAgentConformance` need updating to `@ngaf/chat/testing` in the smoke app — they shouldn't, since the AG-UI smoke doesn't use conformance. Only internal lib tests use it. |
| 218 | + |
| 219 | +- [ ] **Step 6: Run dev server (optional but valuable)** |
| 220 | + |
| 221 | +```bash |
| 222 | +cd ~/tmp/ngaf/smoke-workspace |
| 223 | +npx ng serve ag-ui-fake --port 4300 & |
| 224 | +sleep 8 |
| 225 | +curl -sIo /dev/null -w "%{http_code}\n" http://localhost:4300/ |
| 226 | +# kill the server |
| 227 | +kill %1 2>/dev/null |
| 228 | +``` |
| 229 | + |
| 230 | +Expected: HTTP 200. Real interactive testing requires browser. |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +### Task 4: Bump and publish 0.0.2 |
| 235 | + |
| 236 | +- [ ] **Step 1: Build everything from clean state** |
| 237 | + |
| 238 | +```bash |
| 239 | +cd /Users/blove/repos/angular-agent-framework/.claude/worktrees/post-unification-cleanup |
| 240 | +rm -rf dist/ |
| 241 | +npx nx run-many -t build --projects=chat,langgraph,ag-ui,render,a2ui,partial-json,licensing --skip-nx-cache 2>&1 | tail -3 |
| 242 | +``` |
| 243 | + |
| 244 | +- [ ] **Step 2: Version bump** |
| 245 | + |
| 246 | +```bash |
| 247 | +npx nx release version --specifier=patch 2>&1 | tail -10 |
| 248 | +``` |
| 249 | + |
| 250 | +Expected: all 7 publishable lib package.json files updated to 0.0.2 (synchronized fixed group). |
| 251 | + |
| 252 | +- [ ] **Step 3: Generate changelog + tag** |
| 253 | + |
| 254 | +```bash |
| 255 | +npx nx release changelog 0.0.2 2>&1 | tail -10 |
| 256 | +``` |
| 257 | + |
| 258 | +Expected: `CHANGELOG.md` updated with 0.0.2 entry. New commit `chore(release): publish v0.0.2`. New tag `v0.0.2` (the post-#147 tag pattern; `nx.json` was updated). |
| 259 | + |
| 260 | +- [ ] **Step 4: Source NPM_TOKEN and run publish** |
| 261 | + |
| 262 | +```bash |
| 263 | +set -a; source /Users/blove/repos/angular-agent-framework/.env; set +a |
| 264 | +npx nx release publish --groups=publishable --access=public --otp=NNNNNN |
| 265 | +``` |
| 266 | + |
| 267 | +(User provides the OTP at run time; trusted publishing is configured but local-publish still goes through 2FA per npm account settings.) |
| 268 | + |
| 269 | +Expected: 7 packages publish successfully. |
| 270 | + |
| 271 | +- [ ] **Step 5: Push commit + tag** |
| 272 | + |
| 273 | +```bash |
| 274 | +git push origin HEAD:main |
| 275 | +git push origin v0.0.2 |
| 276 | +``` |
| 277 | + |
| 278 | +Workflow fires on tag push but is idempotent. |
| 279 | + |
| 280 | +- [ ] **Step 6: Verify all 7 at 0.0.2** |
| 281 | + |
| 282 | +```bash |
| 283 | +for pkg in chat langgraph ag-ui render a2ui partial-json licensing; do |
| 284 | + echo -n "@ngaf/$pkg: " |
| 285 | + npm view @ngaf/$pkg version |
| 286 | +done |
| 287 | +``` |
| 288 | + |
| 289 | +Expected: all 7 print `0.0.2`. |
| 290 | + |
| 291 | +--- |
| 292 | + |
| 293 | +### Task 5: Re-run the smoke against 0.0.2 |
| 294 | + |
| 295 | +After 0.0.2 is on npm: |
| 296 | + |
| 297 | +```bash |
| 298 | +cd ~/tmp/ngaf/smoke-workspace |
| 299 | +rm -rf node_modules package-lock.json |
| 300 | +npm install |
| 301 | +# package.json already references @ngaf/* without version pins; will pull 0.0.2 |
| 302 | + |
| 303 | +npx ng build ag-ui-fake |
| 304 | +npx ng build langgraph-build |
| 305 | +``` |
| 306 | + |
| 307 | +Expected: both build clean. Then `ng serve ag-ui-fake --port 4300` and confirm in browser. |
| 308 | + |
| 309 | +If anything else fails: capture findings, repeat the fix-publish cycle. |
| 310 | + |
| 311 | +--- |
| 312 | + |
| 313 | +## Out of Scope |
| 314 | + |
| 315 | +- Renaming or moving `mockAgent` / `mockLangGraphAgent` / `FakeAgent` / `provideFakeAgUiAgent`. They don't import vitest; their bundle cost is negligible. |
| 316 | +- Renaming `lib/testing/` directories. |
| 317 | +- Improving Tailwind / theming setup in the smoke app. |
| 318 | +- Adding LangGraph live-backend test. |
| 319 | + |
| 320 | +## Risk |
| 321 | + |
| 322 | +- **Multi-package version skew during publish.** If the publish for 0.0.2 fails partway (e.g., OTP timeout), some packages land at 0.0.2 while others stay at 0.0.1. The synchronized fixed group + the `--first-release` style retry pattern (re-run with same OTP for missed packages) mitigates this. |
| 323 | +- **Secondary entry-point convention.** Some Angular consumers (older ng-packagr, certain bundlers) have rough edges with secondary entry points. Smoke-test against the AG-UI app catches obvious cases. |
| 324 | +- **`@ngaf/langgraph` may have similar issues** that didn't surface yet because the smoke didn't actually try to build the langgraph-build app. After 0.0.2 publishes, the smoke MUST build langgraph-build successfully or we have a third packaging bug. |
0 commit comments