Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,21 @@ export async function runImportMarkdown(
// Parse each file for memory entries (lines starting with "- ")
for (const { filePath, scope: discoveredScope } of mdFiles) {
foundFiles++;
let content = await fsPromises.readFile(filePath, "utf-8");
let content: string;
try {
const stats = await fsPromises.stat(filePath);
if (!stats.isFile()) {
// Skip non-file entries (e.g. a directory named "YYYY-MM-DD.md")
console.warn(` [skip] not a file: ${filePath}`);
skipped++;
continue;
}
content = await fsPromises.readFile(filePath, "utf-8");
} catch (err) {
console.warn(` [skip] unreadable: ${filePath} — ${err}`);
skipped++;
continue;
}
// Strip UTF-8 BOM (e.g. from Windows Notepad-saved files)
content = content.replace(/^\uFEFF/, "");
// Normalize line endings: handle both CRLF (\r\n) and LF (\n)
Expand Down
1 change: 1 addition & 0 deletions scripts/ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const CI_TEST_MANIFEST = [
{ group: "core-regression", runner: "node", file: "test/strip-envelope-metadata.test.mjs", args: ["--test"] },
{ group: "cli-smoke", runner: "node", file: "test/cli-smoke.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/functional-e2e.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/import-markdown/import-markdown.test.mjs", args: ["--test"] },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep CI baseline verifier in sync with manifest changes

Adding test/import-markdown/import-markdown.test.mjs to CI_TEST_MANIFEST breaks the repo’s test entrypoint because scripts/verify-ci-test-manifest.mjs enforces an exact baseline list/order and does not include this new file. In this state, node scripts/verify-ci-test-manifest.mjs (and therefore npm test) fails immediately with unexpected manifest entry, so CI cannot run the intended test suite.

Useful? React with 👍 / 👎.

{ group: "core-regression", runner: "node", file: "test/retriever-rerank-regression.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-memory-lifecycle.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-extractor-branches.mjs" },
Expand Down
1 change: 1 addition & 0 deletions scripts/verify-ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const EXPECTED_BASELINE = [
{ group: "core-regression", runner: "node", file: "test/strip-envelope-metadata.test.mjs", args: ["--test"] },
{ group: "cli-smoke", runner: "node", file: "test/cli-smoke.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/functional-e2e.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/import-markdown/import-markdown.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/retriever-rerank-regression.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-memory-lifecycle.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-extractor-branches.mjs" },
Expand Down
33 changes: 33 additions & 0 deletions test/import-markdown/import-markdown.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,39 @@ describe("import-markdown CLI", () => {
);
});
});

describe("skip non-file .md entries", () => {
it("skips a directory named YYYY-MM-DD.md without aborting import", async () => {
const wsDir = await setupWorkspace("nonfile-test");
// Create memory/ subdirectory first
await mkdir(join(wsDir, "memory"), { recursive: true });
// Create a real .md file
await writeFile(
join(wsDir, "memory", "2026-04-11.md"),
"- Real file entry\n",
"utf-8",
);
// Create a directory that looks like a .md file (the bug scenario)
const fakeDir = join(wsDir, "memory", "2026-04-12.md");
await mkdir(fakeDir, { recursive: true });

const ctx = { embedder: mockEmbedder, store: mockStore };
let threw = false;
try {
const { imported, skipped } = await runImportMarkdown(ctx, {
openclawHome: testWorkspaceDir,
workspaceGlob: "nonfile-test",
});
// Should have imported the real file (1 entry from "- Real file entry")
assert.strictEqual(imported, 1, "should import the real .md file");
assert.ok(skipped >= 0);
} catch (err) {
threw = true;
throw new Error(`Import aborted on .md directory: ${err}`);
}
assert.ok(!threw, "import should not abort when encountering .md directory");
});
});
});

// ────────────────────────────────────────────────────────────────────────────── Test runner helper ──────────────────────────────────────────────────────────────────────────────
Expand Down
Loading