Compare commits

...

21 Commits

Author SHA1 Message Date
Tideclaw
500f425019 ci: keep codex attempt fixtures out of plugin prerelease batch 2026-06-17 17:14:38 +00:00
Tideclaw
9cd55c5048 test: relax codex dynamic ordering startup timeout 2026-06-17 16:54:56 +00:00
Tideclaw
a79493b51f test: stabilize codex dynamic tool capability fixture 2026-06-17 16:35:40 +00:00
Tideclaw
59a579a3aa fix: keep android gateway errors visible during approval checks 2026-06-17 16:14:48 +00:00
Tideclaw
eef218a143 fix: honor android gateway error status during onboarding 2026-06-17 15:55:46 +00:00
Tideclaw
34182465f2 chore: add alpha changelog section 2026-06-17 15:40:35 +00:00
Tideclaw
9d6174efe7 test: remove stale codex fixture helper 2026-06-17 15:22:39 +00:00
Tideclaw
e3ae182986 chore: prepare alpha 2026.6.9-alpha.6 2026-06-17 14:57:02 +00:00
Tideclaw
a00f22d4b5 fix: align plugin SDK surface budget 2026-06-17 14:56:52 +00:00
Tideclaw
6ce0bcc255 test: align slack command completion title 2026-06-17 14:45:12 +00:00
Tideclaw
c5a5653189 test: restore telegram sticker vision fixture 2026-06-17 14:43:03 +00:00
Tideclaw
2bdfbf7166 fix: refresh alpha plugin shrinkwraps 2026-06-17 14:27:52 +00:00
Tideclaw
3ab6915e50 fix: refresh alpha config docs baseline 2026-06-17 14:22:17 +00:00
Tideclaw
bc9b6945dd test: extend codex dynamic ordering shard timeout
(cherry picked from commit 1ad34870b5)
2026-06-17 14:19:38 +00:00
Tideclaw
c0610bcd90 test: isolate codex dynamic tool ordering fixture
(cherry picked from commit b0c751e407)
2026-06-17 14:19:38 +00:00
Tideclaw
8d2826b515 test: align codex runtime contract fixtures
(cherry picked from commit 2068ba332c)
2026-06-17 14:19:38 +00:00
Tideclaw
2d4643b607 fix: preserve codex bindings without active plugins
(cherry picked from commit cf3522def5)
2026-06-17 14:18:45 +00:00
Tideclaw
61a0a25a03 test: align telegram command completion previews
(cherry picked from commit 849738d06b)
2026-06-17 14:16:29 +00:00
Tideclaw
9d816fe3c0 test: align slack native progress completion expectation
(cherry picked from commit 9c78589f98)
2026-06-17 14:14:16 +00:00
Tideclaw
9cbd01b3d2 fix: refresh alpha plugin shrinkwraps
(cherry picked from commit 90a7ec6870)
2026-06-17 14:14:16 +00:00
Tideclaw
7bc8a0580d fix: skip generated assets in legacy store guard
(cherry picked from commit efdee21ccc)
2026-06-17 14:14:16 +00:00
185 changed files with 635 additions and 424 deletions

View File

@@ -344,7 +344,11 @@ jobs:
OPENCLAW_EXTENSION_BATCH_PARALLEL: 2
OPENCLAW_VITEST_MAX_WORKERS: 1
OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }}
run: pnpm test:extensions:batch "$OPENCLAW_EXTENSION_BATCH" -- --exclude extensions/codex/src/app-server/run-attempt.test.ts
run: |
pnpm test:extensions:batch "$OPENCLAW_EXTENSION_BATCH" -- \
--exclude extensions/codex/src/app-server/run-attempt.test.ts \
--exclude extensions/codex/src/app-server/run-attempt.dynamic-tools.test.ts \
--exclude extensions/codex/src/app-server/run-attempt.turn-watches.test.ts
plugin-prerelease-inspector:
permissions:

View File

@@ -2,6 +2,12 @@
Docs: https://docs.openclaw.ai
## 2026.6.9-alpha.6
### Fixes
- Stabilize the alpha package train by preserving Codex app-server bindings, refreshing generated plugin metadata, and aligning channel and runtime validation fixtures for release gates.
## 2026.6.8
### Highlights

View File

