Skip to content

deno lint -> oxlint#1561

Merged
viktormarinho merged 16 commits intomainfrom
oxlint
Oct 20, 2025
Merged

deno lint -> oxlint#1561
viktormarinho merged 16 commits intomainfrom
oxlint

Conversation

@viktormarinho
Copy link
Copy Markdown
Contributor

@viktormarinho viktormarinho commented Oct 20, 2025

Note: This movement also takes in account that we want to use Vite+ once its available, for linting formatting and everything. Oxlint is what Vite+ will use under the hood, besides being an improvement from the current deno lint since users no longer need another dependency to develop on the repository.

  • Replaced deno lint with oxlint for linting.
  • Adjusted script commands for consistency and clarity.
  • Updated bun.lockb to reflect changes in dependencies.
  • Refactored header merging logic in various components for improved readability.
  • Enhanced regex patterns in multiple files for consistency in path matching.

These changes streamline the development process and improve code maintainability.

What is this contribution about?

Describe your changes and why they're needed.

Screenshots/Demonstration

Add screenshots or a Loom video if your changes affect the UI.

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by CodeRabbit

Release Notes

  • New Features

    • Integrated oxlint for improved code quality checks across the project.
  • Chores

    • Updated linting and build workflows to use oxlint instead of Deno lint.
    • Removed Deno setup step from test workflow.
    • Updated package name and version strings.
    • Simplified error handling syntax and removed unused code patterns throughout the codebase.
    • Cleaned up configuration files and updated lint directives.

- Replaced `deno lint` with `oxlint` for linting.
- Adjusted script commands for consistency and clarity.
- Updated `bun.lockb` to reflect changes in dependencies.
- Refactored header merging logic in various components for improved readability.
- Enhanced regex patterns in multiple files for consistency in path matching.

These changes streamline the development process and improve code maintainability.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 20, 2025

Warning

Rate limit exceeded

@viktormarinho has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 16 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 40d3961 and 99a94cc.

📒 Files selected for processing (5)
  • .oxlintrc.json (1 hunks)
  • packages/ai/src/agent.ts (2 hunks)
  • packages/runtime/src/index.ts (1 hunks)
  • packages/runtime/src/mcp.ts (1 hunks)
  • packages/sdk/src/actors/index.ts (1 hunks)

Walkthrough

Migrates linting from Deno to Oxlint across the repo, removes an explicit Deno setup step from CI, replaces many deno-lint-ignore annotations with oxlint-disable variants, simplifies several catch clauses, and removes several nullish-fallback spreads that may affect runtime when sources are undefined.

Changes

Cohort / File(s) Summary
CI & Linting config
\.github/workflows/test.yml, \.oxlintrc.json, package.json
Remove explicit Deno setup step from CI; add .oxlintrc.json; update package.json scripts/devDependencies to use oxlint/npm-based build and test scripts.
File-level lint directive migration
apps/api/main.ts, apps/api/tail.ts, apps/web/src/components/integrations/tabs/connection-tabs.tsx, apps/web/src/components/settings/profile.tsx, apps/web/src/components/workflows/detail.tsx, apps/web/src/polyfills.ts, packages/ai/src/deco.ts, packages/ai/src/triggers/trigger.ts, packages/runtime/src/bindings/binder.ts, packages/runtime/src/index.ts, packages/runtime/src/mastra.ts, packages/runtime/src/proxy.ts, packages/runtime/src/workflow.ts, packages/sdk/src/mcp/bindings/binder.ts, packages/sdk/src/mcp/context.ts, packages/sdk/src/mcp/databases/migration.ts, packages/sdk/src/mcp/middlewares.ts
Replace file-level // deno-lint-ignore-file with /* oxlint-disable */ variants; no runtime behavior changes.
Inline lint directive migration
(many files, e.g. apps/api/src/email.ts, apps/web/src/components/..., packages/ai/src/..., packages/sdk/src/..., packages/runtime/src/...)
Replace inline // deno-lint-ignore with // oxlint-disable-next-line variants at many call sites; no functional changes.
Simplified error handling (bare catch)
apps/api/src/auth/index.ts, apps/web/src/components/apps/auth.tsx, apps/web/src/components/chat/audio-button.tsx, apps/web/src/components/integrations/tool-call-form.tsx, apps/web/src/components/views/internal-resource-list.tsx, apps/web/src/components/workflows/workflow-step-card.tsx, packages/cli/src/commands/hosting/deploy.ts, packages/cli/src/lib/config.ts, packages/cli/src/lib/fs.ts, packages/cli/src/lib/session.ts, packages/create-deco/index.js
Replace catch (_) / catch (_error) with bare catch in multiple places, removing unused error bindings.
Removed nullish-fallback spreads (may cause runtime changes)
apps/api/src/api.ts, apps/outbound/main.ts, apps/web/src/components/agent/provider.tsx, apps/web/src/components/settings/usage/usage-stacked-bar-chart.tsx, apps/web/src/utils/view-template.ts, packages/cli/src/lib/prompt-ide-setup.ts, packages/runtime/src/index.ts, packages/runtime/src/mcp-client.ts, packages/runtime/src/mcp.ts, packages/sdk/src/actors/index.ts, packages/sdk/src/mcp/knowledge/api.ts
Replace ...(obj ?? {}) patterns with ...obj, remove fallback guards—can throw when obj/sources are undefined.
Regex normalization
apps/web/src/components/layout/decopilot-layout.tsx, apps/web/src/components/layout/project.tsx, docs/view/src/components/ui/LanguageSelector.tsx, packages/runtime/src/bindings/deconfig/helpers.ts, packages/runtime/src/bindings/resources/helpers.ts, packages/runtime/src/bindings/resources/schemas.ts, packages/sdk/src/mcp/deconfig-v2/index.ts, packages/sdk/src/mcp/resources-v2/helpers.ts
Simplify regexes by removing unnecessary escaped slashes inside character classes (e.g., [^\/]+[^/]+); behavior preserved.
Type/interface removals
apps/web/src/components/chat/chat-message.tsx, docs/view/src/components/ui/Sidebar.tsx
Remove ToolInvocation and TreeNode interface declarations.
Minor refactors & destructuring
apps/web/src/components/tools/tool-detail.tsx, packages/sdk/src/crud/knowledge.ts, packages/sdk/src/hooks/members.ts, packages/sdk/src/hooks/workflow-builder.ts, packages/ai/src/agent.ts, packages/sdk/src/auth/policy.ts
Simplify destructuring, remove redundant await, drop unused imports/aliases; no behavioral changes.
Bash completion normalization
packages/cli/src/commands/completion/install.ts
Convert escaped bash interpolations to normal variable expansions (e.g., \$var$var), no logic change.
Critical metadata merge change
packages/ai/src/agent.ts
Change metadata spread from ...(opts?.metadata ?? {}) to ...opts?.metadata in onBeforeInvoke—alters behavior when metadata is undefined.
Validation logic change
apps/web/src/stores/workflows/hooks.ts
hasValidValue now uses .some() only (no length check), changing validation semantics.
Docs lint removals
docs/server/deco.gen.ts, docs/server/main.ts
Remove file-level deno-lint directives; no runtime changes.

