fix(ci): default local low-memory checks

This commit is contained in:
Vincent Koc 2026-03-31 15:03:08 +09:00
parent 3a87783632
commit 8dfbcaa200
13 changed files with 198 additions and 90 deletions

View File

@ -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

View File

@ -71,6 +71,8 @@ jobs:
echo "Publishing openclaw@${PACKAGE_VERSION}"
- name: Check
env:
OPENCLAW_LOCAL_CHECK: "0"
run: pnpm check
- name: Build

View File

@ -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:

View File

@ -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.

View File

@ -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<unknown>>(),
);
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 };
});

View File

@ -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();

View File

@ -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"),

View File

@ -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",

View File

@ -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

42
scripts/run-oxlint.mjs Normal file
View File

@ -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);

37
scripts/run-tsgo.mjs Normal file
View File

@ -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);

View File

@ -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");

View File

@ -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.