From 8dfbcaa200b37d8b8c1bfeea559033ceed278593 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 31 Mar 2026 15:03:08 +0900 Subject: [PATCH] fix(ci): default local low-memory checks --- .github/workflows/ci.yml | 2 + .github/workflows/openclaw-npm-release.yml | 2 + AGENTS.md | 1 + CHANGELOG.md | 1 + .../telegram/src/bot-message-dispatch.test.ts | 16 ++-- .../src/bot.create-telegram-bot.test.ts | 7 +- extensions/telegram/src/bot.test.ts | 77 +++++++++++-------- package.json | 7 +- pnpm-lock.yaml | 76 +++++++++--------- scripts/run-oxlint.mjs | 42 ++++++++++ scripts/run-tsgo.mjs | 37 +++++++++ src/config/io.ts | 10 +-- src/plugins/types.ts | 10 +-- 13 files changed, 198 insertions(+), 90 deletions(-) create mode 100644 scripts/run-oxlint.mjs create mode 100644 scripts/run-tsgo.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e91a77f0b8f..99339784484 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -459,6 +459,8 @@ jobs: use-sticky-disk: "false" - name: Check types and lint and oxfmt + env: + OPENCLAW_LOCAL_CHECK: "0" run: pnpm check - name: Strict TS build smoke diff --git a/.github/workflows/openclaw-npm-release.yml b/.github/workflows/openclaw-npm-release.yml index 6e720cbd2e7..a22bbc0f6d4 100644 --- a/.github/workflows/openclaw-npm-release.yml +++ b/.github/workflows/openclaw-npm-release.yml @@ -71,6 +71,8 @@ jobs: echo "Publishing openclaw@${PACKAGE_VERSION}" - name: Check + env: + OPENCLAW_LOCAL_CHECK: "0" run: pnpm check - name: Build diff --git a/AGENTS.md b/AGENTS.md index 59950ad22d5..fcd39535ab4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -112,6 +112,7 @@ - Type-check/build: `pnpm build` - TypeScript checks: `pnpm tsgo` - Lint/format: `pnpm check` +- Local agent/dev shells default to lower-memory `OPENCLAW_LOCAL_CHECK=1` behavior for `pnpm tsgo` and `pnpm lint`; set `OPENCLAW_LOCAL_CHECK=0` in CI/shared runs. - Format check: `pnpm format` (oxfmt --check) - Format fix: `pnpm format:fix` (oxfmt --write) - Terminology: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c5f732eaec..9367fc943cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Docs: https://docs.openclaw.ai - Memory/QMD: point `QMD_CONFIG_DIR` at the nested `xdg-config/qmd` directory so per-agent collection config resolves correctly. (#39078) Thanks @smart-tinker and @vincentkoc. - Memory/QMD: include deduplicated default plus per-agent `memorySearch.extraPaths` when building QMD custom collections, so shared and agent-specific extra roots both get indexed consistently. (#57315) Thanks @Vitalcheffe and @vincentkoc. - Memory/session indexer: include `.jsonl.reset.*` and `.jsonl.deleted.*` transcripts in the memory host session scan while still excluding `.jsonl.bak.*` compaction backups and lock files, so memory search sees archived session history without duplicating stale snapshots. Thanks @hclsys and @vincentkoc. +- CI/dev checks: default local `pnpm check` to a lower-memory typecheck/lint path while keeping CI on the normal parallel path, and harden Telegram test typing/literals around native TypeScript-Go tooling crashes. - Agents/sandbox: honor `tools.sandbox.tools.alsoAllow`, let explicit sandbox re-allows remove matching built-in default-deny tools, and keep sandbox explain/error guidance aligned with the effective sandbox tool policy. (#54492) Thanks @ngutman. - LINE/ACP: add current-conversation binding and inbound binding-routing parity so `/acp spawn ... --thread here`, configured ACP bindings, and active conversation-bound ACP sessions work on LINE like the other conversation channels. - LINE/markdown: preserve underscores inside Latin, Cyrillic, and CJK words when stripping markdown, while still removing standalone `_italic_` markers on the shared text-runtime path used by LINE and TTS. (#47465) Thanks @jackjin1997. diff --git a/extensions/telegram/src/bot-message-dispatch.test.ts b/extensions/telegram/src/bot-message-dispatch.test.ts index 229b00a17d3..cdf6bcc0aeb 100644 --- a/extensions/telegram/src/bot-message-dispatch.test.ts +++ b/extensions/telegram/src/bot-message-dispatch.test.ts @@ -6,8 +6,14 @@ import { createTestDraftStream, } from "./draft-stream.test-helpers.js"; +type DispatchReplyWithBufferedBlockDispatcherArgs = Parameters< + TelegramBotDeps["dispatchReplyWithBufferedBlockDispatcher"] +>[0]; + const createTelegramDraftStream = vi.hoisted(() => vi.fn()); -const dispatchReplyWithBufferedBlockDispatcher = vi.hoisted(() => vi.fn()); +const dispatchReplyWithBufferedBlockDispatcher = vi.hoisted(() => + vi.fn<(params: DispatchReplyWithBufferedBlockDispatcherArgs) => Promise>(), +); const deliverReplies = vi.hoisted(() => vi.fn()); const emitInternalMessageSentHook = vi.hoisted(() => vi.fn()); const createForumTopicTelegram = vi.hoisted(() => vi.fn()); @@ -2113,7 +2119,7 @@ describe("dispatchTelegramMessage draft streaming", () => { const draftStream = createDraftStream(999); createTelegramDraftStream.mockReturnValue(draftStream); dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ dispatcherOptions }) => { - dispatcherOptions.onSkip?.({ text: "" }, { reason: "no_reply", kind: "final" }); + dispatcherOptions.onSkip?.({ text: "" }, { reason: "empty", kind: "final" }); return { queuedFinal: false }; }); deliverReplies.mockResolvedValueOnce({ delivered: true }); @@ -2139,7 +2145,7 @@ describe("dispatchTelegramMessage draft streaming", () => { try { await dispatcherOptions.deliver({ text: "Hello" }, { kind: "final" }); } catch (err) { - dispatcherOptions.onError(err, { kind: "final" }); + dispatcherOptions.onError?.(err, { kind: "final" }); } return { queuedFinal: false }; }); @@ -2167,7 +2173,7 @@ describe("dispatchTelegramMessage draft streaming", () => { try { await dispatcherOptions.deliver({ text: "Hello" }, { kind: "final" }); } catch (err) { - dispatcherOptions.onError(err, { kind: "final" }); + dispatcherOptions.onError?.(err, { kind: "final" }); } return { queuedFinal: false }; }); @@ -2231,7 +2237,7 @@ describe("dispatchTelegramMessage draft streaming", () => { try { await dispatcherOptions.deliver({ text: "Hello" }, { kind: "final" }); } catch (err) { - dispatcherOptions.onError(err, { kind: "final" }); + dispatcherOptions.onError?.(err, { kind: "final" }); } return { queuedFinal: false }; }); diff --git a/extensions/telegram/src/bot.create-telegram-bot.test.ts b/extensions/telegram/src/bot.create-telegram-bot.test.ts index 425bafdf3ce..e436d46d8e5 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.test.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.test.ts @@ -3,6 +3,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vites import { escapeRegExp, formatEnvelopeTimestamp } from "../../../test/helpers/envelope-timestamp.js"; import { withEnvAsync } from "../../../test/helpers/plugins/env.js"; const harness = await import("./bot.create-telegram-bot.test-harness.js"); +const EYES_EMOJI = "\u{1F440}"; const { answerCallbackQuerySpy, botCtorSpy, @@ -1716,7 +1717,7 @@ describe("createTelegramBot", () => { loadConfig.mockReturnValue({ messages: { - ackReaction: "👀", + ackReaction: EYES_EMOJI, ackReactionScope: "group-mentions", groupChat: { mentionPatterns: ["\\bbert\\b"] }, }, @@ -1738,7 +1739,9 @@ describe("createTelegramBot", () => { }, }); - expect(setMessageReactionSpy).toHaveBeenCalledWith(7, 123, [{ type: "emoji", emoji: "👀" }]); + expect(setMessageReactionSpy).toHaveBeenCalledWith(7, 123, [ + { type: "emoji", emoji: EYES_EMOJI }, + ]); }); it("clears native commands when disabled", () => { resetHarnessSpies(); diff --git a/extensions/telegram/src/bot.test.ts b/extensions/telegram/src/bot.test.ts index 73c53eb64bf..2e13fbe8331 100644 --- a/extensions/telegram/src/bot.test.ts +++ b/extensions/telegram/src/bot.test.ts @@ -41,6 +41,15 @@ let createTelegramBot: ( const loadConfig = getLoadConfigMock(); const readChannelAllowFromStore = getReadChannelAllowFromStoreMock(); +const PUZZLE_EMOJI = "\u{1F9E9}"; +const CROSS_MARK_EMOJI = "\u{274C}"; +const INFO_EMOJI = "\u{2139}\u{FE0F}"; +const CHECK_MARK_EMOJI = "\u{2705}"; +const THUMBS_UP_EMOJI = "\u{1F44D}"; +const FIRE_EMOJI = "\u{1F525}"; +const PARTY_EMOJI = "\u{1F389}"; +const EYES_EMOJI = "\u{1F440}"; +const HEART_EMOJI = "\u{2764}\u{FE0F}"; function createSignal() { let resolve!: () => void; @@ -427,7 +436,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 21, text: [ - "🧩 Yep-needs approval again.", + `${PUZZLE_EMOJI} Yep-needs approval again.`, "", "Run:", "/approve 138e9b8c allow-once", @@ -666,7 +675,7 @@ describe("createTelegramBot", () => { expect(sendMessageSpy).toHaveBeenCalledTimes(1); expect(sendMessageSpy.mock.calls[0]?.[1]).toBe( - "❌ Failed to submit approval. Please try again or contact an admin.", + `${CROSS_MARK_EMOJI} Failed to submit approval. Please try again or contact an admin.`, ); }); @@ -794,7 +803,7 @@ describe("createTelegramBot", () => { expect(replySpy).not.toHaveBeenCalled(); expect(sendMessageSpy).toHaveBeenCalledWith( 1234, - "❌ Failed to submit approval. Please try again or contact an admin.", + `${CROSS_MARK_EMOJI} Failed to submit approval. Please try again or contact an admin.`, undefined, ); expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-legacy-plugin-fallback-blocked"); @@ -881,7 +890,7 @@ describe("createTelegramBot", () => { const [chatId, messageId, text, params] = editMessageTextSpy.mock.calls[0] ?? []; expect(chatId).toBe(1234); expect(messageId).toBe(12); - expect(String(text)).toContain("â„šī¸ Commands"); + expect(String(text)).toContain(`${INFO_EMOJI} Commands`); expect(params).toEqual( expect.objectContaining({ reply_markup: expect.any(Object), @@ -1014,7 +1023,9 @@ describe("createTelegramBot", () => { expect(replySpy).not.toHaveBeenCalled(); expect(editMessageTextSpy).toHaveBeenCalledTimes(1); - expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain("✅ Model reset to default"); + expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain( + `${CHECK_MARK_EMOJI} Model reset to default`, + ); const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0]; expect(entry?.providerOverride).toBeUndefined(); @@ -1078,7 +1089,9 @@ describe("createTelegramBot", () => { expect(replySpy).not.toHaveBeenCalled(); expect(editMessageTextSpy).toHaveBeenCalledTimes(1); - expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain("✅ Model reset to default"); + expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain( + `${CHECK_MARK_EMOJI} Model reset to default`, + ); const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0]; expect(entry?.providerOverride).toBeUndefined(); @@ -2115,13 +2128,13 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada", username: "ada_bot" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1); expect(enqueueSystemEventSpy).toHaveBeenCalledWith( - "Telegram reaction added: 👍 by Ada (@ada_bot) on msg 42", + `Telegram reaction added: ${THUMBS_UP_EMOJI} by Ada (@ada_bot) on msg 42`, expect.objectContaining({ contextKey: expect.stringContaining("telegram:reaction:add:1234:42:9"), }), @@ -2139,7 +2152,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, expectedEnqueueCalls: 0, }, @@ -2157,7 +2170,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, expectedEnqueueCalls: 0, }, @@ -2171,7 +2184,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, expectedEnqueueCalls: 1, }, @@ -2190,7 +2203,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "đŸ”Ĩ" }], + new_reaction: [{ type: "emoji", emoji: FIRE_EMOJI }], }, expectedEnqueueCalls: 0, }, @@ -2241,7 +2254,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, }); @@ -2272,7 +2285,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👍" }], + new_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], }, }); @@ -2303,13 +2316,13 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "🎉" }], + new_reaction: [{ type: "emoji", emoji: PARTY_EMOJI }], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1); expect(enqueueSystemEventSpy).toHaveBeenCalledWith( - "Telegram reaction added: 🎉 by Ada on msg 99", + `Telegram reaction added: ${PARTY_EMOJI} by Ada on msg 99`, expect.any(Object), ); }); @@ -2338,7 +2351,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "🎉" }], + new_reaction: [{ type: "emoji", emoji: PARTY_EMOJI }], }, }); @@ -2369,7 +2382,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Ada" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "🎉" }], + new_reaction: [{ type: "emoji", emoji: PARTY_EMOJI }], }, }); @@ -2400,7 +2413,7 @@ describe("createTelegramBot", () => { user: { id: 9, first_name: "Bot", is_bot: true }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "🎉" }], + new_reaction: [{ type: "emoji", emoji: PARTY_EMOJI }], }, }); @@ -2429,7 +2442,7 @@ describe("createTelegramBot", () => { message_id: 42, user: { id: 9, first_name: "Ada" }, date: 1736380800, - old_reaction: [{ type: "emoji", emoji: "👍" }], + old_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], new_reaction: [], }, }); @@ -2459,19 +2472,19 @@ describe("createTelegramBot", () => { message_id: 42, user: { id: 9, first_name: "Ada" }, date: 1736380800, - old_reaction: [{ type: "emoji", emoji: "👍" }], + old_reaction: [{ type: "emoji", emoji: THUMBS_UP_EMOJI }], new_reaction: [ - { type: "emoji", emoji: "👍" }, - { type: "emoji", emoji: "đŸ”Ĩ" }, - { type: "emoji", emoji: "🎉" }, + { type: "emoji", emoji: THUMBS_UP_EMOJI }, + { type: "emoji", emoji: FIRE_EMOJI }, + { type: "emoji", emoji: PARTY_EMOJI }, ], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(2); expect(enqueueSystemEventSpy.mock.calls.map((call) => call[0])).toEqual([ - "Telegram reaction added: đŸ”Ĩ by Ada on msg 42", - "Telegram reaction added: 🎉 by Ada on msg 42", + `Telegram reaction added: ${FIRE_EMOJI} by Ada on msg 42`, + `Telegram reaction added: ${PARTY_EMOJI} by Ada on msg 42`, ]); }); @@ -2500,13 +2513,13 @@ describe("createTelegramBot", () => { user: { id: 10, first_name: "Bob", username: "bob_user" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "đŸ”Ĩ" }], + new_reaction: [{ type: "emoji", emoji: FIRE_EMOJI }], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1); expect(enqueueSystemEventSpy).toHaveBeenCalledWith( - "Telegram reaction added: đŸ”Ĩ by Bob (@bob_user) on msg 100", + `Telegram reaction added: ${FIRE_EMOJI} by Bob (@bob_user) on msg 100`, expect.objectContaining({ sessionKey: expect.stringContaining("telegram:group:5678:topic:1"), contextKey: expect.stringContaining("telegram:reaction:add:5678:100:10"), @@ -2538,13 +2551,13 @@ describe("createTelegramBot", () => { user: { id: 10, first_name: "Bob" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "👀" }], + new_reaction: [{ type: "emoji", emoji: EYES_EMOJI }], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1); expect(enqueueSystemEventSpy).toHaveBeenCalledWith( - "Telegram reaction added: 👀 by Bob on msg 101", + `Telegram reaction added: ${EYES_EMOJI} by Bob on msg 101`, expect.objectContaining({ sessionKey: expect.stringContaining("telegram:group:5678:topic:1"), contextKey: expect.stringContaining("telegram:reaction:add:5678:101:10"), @@ -2575,13 +2588,13 @@ describe("createTelegramBot", () => { user: { id: 11, first_name: "Charlie" }, date: 1736380800, old_reaction: [], - new_reaction: [{ type: "emoji", emoji: "â¤ī¸" }], + new_reaction: [{ type: "emoji", emoji: HEART_EMOJI }], }, }); expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1); expect(enqueueSystemEventSpy).toHaveBeenCalledWith( - "Telegram reaction added: â¤ī¸ by Charlie on msg 200", + `Telegram reaction added: ${HEART_EMOJI} by Charlie on msg 200`, expect.objectContaining({ sessionKey: expect.stringContaining("telegram:group:9999"), contextKey: expect.stringContaining("telegram:reaction:add:9999:200:11"), diff --git a/package.json b/package.json index d55afb78028..cc258216097 100644 --- a/package.json +++ b/package.json @@ -1024,7 +1024,7 @@ "ios:gen": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate'", "ios:open": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'", "ios:run": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'", - "lint": "oxlint --type-aware --tsconfig tsconfig.oxlint.json", + "lint": "node scripts/run-oxlint.mjs", "lint:agent:ingress-owner": "node scripts/check-ingress-agent-owner-context.mjs", "lint:all": "pnpm lint && pnpm lint:swift", "lint:auth:no-pairing-store-group": "node scripts/check-no-pairing-store-group-auth.mjs", @@ -1034,7 +1034,7 @@ "lint:extensions:no-plugin-sdk-internal": "node scripts/check-extension-plugin-sdk-boundary.mjs --mode=plugin-sdk-internal", "lint:extensions:no-relative-outside-package": "node scripts/check-extension-plugin-sdk-boundary.mjs --mode=relative-outside-package", "lint:extensions:no-src-outside-plugin-sdk": "node scripts/check-extension-plugin-sdk-boundary.mjs --mode=src-outside-plugin-sdk", - "lint:fix": "oxlint --type-aware --tsconfig tsconfig.oxlint.json --fix && pnpm format", + "lint:fix": "node scripts/run-oxlint.mjs --fix && pnpm format", "lint:plugins:no-extension-imports": "node scripts/check-plugin-extension-import-boundary.mjs", "lint:plugins:no-extension-src-imports": "node --import tsx scripts/check-no-extension-src-imports.ts", "lint:plugins:no-extension-test-core-imports": "node --import tsx scripts/check-no-extension-test-core-imports.ts", @@ -1140,6 +1140,7 @@ "test:voicecall:closedloop": "node scripts/test-voicecall-closedloop.mjs", "test:watch": "vitest", "ts-topology": "node --import tsx scripts/ts-topology.ts", + "tsgo": "node scripts/run-tsgo.mjs", "tui": "node scripts/run-node.mjs tui", "tui:dev": "OPENCLAW_PROFILE=dev node scripts/run-node.mjs --dev tui", "ui:build": "node scripts/ui.js build", @@ -1204,7 +1205,7 @@ "@types/node": "^25.5.0", "@types/qrcode-terminal": "^0.12.2", "@types/ws": "^8.18.1", - "@typescript/native-preview": "7.0.0-dev.20260327.2", + "@typescript/native-preview": "7.0.0-dev.20260330.1", "@vitest/coverage-v8": "^4.1.2", "jscpd": "4.0.8", "jsdom": "^29.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e4b00e8942..f45d7e4a408 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -200,8 +200,8 @@ importers: specifier: ^8.18.1 version: 8.18.1 '@typescript/native-preview': - specifier: 7.0.0-dev.20260327.2 - version: 7.0.0-dev.20260327.2 + specifier: 7.0.0-dev.20260330.1 + version: 7.0.0-dev.20260330.1 '@vitest/coverage-v8': specifier: ^4.1.2 version: 4.1.2(@vitest/browser@4.1.2(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2))(vitest@4.1.2) @@ -228,7 +228,7 @@ importers: version: 0.21.1(signal-polyfill@0.2.2) tsdown: specifier: 0.21.7 - version: 0.21.7(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@6.0.2) + version: 0.21.7(@typescript/native-preview@7.0.0-dev.20260330.1)(typescript@6.0.2) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -3471,43 +3471,43 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-lEcUWwu2DLY0NjoB3x7Fivz63zd57D1fD6PD8ByQqa0/xO8+EC5GHr5YniJlHSpF05cn2sgl7SPS92qVs0Xhlw==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-jX47OX4svh3/CzSDYd81+kELLP5r0+G7lFGiMAVUNpD+ZLmyh/nrkuuI643pGe8D0i9dTfg/aiZQq6d/00Feog==} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-IvUv0dCaVNKbA9Oq/GEEhtBPF9PP3E5MfW4pla4NpDsZh+6/nL5p0WXvlocV0fe1rT9fqmCQfk3oH+XrN1I8Qw==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-JysPTOMnyje+LkdB3LR+Emnl7hJCvMzUVRcOVJyzmxWOMFNCYPWNK3wDdwuoS6jE5Hii9vInt/xtn3pc+kgb+A==} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-k98Q20XAC8bM9L915GFIfjo/ii/sYIaEzIDH3l6MwhiJMDPucARQpfbReUdXl8N3TsdCNwk8xay0pNIK0DOkvg==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-9zlw4ENr6HAUNO+OiWuoQpWUGk4lkqb8NUyXDvTqtlgZGvjyePNVy8OW7KlPuPtCaQS3btV7w4h5X1wlTm2bFA==} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-7ATSft1YojnRp/VG70i97CxFe+umhTHYA/jJwQBPrjdopAFa5IvFDr4kNajjy1uypbz/x6pfvCnTdOd1/lM3FQ==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-rVwd9ZgjR8Le6ItUD/p59LCOYdZbi4DZYavXAMzPPpaJCnmdHwOcJFWc61vricsQljRjVBnunQknHfYABZDq9Q==} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-XTe5M1sTwjlxHS1NaNci4vf2nR7bAEwPB70SbhbSTS9ka+75mTP7cv8jHbGhKXEPxDLURBPSyvionog4+5NXmA==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-7cB4e12e61xaXgJu6N9rMP+6qdkODVsW8zGjVS5a+cobBCsJSdMnlshfitlL9a+BYWe9HseMqPnLcsaE+t22CQ==} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-1F86Pmf1QcHv0IENBJJ7nWWVSWjR1nn4jokuSbWiPkKGD57rkJWiHY7xtpt4ql8ZG4bIWxdHonLaepBfjIkaug==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-4wv/FX9F5oAQhzjqwL8KN4O5xgciBy5pT2yLP45xcQahxFUoPnQeF9Pz2x/jwXZSmuh8E1DQWX9evSVGA1MV2A==} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-zMI8AIWRr98hOgTC5DCe3GD/MGHfusX/E/Dz64Xcf+re4EUVS/pXP5fAUb3dQr8ndi9mHbM0DEmNb4ctSxsxew==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-zKDOG/nq1yTx3cjfc19VFO+TYK2+03Wc17pGdD+X+dWTj15LZ2PKk3s4OtT2b8siTcAUn7zmwLsMCWPYO7xXQw==} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260327.2': - resolution: {integrity: sha512-npU/LrswTK7gawemSkI2BufIgNgoOHA1OwwIC5EUh++oWLDuWZSvSAcH6mfn28NOt5A196zrHQd3SK7f5XCVAw==} + '@typescript/native-preview@7.0.0-dev.20260330.1': + resolution: {integrity: sha512-tyRn6/PAYpkN35bKz2RPfzV/QAACvle9EYlYyywn/p/qPI5yOBLka0zM/2dGKx+o5vHVQ1gr/iVrgW8w7Wqc8Q==} hasBin: true '@ungap/structured-clone@1.3.0': @@ -9940,36 +9940,36 @@ snapshots: '@types/node': 25.5.0 optional: true - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260327.2': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260327.2': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260327.2': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260327.2': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260327.2': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260327.2': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260327.2': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260330.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260327.2': + '@typescript/native-preview@7.0.0-dev.20260330.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260327.2 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260327.2 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260327.2 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260327.2 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260327.2 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260327.2 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260327.2 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260330.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260330.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260330.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260330.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260330.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260330.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260330.1 '@ungap/structured-clone@1.3.0': {} @@ -12602,7 +12602,7 @@ snapshots: glob: 7.2.3 optional: true - rolldown-plugin-dts@0.23.2(@typescript/native-preview@7.0.0-dev.20260327.2)(rolldown@1.0.0-rc.12)(typescript@6.0.2): + rolldown-plugin-dts@0.23.2(@typescript/native-preview@7.0.0-dev.20260330.1)(rolldown@1.0.0-rc.12)(typescript@6.0.2): dependencies: '@babel/generator': 8.0.0-rc.3 '@babel/helper-validator-identifier': 8.0.0-rc.3 @@ -12616,7 +12616,7 @@ snapshots: picomatch: 4.0.4 rolldown: 1.0.0-rc.12 optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260327.2 + '@typescript/native-preview': 7.0.0-dev.20260330.1 typescript: 6.0.2 transitivePeerDependencies: - oxc-resolver @@ -13109,7 +13109,7 @@ snapshots: ts-algebra@2.0.0: {} - tsdown@0.21.7(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@6.0.2): + tsdown@0.21.7(@typescript/native-preview@7.0.0-dev.20260330.1)(typescript@6.0.2): dependencies: ansis: 4.2.0 cac: 7.0.0 @@ -13120,7 +13120,7 @@ snapshots: obug: 2.1.1 picomatch: 4.0.4 rolldown: 1.0.0-rc.12 - rolldown-plugin-dts: 0.23.2(@typescript/native-preview@7.0.0-dev.20260327.2)(rolldown@1.0.0-rc.12)(typescript@6.0.2) + rolldown-plugin-dts: 0.23.2(@typescript/native-preview@7.0.0-dev.20260330.1)(rolldown@1.0.0-rc.12)(typescript@6.0.2) semver: 7.7.4 tinyexec: 1.0.4 tinyglobby: 0.2.15 diff --git a/scripts/run-oxlint.mjs b/scripts/run-oxlint.mjs new file mode 100644 index 00000000000..b5acd423dae --- /dev/null +++ b/scripts/run-oxlint.mjs @@ -0,0 +1,42 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; + +const isLocalCheckEnabled = (env) => { + const raw = env.OPENCLAW_LOCAL_CHECK?.trim().toLowerCase(); + return raw !== "0" && raw !== "false"; +}; + +const hasFlag = (args, name) => args.some((arg) => arg === name || arg.startsWith(`${name}=`)); + +const args = process.argv.slice(2); +const env = { ...process.env }; +const finalArgs = [...args]; +const separatorIndex = finalArgs.indexOf("--"); + +const insertBeforeSeparator = (...items) => { + const index = separatorIndex === -1 ? finalArgs.length : separatorIndex; + finalArgs.splice(index, 0, ...items); +}; + +if (!hasFlag(finalArgs, "--type-aware")) { + insertBeforeSeparator("--type-aware"); +} +if (!hasFlag(finalArgs, "--tsconfig")) { + insertBeforeSeparator("--tsconfig", "tsconfig.oxlint.json"); +} +if (isLocalCheckEnabled(env) && !hasFlag(finalArgs, "--threads")) { + insertBeforeSeparator("--threads=1"); +} + +const oxlintPath = path.resolve("node_modules", ".bin", "oxlint"); +const result = spawnSync(oxlintPath, finalArgs, { + stdio: "inherit", + env, + shell: process.platform === "win32", +}); + +if (result.error) { + throw result.error; +} + +process.exit(result.status ?? 1); diff --git a/scripts/run-tsgo.mjs b/scripts/run-tsgo.mjs new file mode 100644 index 00000000000..bc0bac075a6 --- /dev/null +++ b/scripts/run-tsgo.mjs @@ -0,0 +1,37 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; + +const isLocalCheckEnabled = (env) => { + const raw = env.OPENCLAW_LOCAL_CHECK?.trim().toLowerCase(); + return raw !== "0" && raw !== "false"; +}; + +const args = process.argv.slice(2); +const env = { ...process.env }; +const finalArgs = [...args]; +const separatorIndex = finalArgs.indexOf("--"); + +const insertBeforeSeparator = (...items) => { + const index = separatorIndex === -1 ? finalArgs.length : separatorIndex; + finalArgs.splice(index, 0, ...items); +}; + +if (isLocalCheckEnabled(env) && !finalArgs.includes("--singleThreaded")) { + insertBeforeSeparator("--singleThreaded"); + if (!env.GOGC) { + env.GOGC = "30"; + } +} + +const tsgoPath = path.resolve("node_modules", ".bin", "tsgo"); +const result = spawnSync(tsgoPath, finalArgs, { + stdio: "inherit", + env, + shell: process.platform === "win32", +}); + +if (result.error) { + throw result.error; +} + +process.exit(result.status ?? 1); diff --git a/src/config/io.ts b/src/config/io.ts index 9d586c50e5f..8df3f15a6d2 100644 --- a/src/config/io.ts +++ b/src/config/io.ts @@ -1721,7 +1721,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { const effectiveConfigRaw = legacyResolution.effectiveConfigRaw; for (const w of readResolution.envWarnings) { deps.logger.warn( - `Config (${configPath}): missing env var "${w.varName}" at ${w.configPath} — feature using this value will be unavailable`, + `Config (${configPath}): missing env var "${w.varName}" at ${w.configPath} - feature using this value will be unavailable`, ); } warnOnConfigMiskeys(effectiveConfigRaw, deps.logger); @@ -1971,7 +1971,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { // sections reference unset env vars (e.g. optional provider API keys). const envVarWarnings = readResolution.envWarnings.map((w) => ({ path: w.configPath, - message: `Missing env var "${w.varName}" — feature using this value will be unavailable`, + message: `Missing env var "${w.varName}" - feature using this value will be unavailable`, })); const resolvedConfigRaw = readResolution.resolvedConfigRaw; @@ -2021,7 +2021,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { const nodeErr = err as NodeJS.ErrnoException; let message: string; if (nodeErr?.code === "EACCES") { - // Permission denied — common in Docker/container deployments where the + // Permission denied - common in Docker/container deployments where the // config file is owned by root but the gateway runs as a non-root user. const uid = process.getuid?.(); const uidHint = typeof uid === "number" ? String(uid) : "$(id -u)"; @@ -2123,7 +2123,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { // Restore ${VAR} env var references that were resolved during config loading. // Read the current file (pre-substitution) and restore any references whose - // resolved values match the incoming config — so we don't overwrite + // resolved values match the incoming config - so we don't overwrite // "${ANTHROPIC_API_KEY}" with "sk-ant-..." when the caller didn't change it. // // We use only the root file's parsed content (no $include resolution) to avoid @@ -2179,7 +2179,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { } } } - // Do NOT apply runtime defaults when writing — user config should only contain + // Do NOT apply runtime defaults when writing - user config should only contain // explicitly set values. Runtime defaults are applied when loading (issue #6070). const stampedOutputConfig = stampConfigVersion(outputConfig); const json = JSON.stringify(stampedOutputConfig, null, 2).trimEnd().concat("\n"); diff --git a/src/plugins/types.ts b/src/plugins/types.ts index a9f81c8f1c4..1bbc1ab0369 100644 --- a/src/plugins/types.ts +++ b/src/plugins/types.ts @@ -121,7 +121,7 @@ export type OpenClawPluginToolContext = { agentDir?: string; agentId?: string; sessionKey?: string; - /** Ephemeral session UUID — regenerated on /new and /reset. Use for per-conversation isolation. */ + /** Ephemeral session UUID - regenerated on /new and /reset. Use for per-conversation isolation. */ sessionId?: string; browser?: { sandboxBridgeUrl?: string; @@ -1750,7 +1750,7 @@ export type OpenClawPluginApi = { * Use this for simple state-toggling or status commands that don't need AI reasoning. */ registerCommand: (command: OpenClawPluginCommandDefinition) => void; - /** Register a context engine implementation (exclusive slot — only one active at a time). */ + /** Register a context engine implementation (exclusive slot - only one active at a time). */ registerContextEngine: ( id: string, factory: import("../context-engine/registry.js").ContextEngineFactory, @@ -2021,7 +2021,7 @@ export type PluginHookBeforeCompactionEvent = { sessionFile?: string; }; -// before_reset hook — fired when /new or /reset clears a session +// before_reset hook - fired when /new or /reset clears a session export type PluginHookBeforeResetEvent = { sessionFile?: string; messages?: unknown[]; @@ -2141,7 +2141,7 @@ export type PluginHookMessageSentEvent = { export type PluginHookToolContext = { agentId?: string; sessionKey?: string; - /** Ephemeral session UUID — regenerated on /new and /reset. */ + /** Ephemeral session UUID - regenerated on /new and /reset. */ sessionId?: string; /** Stable run identifier for this agent invocation. */ runId?: string; @@ -2181,7 +2181,7 @@ export type PluginHookBeforeToolCallResult = { severity?: "info" | "warning" | "critical"; timeoutMs?: number; timeoutBehavior?: "allow" | "deny"; - /** Set automatically by the hook runner — plugins should not set this. */ + /** Set automatically by the hook runner - plugins should not set this. */ pluginId?: string; /** * Best-effort callback invoked with the final outcome after approval resolves, times out, or is cancelled.