Sequence Diagram(s)

sequenceDiagram
  participant CI as GitHub Actions
  participant Setup as denoland/setup-deno@v2
  participant Install as InstallDeps
  participant Test as RunTests

  Note over CI: Previous workflow
  CI->>Setup: setup deno (deno-version input)
  Setup-->>CI: deno available
  CI->>Install: install dependencies
  Install-->>CI: deps installed
  CI->>Test: run tests

  Note over CI: New workflow (this PR)
  CI->>Install: install dependencies
  Install-->>CI: deps installed
  CI->>Test: run tests
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Suggested reviewers

  • mcandeia
  • tlgimenes
  • lucis

Poem

🐰 From deno lint to oxlint we hop,

Tidied comments, then gave guards a drop.
Watch those spreads that lost their shield—
When undefined arrives, the code might yield.
A carrot of tests keeps the garden well-trod. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "deno lint -> oxlint" accurately summarizes the primary technical change in the changeset. The bulk of the modifications involve replacing deno-lint directives with oxlint directives across numerous files, updating the lint command in package.json, removing the Deno setup step from CI, and adding an oxlint configuration file. While the changeset includes additional refactoring activities (header merging logic improvements, regex pattern cleanup, catch block simplifications), these appear to be secondary improvements aligned with the primary transition. A developer scanning the repository history would clearly understand this changeset is about switching the linting toolchain from Deno to Oxlint.
Description Check ✅ Passed The PR description includes substantive information addressing the main objectives: it explains the motivation (Vite+ alignment, removing Deno as a development dependency), lists specific changes organized by category (linting, scripts, dependencies, refactoring, regex patterns), and provides context about how these changes streamline development. While the template sections for "What is this contribution about?" and "Screenshots/Demonstration" are present but not explicitly filled with custom content beyond the template prompts, the essential information is clearly communicated in the opening paragraphs and bullet points. The Review Checklist section is present with checkboxes, though none are marked as completed. The description follows the required template structure and contains substantially complete documentation of the changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Introduced a new `.oxlintrc.json` file to configure linting rules, specifically turning off the `no-unused-expressions` rule and ignoring certain patterns.
- Refactored error handling in various components to remove unused error parameters, improving code clarity and consistency.
- Updated `bun.lockb` to reflect dependency changes.

These updates enhance the linting process and improve the overall readability of the codebase.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Oct 20, 2025

Deploying chat with  Cloudflare Pages  Cloudflare Pages

Latest commit: 99a94cc
Status: ✅  Deploy successful!
Preview URL: https://20872d56.chat-46r.pages.dev
Branch Preview URL: https://oxlint.chat-46r.pages.dev

View logs

- Removed unused compiler options and lint configuration from package.json, streamlining the file for better clarity.
- Updated error handling in the getAppUUID function to log the error object instead of a generic variable, enhancing debugging capabilities.

These changes improve the maintainability and readability of the codebase.
- Updated the metadata assignment in the AIAgent class to ensure proper handling of timings. This change enhances the clarity and maintainability of the code by explicitly spreading the existing metadata before adding new properties.

No functionality is broken; this update improves the robustness of the agent's context management.
- Added `no-explicit-any` and `ban-types` rules to `.oxlintrc.json` with warnings to improve type safety.
- Updated ignore patterns to include `docs/*` for better linting coverage.
- Replaced `deno-lint-ignore-file` comments with `oxlint-disable` for consistency across the codebase.

These changes enhance the linting process and promote better coding practices throughout the project.
- Replaced `deno-lint-ignore` comments with `oxlint-disable-next-line` across multiple files to standardize linting practices.
- This change improves code consistency and aligns with the updated linting rules established in previous commits.
- Added a new linting rule to enforce kebab-case naming for filenames in the project, improving consistency in file naming conventions.
- Updated `.oxlintrc.json` to include the new rule and associated plugin, enhancing the linting configuration.
- Removed the old TypeScript implementation of the kebab-case rule in favor of the new JavaScript version for better compatibility with the current linting setup.

These changes promote better coding practices and maintainability across the codebase.
- Moved the linting rules section within `.oxlintrc.json` to improve clarity and organization.
- Retained existing rules such as `no-unused-expressions`, `no-explicit-any`, `enforce-kebab-case-file-names/kebab-case`, and `ban-types` to maintain code quality and consistency.

These adjustments enhance the readability of the linting configuration while preserving the established linting practices.
- Eliminated the Deno setup step from the GitHub Actions workflow as linting has been fully migrated to Biome.
- Updated package.json to remove the deprecated Deno lint command, streamlining the linting process.

These changes enhance the CI configuration by removing unnecessary steps and aligning with the current linting practices.
@viktormarinho viktormarinho marked this pull request as ready for review October 20, 2025 02:50
- Refactored the `handleLiteral` function in `ensure-tailwind-design-system-tokens.js` to use a more concise parameter destructuring syntax, improving code readability.
- Updated `.oxlintrc.json` to streamline the configuration by consolidating the `jsPlugins` array into a single line.

These changes enhance the clarity of the code and maintain consistency in the linting configuration.
- Eliminated the `no-explicit-any` linting directive from `do-storage.ts` to align with updated linting practices.
- This change enhances code clarity by removing unnecessary linting comments and maintaining consistency across the codebase.
- Updated the version of `deco-cli` from `0.22.4` to `0.22.5` to reflect recent changes.
- Incremented the version of `@deco/workers-runtime` from `0.23.1` to `0.23.2` for consistency with the latest updates.

These version bumps ensure that the packages are aligned with the latest developments in the codebase.
- Updated the package name in package.json to reflect the new branding for the admin interface.
- This change aligns the package with the overall project structure and naming conventions.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (18)
packages/cli/src/lib/prompt-ide-setup.ts (2)

62-72: Restore the nullish coalescing fallback to prevent silent data loss.

If the existing mcp.json file parses successfully but lacks the mcpServers property (e.g., the file contains {} or has a different structure), existingConfig.mcpServers will be undefined at runtime despite the MCPConfig type annotation. Spreading undefined in an object literal is safe but silent—any existing config that doesn't match the expected interface will be dropped without warning.

