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
5 changes: 5 additions & 0 deletions .changeset/session-workdir-resume-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Restore older working-directory sessions in `/sessions` and `kimi --continue`.
4 changes: 3 additions & 1 deletion apps/kimi-code/src/cli/v2/run-v2-print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,9 @@ async function resolveNativeSession(

if (opts.continue) {
const page = await index.listRecent({});
const previous = page.items.find((summary) => summary.cwd === workDir);
const previous = page.items.find(
(summary) => summary.cwd !== undefined && resolve(summary.cwd) === resolve(workDir),
);
if (previous !== undefined) {
const session = await resumeById(previous.id);
const agent = await ensureMainAgent(session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,20 @@ export class FileSessionIndex extends Disposable implements ISessionIndex {

async listRecent(query: SessionListQuery): Promise<Page<SessionSummary>> {
return this.withReadModel(
(generation) => this.listRecentFromReadModel(generation, query),
async (generation) => {
const page = await this.listRecentFromReadModel(generation, query);
// A workspace-scoped read that returns nothing can still hide sessions
// that exist on disk but were not projected into the read model (e.g.
// legacy/v1-era sessions recorded with only `workDir`, or sessions in
// alias buckets). Coalesce onto the authoritative source so `/sessions`
// (working-directory scope) and `--continue` never hide them. Unscooped
Comment on lines +272 to +276

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 Move method-body narration into the file header

This newly added explanatory block sits inside listRecent and narrates the implementation, while the scoped v2 guide requires comments to live solely in the top-of-file /** */ block and describe external responsibilities. Remove the inline narration or fold the relevant responsibility-level context into the existing module header.

AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L36-L38

Useful? React with 👍 / 👎.

// reads stay on the projected recency column.
if (page.items.length === 0 && query.workspaceIds !== undefined) {

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 Include authoritative misses in every affected listing

When a published generation omits a legacy/v1 session, this fallback runs only if the projected workspace page is completely empty. If that workspace has even one projected session, /sessions returns the nonempty stale page and still hides the omitted sessions; moreover, --continue calls listRecent({}), so its unscoped query can never enter this branch. Thus the exact stale-generation scenario this change targets remains broken for partial workspace misses and all unscoped resume reads; merge or otherwise reconcile authoritative results rather than treating only an empty scoped page as a miss.

AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L81-L83

Useful? React with 👍 / 👎.

const legacy = await this.listLegacy(query);
if (legacy.items.length > 0) return legacy;
}
return page;
},
() => this.listLegacy(query),
);
}
Expand Down
16 changes: 16 additions & 0 deletions packages/agent-core-v2/test/app/sessionIndex/sessionIndex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,22 @@ describe('FileSessionIndex (read model)', () => {
expect(fileStorage.listCalls).toBe(0);
});

it('coalesces a workspace-scoped miss onto the authoritative directory', async () => {
const store = build();
await store.prepare();
store.stopReconcileLoop();
// A legacy/v1-era session recorded with only `workDir` (no `cwd`) that
// exists on disk but was never projected into the read model.
await seedSession('legacy', { workDir: WORK_DIR, createdAt: 1, updatedAt: 2 });

// Read model answers empty for the workspace; the built-in fallback must
// surface the on-disk session so `/sessions` (cwd scope) and --continue
// do not hide it.
const page = await store.listRecent({ workspaceIds: [workspaceId] });
expect(page.items.map((s) => s.id)).toEqual(['legacy']);
expect(page.items[0]).toMatchObject({ cwd: WORK_DIR });
});

it('paginates exactly through same-millisecond ties', async () => {
const specs: [string, number][] = [
['a', 100],
Expand Down