Skip to content

feat: unlock three underused library features (prompt caching, Static scrollback, strict CLI)#227

Merged
kelsonpw merged 5 commits intomainfrom
omnara/explore-unused-library-features
Apr 24, 2026
Merged

feat: unlock three underused library features (prompt caching, Static scrollback, strict CLI)#227
kelsonpw merged 5 commits intomainfrom
omnara/explore-unused-library-features

Conversation

@kelsonpw
Copy link
Copy Markdown
Collaborator

@kelsonpw kelsonpw commented Apr 24, 2026

Summary

Three independent improvements surfaced by a library-audit pass — each pulls on a feature we already had installed but weren't using. Grouped in one PR because they're small and share context, but each is an isolated commit so they can be split/reverted independently.

  • feat(agent) — Enable prompt caching on the system prompt via excludeDynamicSections: true. The Claude Agent SDK caches implicitly, but per-session dynamic sections (cwd, date, git status) were busting the cache every run. Moves them into the first user message so the static preset + our ~3KB commandments stay cacheable across runs and machines. Impact measurable via cache_read_input_tokens in benchmarks/cache-tracker.ts.
  • feat(tui) — Render completed Q&A turns via Ink <Static> so they persist in terminal scrollback after the TUI exits (same pattern Claude Code uses). Drops the responseIsLong modal-style branch that hid the wizard screen for long replies.
  • feat(cli) — Enable yargs .strict() and .check() on --app-id. Typos like --app-ids now fail fast instead of falling through silently. --app-id=foo surfaces a yargs-native error instead of silently becoming 0. Also declares the feedback command's variadic [words..] positional so strict parsing accepts it. Middleware for consolidating credential resolution is paired with the upcoming bin.ts command-module split.

Context

Product of a subagent audit (general-purpose × 2 — TS/AI engineer + OSS CLI maintainer) asking "what features of libraries we already have are we underusing?" Top findings were prioritized and this PR implements the three highest-leverage ones. Remaining audit items tracked locally: PreCompact hook, MCP resources, discriminated-union message schemas, zod brands, nanostores computed, measureElement/useFocus, <Static>/screen snapshot tests, .completion(), bin.ts command-module split.

Test plan

  • pnpm tsc --noEmit — clean
  • pnpm test — 1139 passed, 17 skipped
  • pnpm lint — clean
  • pnpm build + smoke test — passes
  • Verified .strict() live: --app-ids=fooUnknown arguments: app-ids, appIds; --app-id=notanumber--app-id must be a positive integer; detect --help still renders
  • Manual TUI run to eyeball <Static> scrollback persistence on exit
  • Next agent run: confirm cache_read_input_tokens climbs vs. prior runs in the benchmark log

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because it tightens CLI argument validation (yargs.strict() and --app-id checks) which may break previously-tolerated invocations, and it changes agent/TUI runtime behavior (prompt caching + console rendering) that could surface edge-case regressions.

Overview
Improves wizard efficiency and UX in three places. The agent now enables system-prompt caching via excludeDynamicSections: true, avoiding per-run dynamic context invalidating the Claude Agent SDK cache.

The TUI console switches to an append-only Q&A log using Ink Static, preserving completed user/assistant turns in terminal scrollback and removing the prior “long response” modal-style rendering.

The CLI becomes stricter: it adds a yargs .check() to reject non-numeric/invalid --app-id, enables .strict() to fail fast on unknown flags/subcommands, and updates feedback to accept variadic positional words while adding hidden passthrough options so env-var injected flags still parse under strict mode.

Reviewed by Cursor Bugbot for commit b9ff4a9. Bugbot is set up for automated code reviews on this repo. Configure here.

@kelsonpw kelsonpw requested a review from a team as a code owner April 24, 2026 15:55
@kelsonpw kelsonpw requested a review from a team April 24, 2026 15:55
@github-actions
Copy link
Copy Markdown
Contributor

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci django
  • /wizard-ci fastapi
  • /wizard-ci flask
  • /wizard-ci javascript-node
  • /wizard-ci javascript-web
  • /wizard-ci next-js
  • /wizard-ci python
  • /wizard-ci react-router
  • /wizard-ci vue

