Convex-only Slice 1: clients talk to Convex, Flue is a private worker

Normalize the topology so web/desktop/mobile clients communicate only with
Convex. Convex admits durable commands, dispatches private Flue turns through
FLUE_URL, and stores the product-facing result before clients observe it.

- Normalized relational schema: organizations, projects, conversations/turns/
  messages/attachments, signals/sources/constraints, works/events/attachments.
- Conversation turns queued in Convex; the agent runAction dispatches to Flue
  and persists assistant response, signals, and proposed work back into Convex.
- Browser chat moved off the Flue transport: use-chat-agent now reads reactive
  Convex rows and sends through conversationMessages.send.
- Fixed signed-in blank screen: gate all product queries on useConvexAuth
  (isAuthenticated && !isRefreshing) plus personal-org bootstrap.
- Pinned react/react-dom to 19.2.8 via catalog to fix SSR dual-React crash.
- Removed ~16.6k net lines: daemon, AgentOS/Orb, project issues/runs/artifacts,
  todos, browser Flue transport, mobile execution views, smoke scripts.

Verified end-to-end on cheaptricks: connect repo, send actionable message,
Flue turn completes, Signal + proposed Work created with exact provenance,
persists across refresh.
This commit is contained in:
-Puter
2026-07-27 21:32:17 +05:30
parent 4c741fbe06
commit a5414d83bd
127 changed files with 1283 additions and 17784 deletions

View File

@@ -55,7 +55,7 @@ const attachSignal = async (
organizationId: String(signal.organizationId),
projectId: String(signal.projectId),
signalId: String(signal._id),
title: signal.problemStatement.title,
title: signal.title,
},
work: {
organizationId: String(work.organizationId),
@@ -81,18 +81,14 @@ const attachSignal = async (
const createdAt = Date.now();
await ctx.db.insert("signalWorkAttachments", {
createdAt,
organizationId: work.organizationId,
projectId: work.projectId,
signalId: signal._id,
workId: work._id,
});
await ctx.db.insert("workEvents", {
createdAt,
data: event.data,
idempotencyKey: event.idempotencyKey,
kind: event.kind,
organizationId: work.organizationId,
projectId: work.projectId,
signalId: signal._id,
workId: work._id,
});
await ctx.db.patch(work._id, { updatedAt: createdAt });
@@ -138,8 +134,19 @@ export const createFromSignal = mutation({
return { created: false, workId: existingAttachment.workId };
}
const constraints = await ctx.db
.query("signalConstraints")
.withIndex("by_signalId_and_ordinal", (q) => q.eq("signalId", signal._id))
.collect();
const draft = await Effect.runPromise(
workDraftFromSignal(signal.problemStatement)
workDraftFromSignal({
constraints: constraints
.sort((left, right) => left.ordinal - right.ordinal)
.map((constraint) => constraint.value),
desiredOutcome: signal.desiredOutcome,
summary: signal.summary,
title: signal.title,
})
).catch((error: unknown) => {
throw new ConvexError(
error instanceof Error ? error.message : "Invalid Work proposal"
@@ -169,18 +176,14 @@ export const createFromSignal = mutation({
});
await ctx.db.insert("signalWorkAttachments", {
createdAt,
organizationId: signal.organizationId,
projectId: signal.projectId as Id<"projects">,
signalId: signal._id,
workId,
});
await ctx.db.insert("workEvents", {
createdAt,
data: event.data,
idempotencyKey: event.idempotencyKey,
kind: event.kind,
organizationId: signal.organizationId,
projectId: signal.projectId as Id<"projects">,
signalId: signal._id,
workId,
});
return { created: true, workId };
@@ -231,23 +234,23 @@ export const listForProject = query({
}
const sources = await ctx.db
.query("signalSources")
.withIndex("by_signal_and_ordinal", (q) =>
.withIndex("by_signalId_and_ordinal", (q) =>
q.eq("signalId", signal._id)
)
.collect();
return {
createdAt: signal.createdAt,
signalId: signal._id,
summary: signal.problemStatement.summary,
summary: signal.summary,
sources: sources
.sort((a, b) => a.ordinal - b.ordinal)
.map((source) => ({
createdAt: source.sourceCreatedAt,
messageId: source.messageId,
messageId: String(source.messageId),
rawText: source.rawTextSnapshot,
submissionId: source.submissionId ?? null,
submissionId: null,
})),
title: signal.problemStatement.title,
title: signal.title,
};
})
);