Files
exe.dev user e859245867 Add minimal stock listing app: actions, Postgres schema, stocks page, Claude Agent SDK harness
- Add stocks table (server/db) with list/get/add/update/delete actions, scoped
  per user, backing both the chat agent and the /stocks UI via
  useActionQuery/useActionMutation
- Add mobile-first /stocks page (shadcn table/cards, watchlist, search) and
  wire it into the sidebar, navigation state, and view-screen context
- Install the platform's Claude Agent SDK harness (server/plugins,
  server/routes/api/claude-agent) so the app agent runs on the platform's own
  Claude subscription instead of the Builder.io gateway; fix the vendored
  turn.post.ts route to resolve the session and wrap it in
  runWithRequestContext, since custom /api/ routes aren't auto-wrapped in
  request context the way /_agent-native/actions/* are
- Add shadcn table/badge/dialog/select components (Tabler icons, not lucide)
2026-07-29 12:18:14 +00:00

78 lines
2.0 KiB
TypeScript

import {
ensureAdditiveColumns,
getDbExec,
runMigrations,
} from "@agent-native/core/db";
import * as schema from "../db/schema.js";
const runStocksMigrations = runMigrations(
[
{
version: 1,
name: "stocks-table",
sql: `CREATE TABLE IF NOT EXISTS stocks (
id TEXT PRIMARY KEY,
symbol TEXT NOT NULL,
company_name TEXT NOT NULL,
exchange TEXT NOT NULL DEFAULT 'NASDAQ',
sector TEXT,
currency TEXT NOT NULL DEFAULT 'USD',
price REAL NOT NULL DEFAULT 0,
change_percent REAL NOT NULL DEFAULT 0,
market_cap INTEGER,
watchlisted BOOLEAN NOT NULL DEFAULT FALSE,
owner_email TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
)`,
},
{
version: 2,
name: "stocks-owner-symbol-unique-index",
sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_stocks_owner_symbol
ON stocks (owner_email, symbol)`,
},
{
version: 3,
name: "stocks-owner-watchlisted-index",
sql: `CREATE INDEX IF NOT EXISTS idx_stocks_owner_watchlisted
ON stocks (owner_email, watchlisted)`,
},
],
{ table: "stocks_migrations" },
);
function isDrizzleTable(value: unknown): value is object {
return (
!!value &&
typeof value === "object" &&
Object.getOwnPropertySymbols(value).some((s) =>
s.toString().includes("drizzle"),
)
);
}
const schemaTables = Object.values(schema).filter(isDrizzleTable);
export default async (nitroApp: any): Promise<void> => {
await runStocksMigrations(nitroApp);
try {
const summary = await ensureAdditiveColumns({
db: getDbExec(),
tables: schemaTables,
});
if (summary.errors.length > 0) {
console.warn(
"[db] ensureAdditiveColumns completed with errors:",
summary.errors,
);
}
} catch (err) {
console.warn(
"[db] ensureAdditiveColumns failed (non-fatal):",
err instanceof Error ? err.message : err,
);
}
};