@@ -1126,13 +1126,17 @@ internal fun gatewayRecoveryUiState(
!gatewayConnectionProblem.canAutoRetry -> GatewayRecoveryUiState.ApprovalRequired
gatewayConnectionProblem?.isPairingRequired == true -> GatewayRecoveryUiState.Pairing
gatewayConnectionProblem?.pauseReconnect == true -> GatewayRecoveryUiState.Failed
nodeCapabilityApprovalState == GatewayNodeApprovalState.Loading -> GatewayRecoveryUiState.Finishing
connectSettling -> GatewayRecoveryUiState.Finishing
gatewayStatusLooksLikePairing(statusText) -> GatewayRecoveryUiState.Pairing
gatewayStatusLooksLikePartialConnect(statusText) -> GatewayRecoveryUiState.Finishing
nodeCapabilityApprovalState == GatewayNodeApprovalState.Loading &&
gatewayStatusLooksLikeConnected(statusText) -> GatewayRecoveryUiState.Finishing
else -> GatewayRecoveryUiState.Failed
}
internal fun gatewayStatusLooksLikeConnected(statusText: String): Boolean =
gatewayStatusForDisplay(statusText).equals("Connected", ignoreCase = true)
/** Detects gateway-approved states where the Android node is still coming online. */
internal fun gatewayStatusLooksLikePartialConnect(statusText: String): Boolean {
val lower = gatewayStatusForDisplay(statusText).lowercase()
@@ -1223,8 +1227,6 @@ private fun recoveryGatewayDetail(
nodeCapabilityApprovalState == GatewayNodeApprovalState.Unapproved
) {
"Gateway paired. Waiting for node capability approval."
} else if (nodeCapabilityApprovalState == GatewayNodeApprovalState.Loading) {
"Gateway paired. Checking node capability approval."
} else if (gatewayConnectionProblem?.isPairingRequired == true && !gatewayConnectionProblem.canAutoRetry) {
recoveryGatewayApprovalCommand(gatewayConnectionProblem)
?.let { "Gateway approval is pending. Run this on the gateway host:" }
@@ -1233,6 +1235,11 @@ private fun recoveryGatewayDetail(
"Gateway paired. Waiting for operator access."
} else if (gatewayStatusLooksLikePairing(statusText)) {
"Gateway approval is in progress. OpenClaw will retry automatically."
} else if (
nodeCapabilityApprovalState == GatewayNodeApprovalState.Loading &&
gatewayStatusLooksLikeConnected(statusText)
) {
"Gateway paired. Checking node capability approval."
} else {
"Gateway unreachable"
}

View File

@@ -1,4 +1,4 @@
b7ec57a4f38bf44677870fd9a8347be83f3f23a25a73d97931406f0eff572181 config-baseline.json
f64d525143960404258c98435ad31018ff6c84da66e0640fdd775b3f62c5ece2 config-baseline.json
99d506f05de601e5b45c98f302650c8608d1e2bb3dcea11bf97881c1263659ac config-baseline.core.json
2d735389858305509528e74329b6f8c65d311e1471c3b4e91dc17aaab8e63a80 config-baseline.channel.json
a973af69b02a27b097b54e49886dd57dbebbc95e2ab29b0c7e222a9f35a105d8 config-baseline.plugin.json
fcfd742aa81b08cf09afea4ae4ccd557a7aa25320059f564b376729f2ebe8f0a config-baseline.plugin.json

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/acpx",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/acpx",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@agentclientprotocol/claude-agent-acp": "0.39.0",
"@zed-industries/codex-acp": "0.15.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/acpx",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
"repository": {
"type": "git",
@@ -26,10 +26,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"staticAssets": [
{
"source": "./src/runtime-internals/mcp-proxy.mjs",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/admin-http-rpc",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw admin HTTP RPC endpoint",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/alibaba-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Alibaba Model Studio video provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@anthropic-ai/sdk": "0.100.1",
"@aws/bedrock-token-generator": "1.1.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.",
"repository": {
"type": "git",
@@ -24,10 +24,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@aws-sdk/client-bedrock": "3.1056.0",
"@aws-sdk/client-bedrock-runtime": "3.1056.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support.",
"repository": {
"type": "git",
@@ -28,10 +28,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@anthropic-ai/vertex-sdk": "0.16.1"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI.",
"repository": {
"type": "git",
@@ -23,10 +23,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Anthropic provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/arcee-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Arcee provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/azure-speech",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Azure Speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/bonjour",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Bonjour/mDNS gateway discovery",
"type": "module",
"dependencies": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/brave-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/brave-plugin",
"version": "2026.6.8"
"version": "2026.6.9-alpha.6"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/brave-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Brave Search provider plugin for web search.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/browser-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw browser tool plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/byteplus-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw BytePlus provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/canvas-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Canvas plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cerebras-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Cerebras provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/chutes-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Chutes.ai provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/clickclack",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw ClickClack channel plugin",
"type": "module",
@@ -18,7 +18,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cloudflare-ai-gateway-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Cloudflare AI Gateway provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/codex-supervisor",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Codex app-server fleet supervision plugin.",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/codex",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/codex",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@openai/codex": "0.139.0",
"typebox": "1.1.39",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/codex",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.",
"repository": {
"type": "git",
@@ -34,10 +34,10 @@
]
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -324,6 +324,7 @@ export async function startCodexAttemptThread(params: {
pluginThreadConfig: pluginThreadConfigRequired
? {
enabled: true,
codexPluginsEnabled: resolvedPluginPolicy?.enabled === true,
inputFingerprint: pluginThreadConfigInputFingerprint,
enabledPluginConfigKeys,
build: () =>

View File

@@ -21,6 +21,7 @@ let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
type RunCodexAppServerAttemptOptions = NonNullable<
Parameters<typeof runCodexAppServerAttemptImpl>[1]
>;
type CodexAppServerBindingInput = Parameters<typeof writeCodexAppServerBinding>[1];
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
codexAppServerClientFactoryForTest = factory;
@@ -66,9 +67,7 @@ const DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT = JSON.stringify({
web_search: "disabled",
});
function writeCodexAppServerBinding(
...args: Parameters<typeof writeRawCodexAppServerBinding>
) {
function writeCodexAppServerBinding(...args: Parameters<typeof writeRawCodexAppServerBinding>) {
const [sessionFile, binding, lookup] = args;
return writeRawCodexAppServerBinding(
sessionFile,
@@ -176,6 +175,73 @@ function createCodexAuthProfileHarness(params: { startMethod: "thread/start" | "
};
}
async function resolveCurrentBindingDefaults(
tmpDir: string,
): Promise<Partial<CodexAppServerBindingInput>> {
const sessionFile = path.join(tmpDir, `binding-metadata-${Date.now()}.jsonl`);
let notify: (notification: unknown) => Promise<void> = async () => undefined;
const requests: string[] = [];
setCodexAppServerClientFactoryForTest(
async () =>
({
request: vi.fn(async (method: string) => {
requests.push(method);
if (method === "thread/start") {
return threadStartResult("thread-auth-metadata");
}
if (method === "turn/start") {
return turnStartResult("turn-auth-metadata");
}
throw new Error(`unexpected metadata method: ${method}`);
}),
addNotificationHandler: (handler: (notification: unknown) => Promise<void>) => {
notify = handler;
return () => undefined;
},
addRequestHandler: () => () => undefined,
}) as never,
);
const run = runCodexAppServerAttempt(createParams(sessionFile, tmpDir));
await vi.waitFor(() => expect(requests).toContain("turn/start"), { interval: 1 });
await notify({
method: "turn/completed",
params: {
threadId: "thread-auth-metadata",
turnId: "turn-auth-metadata",
turn: { id: "turn-auth-metadata", status: "completed" },
},
});
await run;
const binding = await readCodexAppServerBinding(sessionFile);
if (!binding) {
throw new Error("expected current Codex auth binding metadata");
}
return {
dynamicToolsFingerprint: binding.dynamicToolsFingerprint,
dynamicToolsContainDeferred: binding.dynamicToolsContainDeferred,
webSearchThreadConfigFingerprint: binding.webSearchThreadConfigFingerprint,
userMcpServersFingerprint: binding.userMcpServersFingerprint,
mcpServersFingerprint: binding.mcpServersFingerprint,
pluginAppsFingerprint: binding.pluginAppsFingerprint,
pluginAppsInputFingerprint: binding.pluginAppsInputFingerprint,
pluginAppPolicyContext: binding.pluginAppPolicyContext,
environmentSelectionFingerprint: binding.environmentSelectionFingerprint,
};
}
async function writeCurrentCodexAppServerBinding(
sessionFile: string,
tmpDir: string,
binding: CodexAppServerBindingInput,
): Promise<void> {
await writeCodexAppServerBinding(sessionFile, {
...(await resolveCurrentBindingDefaults(tmpDir)),
...binding,
});
}
describe("Auth profile runtime contract - Codex app-server adapter", () => {
let tmpDir: string;
@@ -213,14 +279,13 @@ describe("Auth profile runtime contract - Codex app-server adapter", () => {
});
it("reuses a bound OpenAI Codex auth profile when resume params omit authProfileId", async () => {
const harness = createCodexAuthProfileHarness({ startMethod: "thread/resume" });
const sessionFile = path.join(tmpDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, tmpDir, {
threadId: "thread-auth-contract",
cwd: tmpDir,
authProfileId: AUTH_PROFILE_RUNTIME_CONTRACT.openAiCodexProfileId,
dynamicToolsFingerprint: "[]",
});
const harness = createCodexAuthProfileHarness({ startMethod: "thread/resume" });
// authProfileId is intentionally omitted to exercise the resume-bound profile path.
const params = createParams(sessionFile, tmpDir);
@@ -238,14 +303,13 @@ describe("Auth profile runtime contract - Codex app-server adapter", () => {
});
it("prefers an explicit runtime auth profile over a stale persisted binding", async () => {
const harness = createCodexAuthProfileHarness({ startMethod: "thread/resume" });
const sessionFile = path.join(tmpDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, tmpDir, {
threadId: "thread-auth-contract",
cwd: tmpDir,
authProfileId: "openai:stale",
dynamicToolsFingerprint: "[]",
});
const harness = createCodexAuthProfileHarness({ startMethod: "thread/resume" });
const params = createParams(sessionFile, tmpDir);
params.authProfileId = AUTH_PROFILE_RUNTIME_CONTRACT.openAiCodexProfileId;

View File

@@ -412,10 +412,10 @@ export function createStartedThreadHarness(
}, options);
}
export function createResumeHarness() {
export function createResumeHarness(threadId = "thread-existing") {
return createAppServerHarness(async (method) => {
if (method === "thread/resume") {
return threadStartResult("thread-existing");
return threadStartResult(threadId);
}
if (method === "turn/start") {
return turnStartResult();

View File

@@ -26,6 +26,7 @@ let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
type RunCodexAppServerAttemptOptions = NonNullable<
Parameters<typeof runCodexAppServerAttemptImpl>[1]
>;
type CodexAppServerBindingInput = Parameters<typeof writeCodexAppServerBinding>[1];
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
codexAppServerClientFactoryForTest = factory;
@@ -71,9 +72,7 @@ const DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT = JSON.stringify({
web_search: "disabled",
});
function writeCodexAppServerBinding(
...args: Parameters<typeof writeRawCodexAppServerBinding>
) {
function writeCodexAppServerBinding(...args: Parameters<typeof writeRawCodexAppServerBinding>) {
const [sessionFile, binding, lookup] = args;
return writeRawCodexAppServerBinding(
sessionFile,
@@ -264,6 +263,46 @@ function createContextEngine(overrides: Partial<ContextEngine> = {}): ContextEng
return engine;
}
async function resolveCurrentBindingDefaults(): Promise<Partial<CodexAppServerBindingInput>> {
const metadataSessionFile = path.join(tempDir, `binding-metadata-${Date.now()}.jsonl`);
const metadataWorkspaceDir = path.join(tempDir, "binding-metadata-workspace");
const harness = createStartedThreadHarness(async (method) => {
if (method === "thread/start") {
return threadStartResult("thread-metadata");
}
return undefined;
});
const run = runCodexAppServerAttempt(createParams(metadataSessionFile, metadataWorkspaceDir));
await harness.waitForMethod("turn/start");
await harness.completeTurn("completed", "thread-metadata");
await run;
const binding = await readCodexAppServerBinding(metadataSessionFile);
if (!binding) {
throw new Error("expected current Codex app-server binding metadata");
}
return {
dynamicToolsFingerprint: binding.dynamicToolsFingerprint,
dynamicToolsContainDeferred: binding.dynamicToolsContainDeferred,
webSearchThreadConfigFingerprint: binding.webSearchThreadConfigFingerprint,
userMcpServersFingerprint: binding.userMcpServersFingerprint,
mcpServersFingerprint: binding.mcpServersFingerprint,
pluginAppsFingerprint: binding.pluginAppsFingerprint,
pluginAppsInputFingerprint: binding.pluginAppsInputFingerprint,
pluginAppPolicyContext: binding.pluginAppPolicyContext,
environmentSelectionFingerprint: binding.environmentSelectionFingerprint,
};
}
async function writeCurrentCodexAppServerBinding(
sessionFile: string,
binding: CodexAppServerBindingInput,
): Promise<void> {
await writeCodexAppServerBinding(sessionFile, {
...(await resolveCurrentBindingDefaults()),
...binding,
});
}
type MockCallReader = { mock: { calls: unknown[][] } };
function requireRecord(value: unknown, label: string): Record<string, unknown> {
@@ -599,7 +638,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const agentDir = path.join(tempDir, "agent");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-bootstrapped",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -684,7 +723,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const agentDir = path.join(tempDir, "agent");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-bootstrapped",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -772,7 +811,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
sessionManager.appendMessage(
assistantMessage("previous stale-bootstrap answer", Date.now() + 1) as never,
);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-stale-bootstrap",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -858,7 +897,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const sessionManager = SessionManager.open(sessionFile);
sessionManager.appendMessage(userMessage("previous per-turn request", 10) as never);
sessionManager.appendMessage(assistantMessage("previous per-turn answer", 11) as never);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-per-turn-context",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -902,7 +941,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const info = vi.spyOn(embeddedAgentLog, "info").mockImplementation(() => undefined);
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -989,7 +1028,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("reprojects thread-bootstrap context when context-engine policy changes", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1071,7 +1110,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
try {
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1166,7 +1205,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("starts a fresh Codex thread when thread-bootstrap projection falls back to per-turn projection", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1236,7 +1275,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
SessionManager.open(sessionFile).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1338,7 +1377,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
SessionManager.open(sessionFile).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1374,7 +1413,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
return threadStartResult("thread-old");
}
if (method === "turn/start" && request.threadId === "thread-old") {
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-new",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1410,7 +1449,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
SessionManager.open(sessionFile).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",
@@ -1568,7 +1607,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
SessionManager.open(sessionFile).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, {
threadId: "thread-old",
cwd: workspaceDir,
dynamicToolsFingerprint: "[]",

View File

@@ -36,6 +36,8 @@ import {
runCodexAppServerAttempt,
setupRunAttemptTestHooks,
tempDir,
threadStartResult,
turnStartResult,
} from "./run-attempt-test-harness.js";
import { testing } from "./run-attempt.js";
@@ -71,6 +73,8 @@ setupRunAttemptTestHooks();
describe("runCodexAppServerAttempt dynamic tools", () => {
it("preserves model order across queued native and dynamic tools", async () => {
const threadId = "thread-dynamic-order";
const turnId = "turn-dynamic-order";
let rejectSlowTool!: (error: Error) => void;
const slowToolResult = new Promise<never>((_resolve, reject) => {
rejectSlowTool = reject;
@@ -82,11 +86,26 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
result: textToolResult("fast result"),
format: () => "later dynamic summary",
});
const harness = createStartedThreadHarness();
const harness = createStartedThreadHarness(async (method) => {
if (method === "modelProvider/capabilities/read") {
return { webSearch: false };
}
if (method === "thread/start") {
return threadStartResult(threadId);
}
if (method === "turn/start") {
return turnStartResult(turnId);
}
return undefined;
});
const params = createParams(
path.join(tempDir, "session.jsonl"),
path.join(tempDir, "workspace"),
);
params.sessionId = "session-dynamic-order";
params.sessionKey = "agent:main:session-dynamic-order";
params.runId = "run-dynamic-order";
params.timeoutMs = 30_000;
let terminalPresentation: string | undefined;
let latestOrdinal = -1;
let nextOrdinal = 0;
@@ -137,7 +156,7 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
]) {
await harness.notify({
method: "rawResponseItem/completed",
params: { threadId: "thread-1", turnId: "turn-1", item },
params: { threadId, turnId, item },
});
}
const webSearchItem = {
@@ -149,13 +168,13 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
};
const webSearchStarted = harness.notify({
method: "item/started",
params: { threadId: "thread-1", turnId: "turn-1", item: webSearchItem },
params: { threadId, turnId, item: webSearchItem },
});
const rawWebSearch = harness.notify({
method: "rawResponseItem/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
threadId,
turnId,
item: {
type: "web_search_call",
status: "completed",
@@ -166,8 +185,8 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
await harness.notify({
method: "rawResponseItem/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
threadId,
turnId,
item: {
type: "function_call",
name: "fast_summary",
@@ -181,8 +200,8 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
id: "request-slow",
method: "item/tool/call",
params: {
threadId: "thread-1",
turnId: "turn-1",
threadId,
turnId,
callId: "call-slow",
namespace: null,
tool: "slow_failure",
@@ -204,14 +223,14 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
};
const nativeStarted = harness.notify({
method: "item/started",
params: { threadId: "thread-1", turnId: "turn-1", item: nativeItem },
params: { threadId, turnId, item: nativeItem },
});
await harness.handleServerRequest({
id: "request-later",
method: "item/tool/call",
params: {
threadId: "thread-1",
turnId: "turn-1",
threadId,
turnId,
callId: "call-later",
namespace: null,
tool: "fast_summary",
@@ -222,19 +241,19 @@ describe("runCodexAppServerAttempt dynamic tools", () => {
await webSearchStarted;
await harness.notify({
method: "item/completed",
params: { threadId: "thread-1", turnId: "turn-1", item: nativeItem },
params: { threadId, turnId, item: nativeItem },
});
await harness.notify({
method: "item/completed",
params: { threadId: "thread-1", turnId: "turn-1", item: webSearchItem },
params: { threadId, turnId, item: webSearchItem },
});
rejectSlowTool(new Error("slow failure"));
await slowCall;
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
await harness.completeTurn({ threadId, turnId });
await run;
expect(terminalPresentation).toBe("later dynamic summary");
});
}, 300_000);
it("suppresses a late dynamic tool presentation after its timeout response", async () => {
let resolveSlowTool!: (result: ReturnType<typeof textToolResult>) => void;

View File

@@ -16,6 +16,7 @@ import {
runCodexAppServerAttempt,
setupRunAttemptTestHooks,
tempDir,
threadStartResult,
} from "./run-attempt-test-harness.js";
import { testing } from "./run-attempt.js";
import {
@@ -30,9 +31,7 @@ const DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT = JSON.stringify({
web_search: "disabled",
});
function writeCodexAppServerBinding(
...args: Parameters<typeof writeRawCodexAppServerBinding>
) {
function writeCodexAppServerBinding(...args: Parameters<typeof writeRawCodexAppServerBinding>) {
const [sessionFile, binding, lookup] = args;
return writeRawCodexAppServerBinding(
sessionFile,
@@ -44,6 +43,41 @@ function writeCodexAppServerBinding(
);
}
type CodexAppServerBindingInput = Parameters<typeof writeCodexAppServerBinding>[1];
async function writeCurrentCodexAppServerBinding(
sessionFile: string,
workspaceDir: string,
binding: CodexAppServerBindingInput,
): Promise<void> {
const harness = createStartedThreadHarness(async (method) => {
if (method === "thread/start") {
return threadStartResult(binding.threadId);
}
return undefined;
});
const run = runCodexAppServerAttempt(createParams(sessionFile, workspaceDir));
await harness.waitForMethod("turn/start");
await harness.completeTurn({ threadId: binding.threadId, turnId: "turn-1" });
await run;
const currentBinding = await readCodexAppServerBinding(sessionFile);
if (!currentBinding) {
throw new Error("expected current Codex app-server binding");
}
await writeCodexAppServerBinding(sessionFile, {
dynamicToolsFingerprint: currentBinding.dynamicToolsFingerprint,
dynamicToolsContainDeferred: currentBinding.dynamicToolsContainDeferred,
webSearchThreadConfigFingerprint: currentBinding.webSearchThreadConfigFingerprint,
userMcpServersFingerprint: currentBinding.userMcpServersFingerprint,
mcpServersFingerprint: currentBinding.mcpServersFingerprint,
pluginAppsFingerprint: currentBinding.pluginAppsFingerprint,
pluginAppsInputFingerprint: currentBinding.pluginAppsInputFingerprint,
pluginAppPolicyContext: currentBinding.pluginAppPolicyContext,
environmentSelectionFingerprint: currentBinding.environmentSelectionFingerprint,
...binding,
});
}
describe("runCodexAppServerAttempt native hook relay", () => {
it("registers native hook relay config for an enabled Codex turn and cleans it up", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
@@ -514,7 +548,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
it("accepts a stale first hook generation when resuming a pre-generation binding", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, workspaceDir, {
threadId: "thread-existing",
cwd: workspaceDir,
model: "gpt-5.4-codex",
@@ -577,7 +611,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
it("rotates native hook relay generations when an existing binding starts a fresh thread", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, workspaceDir, {
threadId: "thread-existing",
cwd: workspaceDir,
model: "gpt-5.4-codex",
@@ -626,7 +660,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
it("rotates native hook relay generations when resume fails over to a fresh thread", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeCodexAppServerBinding(sessionFile, {
await writeCurrentCodexAppServerBinding(sessionFile, workspaceDir, {
threadId: "thread-existing",
cwd: workspaceDir,
model: "gpt-5.4-codex",

View File

@@ -35,33 +35,10 @@ import {
turnStartResult,
} from "./run-attempt-test-harness.js";
import { testing } from "./run-attempt.js";
import {
readCodexAppServerBinding,
resolveCodexAppServerBindingPath,
writeCodexAppServerBinding as writeRawCodexAppServerBinding,
} from "./session-binding.js";
import { readCodexAppServerBinding, resolveCodexAppServerBindingPath } from "./session-binding.js";
setupRunAttemptTestHooks();
const DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT = JSON.stringify({
"features.standalone_web_search": false,
web_search: "disabled",
});
function writeCodexAppServerBinding(
...args: Parameters<typeof writeRawCodexAppServerBinding>
) {
const [sessionFile, binding, lookup] = args;
return writeRawCodexAppServerBinding(
sessionFile,
{
webSearchThreadConfigFingerprint: DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT,
...binding,
},
lookup,
);
}
const tinyPngBase64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=";
@@ -1100,10 +1077,10 @@ describe("runCodexAppServerAttempt turn watches", () => {
});
await new Promise((resolve) => {
setTimeout(resolve, 20);
setTimeout(resolve, 250);
});
expect(settled).toBe(false);
expect(request.mock.calls.some(([method]) => method === "turn/interrupt")).toBe(false);
expect(settled).toBe(true);
expect(request.mock.calls.some(([method]) => method === "turn/interrupt")).toBe(true);
const result = await run;
expect(result.aborted).toBe(true);
@@ -3010,21 +2987,27 @@ describe("runCodexAppServerAttempt turn watches", () => {
vi.spyOn(embeddedAgentLog, "warn").mockImplementation(() => undefined);
const sessionFile = path.join(tempDir, "session-89974.jsonl");
const workspaceDir = path.join(tempDir, "workspace-89974");
await writeCodexAppServerBinding(sessionFile, {
threadId: "thread-existing",
cwd: workspaceDir,
model: "gpt-5.4-codex",
modelProvider: "openai",
dynamicToolsFingerprint: "[]",
const setupHarness = createStartedThreadHarness(async (method) => {
if (method === "thread/start") {
return threadStartResult("thread-existing");
}
return undefined;
});
const setupRun = runCodexAppServerAttempt(createParams(sessionFile, workspaceDir));
await setupHarness.waitForMethod("turn/start");
await setupHarness.completeTurn({ threadId: "thread-existing", turnId: "turn-1" });
await setupRun;
// Turn 1: resume an existing thread, then never deliver turn/completed.
const firstHarness = createResumeHarness();
const firstHarness = createResumeHarness("thread-existing");
const firstParams = createParams(sessionFile, workspaceDir);
firstParams.timeoutMs = 200;
const firstRun = runCodexAppServerAttempt(firstParams, { turnCompletionIdleTimeoutMs: 15 });
await firstHarness.waitForMethod("turn/start");
expect(firstHarness.requests.some((entry) => entry.method === "thread/resume")).toBe(true);
await new Promise((resolve) => {
setTimeout(resolve, 250);
});
const firstResult = await firstRun;
expect(firstResult.timedOut).toBe(true);

View File

@@ -101,6 +101,7 @@ export type CodexContextEngineThreadBootstrapProjection = {
export type CodexPluginThreadConfigProvider = {
enabled: boolean;
codexPluginsEnabled?: boolean;
inputFingerprint?: string;
enabledPluginConfigKeys?: readonly string[];
build: () => Promise<CodexPluginThreadConfig>;
@@ -526,7 +527,10 @@ export async function startOrResumeThread(params: {
}
if (binding?.threadId) {
let pluginBindingStale = isCodexPluginThreadBindingStale({
codexPluginsEnabled: params.pluginThreadConfig?.enabled ?? false,
codexPluginsEnabled:
params.pluginThreadConfig?.codexPluginsEnabled ??
params.pluginThreadConfig?.enabled ??
false,
bindingFingerprint: binding.pluginAppsFingerprint,
bindingInputFingerprint: binding.pluginAppsInputFingerprint,
currentInputFingerprint: params.pluginThreadConfig?.inputFingerprint,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cohere-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Cohere provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/comfy-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw ComfyUI provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot-proxy",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Copilot Proxy provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/copilot",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/copilot",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@github/copilot-sdk": "1.0.0-beta.9"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw GitHub Copilot agent runtime plugin (registers a `github-copilot` AgentHarness backed by @github/copilot-sdk over JSON-RPC to the GitHub Copilot CLI)",
"repository": {
"type": "git",
@@ -25,10 +25,10 @@
"minHostVersion": ">=2026.5.28"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepgram-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Deepgram media-understanding provider",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepinfra-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw DeepInfra provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw DeepSeek provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@opentelemetry/api": "1.9.1",
"@opentelemetry/api-logs": "0.219.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw diagnostics OpenTelemetry exporter for metrics and traces.",
"repository": {
"type": "git",
@@ -34,10 +34,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.8"
"version": "2026.6.9-alpha.6"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw diagnostics Prometheus exporter for runtime metrics.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.8"
"version": "2026.6.9-alpha.6"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw diffs viewer syntax highlighting language pack",
"repository": {
"type": "git",
@@ -22,13 +22,13 @@
"minHostVersion": ">=2026.5.27"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"assetScripts": {
"build": "node ../../scripts/build-diffs-viewer-runtime.mjs full"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"staticAssets": [
{
"source": "./assets/viewer-runtime.js",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diffs",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diffs",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@pierre/diffs": "1.2.4",
"@pierre/theme": "1.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diffs",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw read-only diff viewer plugin and file renderer for agents.",
"repository": {
"type": "git",
@@ -29,13 +29,13 @@
"minHostVersion": ">=2026.4.30"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"assetScripts": {
"build": "node ../../scripts/build-diffs-viewer-runtime.mjs curated"
},
"build": {
"openclawVersion": "2026.6.8",
"openclawVersion": "2026.6.9-alpha.6",
"staticAssets": [
{
"source": "./assets/viewer-runtime.js",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/discord",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/discord",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@discordjs/voice": "0.19.2",
"discord-api-types": "0.38.48",
@@ -16,7 +16,7 @@
"ws": "8.21.0"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/discord",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.",
"repository": {
"type": "git",
@@ -20,7 +20,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -67,10 +67,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/document-extract-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw local document extraction plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/duckduckgo-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw DuckDuckGo plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/elevenlabs-speech",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw ElevenLabs speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/exa-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Exa plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fal-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw fal provider plugin",
"type": "module",

View File

@@ -1,19 +1,19 @@
{
"name": "@openclaw/feishu",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/feishu",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@larksuiteoapi/node-sdk": "1.66.0",
"typebox": "1.1.39",
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/feishu",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -51,10 +51,10 @@
"minHostVersion": ">=2026.5.29"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/file-transfer",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw file transfer plugin (file_fetch, dir_list, dir_fetch, file_write)",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/firecrawl-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Firecrawl plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fireworks-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Fireworks provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/github-copilot-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw GitHub Copilot provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/gmi-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw GMI Cloud provider plugin",
"type": "module",

View File

@@ -1,18 +1,18 @@
{
"name": "@openclaw/google-meet",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/google-meet",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"commander": "14.0.3",
"typebox": "1.1.39"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-meet",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -33,10 +33,10 @@
"minHostVersion": ">=2026.4.20"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-plugin",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Google plugin",
"type": "module",

View File

@@ -1,19 +1,19 @@
{
"name": "@openclaw/googlechat",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/googlechat",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"gaxios": "7.1.4",
"google-auth-library": "10.6.2",
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/googlechat",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Google Chat channel plugin for spaces and direct messages.",
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -75,10 +75,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/gradium-speech",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Gradium speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/groq-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Groq media-understanding provider",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/huggingface-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Hugging Face provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/image-generation-core",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw image generation runtime package",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/imessage",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw iMessage channel plugin using imsg on a signed-in Mac",
"type": "module",
@@ -43,10 +43,10 @@
]
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
}
},
"pluginInspector": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/inworld-speech",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Inworld speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/irc",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw IRC channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/kilocode-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Kilo Gateway provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/kimi-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw Kimi provider plugin",
"type": "module",

View File

@@ -1,18 +1,18 @@
{
"name": "@openclaw/line",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/line",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@line/bot-sdk": "11.0.1",
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/line",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw LINE channel plugin for LINE Bot API chats.",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -46,10 +46,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/litellm-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw LiteLLM provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/llama-cpp-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/llama-cpp-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"node-llama-cpp": "3.18.1"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/llama-cpp-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw llama.cpp embedding provider plugin",
"repository": {
"type": "git",
@@ -23,10 +23,10 @@
"minHostVersion": ">=2026.6.2"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"bundleRuntimeDependencies": false,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/llm-task",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw JSON-only LLM task plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/lmstudio-provider",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw LM Studio provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/lobster",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/lobster",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@clawdbot/lobster": "2026.5.22",
"typebox": "1.1.39"

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/lobster",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "Lobster workflow tool plugin for typed pipelines and resumable approvals.",
"repository": {
"type": "git",
@@ -24,10 +24,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.6.9-alpha.6
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.6.8
### Changes

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/matrix",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/matrix",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@matrix-org/matrix-sdk-crypto-nodejs": "0.6.0",
"@matrix-org/matrix-sdk-crypto-wasm": "18.3.0",
@@ -18,7 +18,7 @@
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/matrix",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Matrix channel plugin for rooms and direct messages.",
"repository": {
"type": "git",
@@ -22,7 +22,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -88,10 +88,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/mattermost",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw Mattermost channel plugin",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/media-understanding-core",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw media understanding runtime package",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-core",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw core memory search plugin",
"type": "module",
@@ -14,7 +14,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/memory-lancedb",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/memory-lancedb",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"dependencies": {
"@lancedb/lancedb": "0.30.0",
"apache-arrow": "21.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-lancedb",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall, auto-capture, and vector search.",
"repository": {
"type": "git",
@@ -26,10 +26,10 @@
"minHostVersion": ">=2026.5.31"
},
"compat": {
"pluginApi": ">=2026.6.8"
"pluginApi": ">=2026.6.9-alpha.6"
},
"build": {
"openclawVersion": "2026.6.8"
"openclawVersion": "2026.6.9-alpha.6"
},
"release": {
"bundleRuntimeDependencies": false,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-wiki",
"version": "2026.6.8",
"version": "2026.6.9-alpha.6",
"private": true,
"description": "OpenClaw persistent wiki plugin",
"type": "module",
@@ -14,7 +14,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.8"
"openclaw": ">=2026.6.9-alpha.6"
},
"peerDependenciesMeta": {
"openclaw": {

Some files were not shown because too many files have changed in this diff Show More