Skip to content

Commit 554069d

Browse files
committed
Merge remote-tracking branch 'origin/master' into feat/master-retrieval-and-context
# Conflicts: # package.json
2 parents 7061f06 + 6761c09 commit 554069d

File tree

5 files changed

+170
-4
lines changed

5 files changed

+170
-4
lines changed

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ on:
55
pull_request:
66

77
jobs:
8+
version-sync:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
14+
- name: Check version consistency
15+
run: |
16+
pkg_ver=$(node -p "JSON.parse(require('fs').readFileSync('package.json','utf8')).version")
17+
plugin_ver=$(node -p "JSON.parse(require('fs').readFileSync('openclaw.plugin.json','utf8')).version")
18+
if [ "$pkg_ver" != "$plugin_ver" ]; then
19+
echo "::error::Version mismatch: package.json=$pkg_ver, openclaw.plugin.json=$plugin_ver"
20+
exit 1
21+
fi
22+
echo "Versions match: $pkg_ver"
23+
824
cli-smoke:
925
runs-on: ubuntu-latest
1026
steps:

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@
3535
]
3636
},
3737
"scripts": {
38-
"test": "node test/embedder-error-hints.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node test/plugin-manifest-regression.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs",
39-
"test:openclaw-host": "node test/openclaw-host-functional.mjs"
38+
"test": "node test/embedder-error-hints.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node test/plugin-manifest-regression.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs",
39+
"test:openclaw-host": "node test/openclaw-host-functional.mjs",
40+
"version": "node scripts/sync-plugin-version.mjs openclaw.plugin.json package.json && git add openclaw.plugin.json"
4041
},
4142
"devDependencies": {
4243
"commander": "^14.0.0",
4344
"jiti": "^2.6.0",
4445
"typescript": "^5.9.3"
4546
}
46-
}
47+
}

scripts/sync-plugin-version.mjs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { readFileSync, writeFileSync } from "node:fs";
2+
import path from "node:path";
3+
import { fileURLToPath } from "node:url";
4+
5+
function parseJsonStringToken(text, startIndex) {
6+
let index = startIndex + 1;
7+
8+
while (index < text.length) {
9+
const ch = text[index];
10+
if (ch === "\\") {
11+
index += 2;
12+
continue;
13+
}
14+
if (ch === "\"") {
15+
return {
16+
raw: text.slice(startIndex + 1, index),
17+
end: index,
18+
};
19+
}
20+
index += 1;
21+
}
22+
23+
throw new Error("Unterminated JSON string");
24+
}
25+
26+
function skipWhitespace(text, startIndex) {
27+
let index = startIndex;
28+
while (index < text.length && /\s/.test(text[index])) {
29+
index += 1;
30+
}
31+
return index;
32+
}
33+
34+
export function replaceTopLevelVersion(text, nextVersion) {
35+
let depth = 0;
36+
37+
for (let index = 0; index < text.length; index += 1) {
38+
const ch = text[index];
39+
40+
if (ch === "\"") {
41+
const token = parseJsonStringToken(text, index);
42+
43+
if (depth === 1 && token.raw === "version") {
44+
const colonIndex = skipWhitespace(text, token.end + 1);
45+
if (text[colonIndex] !== ":") {
46+
throw new Error("Malformed JSON: expected ':' after version key");
47+
}
48+
49+
const valueIndex = skipWhitespace(text, colonIndex + 1);
50+
if (text[valueIndex] !== "\"") {
51+
throw new Error("Malformed JSON: expected string version value");
52+
}
53+
54+
const currentValue = parseJsonStringToken(text, valueIndex);
55+
const escapedVersion = JSON.stringify(nextVersion);
56+
return `${text.slice(0, valueIndex)}${escapedVersion}${text.slice(currentValue.end + 1)}`;
57+
}
58+
59+
index = token.end;
60+
continue;
61+
}
62+
63+
if (ch === "{") {
64+
depth += 1;
65+
continue;
66+
}
67+
68+
if (ch === "}") {
69+
depth -= 1;
70+
}
71+
}
72+
73+
throw new Error("Top-level version field not found in manifest");
74+
}
75+
76+
export function syncManifestVersion({
77+
manifestPath,
78+
packagePath,
79+
}) {
80+
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
81+
const manifestText = readFileSync(manifestPath, "utf8");
82+
const updatedManifestText = replaceTopLevelVersion(manifestText, pkg.version);
83+
84+
if (updatedManifestText !== manifestText) {
85+
writeFileSync(manifestPath, updatedManifestText);
86+
return true;
87+
}
88+
89+
return false;
90+
}
91+
92+
const isDirectRun = process.argv[1] === fileURLToPath(import.meta.url);
93+
94+
if (isDirectRun) {
95+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
96+
const manifestPath = process.argv[2] ?? path.resolve(scriptDir, "../openclaw.plugin.json");
97+
const packagePath = process.argv[3] ?? path.resolve(scriptDir, "../package.json");
98+
99+
syncManifestVersion({ manifestPath, packagePath });
100+
}

