Loading files
/**
* What is installed on THIS machine: `~/.harness/dsh/installed.json` plus one directory (or, for a
* `--link` install, one symlink) per DSH under `~/.harness/dsh/<owner>/<name>`.
*
* The index is the source of truth for "installed"; a directory without an index row is ignored,
* and a row whose manifest no longer parses is reported broken rather than silently dropped, so a
* DSH that breaks on update is visible in `harness dsh list` instead of vanishing from the picker.
*/
import { mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs'
import { randomUUID } from 'node:crypto'
import { join } from 'node:path'
import { env } from '../config/env.js'
import { DSH_ID_RE, readDshManifest, type DshManifest } from './manifest.js'
export interface InstalledDshRecord {
id: string
/** `<root>/<owner>/<name>`, whether a clone or a symlink. */
dir: string
/** The git URL or local path it came from. */
source: string
ref: string | null
/** The folder of `source` that was installed, for a package that is one folder of a repo. */
path?: string | null
commit: string | null
/** Git tree of the package folder, independent of unrelated monorepo commits. */
revision?: string | null
/** True when `dir` is a symlink to a checkout — the development loop. */
linked: boolean
installedAt: number
updatedAt?: number
}
export interface InstalledDsh extends InstalledDshRecord {
manifest: DshManifest
/** `dir` with symlinks resolved — where the files really are. */
realDir: string
}
export interface BrokenDsh extends InstalledDshRecord {
error: string
}
const INDEX_FILE = 'installed.json'
export function dshRootDir(): string {
return env.DSH_DIR
}
export function dshInstallDir(id: string): string {
return join(dshRootDir(), ...id.split('/'))
}
function indexPath(): string {
return join(dshRootDir(), INDEX_FILE)
}
function validRecord(value: unknown): value is InstalledDshRecord {
if (!value || typeof value !== 'object') return false
const row = value as Partial<InstalledDshRecord>
return typeof row.id === 'string' && DSH_ID_RE.test(row.id)
&& typeof row.dir === 'string' && row.dir.length > 0
&& typeof row.source === 'string'
&& (row.ref === null || typeof row.ref === 'string')
&& (row.commit === null || typeof row.commit === 'string')
&& typeof row.linked === 'boolean'
&& typeof row.installedAt === 'number'
}
export function readInstalledIndex(): InstalledDshRecord[] {
let text: string
try {
text = readFileSync(indexPath(), 'utf8')
} catch {
return []
}
try {
const parsed = JSON.parse(text) as unknown
return Array.isArray(parsed) ? parsed.filter(validRecord) : []
} catch {
return []
}
}
export function writeInstalledIndex(records: readonly InstalledDshRecord[]): void {
mkdirSync(dshRootDir(), { recursive: true, mode: 0o700 })
const temporary = `${indexPath()}.${randomUUID()}.tmp`
writeFileSync(temporary, JSON.stringify(records, null, 2) + '\n', { mode: 0o600 })
renameSync(temporary, indexPath())
}
export function upsertInstalledRecord(record: InstalledDshRecord): void {
const others = readInstalledIndex().filter((row) => row.id !== record.id)
writeInstalledIndex([...others, record].sort((a, b) => a.id.localeCompare(b.id)))
invalidateInstalledDsh()
}
export function removeInstalledRecord(id: string): boolean {
const before = readInstalledIndex()
const after = before.filter((row) => row.id !== id)
if (after.length === before.length) return false
writeInstalledIndex(after)
invalidateInstalledDsh()
return true
}
/** Load one record's manifest, or say why it is broken. */
export function resolveInstalled(record: InstalledDshRecord): InstalledDsh | BrokenDsh {
let realDir: string
try {
realDir = realpathSync(record.dir)
} catch {
// Gone, or a link to nothing: realpath fails exactly where existsSync would say false.
return { ...record, error: `${record.dir} is missing` }
}
const manifest = readDshManifest(realDir)
if (!manifest.ok) return { ...record, error: manifest.error }
if (manifest.manifest.id !== record.id) {
return { ...record, error: `manifest id ${manifest.manifest.id} does not match the installed id ${record.id}` }
}
return { ...record, manifest: manifest.manifest, realDir }
}
export function isBrokenDsh(value: InstalledDsh | BrokenDsh): value is BrokenDsh {
return 'error' in value
}
// The daemon asks "is this agent's DSH installed" on every frame it projects, which is every
// announce of every agent. A short cache keeps that off the disk; installs and removals clear it.
const CACHE_TTL_MS = 2_000
let cache: { at: number; installed: InstalledDsh[]; broken: BrokenDsh[] } | null = null
function stateNow(): { installed: InstalledDsh[]; broken: BrokenDsh[] } {
if (cache && Date.now() - cache.at < CACHE_TTL_MS) return cache
const installed: InstalledDsh[] = []
const broken: BrokenDsh[] = []
for (const entry of readInstalledIndex().map(resolveInstalled)) {
if (isBrokenDsh(entry)) broken.push(entry)
else installed.push(entry)
}
cache = { at: Date.now(), installed, broken }
return cache
}
/** Forget the cached index — after an install, a removal, or in a spec that rewrites the directory. */
export function invalidateInstalledDsh(): void {
cache = null
}
/** Every installed DSH whose manifest loads. Broken ones are returned separately by `listDshState`. */
export function listInstalledDsh(): InstalledDsh[] {
return stateNow().installed
}
export function listDshState(): { installed: InstalledDsh[]; broken: BrokenDsh[] } {
return stateNow()
}
/**
* The installed harness for an id — by its own id first, then by a name it went by before
* (`formerly` in the manifest): an agent created under the old name keeps its harness, its viewer
* and its verdict across a rename instead of falling back to a plain engine.
*/
export function installedDsh(id: string): InstalledDsh | undefined {
const { installed } = stateNow()
return installed.find((entry) => entry.id === id)
?? installed.find((entry) => entry.manifest.formerly?.includes(id))
}
442335385This file is pinned to the selected release. Download the original to open it in your design tool.