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)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
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,
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user