test/functional-e2e.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ async function runFunctionalE2E() {
6262
const workDir = mkdtempSync(path.join(tmpdir(), "memory-lancedb-pro-e2e-"));
6363

6464
try {
65+
const pkg = JSON.parse(
66+
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
67+
);
6568
const { createMemoryCLI } = jiti("../cli.ts");
6669
const { MemoryStore } = jiti("../src/store.ts");
6770
const { createRetriever, DEFAULT_RETRIEVAL_CONFIG } = jiti("../src/retriever.ts");
@@ -145,7 +148,7 @@ async function runFunctionalE2E() {
145148
const versionOutput = await captureStdout(async () => {
146149
await program.parseAsync(["node", "openclaw", "memory-pro", "version"]);
147150
});
148-
assert.match(versionOutput, /1\.1\.0-beta\.5/);
151+
assert.match(versionOutput, new RegExp(pkg.version.replaceAll(".", "\\.")));
149152

150153
const importOutput = await captureStdout(async () => {
151154
await program.parseAsync([

test/sync-plugin-version.test.mjs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import assert from "node:assert/strict";
2+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3+
import { tmpdir } from "node:os";
4+
import path from "node:path";
5+
import test from "node:test";
6+
7+
import { syncManifestVersion } from "../scripts/sync-plugin-version.mjs";
8+
9+
test("syncManifestVersion only updates the top-level manifest version", () => {
10+
const tempDir = mkdtempSync(path.join(tmpdir(), "sync-plugin-version-"));
11+
12+
try {
13+
const packagePath = path.join(tempDir, "package.json");
14+
const manifestPath = path.join(tempDir, "openclaw.plugin.json");
15+
const originalManifest = `{
16+
"id": "memory-lancedb-pro",
17+
"version": "1.1.0-beta.5",
18+
"uiHints": {
19+
"llm.apiKey": {
20+
"label": "Legacy help text"
21+
},
22+
"llm.apiKey": {
23+
"label": "Current help text"
24+
}
25+
}
26+
}
27+
`;
28+
29+
writeFileSync(
30+
packagePath,
31+
JSON.stringify({ name: "memory-lancedb-pro", version: "1.1.1-beta.0" }, null, 2),
32+
);
33+
writeFileSync(manifestPath, originalManifest);
34+
35+
syncManifestVersion({ manifestPath, packagePath });
36+
37+
const updatedManifest = readFileSync(manifestPath, "utf8");
38+
assert.equal(
39+
updatedManifest,
40+
originalManifest.replace('"version": "1.1.0-beta.5"', '"version": "1.1.1-beta.0"'),
41+
);
42+
assert.equal(updatedManifest.match(/"llm\.apiKey"/g)?.length, 2);
43+
} finally {
44+
rmSync(tempDir, { recursive: true, force: true });
45+
}
46+
});

0 commit comments

Comments
 (0)