Test an individual app:

  • /wizard-ci django/django3-saas
  • /wizard-ci fastapi/fastapi3-ai-saas
  • /wizard-ci flask/flask3-social-media
Show more apps
  • /wizard-ci javascript-node/express-todo
  • /wizard-ci javascript-node/fastify-blog
  • /wizard-ci javascript-node/hono-links
  • /wizard-ci javascript-node/koa-notes
  • /wizard-ci javascript-node/native-http-contacts
  • /wizard-ci javascript-web/saas-dashboard
  • /wizard-ci next-js/15-app-router-saas
  • /wizard-ci next-js/15-app-router-todo
  • /wizard-ci next-js/15-pages-router-saas
  • /wizard-ci next-js/15-pages-router-todo
  • /wizard-ci python/meeting-summarizer
  • /wizard-ci react-router/react-router-v7-project
  • /wizard-ci react-router/rrv7-starter
  • /wizard-ci react-router/saas-template
  • /wizard-ci react-router/shopper
  • /wizard-ci vue/movies

Results will be posted here when complete.

Copy link
Copy Markdown
Contributor

@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.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Strict mode rejects documented env vars on subcommands
    • Added hidden global option shadows for agent, install-dir, and classic (matching the existing pattern for dev, log, and token) so that .strict() accepts env-var-injected values on all subcommands.

Create PR

Or push these changes by commenting:

