Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
19685617cThis file is pinned to the selected release. Download the original to open it in your design tool.
/** Session-scoped harness content. No native skill directories or shared mutable engine config.
* Create snapshots instructions/env/argv; resume reads that snapshot; fork copies it under a new
* key. Toolchains and skill assets stay at their installed package paths, as in spec 1.
*/
import { createHash } from 'node:crypto'
import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'
import { basename, join, resolve } from 'node:path'
import { z } from 'zod'
import { PROCESS_ENGINES, type AgentEngine } from '../engines/types.js'
import { HARNESS_BOOTSTRAP, harnessAdapter } from './adapters.js'
import { installedDsh, type InstalledDsh } from './installed.js'
import { dshAccountEnv, dshLaunch, type DshAccount, type DshLaunch } from './launch.js'
import { compatibleHarnessEngines } from './compatibility.js'
import { skillDirsIn } from './materialize.js'
import { installLessons, type RuntimeLessons } from '../pair/learn/publish.js'
const Snapshot = z.object({
version: z.literal(1),
id: z.string(),
engine: z.enum(PROCESS_ENGINES as [typeof PROCESS_ENGINES[number], ...typeof PROCESS_ENGINES[number][]]),
instructions: z.string(),
env: z.record(z.string(), z.string()),
args: z.array(z.string()),
skills: z.array(z.object({ name: z.string().regex(/^[^/\\\x00]+$/).refine(name => name !== '.' && name !== '..'), dir: z.string() })),
})
type RuntimeSnapshot = z.infer<typeof Snapshot>
export function harnessRuntimeDir(workspace: string, key: string): string {
if (!key) throw new Error('A harness runtime needs a session key')
return join(workspace, '.harness', 'runtime', createHash('sha256').update(key).digest('hex'))
}
/** Do not follow user-created links when writing managed files. The project itself may be a link. */
function ensureRuntimeDir(workspace: string, dir: string): void {
const root = resolve(workspace)
let path = root
for (const part of dir.slice(root.length + 1).split('/')) {
path = join(path, part)
if (existsSync(path) || isLink(path)) {
const stat = lstatSync(path)
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(`Harness runtime directory is not a plain directory: ${path}`)
} else mkdirSync(path)
}
}
function isLink(path: string): boolean {
try { return lstatSync(path).isSymbolicLink() } catch { return false }
}
function writeManagedFile(path: string, body: string): void {
if (isLink(path)) throw new Error(`Refusing to replace a symlink: ${path}`)
writeFileSync(path, body, { mode: 0o600 })
}
/** Older versions appended a marker without an end marker. Remove only text that exactly matches
* an installed package's instructions; refuse ambiguous edits instead of guessing where user text
* ends. Also remove only native skill links whose targets are demonstrably owned by that package.
*/
export function migrateHarnessInstructions(workspace: string, current: InstalledDsh,
lookup: (id: string) => InstalledDsh | null | undefined = installedDsh): void {
const path = join(workspace, 'AGENTS.md')
if (!existsSync(path)) return
const before = readFileSync(path, 'utf8')
let after = before
const packages: InstalledDsh[] = []
for (const match of before.matchAll(/^<!-- harness:dsh ([a-z0-9/-]+) -->\r?\n/gm)) {
const id = match[1]!
const pkg = id === current.id || current.manifest.formerly?.includes(id) ? current : lookup(id)
const instructions = pkg?.manifest.agent?.instructions
if (!pkg || !instructions) throw new Error(`Cannot safely migrate old harness instructions for ${id} in ${path}; restore the package or remove its marked section.`)
const body = readFileSync(join(pkg.realDir, instructions), 'utf8').trim()
const block = `${match[0]}${body}\n`
if (!after.includes(block)) throw new Error(`The old harness instructions for ${id} in ${path} were edited; move that marked section out of AGENTS.md before launching.`)
after = after.replace(block, '')
packages.push(pkg)
}
if (after === before) return
// Keep the exact pre-migration bytes; never replace somebody's earlier backup.
const backup = join(workspace, '.harness', 'legacy-AGENTS.md')
ensureRuntimeDir(workspace, join(resolve(workspace), '.harness'))
if (!existsSync(backup) && !isLink(backup)) writeFileSync(backup, before, { flag: 'wx', mode: 0o600 })
writeManagedFile(path, after)
for (const pkg of packages) {
for (const root of pkg.manifest.agent?.skills ?? []) {
for (const skill of skillDirsIn(join(pkg.realDir, root))) {
for (const native of ['.claude/skills', '.agents/skills']) {
if (isLink(join(workspace, native.split('/')[0]!)) || isLink(join(workspace, native))) continue
const link = join(workspace, native, basename(skill))
// unlinkSync, not rmSync: on current Node rmSync follows a link to a directory and
// throws EISDIR, which crashed the migration it exists to finish. A link is unlinked.
if (isLink(link) && resolve(link, '..', readlinkSync(link)) === resolve(skill)) unlinkSync(link)
}
}
}
}
}
function installBootstrap(workspace: string, engine: AgentEngine): void {
const adapter = harnessAdapter(engine)
const file = adapter.instructionFiles.find(name => existsSync(join(workspace, name)))
?? (engine === 'claude' ? 'CLAUDE.md' : 'AGENTS.md')
const path = join(workspace, file)
const before = existsSync(path) ? readFileSync(path, 'utf8') : ''
if (before.includes(HARNESS_BOOTSTRAP)) return
if (before.includes('<!-- harness:runtime')) throw new Error(`The Harness bootstrap in ${path} was edited; restore it before launching.`)
const projectRules = engine === 'claude' && existsSync(join(workspace, 'AGENTS.md')) && !before.split('\n').some(line => line.trim() === '@AGENTS.md')
? '@AGENTS.md\n' : ''
// Preserve all project bytes. Only the generic, env-dispatched bootstrap is shared by sessions.
writeManagedFile(path, `${before}${before.endsWith('\n') || !before ? '' : '\n'}\n${projectRules}${HARNESS_BOOTSTRAP}`)
}
function snapshot(dsh: InstalledDsh, workspace: string, engine: AgentEngine): RuntimeSnapshot {
harnessAdapter(engine)
const source = dsh.manifest.agent?.instructions
const instructions = source ? readFileSync(join(dsh.realDir, source), 'utf8') : ''
const skills: RuntimeSnapshot['skills'] = []
for (const root of dsh.manifest.agent?.skills ?? []) {
const dirs = skillDirsIn(join(dsh.realDir, root))
if (!dirs.length) throw new Error(`No SKILL.md under ${join(dsh.realDir, root)}; repair the harness installation.`)
for (const dir of dirs) {
const name = basename(dir)
const found = skills.find(skill => skill.name === name)
if (found && found.dir !== dir) throw new Error(`Duplicate harness skill name: ${name}`)
if (!found) skills.push({ name, dir })
}
}
const launch = dshLaunch(dsh, workspace, {}, engine)
return Snapshot.parse({ version: 1, id: dsh.id, engine, instructions, env: launch.env, args: launch.args, skills })
}
/** Prepare before spawning any engine process. `sourceKey` is a fork's original bundle. A saved
* bundle is authoritative: changing the store default or instructions cannot retarget a session.
*/
/**
* Why `engine` cannot run the harness `id`, or null when it can. The words are what a refused
* create says, so they name what WOULD work rather than only what was wrong.
*/
export function incompatibleHarnessEngine(id: string, manifest: { kind?: string; engine?: AgentEngine },
engine: AgentEngine): string | null {
const supported = compatibleHarnessEngines(manifest)
if (supported.includes(engine)) return null
return supported.length
? `${id} supports ${supported.join(', ')}; ${engine} is not compatible`
: `${id} cannot run as an agent`
}
/**
* The runtime bundle a fork copies. A session records its key when it is created; one created
* before keys were recorded still has a bundle under its agent id if it ran on this version, and
* that is the one to copy. Neither means the fork starts a fresh bundle rather than failing.
*/
export function forkRuntimeKey(source: { cwd: string; agentId: string; dshRuntime?: string | null }): string | null {
if (source.dshRuntime) return source.dshRuntime
return existsSync(join(harnessRuntimeDir(source.cwd, source.agentId), 'runtime.json')) ? source.agentId : null
}
/**
* `prepare`, refused rather than thrown. A runtime that cannot be prepared — a missing skill, a
* corrupt snapshot, an occupied path — has to fail the one create or fork that asked for it, never
* the daemon that is serving every other session.
*/
export function harnessLaunchOrRefusal(prepare: () => DshLaunch):
{ ok: true; launch: DshLaunch } | { ok: false; error: 'DSH_RUNTIME_FAILED'; detail: string } {
try {
return { ok: true, launch: prepare() }
} catch (error) {
return { ok: false, error: 'DSH_RUNTIME_FAILED', detail: error instanceof Error ? error.message : String(error) }
}
}
/**
* `lessons`: the approved lesson skills this session loads (pair/learn/publish.ts runtimeLessons). They are
* copied, read-only, to `<runtime>/lessons` and indexed in CONTEXT.md, one line each — the Store runtime path is how a
* lesson reaches every engine without a byte in an engine's own folders. Never fails a launch.
*/
export function prepareHarnessLaunch(dsh: InstalledDsh, workspace: string, engine: AgentEngine,
key: string, account: DshAccount = {}, sourceKey?: string | null, lessons?: RuntimeLessons | null): DshLaunch {
const adapter = harnessAdapter(engine)
if (dsh.manifest.kind === 'viewer') throw new Error(`${dsh.id} is a viewer, not a harness`)
const ws = realpathSync(workspace)
const dir = harnessRuntimeDir(ws, key)
ensureRuntimeDir(ws, dir)
const ignoreFile = join(ws, '.harness', '.gitignore')
const ignored = existsSync(ignoreFile) ? readFileSync(ignoreFile, 'utf8') : ''
const ignoreRules = ['runtime/', 'legacy-AGENTS.md'].filter(rule => !ignored.split('\n').includes(rule))
if (ignoreRules.length) writeManagedFile(ignoreFile, `${ignored}${ignored && !ignored.endsWith('\n') ? '\n' : ''}${ignoreRules.join('\n')}\n`)
const file = join(dir, 'runtime.json')
const from = sourceKey ? join(harnessRuntimeDir(ws, sourceKey), 'runtime.json') : file
if (sourceKey) {
ensureRuntimeDir(ws, harnessRuntimeDir(ws, sourceKey))
if (!existsSync(from)) throw new Error(`The original harness runtime is missing: ${from}`)
}
if (isLink(from)) throw new Error(`Harness runtime snapshot is a symlink: ${from}`)
const data = existsSync(from) ? Snapshot.parse(JSON.parse(readFileSync(from, 'utf8'))) : snapshot(dsh, ws, engine)
if (data.engine !== engine || (data.id !== dsh.id && !dsh.manifest.formerly?.includes(data.id))) {
throw new Error(`Harness runtime belongs to ${data.id} / ${data.engine}, not ${dsh.id} / ${engine}`)
}
if (sourceKey && (existsSync(file) || isLink(file))) {
if (isLink(file)) throw new Error(`Harness runtime snapshot is a symlink: ${file}`)
const saved = Snapshot.parse(JSON.parse(readFileSync(file, 'utf8')))
if (JSON.stringify(saved) !== JSON.stringify(data)) throw new Error(`The fork destination already has a different harness runtime: ${file}`)
}
const skillsDir = join(dir, 'skills')
ensureRuntimeDir(ws, skillsDir)
// Validate before modifying project instructions or committing a snapshot.
for (const skill of data.skills) {
if (!existsSync(join(skill.dir, 'SKILL.md'))) throw new Error(`Harness skill is missing: ${skill.dir}; repair the harness installation.`)
const link = join(skillsDir, skill.name)
if (existsSync(link) || isLink(link)) {
if (!isLink(link) || readlinkSync(link) !== skill.dir) throw new Error(`Harness skill path is already occupied: ${link}`)
} else symlinkSync(skill.dir, link)
}
migrateHarnessInstructions(ws, dsh)
installBootstrap(ws, engine)
const lessonIndex = installLessons(dir, lessons)
const env: Record<string, string> = { ...data.env, ...dshAccountEnv(account), HARNESS_CONTEXT_FILE: join(dir, 'CONTEXT.md'), HARNESS_SKILLS_DIR: skillsDir }
// Spec-1 packages used their default engine's discovery paths in env. Translate the path, not
// arbitrary engine names or source paths inside an upstream installation.
for (const [name, value] of Object.entries(env)) {
env[name] = value.replaceAll(`${ws}/.claude/skills`, skillsDir).replaceAll(`${ws}/.agents/skills`, skillsDir)
}
const context = [
`# ${dsh.manifest.name} (${data.id})`,
`Engine: ${engine}. Workspace: ${JSON.stringify(ws)}.`,
'Use your file and shell tools for these instructions, skills, and toolchain commands.',
'Legacy references to .claude/skills or .agents/skills mean HARNESS_SKILLS_DIR for this session.',
'', data.instructions.trim()
.replace(/^You are (?:Claude Code|Codex) in /gm, 'You are an agent in ')
// Rewrite workspace-relative examples into executable, quoted commands. Upstream paths such
// as $STUDIO_UPSTREAM/.claude/skills remain source paths and must not be redirected.
.replace(/(?<![\w/$.{}-])\.(?:claude|agents)\/skills(?![\w-])/g, '"$HARNESS_SKILLS_DIR"'),
'', '## Harness skills',
...data.skills.map(skill => `- ${skill.name}: ${JSON.stringify(join(skillsDir, skill.name, 'SKILL.md'))}`),
'',
...lessonIndex,
].join('\n')
writeManagedFile(env.HARNESS_CONTEXT_FILE!, context)
if (!existsSync(file)) writeManagedFile(file, `${JSON.stringify(data, null, 2)}\n`)
return { env, args: [...data.args, ...(adapter.contextArgs?.(env.HARNESS_CONTEXT_FILE!) ?? [])] }
}