Type Codex rollout parser
This commit is contained in:
@@ -100,6 +100,24 @@ type CodexOptionsOverrides = Partial<ThreadOptions> & { skipGitRepoCheck?: boole
|
|||||||
const MAX_ROLLOUT_SEARCH_DEPTH = 5;
|
const MAX_ROLLOUT_SEARCH_DEPTH = 5;
|
||||||
type ToolCallTimelineItem = Extract<AgentTimelineItem, { type: "tool_call" }>;
|
type ToolCallTimelineItem = Extract<AgentTimelineItem, { type: "tool_call" }>;
|
||||||
|
|
||||||
|
type ExecPermissionRequestPayload = {
|
||||||
|
call_id?: string;
|
||||||
|
command?: string | string[];
|
||||||
|
cwd?: string;
|
||||||
|
reason?: string;
|
||||||
|
risk?: { description?: string } & Record<string, unknown>;
|
||||||
|
parsed_cmd?: string[];
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PatchPermissionRequestPayload = {
|
||||||
|
call_id?: string;
|
||||||
|
changes?: Record<string, unknown>;
|
||||||
|
grant_root?: string;
|
||||||
|
reason?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
function createToolCallTimelineItem(
|
function createToolCallTimelineItem(
|
||||||
data: Omit<ToolCallTimelineItem, "type">
|
data: Omit<ToolCallTimelineItem, "type">
|
||||||
): AgentTimelineItem {
|
): AgentTimelineItem {
|
||||||
@@ -612,12 +630,12 @@ class CodexAgentSession implements AgentSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === "exec_approval_request") {
|
if (eventType === "exec_approval_request") {
|
||||||
const request = this.buildExecPermissionRequest(event as any);
|
const request = this.buildExecPermissionRequest(event);
|
||||||
return this.enqueuePermissionRequest(request);
|
return this.enqueuePermissionRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === "apply_patch_approval_request") {
|
if (eventType === "apply_patch_approval_request") {
|
||||||
const request = this.buildPatchPermissionRequest(event as any);
|
const request = this.buildPatchPermissionRequest(event);
|
||||||
return this.enqueuePermissionRequest(request);
|
return this.enqueuePermissionRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,10 +670,11 @@ class CodexAgentSession implements AgentSession {
|
|||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildExecPermissionRequest(raw: any): AgentPermissionRequest | null {
|
private buildExecPermissionRequest(rawInput: unknown): AgentPermissionRequest | null {
|
||||||
if (!raw || typeof raw !== "object") {
|
if (!rawInput || typeof rawInput !== "object") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const raw = rawInput as ExecPermissionRequestPayload;
|
||||||
|
|
||||||
const commandParts: string[] = Array.isArray(raw.command)
|
const commandParts: string[] = Array.isArray(raw.command)
|
||||||
? raw.command.filter((entry: unknown) => typeof entry === "string")
|
? raw.command.filter((entry: unknown) => typeof entry === "string")
|
||||||
@@ -705,10 +724,11 @@ class CodexAgentSession implements AgentSession {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildPatchPermissionRequest(raw: any): AgentPermissionRequest | null {
|
private buildPatchPermissionRequest(rawInput: unknown): AgentPermissionRequest | null {
|
||||||
if (!raw || typeof raw !== "object") {
|
if (!rawInput || typeof rawInput !== "object") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const raw = rawInput as PatchPermissionRequestPayload;
|
||||||
|
|
||||||
const requestId = typeof raw.call_id === "string" && raw.call_id.length ? raw.call_id : randomUUID();
|
const requestId = typeof raw.call_id === "string" && raw.call_id.length ? raw.call_id : randomUUID();
|
||||||
const changes = raw.changes && typeof raw.changes === "object" ? raw.changes : undefined;
|
const changes = raw.changes && typeof raw.changes === "object" ? raw.changes : undefined;
|
||||||
@@ -883,17 +903,17 @@ async function parseRolloutFile(filePath: string, threadId: string): Promise<Age
|
|||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRolloutEntry(line: string): { type: string; payload?: any } | null {
|
function parseRolloutEntry(line: string): RolloutEntry | null {
|
||||||
if (!line) {
|
if (!line) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(line);
|
const parsed = JSON.parse(line);
|
||||||
if (parsed && typeof parsed === "object" && "type" in parsed) {
|
if (isRolloutEntry(parsed)) {
|
||||||
return parsed as { type: string; payload?: any };
|
return parsed;
|
||||||
}
|
}
|
||||||
if (parsed && typeof parsed === "object" && typeof (parsed as any).output === "string") {
|
if (parsed && typeof parsed === "object" && typeof (parsed as { output?: unknown }).output === "string") {
|
||||||
return parseRolloutEntry((parsed as any).output);
|
return parseRolloutEntry((parsed as { output: string }).output);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
@@ -901,8 +921,28 @@ function parseRolloutEntry(line: string): { type: string; payload?: any } | null
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isRolloutEntry(value: unknown): value is RolloutEntry {
|
||||||
|
if (!value || typeof value !== "object" || !("type" in value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const type = (value as { type?: unknown }).type;
|
||||||
|
return type === "response_item" || type === "event_msg";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSessionMetaEntry(value: unknown): value is SessionMetaEntry {
|
||||||
|
return Boolean(value && typeof value === "object" && (value as { type?: unknown }).type === "session_meta");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isResponseItemEntry(value: unknown): value is ResponseItemEntry {
|
||||||
|
return Boolean(value && typeof value === "object" && (value as { type?: unknown }).type === "response_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRolloutMessagePayload(payload: RolloutResponsePayload | undefined): payload is RolloutMessagePayload {
|
||||||
|
return Boolean(payload && payload.type === "message");
|
||||||
|
}
|
||||||
|
|
||||||
function handleRolloutResponseItem(
|
function handleRolloutResponseItem(
|
||||||
payload: any,
|
payload: RolloutResponsePayload | undefined,
|
||||||
events: AgentStreamEvent[],
|
events: AgentStreamEvent[],
|
||||||
commandCalls: Map<string, { command: string }>
|
commandCalls: Map<string, { command: string }>
|
||||||
): void {
|
): void {
|
||||||
@@ -946,7 +986,7 @@ function handleRolloutResponseItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRolloutEventMessage(payload: any, events: AgentStreamEvent[]): void {
|
function handleRolloutEventMessage(payload: RolloutEventPayload | undefined, events: AgentStreamEvent[]): void {
|
||||||
if (!payload || typeof payload !== "object") {
|
if (!payload || typeof payload !== "object") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -956,7 +996,7 @@ function handleRolloutEventMessage(payload: any, events: AgentStreamEvent[]): vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRolloutFunctionCall(
|
function handleRolloutFunctionCall(
|
||||||
payload: any,
|
payload: RolloutFunctionCallPayload,
|
||||||
events: AgentStreamEvent[],
|
events: AgentStreamEvent[],
|
||||||
commandCalls: Map<string, { command: string }>
|
commandCalls: Map<string, { command: string }>
|
||||||
): void {
|
): void {
|
||||||
@@ -966,7 +1006,7 @@ function handleRolloutFunctionCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name === "shell") {
|
if (name === "shell") {
|
||||||
const args = safeJsonParse(payload.arguments);
|
const args = safeJsonParse<Record<string, unknown>>(payload.arguments);
|
||||||
const command = formatCommand(args);
|
const command = formatCommand(args);
|
||||||
if (command && typeof payload.call_id === "string") {
|
if (command && typeof payload.call_id === "string") {
|
||||||
commandCalls.set(payload.call_id, { command });
|
commandCalls.set(payload.call_id, { command });
|
||||||
@@ -975,7 +1015,7 @@ function handleRolloutFunctionCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name === "update_plan") {
|
if (name === "update_plan") {
|
||||||
const args = safeJsonParse(payload.arguments);
|
const args = safeJsonParse<{ plan?: unknown }>(payload.arguments);
|
||||||
const planItems = parsePlanItems(args);
|
const planItems = parsePlanItems(args);
|
||||||
if (planItems.length) {
|
if (planItems.length) {
|
||||||
events.push({ type: "timeline", provider: "codex", item: { type: "todo", items: planItems, raw: payload } });
|
events.push({ type: "timeline", provider: "codex", item: { type: "todo", items: planItems, raw: payload } });
|
||||||
@@ -1000,7 +1040,7 @@ function handleRolloutFunctionCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function finalizeRolloutFunctionCall(
|
function finalizeRolloutFunctionCall(
|
||||||
payload: any,
|
payload: RolloutFunctionCallOutputPayload,
|
||||||
events: AgentStreamEvent[],
|
events: AgentStreamEvent[],
|
||||||
commandCalls: Map<string, { command: string }>
|
commandCalls: Map<string, { command: string }>
|
||||||
): void {
|
): void {
|
||||||
@@ -1011,7 +1051,7 @@ function finalizeRolloutFunctionCall(
|
|||||||
if (!command) {
|
if (!command) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const result = safeJsonParse(payload.output);
|
const result = safeJsonParse<CommandExecutionResult>(payload.output);
|
||||||
const exitCode = result?.metadata?.exit_code;
|
const exitCode = result?.metadata?.exit_code;
|
||||||
const status = exitCode === undefined || exitCode === 0 ? "completed" : "failed";
|
const status = exitCode === undefined || exitCode === 0 ? "completed" : "failed";
|
||||||
events.push({
|
events.push({
|
||||||
@@ -1032,7 +1072,7 @@ function finalizeRolloutFunctionCall(
|
|||||||
commandCalls.delete(payload.call_id);
|
commandCalls.delete(payload.call_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRolloutCustomToolCall(payload: any, events: AgentStreamEvent[]): void {
|
function handleRolloutCustomToolCall(payload: RolloutCustomToolCallPayload, events: AgentStreamEvent[]): void {
|
||||||
if (payload?.name === "apply_patch" && typeof payload.input === "string") {
|
if (payload?.name === "apply_patch" && typeof payload.input === "string") {
|
||||||
const files = parsePatchFiles(payload.input);
|
const files = parsePatchFiles(payload.input);
|
||||||
if (files.length) {
|
if (files.length) {
|
||||||
@@ -1076,6 +1116,91 @@ type RolloutCandidate = {
|
|||||||
mtime: Date;
|
mtime: Date;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RolloutContentBlock = {
|
||||||
|
text?: string;
|
||||||
|
message?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutMessagePayload = {
|
||||||
|
type: "message";
|
||||||
|
role?: string;
|
||||||
|
content?: RolloutContentBlock[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutReasoningSummary = {
|
||||||
|
text?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutReasoningPayload = {
|
||||||
|
type: "reasoning";
|
||||||
|
summary?: RolloutReasoningSummary[];
|
||||||
|
text?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutFunctionCallPayload = {
|
||||||
|
type: "function_call";
|
||||||
|
name?: string;
|
||||||
|
arguments?: string;
|
||||||
|
call_id?: string;
|
||||||
|
status?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutFunctionCallOutputPayload = {
|
||||||
|
type: "function_call_output";
|
||||||
|
call_id?: string;
|
||||||
|
output?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutCustomToolCallPayload = {
|
||||||
|
type: "custom_tool_call";
|
||||||
|
name?: string;
|
||||||
|
status?: string;
|
||||||
|
input?: string | Record<string, unknown>;
|
||||||
|
output?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutResponsePayload =
|
||||||
|
| RolloutMessagePayload
|
||||||
|
| RolloutReasoningPayload
|
||||||
|
| RolloutFunctionCallPayload
|
||||||
|
| RolloutFunctionCallOutputPayload
|
||||||
|
| RolloutCustomToolCallPayload;
|
||||||
|
|
||||||
|
type RolloutEventPayload = {
|
||||||
|
type: string;
|
||||||
|
text?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RolloutEntry =
|
||||||
|
| { type: "response_item"; payload?: RolloutResponsePayload }
|
||||||
|
| { type: "event_msg"; payload?: RolloutEventPayload };
|
||||||
|
|
||||||
|
type CommandExecutionResult = {
|
||||||
|
metadata?: {
|
||||||
|
exit_code?: number;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SessionMetaPayload = {
|
||||||
|
id?: string;
|
||||||
|
cwd?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SessionMetaEntry = {
|
||||||
|
type: "session_meta";
|
||||||
|
payload?: SessionMetaPayload;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ResponseItemEntry = {
|
||||||
|
type: "response_item";
|
||||||
|
payload?: RolloutResponsePayload;
|
||||||
|
};
|
||||||
|
|
||||||
async function collectRecentRolloutFiles(rootDir: string, limit: number): Promise<RolloutCandidate[]> {
|
async function collectRecentRolloutFiles(rootDir: string, limit: number): Promise<RolloutCandidate[]> {
|
||||||
const candidates: RolloutCandidate[] = [];
|
const candidates: RolloutCandidate[] = [];
|
||||||
async function traverse(dir: string): Promise<void> {
|
async function traverse(dir: string): Promise<void> {
|
||||||
@@ -1132,18 +1257,23 @@ async function parseRolloutDescriptor(
|
|||||||
for (const rawLine of content.split(/\r?\n/)) {
|
for (const rawLine of content.split(/\r?\n/)) {
|
||||||
const line = rawLine.trim();
|
const line = rawLine.trim();
|
||||||
if (!line) continue;
|
if (!line) continue;
|
||||||
let entry: any;
|
let entry: unknown;
|
||||||
try {
|
try {
|
||||||
entry = JSON.parse(line);
|
entry = JSON.parse(line);
|
||||||
} catch {
|
} catch {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!sessionId && entry?.type === "session_meta" && entry.payload) {
|
if (!sessionId && isSessionMetaEntry(entry) && entry.payload) {
|
||||||
sessionId = typeof entry.payload.id === "string" ? entry.payload.id : null;
|
sessionId = typeof entry.payload.id === "string" ? entry.payload.id : null;
|
||||||
if (typeof entry.payload.cwd === "string" && entry.payload.cwd.length > 0) {
|
if (typeof entry.payload.cwd === "string" && entry.payload.cwd.length > 0) {
|
||||||
cwd = entry.payload.cwd;
|
cwd = entry.payload.cwd;
|
||||||
}
|
}
|
||||||
} else if (!title && entry?.type === "response_item" && entry.payload?.role === "user") {
|
} else if (
|
||||||
|
!title &&
|
||||||
|
isResponseItemEntry(entry) &&
|
||||||
|
isRolloutMessagePayload(entry.payload) &&
|
||||||
|
entry.payload.role === "user"
|
||||||
|
) {
|
||||||
title = extractCodexUserPrompt(entry.payload);
|
title = extractCodexUserPrompt(entry.payload);
|
||||||
}
|
}
|
||||||
if (sessionId && cwd && title) {
|
if (sessionId && cwd && title) {
|
||||||
@@ -1177,12 +1307,11 @@ async function parseRolloutDescriptor(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractCodexUserPrompt(payload: any): string | null {
|
function extractCodexUserPrompt(payload: RolloutMessagePayload): string | null {
|
||||||
const content = payload?.content;
|
if (!Array.isArray(payload.content)) {
|
||||||
if (!Array.isArray(content)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (const block of content) {
|
for (const block of payload.content) {
|
||||||
if (block && typeof block === "object" && typeof block.text === "string") {
|
if (block && typeof block === "object" && typeof block.text === "string") {
|
||||||
return block.text.trim();
|
return block.text.trim();
|
||||||
}
|
}
|
||||||
@@ -1207,12 +1336,13 @@ function extractMessageText(content: unknown): string {
|
|||||||
if (!block || typeof block !== "object") {
|
if (!block || typeof block !== "object") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const text = typeof (block as any).text === "string" ? (block as any).text : undefined;
|
const record = block as Record<string, unknown>;
|
||||||
|
const text = typeof record.text === "string" ? record.text : undefined;
|
||||||
if (text && text.trim()) {
|
if (text && text.trim()) {
|
||||||
parts.push(text.trim());
|
parts.push(text.trim());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const message = typeof (block as any).message === "string" ? (block as any).message : undefined;
|
const message = typeof record.message === "string" ? record.message : undefined;
|
||||||
if (message && message.trim()) {
|
if (message && message.trim()) {
|
||||||
parts.push(message.trim());
|
parts.push(message.trim());
|
||||||
}
|
}
|
||||||
@@ -1220,10 +1350,10 @@ function extractMessageText(content: unknown): string {
|
|||||||
return parts.join("\n").trim();
|
return parts.join("\n").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractReasoningText(payload: any): string {
|
function extractReasoningText(payload: RolloutReasoningPayload): string {
|
||||||
if (Array.isArray(payload?.summary)) {
|
if (Array.isArray(payload?.summary)) {
|
||||||
const text = payload.summary
|
const text = payload.summary
|
||||||
.map((item: any) => (typeof item?.text === "string" ? item.text : ""))
|
.map((item) => (item && typeof item.text === "string" ? item.text : ""))
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n")
|
.join("\n")
|
||||||
.trim();
|
.trim();
|
||||||
@@ -1237,18 +1367,20 @@ function extractReasoningText(payload: any): string {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePlanItems(args: any): { text: string; completed: boolean }[] {
|
function parsePlanItems(args: unknown): { text: string; completed: boolean }[] {
|
||||||
const plan = Array.isArray(args?.plan) ? args.plan : [];
|
const planValue = typeof args === "object" && args ? (args as { plan?: unknown }).plan : undefined;
|
||||||
|
const plan = Array.isArray(planValue) ? planValue : [];
|
||||||
const items: { text: string; completed: boolean }[] = [];
|
const items: { text: string; completed: boolean }[] = [];
|
||||||
for (const step of plan) {
|
for (const step of plan) {
|
||||||
if (!step || typeof step !== "object") {
|
if (!step || typeof step !== "object") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const text = typeof step.step === "string" ? step.step : typeof step.text === "string" ? step.text : "";
|
const record = step as { step?: unknown; text?: unknown; status?: unknown };
|
||||||
|
const text = typeof record.step === "string" ? record.step : typeof record.text === "string" ? record.text : "";
|
||||||
if (!text) {
|
if (!text) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const status = typeof step.status === "string" ? step.status : "";
|
const status = typeof record.status === "string" ? record.status : "";
|
||||||
items.push({ text, completed: status === "completed" });
|
items.push({ text, completed: status === "completed" });
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
@@ -1280,7 +1412,7 @@ function parsePatchFiles(patch: string): { path: string; kind: string }[] {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeJsonParse<T = any>(value: unknown): T | null {
|
function safeJsonParse<T = unknown>(value: unknown): T | null {
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1291,15 +1423,16 @@ function safeJsonParse<T = any>(value: unknown): T | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCommand(args: any): string | null {
|
function formatCommand(args: unknown): string | null {
|
||||||
if (!args) {
|
if (!args || typeof args !== "object") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (Array.isArray(args.command)) {
|
const record = args as { command?: unknown };
|
||||||
return args.command.join(" ");
|
if (Array.isArray(record.command)) {
|
||||||
|
return record.command.join(" ");
|
||||||
}
|
}
|
||||||
if (typeof args.command === "string") {
|
if (typeof record.command === "string") {
|
||||||
return args.command;
|
return record.command;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
- Dropped the old status dot from `AgentStatusBar` (the permission/mode selector now stands alone) and introduced an in-stream "Working" chip inside `AgentStreamView` that renders three bouncing dots via Reanimated whenever the agent reports `status === "running"`, so busy turns surface directly in the chat timeline.
|
- Dropped the old status dot from `AgentStatusBar` (the permission/mode selector now stands alone) and introduced an in-stream "Working" chip inside `AgentStreamView` that renders three bouncing dots via Reanimated whenever the agent reports `status === "running"`, so busy turns surface directly in the chat timeline.
|
||||||
- [x] npm run typecheck and fix all problems
|
- [x] npm run typecheck and fix all problems
|
||||||
- Split the server build/typecheck configs so the typechecker can include the app stream helpers without breaking builds, added path aliases for `@server/*`, and tightened the shared stream types (status unions + `isAgentToolCallItem`) so the server e2e suites can import them safely. Cleaned up every failing app/server test by narrowing tool-call payloads via the helper, updated the harness + Codex/Claude specs, and re-ran `npm run typecheck` (app + server) to green.
|
- Split the server build/typecheck configs so the typechecker can include the app stream helpers without breaking builds, added path aliases for `@server/*`, and tightened the shared stream types (status unions + `isAgentToolCallItem`) so the server e2e suites can import them safely. Cleaned up every failing app/server test by narrowing tool-call payloads via the helper, updated the harness + Codex/Claude specs, and re-ran `npm run typecheck` (app + server) to green.
|
||||||
- [ ] audit codebase for unecessary untyped code, hacks, casts, and `any`, type things properly
|
- [x] audit codebase for unecessary untyped code, hacks, casts, and `any`, type things properly
|
||||||
|
- Tightened the Codex rollout parser typings so permission requests, rollout/event payloads, plan arguments, and JSON helpers all operate on well-defined TypeScript structures instead of `any`. Added explicit payload/entry guards, removed unsafe casts throughout `packages/server/src/server/agent/providers/codex-agent.ts`, and re-ran `npm run typecheck --workspace=@voice-dev/server` to validate the stricter typing.
|
||||||
- [ ] audit codebase for duplicated code, clean it up
|
- [ ] audit codebase for duplicated code, clean it up
|
||||||
- [ ] rename the project to Paseo, including the Expo app, package names etc.
|
- [ ] rename the project to Paseo, including the Expo app, package names etc.
|
||||||
|
|||||||
Reference in New Issue
Block a user