mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
/**
|
|
* `LocalSpillStore`: the host-filesystem implementation of the
|
|
* `@deepseek-ai/dsh-spill` storage seam. Persists a tool's oversized text to a
|
|
* private, session-scoped file (see `./store.ts` for the traversal-safe naming
|
|
* and exclusive owner-only write) and returns a path locator plus local
|
|
* read/grep retrieval guidance.
|
|
*
|
|
* @module @deepseek-ai/dsh-spill-local
|
|
*/
|
|
|
|
import { Context } from 'cordis'
|
|
import { resolve } from 'node:path'
|
|
import z from 'schemastery'
|
|
import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill'
|
|
import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill'
|
|
import { privateRoot, saveTextFile } from './store.ts'
|
|
|
|
export { encodeSegment, privateRoot, saveTextFile, sessionDir } from './store.ts'
|
|
export type { SavedText, SaveTextOptions } from './store.ts'
|
|
|
|
/** Plugin config (all optional — `static Config` supplies the defaults). */
|
|
export interface Config {
|
|
/**
|
|
* Root directory for spill files. Omitted uses a lazily-created private
|
|
* (0700) per-process directory under the OS temp dir — the safe default for
|
|
* a local deployment. Set it to keep spill files under a known location.
|
|
*/
|
|
root?: string
|
|
}
|
|
|
|
/**
|
|
* Local-filesystem spill backend. Files land under `<root>/session-<hash>/…`
|
|
* with unpredictable names, an exclusive owner-only (0600) write, and a private
|
|
* (0700) root — a spilled tool result must not be readable by other local users
|
|
* or redirectable via a planted symlink.
|
|
*/
|
|
export class LocalSpillStore extends SpillStore {
|
|
static Config: z<Config> = z.object({
|
|
root: z.string(),
|
|
})
|
|
|
|
/** Resolved absolute spill root (config `root`, else the private default), fixed at construction. */
|
|
readonly root: string
|
|
|
|
constructor(ctx: Context, config: Config) {
|
|
super(ctx)
|
|
this.root = config.root !== undefined ? resolve(config.root) : privateRoot()
|
|
}
|
|
|
|
async saveText(input: SaveTextSpill): Promise<SpillRef> {
|
|
const saved = await saveTextFile({
|
|
root: this.root,
|
|
sessionId: input.owner.sessionId,
|
|
suggestedName: input.suggestedName,
|
|
content: input.content,
|
|
})
|
|
return {
|
|
locator: SpillLocator(saved.path),
|
|
bytes: saved.bytes,
|
|
retrievalHint: 'Use read with offset/limit, or grep this path to search within it.',
|
|
}
|
|
}
|
|
}
|
|
|
|
export default LocalSpillStore
|