Apply this diff to restore defensive handling:

     const config = {
       mcpServers: {
-        ...existingConfig.mcpServers,
+        ...(existingConfig.mcpServers ?? {}),
         ...mcpConfig.mcpServers,
       },
     };

Alternatively, consider adding runtime validation (e.g., Zod schema) to ensure the parsed JSON conforms to MCPConfig before using it.


96-106: Restore the nullish coalescing fallback to prevent silent data loss.

If the existing mcp.json file parses successfully but lacks the mcpServers property (e.g., the file contains {} or has a different structure), existingConfig.mcpServers will be undefined at runtime despite the MCPConfig type annotation. Spreading undefined in an object literal is safe but silent—any existing config that doesn't match the expected interface will be dropped without warning.

Apply this diff to restore defensive handling:

     const config = {
       mcpServers: {
-        ...existingConfig.mcpServers,
+        ...(existingConfig.mcpServers ?? {}),
         ...mcpConfig.mcpServers,
       },
     };

Alternatively, consider adding runtime validation (e.g., Zod schema) to ensure the parsed JSON conforms to MCPConfig before using it.

apps/api/src/email.ts (1)

82-83: Potential bug: inconsistent Cc handling.

Line 82 retrieves the Cc header into the cc variable using message.headers.get("Cc"), but line 83 checks cc for truthiness and then accesses message.cc (a different property) instead. This appears to be a logic error where the retrieved header value isn't actually used.

Consider fixing the logic to use the retrieved header value:

 const cc = message.headers.get("Cc");
-// @ts-ignore: cc is not a valid property of the EmailMessage class
-cc && msg.setCc(message.cc);
+if (cc) {
+  msg.setCc(cc);
+}
packages/runtime/src/proxy.ts (1)

165-168: execute() drops inputs by calling with input.context

This breaks tools that expect the full input. Pass the input object directly.

Apply:

-          execute: (input: any) => {
-            return callToolFn(input.context);
-          },
+          execute: (input: any) => {
+            return callToolFn(input);
+          },
packages/sdk/src/mcp/hosting/assertions.ts (1)

81-104: Overly permissive type compatibility (string ↔ number) can miss breakages

Treating string→number or number→string as compatible can be breaking in practice.

Tighten compatibility:

-      if (fromT === "string" && toT === "number") return true; // strings can often be parsed as numbers
-      if (fromT === "number" && toT === "string") return true; // numbers can be stringified
+      // Only allow safe widen/narrow within numeric domain
+      // string<->number is NOT safe: parsing/stringifying is not guaranteed
+      if (fromT === "integer" && toT === "number") return true;
+      if (fromT === "number" && toT === "integer") return false;

Optionally, allow explicit whitelisting via config if you truly coerce at runtime.

packages/sdk/src/mcp/api-keys/api.ts (1)

519-552: checkAccess ignores the provided key; authorization check always uses the current context

You parse “key” into user but never pass it to authorization. Result: access is checked for c.user, not the supplied key.

Apply:

-    c.resourceAccess.grant(); // this is public because it uses the current key from context
-
-    // TODO(@mcandeia): remove this ignore
-    // eslint-disable-next-line eslint/no-unused-vars
-    let user = c.user;
+    c.resourceAccess.grant(); // public: uses current key unless overridden
+    let user = c.user;
@@
-    const hasAccess = await Promise.all(
+    const ctxForCheck = key ? ({ ...c, user } as typeof c) : c;
+    const hasAccess = await Promise.all(
       tools.map(async (tool) => {
         return [
           tool,
-          await assertWorkspaceResourceAccess(c, tool)
+          await assertWorkspaceResourceAccess(ctxForCheck, tool)
             .then(() => true)
             .catch(() => false),
         ];
       }),
     );

This removes the need for the unused-var suppression and aligns behavior with the tool description.

packages/runtime/src/client.ts (4)

49-54: Set a default Content-Type header for JSON requests

Without Content-Type: application/json, some servers won’t parse the body. Add it to DEFAULT_INIT so both paths inherit it.

Apply this diff:

 export const DEFAULT_INIT: CustomInit = {
   credentials: "include",
   headers: {
+    "Content-Type": "application/json",
     [DECO_MCP_CLIENT_HEADER]: "true",
   },
 };

43-45: Support Authorization bearer tokens in the client

MCP calls should carry Authorization: Bearer when available. Add an authToken helper field and propagate it into headers. Based on learnings.

Apply this diff:

 export type CustomInit = RequestInit & {
   handleResponse?: (response: Response) => Promise<unknown>;
+  authToken?: string; // optional bearer token helper
 };

 // in callMCPTool(...)
   const mergedInit: CustomInit = {
     ...init,
     headers: {
+      "Content-Type": "application/json",
       ...DEFAULT_INIT.headers,
+      ...(init?.authToken
+        ? { Authorization: `Bearer ${init.authToken}` }
+        : {}),
       ...init?.headers,
     },
   };

 // in createClient regular method path
           const mergedInit: CustomInit = {
             ...init,
             ...innerInit,
             headers: {
+              "Content-Type": "application/json",
               ...DEFAULT_INIT.headers,
+              ...((innerInit?.authToken ?? init?.authToken)
+                ? {
+                    Authorization: `Bearer ${
+                      innerInit?.authToken ?? init?.authToken
+                    }`,
+                  }
+                : {}),
               ...init?.headers,
               ...innerInit?.headers,
             },
           };

If you already inject Authorization via init.headers externally, this remains backward‑compatible.

Also applies to: 64-71, 173-190


185-197: Unify error handling: throw on non-OK responses in both paths

callMCPTool throws on !response.ok but the proxy path does not, silently returning JSON for error responses. Align behavior.

Apply this diff:

-          if (typeof mergedInit.handleResponse === "function") {
+          if (typeof mergedInit.handleResponse === "function") {
             return mergedInit.handleResponse(response);
           }
-
-          return response.json();
+          if (!response.ok) {
+            throw new Error(
+              `Failed to call ${String(prop)}: ${response.status} ${response.statusText}`,
+            );
+          }
+          return response.json();

Also applies to: 79-84


133-156: Close EventSource on iterator completion/error to avoid leaks

The async generator never closes the EventSource. Ensure cleanup in finally; optionally hook AbortSignal.

Apply this diff:

-    const eventSource = new EventSource(watchUrl.href);
+    const eventSource = new EventSource(watchUrl.href);
+    const abortHandler =
+      init?.signal ? () => eventSource.close() : undefined;
+    if (init?.signal && abortHandler) {
+      init.signal.addEventListener("abort", abortHandler, { once: true });
+    }

     const eventStream = toAsyncIterator<{ uri: string }>(
       eventSource,
       "message",
     );

-    for await (const event of eventStream) {
-      const uri = event.uri;
-
-      if (uri) {
-        // Call READ to get full resource data
-        const readData = await callMCPTool<{ data: unknown }>(
-          readMethodName,
-          { uri },
-          init,
-        );
-
-        yield { uri, data: readData.data };
-      }
-    }
+    try {
+      for await (const event of eventStream) {
+        const uri = event.uri;
+        if (uri) {
+          const readData = await callMCPTool<{ data: unknown }>(
+            readMethodName,
+            { uri },
+            init,
+          );
+          yield { uri, data: readData.data };
+        }
+      }
+    } finally {
+      eventSource.close();
+      if (init?.signal && abortHandler) {
+        init.signal.removeEventListener("abort", abortHandler);
+      }
+    }
apps/api/tail.ts (3)

224-231: Use each log’s timestamp (falls back to event timestamp)

Currently uses event.eventTimestamp for all logs, losing per‑log timing.

Apply this diff:

-              return {
-                timeUnixNano: event.eventTimestamp * 1000000,
+              return {
+                timeUnixNano:
+                  ((log.timestamp ?? event.eventTimestamp) as number) *
+                  1000000,
                 severityText: log.level,
                 body: { stringValue: message },

305-315: Use each exception’s timestamp (falls back to event timestamp)

Exceptions also have their own timestamps; preserve them.

Apply this diff:

-            scope: {},
-            logRecords: event.exceptions.map((exception) => ({
-              timeUnixNano: event.eventTimestamp * 1000000,
+            scope: {},
+            logRecords: event.exceptions.map((exception) => ({
+              timeUnixNano:
+                ((exception.timestamp ?? event.eventTimestamp) as number) *
+                1000000,
               severityText: "ERROR",

147-159: Harden header filtering to avoid PII leakage

Denylist misses common sensitive headers (x-forwarded-for, cf-connecting-ip, x-api-key, proxy-authorization, etc.). Switch to an allowlist or expand denylist.

Apply this diff and helper:

-                    ? Object.entries(event.event!.request!.headers)
-                        .filter(
-                          ([key]) =>
-                            !key.toLowerCase().includes("authorization") &&
-                            !key.toLowerCase().includes("cookie") &&
-                            !key.toLowerCase().includes("x-real-ip"),
-                        )
+                    ? Object.entries(event.event!.request!.headers)
+                        .filter(([key]) => isSafeHeader(key))
                         .slice(0, 10)

Add this helper near the top (outside the selected range):

const SENSITIVE_HEADER_SUBSTRINGS = [
  "authorization",
  "proxy-authorization",
  "cookie",
  "x-real-ip",
  "x-forwarded-for",
  "cf-connecting-ip",
  "x-client-ip",
  "x-api-key",
  "x-auth-token",
];

function isSafeHeader(name: string): boolean {
  const lower = name.toLowerCase();
  return !SENSITIVE_HEADER_SUBSTRINGS.some((s) => lower.includes(s));
}

As per coding guidelines (privacy/compliance).

apps/web/src/components/settings/profile.tsx (1)

50-51: Brazil placeholder has an extra digit.

E.164 for BR is +55 + 2-digit area + 9-digit local = 13 digits total. Placeholder shows 14. Fix the example.

-      placeholder: "+55119100000000",
+      placeholder: "+5511910000000",
apps/web/src/components/views/internal-resource-list.tsx (3)

86-117: Guard against missing integration connection in runSearch

runSearch may call callTool with an undefined connection, causing runtime errors during initial load. Guard before toggling loading.

Apply this diff:

 async function runSearch(term: string) {
-  setLoading(true);
+  if (!integration?.connection) return;
+  setLoading(true);
   try {
-    const result = (await callTool(integration?.connection, {
+    const result = (await callTool(integration.connection, {
       name: "DECO_CHAT_RESOURCES_SEARCH",
       arguments: { name, term, limit: 50 },
     })) as {
       structuredContent?: {
         items?: Array<{
           name?: string;
           uri: string;
           title?: string;
           description?: string;
           mimeType?: string;
           thumbnail?: string;
         }>;
       };
     };

119-121: Effect deps should include connection; avoid firing before integration is ready

Prevent premature searches; also avoids unhandled rejections.

Apply this diff:

-useEffect(() => {
-  runSearch(q);
-}, [q]);
+useEffect(() => {
+  if (integration?.connection) runSearch(q);
+}, [integration?.connection, q]);

279-283: Regex allows many punctuation due to a hyphen range; sanitize bug

In a character class, 0-9-_ creates the range 9-_. This unintentionally whitelists many chars, so they won’t be replaced. Use 0-9_- or escape -.

Apply this diff:

-  .replace(/[^a-zA-Z0-9-_]/g, "-")
+  .replace(/[^a-zA-Z0-9_-]/g, "-")
packages/sdk/src/mcp/deconfig/branch.ts (1)

1121-1124: Avoid spreading large Uint8Array into fromCharCode; can crash

String.fromCharCode(...uint8Array) overflows for big files. Use chunked encoding.

Apply this diff:

-      if (content) {
-        const uint8Array = new Uint8Array(content);
-        enrichedMetadata.content = btoa(String.fromCharCode(...uint8Array));
-      }
+      if (content) {
+        const u8 = new Uint8Array(content);
+        let binary = "";
+        const CHUNK = 0x8000;
+        for (let i = 0; i < u8.length; i += CHUNK) {
+          binary += String.fromCharCode(...u8.subarray(i, i + CHUNK));
+        }
+        enrichedMetadata.content = btoa(binary);
+      }

If preferred, we can extract a toBase64(u8: Uint8Array) helper and reuse.

🧹 Nitpick comments (47)
packages/sdk/src/mcp/bindings/binder.ts (1)

12-12: Consider replacing any with unknown where feasible.

While not introduced by this PR, the coding guidelines recommend avoiding any in favor of more specific types. Consider whether unknown or more constrained types could replace any in the generic defaults and constraints (e.g., line 12: TDefinition extends readonly ToolBinder[] = any, line 18: TContext = any).

This would improve type safety without significantly impacting the API surface, though it may require downstream adjustments.

As per coding guidelines.

Also applies to: 17-18, 98-98

apps/web/src/components/layout/decopilot-layout.tsx (1)

38-38: LGTM! Regex pattern simplified.

The removal of redundant escapes inside the character class improves readability. The pattern remains functionally equivalent.

Note: This same regex pattern appears in apps/web/src/components/layout/project.tsx at line 248. Consider extracting it to a shared constant to avoid duplication and ensure consistency across both files.

apps/web/src/components/layout/project.tsx (1)

248-248: LGTM! Consider extracting the duplicated pattern.

The regex simplification is correct and improves readability. However, this exact pattern also appears in apps/web/src/components/layout/decopilot-layout.tsx at line 38.

Consider extracting this pattern to a shared constant or utility function to maintain consistency and reduce duplication:

// utils/path-matchers.ts or similar
export const AGENT_DETAIL_PAGE_PATTERN = /\/agent\/[^/]+\/[^/]+$/;

Then import and use it in both files:

+import { AGENT_DETAIL_PAGE_PATTERN } from "../../utils/path-matchers";
+
 export const TopbarControls = () => {
   const location = useLocation();
   const isProjectContext = useIsProjectContext();
-  const isAgentDetailPage = location.pathname.match(/\/agent\/[^/]+\/[^/]+$/);
+  const isAgentDetailPage = location.pathname.match(AGENT_DETAIL_PAGE_PATTERN);
apps/web/src/components/prompts/rich-text/index.tsx (2)

145-153: Remove suppression; type props precisely for MentionNode wrapper

Use React.ComponentProps to avoid any and drop the oxlint disable. As per coding guidelines.

Apply within this hunk:

-    // oxlint-disable-next-line no-explicit-any
-    (props: any) => (
+    (props: ComponentProps<typeof MentionNode>) => (

And add a type-only import (outside this hunk):

-import { useEffect, useMemo, useRef, useCallback } from "react";
+import { useEffect, useMemo, useRef, useCallback, type ComponentProps } from "react";

157-163: Same here: precise props type for MentionDropdown

Mirror the fix to remove any and the oxlint suppression. As per coding guidelines.

Apply within this hunk:

-    // oxlint-disable-next-line no-explicit-any
-    (props: any) => (
+    (props: ComponentProps<typeof MentionDropdown>) => (
apps/web/src/components/rich-text-editor/components/mention-dropdown.tsx (1)

24-26: Type IntegrationAvatar to remove the any + directive

You can drop the oxlint disable by typing props from the callsites.

Apply this inline change:

-  // oxlint-disable-next-line no-explicit-any
-  IntegrationAvatar?: React.ComponentType<any>;
+  IntegrationAvatar?: React.ComponentType<{
+    url?: string;
+    fallback?: string;
+    size?: "xs" | "sm" | "md" | "lg";
+    className?: string;
+  }>;
packages/runtime/src/proxy.ts (1)

86-88: Timeout seems excessively high (~50 minutes)

3000000 ms may exceed platform limits (e.g., Workers). Consider a conservative default (e.g., 120_000) or make it configurable.

-          {
-            timeout: 3000000,
-          },
+          {
+            timeout: options?.timeoutMs ?? 120_000,
+          },
packages/sdk/src/mcp/file-processor.ts (2)

375-381: Fix fractional slice/step when splitting long sentences

Using this.config.chunkSize / 10 yields a fractional step; slice indexes are coerced and can produce uneven chunks.

Use an integer step tied to your 6-char word heuristic:

-          const words = trimmedSentence.split(/\s+/);
-          for (let i = 0; i < words.length; i += this.config.chunkSize / 10) {
-            const chunk = words
-              .slice(i, i + this.config.chunkSize / 10)
-              .join(" ");
-            chunks.push({ content: chunk });
-          }
+          const words = trimmedSentence.split(/\s+/);
+          const step = Math.max(1, Math.floor(this.config.chunkSize / 6));
+          for (let i = 0; i < words.length; i += step) {
+            const chunk = words.slice(i, i + step).join(" ");
+            chunks.push({ content: chunk });
+          }

199-201: Minor: prefer unknown over any here

If you keep the lint rule on, consider narrowing to unknown and refining locally for better type safety.

-  // oxlint-disable-next-line no-explicit-any
-  private chunkLongStringsInObject(json: any): string {
+  private chunkLongStringsInObject(json: unknown): string {
+    const obj = json as Record<string, unknown>;
+    // ...use obj instead of json...
apps/api/src/durable-objects/workspace-database.ts (1)

19-21: Avoid ban-types suppression by using unknown

Switch DurableObjectState<{}> to DurableObjectState and remove the directive.

-    // oxlint-disable-next-line ban-types
-    protected override ctx: DurableObjectState<{}>,
+    protected override ctx: DurableObjectState<unknown>,
apps/api/main.ts (1)

90-99: Reuse the Postgres client across requests

Creating a new client per request can exhaust connections. Cache at module scope.

-  fetch(request: Request, env: any, ctx: ExecutionContext): Promise<Response> {
-    const sql = contextStorage.getStore()?.sql ?? createPostgres(env);
+  // module scope cache
+  let cachedSql: ReturnType<typeof postgres> | undefined;
+  fetch(request: Request, env: any, ctx: ExecutionContext): Promise<Response> {
+    const sql = contextStorage.getStore()?.sql ?? (cachedSql ??= createPostgres(env));
packages/sdk/src/mcp/api-keys/api.ts (2)

385-391: Narrow updateData type to avoid any

Use a precise shape to keep type-safety and drop the oxlint suppression.

-    // oxlint-disable-next-line no-explicit-any
-    const updateData: Record<string, any> = {};
+    const updateData: Partial<{
+      name: string;
+      enabled: boolean;
+      policies: Statement[];
+      updated_at: string;
+    }> = {};

165-167: Optional: avoid any in ensureStateIsWellFormed

You can cast the binding object locally without polluting the broader type.

-          (prop as any)["__type"] = integration.appName; // ensure it's a binding object
+          (prop as Record<string, unknown>)["__type"] = integration.appName; // ensure it's a binding object
packages/ai/src/utils/json-schema-to-model.ts (1)

4-5: Reduce surface any usage in JSON schema helpers

Typing inputs as records improves safety without changing behavior.

Examples:

-export function jsonSchemaPropertiesToTSTypes(value: any): z.ZodTypeAny {
+export function jsonSchemaPropertiesToTSTypes(value: Record<string, unknown>): z.ZodTypeAny {
@@
-export function jsonSchemaToModel(
-  jsonSchema: Record<string, any>,
-): ZodObject<any> {
+export function jsonSchemaToModel(
+  jsonSchema: Record<string, unknown>,
+): ZodObject<z.ZodRawShape> {
@@
-  const zodSchema: Record<string, any> = {};
-  for (const [key, _] of Object.entries(properties)) {
-    const value = _ as any;
+  const zodSchema: Record<string, z.ZodTypeAny> = {};
+  for (const [key, _] of Object.entries(properties)) {
+    const value = _ as Record<string, unknown>;
@@
-      const anyOfTypes = value.anyOf.map((schema: any) =>
+      const anyOfTypes = (value.anyOf as unknown[]).map((schema) =>
         jsonSchemaPropertiesToTSTypes(schema),
       );

Also applies to: 78-80, 86-89, 91-104

packages/runtime/src/client.ts (2)

130-136: SSR safety: guard globalThis.location usage

If createClient is imported server‑side, globalThis.location may be undefined. Add a guard or accept a base URL via init for non‑browser contexts.

Example:

-    const watchUrl = new URL(watchPathname, globalThis.location.origin);
+    const base = (globalThis as any)?.location?.origin ?? "";
+    const watchUrl = new URL(watchPathname, base);

23-30: Reduce any: prefer unknown with constrained generics

Type surfaces use any to satisfy mapping; consider unknown and tightening with generic constraints to preserve safety.

Sketch:

-type SubscribeMethods<T> = {
+type SubscribeMethods<T extends Record<string, (...a: unknown[]) => unknown>> = {
   [K in keyof T as K extends `DECO_RESOURCE_${string}_READ`
     ? SubscribeMethodName<ExtractResourceName<K>>
     : never]: K extends `DECO_RESOURCE_${string}_READ`
-    ? // oxlint-disable-next-line no-explicit-any
-      T[K] extends (...args: any) => any
+    ? T[K] extends (...args: infer _A) => infer _R
       ? (args: { id: string } | { uri: string }) => AsyncIterableIterator<{
           uri: string;
           data: ExtractReadData<Awaited<ReturnType<T[K]>>>;
         }>
       : never
     : never;
 };

-export type MCPClient<T> = {
-  // oxlint-disable-next-line no-explicit-any
-  [K in keyof T]: T[K] extends (...args: any) => any
+export type MCPClient<T extends Record<string, (...a: unknown[]) => unknown>> = {
+  [K in keyof T]: T[K] extends (...args: infer _A) => infer _R
     ? (
       args: Parameters<T[K]>[0],
       init?: CustomInit,
     ) => Promise<Awaited<ReturnType<T[K]>>>
     : never;
 } & SubscribeMethods<T>;

Also applies to: 33-41

apps/api/tail.ts (3)

427-433: Make OTEL header parsing robust (trim and single ‘=’ split)

Current split can mis-handle values containing '=' and lacks trimming.

Apply this diff:

-const otelHeadersToObject = (headers: string) => {
-  const headersParts = headers
-    .split(",")
-    .map((kv) => kv.split("=") as [string, string]);
-  return Object.fromEntries(headersParts);
-};
+const otelHeadersToObject = (headers: string) => {
+  const entries = headers.split(",").map((kv) => {
+    const i = kv.indexOf("=");
+    const k = (i === -1 ? kv : kv.slice(0, i)).trim();
+    const v = (i === -1 ? "" : kv.slice(i + 1)).trim();
+    return [k, v] as const;
+  });
+  return Object.fromEntries(entries);
+};

454-456: Avoid noisy console logs in API path

Always logging OTLP response status can be chatty. Gate behind a DEBUG flag or lower log level.

Example:

-      }).then((res) => {
-        console.log("Traces response:", res.status);
-      });
+      }).then((res) => {
+        if (process.env.DEBUG?.includes("tail")) {
+          console.log("Traces response:", res.status);
+        }
+      });

(Apply similarly to Logs.)

Also applies to: 467-468


471-492: Parallelize per-event ingests to reduce latency

Traces, logs, and exceptions can be sent concurrently.

Example:

-      await ingestLogs(requestLog);
-      if (event.traces && event.traces.length > 0) {
-        const traceData = convertTailTraces(event);
-        traceData && (await ingestTraces(traceData));
-      }
-      if (event.logs && event.logs.length > 0) {
-        const logData = convertTailLogs(event);
-        logData && (await ingestLogs(logData));
-      }
-      if (event.exceptions && event.exceptions.length > 0) {
-        const exceptionData = convertTailExceptions(event);
-        exceptionData && (await ingestLogs(exceptionData));
-      }
+      const ops: Array<Promise<unknown>> = [ingestLogs(requestLog)];
+      if (event.traces?.length) {
+        const d = convertTailTraces(event);
+        if (d) ops.push(ingestTraces(d));
+      }
+      if (event.logs?.length) {
+        const d = convertTailLogs(event);
+        if (d) ops.push(ingestLogs(d));
+      }
+      if (event.exceptions?.length) {
+        const d = convertTailExceptions(event);
+        if (d) ops.push(ingestLogs(d));
+      }
+      await Promise.all(ops);
packages/create-deco/index.js (2)

18-26: Spawn the exact Node binary via process.execPath

More robust than hardcoding "node" (PATH issues). Keep Bun path when actually running under Bun.

Apply this diff:

 function detectRuntime() {
   if (typeof Bun !== "undefined") {
     return "bun";
   }
-  return "node";
+  return process.execPath || "node";
 }
@@
-const child = spawn(runtime, [decoCli, ...commandArgs], {
+const child = spawn(runtime, [decoCli, ...commandArgs], {
   stdio: "inherit",
   cwd: process.cwd(),
 });

Also applies to: 68-71


1-13: Prefer TypeScript in packages/

Repo guideline: “Use TypeScript for all code (no JavaScript files)” and kebab‑case in packages/. Consider moving to TS with a tiny build step that outputs the Node‑shebang JS in dist.

As per coding guidelines.

packages/sdk/src/hooks/tools.ts (2)

61-76: Remove any from queryKey by using a typed discriminator helper

Use property checks instead of casting to any.

Apply this diff:

 export function useTools(connection: MCPConnection, ignoreCache?: boolean) {
+  const connId =
+    "url" in connection
+      ? connection.url
+      : "tenant" in connection
+      ? (connection as { tenant: string }).tenant
+      : "name" in connection
+      ? (connection as { name: string }).name
+      : "unknown";
   const response = useQuery({
     retry: false,
     queryKey: [
       "tools",
       connection.type,
-      // oxlint-disable-next-line no-explicit-any
-      (connection as any).url ||
-        // oxlint-disable-next-line no-explicit-any
-        (connection as any).tenant ||
-        // oxlint-disable-next-line no-explicit-any
-        (connection as any).name,
+      connId,
       ignoreCache,
     ],

48-59: Avoid any in callTool params

toolCallArgs is already typed; cast to a safer indexable type rather than any.

Apply this diff:

   return client.INTEGRATIONS_CALL_TOOL({
     ...("id" in connection ? { id: connection.id } : { connection }),
-    // oxlint-disable-next-line no-explicit-any
-    params: toolCallArgs as any,
+    params: toolCallArgs as Record<string, unknown>,
   });
packages/runtime/src/deprecated.ts (1)

7-9: Minor: avoid default any in generic

You can default to z.ZodTypeAny to drop the disable comment.

Apply this diff:

-// oxlint-disable-next-line no-explicit-any
-export interface DeprecatedEnv<TSchema extends z.ZodTypeAny = any> {
+export interface DeprecatedEnv<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
apps/web/src/components/settings/profile.tsx (1)

1-1: Scope down the lint disable; replace any with precise types.

File-wide oxlint-disable no-explicit-any is over-broad. Type the inputs and error locally, then drop the disable.

-/* oxlint-disable no-explicit-any */
+// (keep file clean — avoid broad disables)

-function getCountryConfig(country: any): Country {
+function getCountryConfig(
+  country: { dial_code: string } & Record<string, unknown>,
+): Country {

-        onError: (err: any) =>
-          setError(err.message || "Failed to update profile"),
+        onError: (err: unknown) =>
+          setError(err instanceof Error ? err.message : "Failed to update profile"),

Also applies to: 30-31, 113-115

apps/api/src/api.ts (1)

153-156: Remove any by narrowing the error type.

No need for an any cast here; narrow to the field you need and drop the disable.

-    // oxlint-disable-next-line no-explicit-any
-    const cause = (err as any as { detail?: unknown }).detail;
+    const cause = (err as { detail?: unknown }).detail;
apps/web/src/hooks/analytics.ts (1)

31-34: Use unknown[] and drop the disable.

Tighten the generic without losing flexibility.

-  // oxlint-disable-next-line no-explicit-any
-    <T extends (...args: any[]) => void>(callback: T) =>
+    <T extends (...args: unknown[]) => void>(callback: T) =>
packages/ai/src/agent/provider-options.ts (1)

8-10: Prefer unknown over any for the options bag.

Keeps it type-safe while remaining flexible; the disable becomes unnecessary.

-  // oxlint-disable-next-line no-explicit-any
-  const opts: Record<string, any> = {};
+  const opts: Record<string, unknown> = {};
apps/web/src/components/views/internal-resource-list.tsx (2)

144-146: Bare catch is fine; consider debug logging

Optional: log at debug level to aid support without user noise.

-} catch {
-  // ignore; default capabilities remain false
-}
+} catch {
+  // ignore; default capabilities remain false
+  // console.debug("Capabilities probe failed");
+}

185-196: Fallback path is good; consider capturing error for observability

Keeping the fallback, add a debug trace so repeated failures are diagnosable.

-} catch {
+} catch {
   // fallback: internal detail
+  // console.debug("OpenItem remote view resolution failed; falling back to internal detail");
packages/cli/src/lib/session.ts (1)

95-99: Differentiate ENOENT vs other unlink errors (optional)

Currently logs “Session file not found” for all errors. Consider checking code === "ENOENT" and logging actual error otherwise.

-} catch {
-  console.warn("Session file not found");
+} catch (e) {
+  const code = (e as { code?: string }).code;
+  console.warn(code === "ENOENT" ? "Session file not found" : `Failed to delete session file: ${String(e)}`);
 }
packages/sdk/src/mcp/deconfig/branch.ts (3)

823-833: notifyWatchers always emits “added” even for modifications

For entries in patch.added that overwrite existing paths, emit type "modified" to match FileChangeEvent. Today watchers cannot distinguish adds vs updates.

Example adjustment:

for (const [path, metadata] of Object.entries(patch.added)) {
  const type = this.state.tree[path] ? "modified" : "added"; // compute before mutating state, or capture a prePatchTree
  events.push({ type, path, metadata, timestamp: patch.timestamp, patchId: patch.id });
}

You may need to compute type before updating this.state.tree in patch() for correctness. Based on learnings.


52-54: Prefer unknown over any for metadata bag

Keeps unsafeness localized and aligns with “prefer specific types” guidance.

-  // oxlint-disable-next-line no-explicit-any
-  metadata: Record<string, any>;
+  metadata: Record<string, unknown>;

1453-1455: Remove unnecessary any cast in diff

This narrower cast keeps types intact without disabling lint.

-// oxlint-disable-next-line no-explicit-any
-const aMeta = otherTree[path] as any as FileMetadata; // desired
+const aMeta = otherTree[path] as FileMetadata | undefined; // desired
packages/runtime/src/workflow.ts (1)

56-61: Avoid {} generic; remove ban-types suppression

Use Record<string, never> (or unknown) instead of {} to drop the disable.

-// oxlint-disable-next-line ban-types
-public override ctx: DurableObjectState<{}>,
+public override ctx: DurableObjectState<Record<string, never>>,
apps/web/src/components/chat/rich-text.tsx (2)

149-159: Type wrapper props instead of any

Keep strong types without relaxing extension expectations.

-// oxlint-disable-next-line no-explicit-any
-return function MentionNodeWrapper(props: any) {
+import type { ComponentProps } from "react";
+return function MentionNodeWrapper(
+  props: ComponentProps<typeof MentionNode>,
+) {

163-190: Type dropdown wrapper; consider stable closure for appendIntegrationTool

Typing: same as above. For stability, if appendIntegrationTool can change, wrap it in a ref to avoid stale captures while keeping the memo’s empty deps.

-// oxlint-disable-next-line no-explicit-any
-return function MentionDropdownWrapper(props: any) {
+import type { ComponentProps } from "react";
+return function MentionDropdownWrapper(
+  props: ComponentProps<typeof MentionDropdown>,
+) {

Optional stabilization:

// before useMemo
const appendToolRef = useRef(appendIntegrationTool);
useEffect(() => { appendToolRef.current = appendIntegrationTool; }, [appendIntegrationTool]);

// inside wrappedCommand
appendToolRef.current(item.tool.integration.id, readToolNameOrToolName);

Confirm appendIntegrationTool is stable; if yes, typing fix alone is enough.

packages/cli/src/lib/config.ts (1)

111-113: Prefer debug logging instead of fully silent catch in readWranglerConfig

Silent failures make troubleshooting harder. Gate a debug log behind an env flag.

-  } catch {
-    return {};
-  }
+  } catch (e) {
+    if (process.env.DEBUG?.includes("deco:config")) {
+      console.debug(`readWranglerConfig: failed to read ${configPath}`, e);
+    }
+    return {};
+  }
apps/web/src/components/json-schema/components/type-select-field.tsx (2)

70-73: Remove any by typing the field path with react-hook-form

Typing name as FieldPath lets you drop the any cast and lint suppression.

Apply:

-  const selectedOption = options.find(
-    // oxlint-disable-next-line no-explicit-any
-    (option: OptionItem) => option.value === form.getValues(name as any)?.value,
-  );
+  const selectedOption = options.find(
+    (option: OptionItem) => option.value === form.getValues(name as FieldPath<T>)?.value,
+  );

And update the prop type to avoid downstream casts (outside this hunk):

-interface TypeSelectFieldProps<T extends FieldValues = FieldValues> {
-  name: string;
+interface TypeSelectFieldProps<T extends FieldValues = FieldValues> {
+  name: FieldPath<T>;

As per coding guidelines.


132-134: Type-safe setValue without any

Leverage PathValue to type the assigned object.

Add import:

-import type { FieldPath, FieldValues, UseFormReturn } from "react-hook-form";
+import type { FieldPath, FieldValues, UseFormReturn, PathValue } from "react-hook-form";

Then:

-    // oxlint-disable-next-line no-explicit-any
-    form.setValue(name as FieldPath<T>, { value: connection.id } as any);
+    form.setValue(
+      name as FieldPath<T>,
+      { value: connection.id } as PathValue<T, FieldPath<T>>,
+    );

If PathValue is too strict for your form schema, keep a narrow helper:

function setOptionValue<P extends FieldPath<T>>(path: P, id: string) {
  form.setValue(path, { value: id } as unknown as PathValue<T, P>);
}

As per coding guidelines.

apps/api/src/auth/index.ts (2)

103-126: Consider logging the error for debugging.

While removing the unused catch parameter is appropriate for lint compliance, the error is completely discarded. This can make debugging authentication issues difficult.

Consider logging the error:

-  } catch {
+  } catch (error) {
+    console.error("Failed to create magic link:", error);
     return { error: "" };
   }

183-208: Consider logging the error for debugging.

Similar to the previous catch block, the error is completely discarded, making it difficult to diagnose authentication failures.

Consider logging the error:

-  } catch {
+  } catch (error) {
+    console.error("Failed to send magic link:", error);
     return ctx.json({ error: "" }, 400);
   }
packages/runtime/src/index.ts (1)

191-195: Redundant nullish coalescing; simplify boolean.

(A || B) ?? false is always boolean; ?? false is unnecessary.

-  env["IS_LOCAL"] =
-    (url?.startsWith("http://localhost") ||
-      url?.startsWith("http://127.0.0.1")) ??
-    false;
+  env["IS_LOCAL"] =
+    url?.startsWith("http://localhost") ||
+    url?.startsWith("http://127.0.0.1");
packages/ai/src/agent.ts (1)

243-246: Remove non-null assertion on user; pass optional value without disabling rule.

metadata?.user! defeats type safety and required a disable. Prefer forwarding optional user.

-      // TODO(@viktormarinho): Remove the !
-      // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
-      user: metadata?.user!,
+      user: metadata?.user,

If PrincipalExecutionContext.user is non-optional, consider making it optional or providing a safe default upstream. Based on learnings.

package.json (3)

16-16: Make build script cross‑platform.

Using PWD=$PWD/apps/web is POSIX‑only. Prefer workspace build.

-    "build": "PWD=$PWD/apps/web npm run build",
+    "build": "npm run build --workspace=apps/web",

9-9: Consider failing on warnings to keep lint strict.

Optional: enforce zero warnings in CI.

-    "lint": "oxlint",
+    "lint": "oxlint --max-warnings=0",

18-18: Clean script misses Bun’s default lock file.

Bun uses bun.lockb. Consider removing both.

-    "clean": "rm -f deno.lock package-lock.json bun.lock && rm -rf node_modules apps/*/node_modules packages/*/node_modules",
+    "clean": "rm -f deno.lock package-lock.json bun.lock bun.lockb && rm -rf node_modules apps/*/node_modules packages/*/node_modules",

Comment thread apps/api/src/email.ts
Comment thread packages/ai/src/agent.ts Outdated
Comment thread packages/ai/src/deco.ts
Comment thread packages/runtime/src/index.ts Outdated
Comment thread packages/runtime/src/mcp-client.ts
Comment thread packages/sdk/src/mcp/hosting/api.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b2cf9c and 40d3961.

📒 Files selected for processing (3)
  • package.json (2 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/runtime/jsr.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/runtime/jsr.json
🧰 Additional context used
📓 Path-based instructions (1)
packages/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep shared logic (UI kit, SDK, runtime, CLI tooling) under packages/

Files:

  • packages/cli/package.json
🔇 Additional comments (5)
packages/cli/package.json (1)

3-3: Version bump is correctly applied.

The minor version increment aligns with the PR's broader tooling migration and follows semantic versioning conventions.

package.json (4)

2-2: Verify the package name change is intentional.

The package name has changed from @deco/chat to @decocms/admin, which is a breaking change for any existing consumers. Verify that:

  1. This rename aligns with the PR's stated objectives (which focus on oxlint migration)
  2. The change is coordinated with npm registry and any existing package publications
  3. Downstream dependencies have been updated or will be notified

9-9: Lint script migration is clean.

Direct replacement of deno lint with oxlint aligns with the PR's tooling migration goals. Ensure oxlint configuration exists in .oxlintrc.json or equivalent.


11-15: New test, formatting, and docs scripts are well-structured.

The additions follow standard patterns and align with the tooling migration goals:

  • "test" and "test:watch" enable vitest-based testing workflows
  • "fmt:check" supports format verification
  • "docs:dev" and "docs:deploy" restore/add documentation workflows

33-33: Oxlint version is appropriately pinned.

The exact version pinning (1.23.0) is consistent with other build/dev tooling (biome, vitest, wrangler) and ensures reproducible linting behavior across environments.

Comment thread package.json
- Reintroduced nullish coalescing in multiple spread operations across various files to ensure safe handling of potentially undefined values.
- Updated components and utility functions in `apps/web`, `packages/ai`, `packages/cli`, `packages/runtime`, and `packages/sdk` to maintain consistency and prevent runtime errors.

These changes enhance the robustness of the code by ensuring that undefined values do not lead to unintended behavior.
- Deleted the `NULLISH_COALESCING_REMOVALS.md` file, which documented the nullish coalescing removals from spread operations.
- This cleanup reflects the completion of the related refactoring work and helps maintain a tidy documentation structure.

No further action is required as the relevant changes have been implemented in the codebase.
…xlintrc.json

- Turned off the `unicorn/no-useless-fallback-in-spread` rule in the linting configuration to prevent unnecessary warnings during development.
- This adjustment aligns the linting rules with current project needs and enhances the developer experience.

No further action is required as this change is purely a configuration update.
@viktormarinho viktormarinho merged commit ff17ba4 into main Oct 20, 2025
3 checks passed
@viktormarinho viktormarinho deleted the oxlint branch October 20, 2025 03:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant