Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 174 additions & 112 deletions README.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions apps/marketing/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@
}

@theme inline {
--font-sans: var(--font-dm-sans), "DM Sans", -apple-system, BlinkMacSystemFont,
"Segoe UI", system-ui, sans-serif;
--font-mono: "SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo,
monospace;
--font-sans:
var(--font-dm-sans), "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,
sans-serif;
--font-mono: "SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
Expand Down
2 changes: 1 addition & 1 deletion apps/marketing/components/ai-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ export function AISection() {

{/* MCP Code Snippet - Use semantic tokens for code syntax */}
<div className="bg-card/30 border border-border/60 rounded-xl p-5 font-mono text-sm">
<p className="text-muted-foreground/70 mb-3">//mcp.sprint.app/sse</p>
<p className="text-muted-foreground/70 mb-3">{"//mcp.sprint.app/sse"}</p>
<div className="space-y-1 mb-6">
<p>
<span className="text-code-constant/70">"mcpServers"</span>
Expand Down
2 changes: 1 addition & 1 deletion apps/marketing/components/dashboard/dashboard-inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function IssueRow({
issue,
selected,
onClick,
isMobile,
isMobile: _isMobile,
}: {
issue: Issue;
selected: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,9 @@ export function DashboardIssueDetail({
</div>

<div className="space-y-4">
{issue.activity.map((activity, index) => (
{issue.activity.map((activity) => (
<ActivityItem
key={index}
key={`${activity.time}-${activity.user}-${activity.action}`}
user={activity.user}
action={activity.action}
time={activity.time}
Expand Down
2 changes: 1 addition & 1 deletion apps/marketing/components/dashboard/dashboard-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ function NavItem({
color,
teamColor,
onClick,
isMobile,
isMobile: _isMobile,
}: {
icon: React.ElementType;
label: string;
Expand Down
6 changes: 3 additions & 3 deletions apps/marketing/components/logo-cloud.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ export function LogoCloud() {
>
{/* Logo grid with variety */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-x-16 gap-y-10 items-center justify-items-center transition-all duration-300 group-hover:blur-[2.5px] group-hover:opacity-50">
{companies.map((company, i) => {
{companies.map((company, companyIndex) => {
const Icon = company.icon;
return (
<motion.div
key={i}
key={company.name}
initial={{ opacity: 0, scale: 0.8 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.4, delay: i * 0.05 }}
transition={{ duration: 0.4, delay: companyIndex * 0.05 }}
className="text-foreground font-semibold text-xl flex items-center gap-2"
>
<Icon className="w-5 h-5 fill-current" />
Expand Down
6 changes: 3 additions & 3 deletions apps/marketing/components/product-direction-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ export function ProductDirectionSection() {
<div className="absolute top-0 left-0 right-0 flex items-end">
{/* Tick marks row */}
<div className="flex items-end gap-[3px] absolute bottom-0 left-[5%] right-0">
{Array.from({ length: 60 }).map((_, i) => (
{Array.from({ length: 60 }, (_, tickIndex) => tickIndex).map((tickIndex) => (
<div
key={i}
key={tickIndex}
className="bg-zinc-600/60"
style={{
width: "1px",
height: i % 7 === 0 ? "16px" : "8px",
height: tickIndex % 7 === 0 ? "16px" : "8px",
}}
/>
))}
Expand Down
4 changes: 2 additions & 2 deletions apps/marketing/components/ui-panel-inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ export function UIPanelInbox() {

{/* List */}
<div className="divide-y divide-zinc-800/30">
{items.map((item, index) => (
{items.map((item) => (
<div
key={index}
key={`${item.id}-${item.title}-${item.time || "0"}`}
className="px-4 py-2.5 hover:bg-zinc-800/30 transition-colors cursor-pointer"
>
<div className="flex items-start gap-3">
Expand Down
27 changes: 15 additions & 12 deletions apps/marketing/components/ui/carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,22 @@ function Carousel({
};
}, [api, onSelect]);

const contextValue = React.useMemo(
() => ({
carouselRef,
api: api,
opts,
orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}),
[api, canScrollNext, canScrollPrev, carouselRef, orientation, opts, scrollNext, scrollPrev],
);

return (
<CarouselContext.Provider
value={{
carouselRef,
api: api,
opts,
orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}}
>
<CarouselContext.Provider value={contextValue}>
<div
onKeyDownCapture={handleKeyDown}
className={cn("relative", className)}
Expand Down
3 changes: 2 additions & 1 deletion apps/marketing/components/ui/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ function ChartContainer({
}) {
const uniqueId = React.useId();
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
const contextValue = React.useMemo(() => ({ config }), [config]);

return (
<ChartContext.Provider value={{ config }}>
<ChartContext.Provider value={contextValue}>
<div
data-slot="chart"
data-chart={chartId}
Expand Down
6 changes: 5 additions & 1 deletion apps/marketing/components/ui/field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ function FieldError({

return (
<ul className="ml-4 flex list-disc flex-col gap-1">
{errors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
{errors
.filter((error): error is { message: string } => typeof error?.message === "string")
.map((error) => (
<li key={error.message}>{error.message}</li>
))}
</ul>
);
}, [children, errors]);
Expand Down
7 changes: 5 additions & 2 deletions apps/marketing/components/ui/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ const FormField = <
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
const fieldContextValue = React.useMemo(() => ({ name: props.name }), [props.name]);

return (
<FormFieldContext.Provider value={{ name: props.name }}>
<FormFieldContext.Provider value={fieldContextValue}>
<Controller {...props} />
</FormFieldContext.Provider>
);
Expand Down Expand Up @@ -71,9 +73,10 @@ const FormItemContext = React.createContext<FormItemContextValue>({} as FormItem

function FormItem({ className, ...props }: React.ComponentProps<"div">) {
const id = React.useId();
const itemContextValue = React.useMemo(() => ({ id }), [id]);

return (
<FormItemContext.Provider value={{ id }}>
<FormItemContext.Provider value={itemContextValue}>
<div data-slot="form-item" className={cn("grid gap-2", className)} {...props} />
</FormItemContext.Provider>
);
Expand Down
5 changes: 2 additions & 3 deletions apps/marketing/components/ui/toggle-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function ToggleGroup({
children,
...props
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> & VariantProps<typeof toggleVariants>) {
const contextValue = React.useMemo(() => ({ variant, size }), [size, variant]);
return (
<ToggleGroupPrimitive.Root
data-slot="toggle-group"
Expand All @@ -30,9 +31,7 @@ function ToggleGroup({
)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
<ToggleGroupContext.Provider value={contextValue}>{children}</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
);
}
Expand Down
89 changes: 86 additions & 3 deletions apps/mobile/ios/App/CapApp-SPM/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,88 @@
# CapApp-SPM
# CapApp-SPM (Capacitor Swift Package)

This package is used to host SPM dependencies for your Capacitor project
This directory is a generated Swift Package integration point for the native mobile
shell. It is managed by Capacitor tooling and should be treated as a reproducible
native dependency boundary.

Do not modify the contents of it or there may be unintended consequences.
## 1) What this package is

- Package name: `CapApp-SPM`
- Product: `CapApp-SPM`
- Target(s): `CapApp-SPM`
- Platforms: iOS 15+

Primary goals:

- provide a stable dependency entrypoint into the native layer,
- keep native package metadata separate from app JS source trees,
- avoid hand-editing generated package internals.

## 2) Files here

- `Package.swift`
- `Sources/` (package targets/source)

The current `Package.swift` includes local package links into Bun-managed `node_modules`
paths, which is why it is intentionally generated rather than hand-maintained.

## 3) Install and wire into an Xcode project

1. In Xcode, open your `.xcworkspace` / `.xcodeproj`.
2. Go to **File → Add Packages…**.
3. Add by local path:
- `apps/mobile/ios/App/CapApp-SPM`
4. Add the `CapApp-SPM` product to the appropriate app target.

### Target mapping quick reference

- Package: `CapApp-SPM`
- Product: `CapApp-SPM`
- Usually added to the main app target and the extensions that depend on Capacitor modules.

## 4) Regenerating after dependency changes

When web/native dependency versions change in `apps/mobile`, regenerate this package
using your normal Capacitor sync workflow (outside this folder) and commit generated
updates if required.

Recommended sequence:

```bash
cd apps/mobile
bun run sync
cd ios/App
# regenerate native project references through your normal mobile tooling
```

Then reopen Xcode and run package resolve.

## 5) Build and debug checks

### Before a build

- Open the workspace cleanly.
- Remove stale derived data if dependency resolution changed.
- Validate package resolve on local machine first.

### Common failure states

- **Package not found / cannot resolve product**
- verify path points to `CapApp-SPM/` and Xcode selected the correct package product.
- **Build fails with module resolution issues**
- clean build folder and re-resolve package dependencies.
- **Code signing breaks after package edits**
- re-check provisioning profile and signing identity for native targets.

## 6) CI/release implications

For release and package integrity:

- keep native package updates deterministic,
- avoid ad-hoc local path edits that are not reflected in source control,
- verify any package-manager-driven changes are generated and committed with the
corresponding release or mobile update.

## 7) Reference

This package is separate from release docs in [`docs/releases/README.md`](/Users/buns/.okcode/worktrees/okcode/okcode-ddc899c0/docs/releases/README.md),
which controls desktop artifact publication and GitHub release behavior.
8 changes: 5 additions & 3 deletions apps/web/src/components/DiffPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,11 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) {
() => renderableFiles.map((fileDiff) => resolveFileDiffPath(fileDiff)),
[renderableFiles],
);
const activeReviewState = patchReviewSelectionKey
? (reviewStateBySelectionKey[patchReviewSelectionKey] ?? {})
: {};
const activeReviewState = useMemo(() => {
return patchReviewSelectionKey
? (reviewStateBySelectionKey[patchReviewSelectionKey] ?? {})
: {};
}, [patchReviewSelectionKey, reviewStateBySelectionKey]);
const acceptedFileCount = useMemo(
() =>
renderableFilePaths.reduce(
Expand Down
29 changes: 21 additions & 8 deletions apps/web/src/components/pr-review/RawPatchViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,27 @@ export function RawPatchViewer({ text, reason }: { text: string; reason: string
) : (
/* Fallback: no file structure detected, render all lines with highlighting */
<div className="overflow-hidden rounded-xl border border-border/70">
{lines.map((line, index) => (
<RawPatchLine
key={index}
line={line}
lineNumber={index + 1}
kind={classifyLine(line)}
/>
))}
{lines
.reduce<Array<{ line: string; key: string; lineNumber: number }>>(
(items, line, lineIndex) => {
const lineNumber = lineIndex + 1;
items.push({
line,
lineNumber,
key: `${lineNumber}-${line}`,
});
return items;
},
[],
)
.map(({ key, line, lineNumber }) => (
<RawPatchLine
key={key}
line={line}
lineNumber={lineNumber}
kind={classifyLine(line)}
/>
))}
</div>
)}
</div>
Expand Down
42 changes: 22 additions & 20 deletions apps/web/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,26 +260,28 @@ export function syncServerReadModel(state: AppState, readModel: OrchestrationRea
}
: null,
messages: thread.messages.map((message) => {
const attachments = message.attachments?.map((attachment) => ({
...(attachment.type === "image"
? {
type: "image" as const,
id: attachment.id,
name: attachment.name,
mimeType: attachment.mimeType,
sizeBytes: attachment.sizeBytes,
url: toAttachmentPreviewUrl(attachmentPreviewRoutePath(attachment.id)),
previewUrl: toAttachmentPreviewUrl(attachmentPreviewRoutePath(attachment.id)),
}
: {
type: "file" as const,
id: attachment.id,
name: attachment.name,
mimeType: attachment.mimeType,
sizeBytes: attachment.sizeBytes,
url: toAttachmentPreviewUrl(attachmentPreviewRoutePath(attachment.id)),
}),
}));
const attachments = message.attachments?.map((attachment) => {
const baseAttachment = {
id: attachment.id,
name: attachment.name,
mimeType: attachment.mimeType,
sizeBytes: attachment.sizeBytes,
url: toAttachmentPreviewUrl(attachmentPreviewRoutePath(attachment.id)),
};

if (attachment.type === "image") {
return {
type: "image" as const,
previewUrl: toAttachmentPreviewUrl(attachmentPreviewRoutePath(attachment.id)),
...baseAttachment,
};
}

return {
type: "file" as const,
...baseAttachment,
};
});
const normalizedMessage: ChatMessage = {
id: message.id,
role: message.role,
Expand Down
Loading
Loading