@cursor push 7270fe2378
Preview (7270fe2378)
diff --git a/bin.ts b/bin.ts
--- a/bin.ts
+++ b/bin.ts
@@ -98,7 +98,7 @@
 // Dynamic import to avoid preloading wizard-session.ts as CJS, which
 // prevents the TUI's ESM dynamic imports from resolving named exports.
 const lazyRunWizard = async (
-  ...args: Parameters<typeof import('./src/run')['runWizard']>
+  ...args: Parameters<(typeof import('./src/run'))['runWizard']>
 ) => {
   const { runWizard } = await import('./src/run.js');
   return runWizard(...args);
@@ -198,9 +198,8 @@
   // the project API key.
   const envAccessToken =
     process.env.AMPLITUDE_TOKEN ?? process.env.AMPLITUDE_WIZARD_TOKEN;
-  const { resolveCredentials, resolveEnvironmentSelection } = await import(
-    './src/lib/credential-resolution.js'
-  );
+  const { resolveCredentials, resolveEnvironmentSelection } =
+    await import('./src/lib/credential-resolution.js');
   await resolveCredentials(session, {
     requireOrgId: false,
     org: options.org as string | undefined,
@@ -652,9 +651,9 @@
       type: 'boolean',
     },
     // Hidden shadows of env-only flags. .env('AMPLITUDE_WIZARD') auto-maps
-    // AMPLITUDE_WIZARD_DEV / _LOG / _TOKEN to these option names; declaring
-    // them here lets .strict() accept the env-var invocation. The actual
-    // values are read via process.env elsewhere.
+    // AMPLITUDE_WIZARD_DEV / _LOG / _TOKEN / _AGENT / _INSTALL_DIR / _CLASSIC
+    // to these option names; declaring them here lets .strict() accept the
+    // env-var injection on every command (not just $0 where they're visible).
     dev: {
       hidden: true,
       describe: 'internal: AMPLITUDE_WIZARD_DEV env-var passthrough',
@@ -670,6 +669,21 @@
       describe: 'internal: AMPLITUDE_WIZARD_TOKEN env-var passthrough',
       type: 'string',
     },
+    agent: {
+      hidden: true,
+      describe: 'internal: AMPLITUDE_WIZARD_AGENT env-var passthrough',
+      type: 'boolean',
+    },
+    'install-dir': {
+      hidden: true,
+      describe: 'internal: AMPLITUDE_WIZARD_INSTALL_DIR env-var passthrough',
+      type: 'string',
+    },
+    classic: {
+      hidden: true,
+      describe: 'internal: AMPLITUDE_WIZARD_CLASSIC env-var passthrough',
+      type: 'boolean',
+    },
   })
   .command(
     ['$0'],
@@ -815,9 +829,8 @@
 
             // If --api-key was provided, skip the OAuth/TUI auth flow entirely.
             if (session.apiKey) {
-              const { DEFAULT_HOST_URL } = await import(
-                './src/lib/constants.js'
-              );
+              const { DEFAULT_HOST_URL } =
+                await import('./src/lib/constants.js');
               session.credentials = {
                 accessToken: session.apiKey,
                 projectApiKey: session.apiKey,
@@ -830,9 +843,8 @@
               const { logToFile } = await import('./src/utils/debug.js');
 
               // Check for crash-recovery checkpoint
-              const { loadCheckpoint } = await import(
-                './src/lib/session-checkpoint.js'
-              );
+              const { loadCheckpoint } =
+                await import('./src/lib/session-checkpoint.js');
               const checkpoint = loadCheckpoint(session.installDir);
               if (checkpoint) {
                 Object.assign(session, checkpoint);
@@ -845,21 +857,18 @@
 
               // Resolve credentials using shared logic (token refresh,
               // env auto-select, pendingOrgs population)
-              const { resolveCredentials } = await import(
-                './src/lib/credential-resolution.js'
-              );
+              const { resolveCredentials } =
+                await import('./src/lib/credential-resolution.js');
               await resolveCredentials(session);
 
               // Resolve org/workspace display names so /whoami shows them.
               // Also extracts the numeric analytics project ID for MCP event detection.
               // Fire-and-forget so it doesn't block startup.
               if (session.region && session.selectedOrgId) {
-                const { getStoredUser, getStoredToken } = await import(
-                  './src/utils/ampli-settings.js'
-                );
-                const { fetchAmplitudeUser, extractAppId } = await import(
-                  './src/lib/api.js'
-                );
+                const { getStoredUser, getStoredToken } =
+                  await import('./src/utils/ampli-settings.js');
+                const { fetchAmplitudeUser, extractAppId } =
+                  await import('./src/lib/api.js');
                 const storedUser = getStoredUser();
                 const realUser =
                   storedUser && storedUser.id !== 'pending' ? storedUser : null;
@@ -915,9 +924,9 @@
                           changed = true;
                           // Fall back to the first workspace if the stored ID is stale.
                           const ws = session.selectedWorkspaceId
-                            ? org.workspaces.find(
+                            ? (org.workspaces.find(
                                 (w) => w.id === session.selectedWorkspaceId,
-                              ) ?? org.workspaces[0]
+                              ) ?? org.workspaces[0])
                             : org.workspaces[0];
                           if (ws) {
                             session.selectedWorkspaceName = ws.name;
@@ -958,9 +967,8 @@
             // Dynamic-import keeps the Claude Agent SDK out of bin.ts load.
             try {
               const fs = await import('fs');
-              const { parseEventPlanContent } = await import(
-                './src/lib/agent-interface.js'
-              );
+              const { parseEventPlanContent } =
+                await import('./src/lib/agent-interface.js');
               const evtPath = resolve(
                 session.installDir,
                 '.amplitude-events.json',
@@ -978,9 +986,8 @@
             }
 
             // Initialize Amplitude Experiment feature flags (non-blocking).
-            const { initFeatureFlags } = await import(
-              './src/lib/feature-flags.js'
-            );
+            const { initFeatureFlags } =
+              await import('./src/lib/feature-flags.js');
             await initFeatureFlags().catch(() => {
               // Flag init failure is non-fatal — all flags default to off
             });
@@ -988,18 +995,16 @@
             // Apply SDK-level opt-out based on feature flags
             analytics.applyOptOut();
 
-            const { FRAMEWORK_REGISTRY } = await import(
-              './src/lib/registry.js'
-            );
+            const { FRAMEWORK_REGISTRY } =
+              await import('./src/lib/registry.js');
             const { detectAllFrameworks } = await import('./src/run.js');
             const installDir = session.installDir ?? process.cwd();
 
             // Verbose startup diagnostics — always written to the log file;
             // visible in the RunScreen "Logs" tab.
             if (session.verbose || session.debug) {
-              const { enableDebugLogs, logToFile } = await import(
-                './src/utils/debug.js'
-              );
+              const { enableDebugLogs, logToFile } =
+                await import('./src/utils/debug.js');
               enableDebugLogs();
               logToFile('[verbose] Amplitude Wizard starting');
               logToFile(`[verbose] node          : ${process.version}`);
@@ -1009,9 +1014,8 @@
               logToFile(`[verbose] argv          : ${process.argv.join(' ')}`);
             }
 
-            const { DETECTION_TIMEOUT_MS } = await import(
-              './src/lib/constants.js'
-            );
+            const { DETECTION_TIMEOUT_MS } =
+              await import('./src/lib/constants.js');
 
             // ── OAuth + account setup ──────────────────────────────
             // Runs concurrently with framework detection while AuthScreen shows.
@@ -1025,19 +1029,15 @@
               if (tui.store.session.credentials !== null) return;
 
               try {
-                const { ampliConfigExists } = await import(
-                  './src/lib/ampli-config.js'
-                );
-                const { performAmplitudeAuth } = await import(
-                  './src/utils/oauth.js'
-                );
+                const { ampliConfigExists } =
+                  await import('./src/lib/ampli-config.js');
+                const { performAmplitudeAuth } =
+                  await import('./src/utils/oauth.js');
                 const { fetchAmplitudeUser } = await import('./src/lib/api.js');
-                const { DEFAULT_AMPLITUDE_ZONE } = await import(
-                  './src/lib/constants.js'
-                );
-                const { storeToken } = await import(
-                  './src/utils/ampli-settings.js'
-                );
+                const { DEFAULT_AMPLITUDE_ZONE } =
+                  await import('./src/lib/constants.js');
+                const { storeToken } =
+                  await import('./src/utils/ampli-settings.js');
 
                 const forceFresh = !ampliConfigExists(installDir);
 
@@ -1198,9 +1198,8 @@
                 };
                 const depNames = Object.keys(allDeps);
 
-                const { DiscoveredFeature } = await import(
-                  './src/lib/wizard-session.js'
-                );
+                const { DiscoveredFeature } =
+                  await import('./src/lib/wizard-session.js');
 
                 if (
                   depNames.some((d) =>
@@ -1212,12 +1211,10 @@
 
                 // LLM SDK detection — sourced from Amplitude LLM analytics skill
                 // Gated by the wizard-llm-analytics feature flag.
-                const { isFlagEnabled } = await import(
-                  './src/lib/feature-flags.js'
-                );
-                const { FLAG_LLM_ANALYTICS } = await import(
-                  './src/lib/feature-flags.js'
-                );
+                const { isFlagEnabled } =
+                  await import('./src/lib/feature-flags.js');
+                const { FLAG_LLM_ANALYTICS } =
+                  await import('./src/lib/feature-flags.js');
                 if (isFlagEnabled(FLAG_LLM_ANALYTICS)) {
                   const LLM_PACKAGES = [
                     'openai',
@@ -1254,9 +1251,8 @@
 
             // Session checkpointing — save at key transitions so crash
             // recovery can skip already-completed steps.
-            const { saveCheckpoint, clearCheckpoint } = await import(
-              './src/lib/session-checkpoint.js'
-            );
+            const { saveCheckpoint, clearCheckpoint } =
+              await import('./src/lib/session-checkpoint.js');
             // After auth completes (most expensive step to repeat)
             tui.store.onEnterScreen(Screen.DataSetup, () => {
               saveCheckpoint(tui.store.session);
@@ -1327,9 +1323,8 @@
             // Before calling the AI agent, do a quick static check to see if
             // Amplitude is already installed in the project. If so, skip the
             // agent entirely and advance directly to MCP setup.
-            const { detectAmplitudeInProject } = await import(
-              './src/lib/detect-amplitude.js'
-            );
+            const { detectAmplitudeInProject } =
+              await import('./src/lib/detect-amplitude.js');
             const localDetection = detectAmplitudeInProject(installDir);
 
             if (localDetection.confidence !== 'none') {
@@ -1339,9 +1334,8 @@
                   localDetection.reason ?? 'unknown'
                 }) — prompting on MCP screen (continue vs run wizard)`,
               );
-              const { RunPhase, OutroKind } = await import(
-                './src/lib/wizard-session.js'
-              );
+              const { RunPhase, OutroKind } =
+                await import('./src/lib/wizard-session.js');
               tui.store.setAmplitudePreDetected();
               tui.store.setRunPhase(RunPhase.Completed);
               const runWizardAnyway =
@@ -1399,9 +1393,8 @@
         const zone = argv.zone as 'us' | 'eu';
 
         try {
-          const { getStoredUser, getStoredToken } = await import(
-            './src/utils/ampli-settings.js'
-          );
+          const { getStoredUser, getStoredToken } =
+            await import('./src/utils/ampli-settings.js');
           // If a valid cached session exists, display the stored user without
           // re-fetching from the API (the cached idToken may be expired).
           const cachedToken = getStoredToken(undefined, zone);
@@ -1464,13 +1457,11 @@
     () => {},
     (argv) => {
       void (async () => {
-        const { getStoredUser, clearStoredCredentials } = await import(
-          './src/utils/ampli-settings.js'
-        );
+        const { getStoredUser, clearStoredCredentials } =
+          await import('./src/utils/ampli-settings.js');
         const { clearApiKey } = await import('./src/utils/api-key-store.js');
-        const { clearCheckpoint } = await import(
-          './src/lib/session-checkpoint.js'
-        );
+        const { clearCheckpoint } =
+          await import('./src/lib/session-checkpoint.js');
         const installDir =
           (argv.installDir as string | undefined) ?? process.cwd();
         const user = getStoredUser();
@@ -1497,9 +1488,8 @@
     () => {},
     (_argv) => {
       void (async () => {
-        const { getStoredUser, getStoredToken } = await import(
-          './src/utils/ampli-settings.js'
-        );
+        const { getStoredUser, getStoredToken } =
+          await import('./src/utils/ampli-settings.js');
         const user = getStoredUser();
         const token = getStoredToken();
         if (user && token && user.id !== 'pending') {
@@ -1555,9 +1545,8 @@
           return;
         }
         try {
-          const { trackWizardFeedback } = await import(
-            './src/utils/track-wizard-feedback.js'
-          );
+          const { trackWizardFeedback } =
+            await import('./src/utils/track-wizard-feedback.js');
           await trackWizardFeedback(message);
           console.log(chalk.green('✔ Thanks — your feedback was sent.'));
           process.exit(0);
@@ -1963,9 +1952,8 @@
           void (async () => {
             try {
               const { startTUI } = await import('./src/ui/tui/start-tui.js');
-              const { buildSession } = await import(
-                './src/lib/wizard-session.js'
-              );
+              const { buildSession } =
+                await import('./src/lib/wizard-session.js');
 
               const { Flow } = await import('./src/ui/tui/router.js');
               const tui = startTUI(WIZARD_VERSION, Flow.McpAdd);
@@ -1977,9 +1965,8 @@
             } catch {
               // TUI unavailable — fallback to logging
               setUI(new LoggingUI());
-              const { addMCPServerToClientsStep } = await import(
-                './src/steps/add-mcp-server-to-clients/index.js'
-              );
+              const { addMCPServerToClientsStep } =
+                await import('./src/steps/add-mcp-server-to-clients/index.js');
               await addMCPServerToClientsStep({
                 local: options.local,
               });
@@ -2005,9 +1992,8 @@
           void (async () => {
             try {
               const { startTUI } = await import('./src/ui/tui/start-tui.js');
-              const { buildSession } = await import(
-                './src/lib/wizard-session.js'
-              );
+              const { buildSession } =
+                await import('./src/lib/wizard-session.js');
 
               const { Flow } = await import('./src/ui/tui/router.js');
               const tui = startTUI(WIZARD_VERSION, Flow.McpRemove);
@@ -2019,9 +2005,8 @@
             } catch {
               // TUI unavailable — fallback to logging
               setUI(new LoggingUI());
-              const { removeMCPServerFromClientsStep } = await import(
-                './src/steps/add-mcp-server-to-clients/index.js'
-              );
+              const { removeMCPServerFromClientsStep } =
+                await import('./src/steps/add-mcp-server-to-clients/index.js');
               await removeMCPServerFromClientsStep({
                 local: options.local,
               });
@@ -2036,9 +2021,8 @@
         () => {
           void (async () => {
             try {
-              const { startAgentMcpServer } = await import(
-                './src/lib/wizard-mcp-server.js'
-              );
+              const { startAgentMcpServer } =
+                await import('./src/lib/wizard-mcp-server.js');
               await startAgentMcpServer();
             } catch (err) {
               const msg = err instanceof Error ? err.message : String(err);
@@ -2059,9 +2043,8 @@
     () => {},
     () => {
       void (async () => {
-        const { getAgentManifest } = await import(
-          './src/lib/agent-manifest.js'
-        );
+        const { getAgentManifest } =
+          await import('./src/lib/agent-manifest.js');
         process.stdout.write(
           JSON.stringify(getAgentManifest(), null, 2) + '\n',
         );

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit e06881d. Configure here.

Comment thread bin.ts
@kelsonpw
Copy link
Copy Markdown
Collaborator Author

@cursor push 7270fe2

@kelsonpw kelsonpw force-pushed the omnara/explore-unused-library-features branch from 2876557 to c919d4a Compare April 24, 2026 19:29
kelsonpw and others added 5 commits April 24, 2026 12:50
The Claude Agent SDK caches the system prompt implicitly, but per-session
dynamic sections (cwd, date, auto-memory, git status) were invalidating the
cache on every run. Setting excludeDynamicSections: true moves those into
the first user message so the static preset + our ~3KB commandments block
stays cacheable across runs and machines. Impact is measurable via
cache_read_input_tokens in benchmarks/cache-tracker.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Completed Q&A turns are now rendered through Ink's <Static> component, so
they're written once above the live region and survive TUI exit (terminal
scrollback). Previously only the latest response was shown inline and got
clobbered on each new question; long responses also displaced the wizard
screen entirely. This mirrors the append-only pattern Claude Code uses for
completed agent output.

Also removes the now-unnecessary responseIsLong preview/dismissal branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.strict() rejects unknown flags and subcommands, catching typos like
--app-ids that would previously fall through silently. .check() validates
--app-id as a positive integer so a bad value fails fast with a
yargs-native error instead of becoming 0 downstream.

The feedback command's positional message is now declared via
[words..] / .positional() so it survives strict parsing. Middleware for
consolidating credential resolution is paired with the upcoming bin.ts
command-module split.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… them

.env('AMPLITUDE_WIZARD') auto-maps AMPLITUDE_WIZARD_DEV / _LOG / _TOKEN to
--dev / --log / --token. With .strict() enabled in the prior commit, these
undeclared options were being rejected, breaking pnpm try / pnpm try:prod
with "Unknown argument: dev".

Declare them as hidden options so strict accepts the env-var invocation.
Actual values are still read via process.env elsewhere — this is purely a
strict-mode compatibility shim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…v vars

.env('AMPLITUDE_WIZARD') auto-maps all AMPLITUDE_WIZARD_* env vars into
argv regardless of which command is active. With .strict() enabled, any
env var that maps to an option only declared in the $0 command builder
(agent, install-dir, classic) would cause yargs to reject it as unknown
when running subcommands like login, feedback, or detect.

Hidden global shadows were already added for dev, log, and token but
agent, install-dir, and classic were missed. This adds the same
treatment for all three.

Applied via @cursor push command
@kelsonpw kelsonpw force-pushed the omnara/explore-unused-library-features branch from c919d4a to b9ff4a9 Compare April 24, 2026 19:51
@kelsonpw kelsonpw merged commit 6bda15c into main Apr 24, 2026
10 checks passed
@kelsonpw kelsonpw deleted the omnara/explore-unused-library-features branch April 24, 2026 20:51
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.

2 participants