mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-06 06:41:56 +00:00
155 lines
4.9 KiB
TypeScript
155 lines
4.9 KiB
TypeScript
import os from 'node:os'
|
|
import { randomUUID } from 'node:crypto'
|
|
import { resolve } from 'node:path'
|
|
|
|
import { ApiClient } from '@/api/api'
|
|
import type { ApiSessionClient } from '@/api/apiSession'
|
|
import type { AgentState, MachineMetadata, Metadata, Session } from '@/api/types'
|
|
import { notifyRunnerSessionStarted } from '@/runner/controlClient'
|
|
import { readSettings } from '@/persistence'
|
|
import { configuration } from '@/configuration'
|
|
import { logger } from '@/ui/logger'
|
|
import { runtimePath } from '@/projectPath'
|
|
import { getInvokedCwd } from '@/utils/invokedCwd'
|
|
import { readWorktreeEnv } from '@/utils/worktreeEnv'
|
|
import packageJson from '../../package.json'
|
|
|
|
export type SessionStartedBy = 'runner' | 'terminal'
|
|
|
|
export type SessionBootstrapOptions = {
|
|
flavor: string
|
|
startedBy?: SessionStartedBy
|
|
workingDirectory?: string
|
|
tag?: string
|
|
agentState?: AgentState | null
|
|
model?: string
|
|
modelReasoningEffort?: string
|
|
effort?: string
|
|
metadataOverrides?: Partial<Metadata>
|
|
}
|
|
|
|
export type SessionBootstrapResult = {
|
|
api: ApiClient
|
|
session: ApiSessionClient
|
|
sessionInfo: Session
|
|
metadata: Metadata
|
|
machineId: string
|
|
startedBy: SessionStartedBy
|
|
workingDirectory: string
|
|
}
|
|
|
|
export function buildMachineMetadata(): MachineMetadata {
|
|
return {
|
|
host: process.env.HAPI_HOSTNAME || os.hostname(),
|
|
platform: os.platform(),
|
|
happyCliVersion: packageJson.version,
|
|
homeDir: os.homedir(),
|
|
happyHomeDir: configuration.happyHomeDir,
|
|
happyLibDir: runtimePath()
|
|
}
|
|
}
|
|
|
|
export function buildSessionMetadata(options: {
|
|
flavor: string
|
|
startedBy: SessionStartedBy
|
|
workingDirectory: string
|
|
machineId: string
|
|
now?: number
|
|
metadataOverrides?: Partial<Metadata>
|
|
}): Metadata {
|
|
const happyLibDir = runtimePath()
|
|
const worktreeInfo = readWorktreeEnv()
|
|
const now = options.now ?? Date.now()
|
|
|
|
return {
|
|
path: options.workingDirectory,
|
|
host: process.env.HAPI_HOSTNAME || os.hostname(),
|
|
version: packageJson.version,
|
|
os: os.platform(),
|
|
machineId: options.machineId,
|
|
homeDir: os.homedir(),
|
|
happyHomeDir: configuration.happyHomeDir,
|
|
happyLibDir,
|
|
happyToolsDir: resolve(happyLibDir, 'tools', 'unpacked'),
|
|
startedFromRunner: options.startedBy === 'runner',
|
|
hostPid: process.pid,
|
|
startedBy: options.startedBy,
|
|
lifecycleState: 'running',
|
|
lifecycleStateSince: now,
|
|
flavor: options.flavor,
|
|
worktree: worktreeInfo ?? undefined,
|
|
...options.metadataOverrides
|
|
}
|
|
}
|
|
|
|
async function getMachineIdOrExit(): Promise<string> {
|
|
const settings = await readSettings()
|
|
const machineId = settings?.machineId
|
|
if (!machineId) {
|
|
console.error(`[START] No machine ID found in settings, which is unexpected since authAndSetupMachineIfNeeded should have created it. Please report this issue on ${packageJson.bugs}`)
|
|
process.exit(1)
|
|
}
|
|
logger.debug(`Using machineId: ${machineId}`)
|
|
return machineId
|
|
}
|
|
|
|
async function reportSessionStarted(sessionId: string, metadata: Metadata): Promise<void> {
|
|
try {
|
|
logger.debug(`[START] Reporting session ${sessionId} to runner`)
|
|
const result = await notifyRunnerSessionStarted(sessionId, metadata)
|
|
if (result?.error) {
|
|
logger.debug(`[START] Failed to report to runner (may not be running):`, result.error)
|
|
} else {
|
|
logger.debug(`[START] Reported session ${sessionId} to runner`)
|
|
}
|
|
} catch (error) {
|
|
logger.debug('[START] Failed to report to runner (may not be running):', error)
|
|
}
|
|
}
|
|
|
|
export async function bootstrapSession(options: SessionBootstrapOptions): Promise<SessionBootstrapResult> {
|
|
const workingDirectory = options.workingDirectory ?? getInvokedCwd()
|
|
const startedBy = options.startedBy ?? 'terminal'
|
|
const sessionTag = options.tag ?? randomUUID()
|
|
const agentState = options.agentState === undefined ? {} : options.agentState
|
|
|
|
const api = await ApiClient.create()
|
|
|
|
const machineId = await getMachineIdOrExit()
|
|
await api.getOrCreateMachine({
|
|
machineId,
|
|
metadata: buildMachineMetadata()
|
|
})
|
|
|
|
const metadata = buildSessionMetadata({
|
|
flavor: options.flavor,
|
|
startedBy,
|
|
workingDirectory,
|
|
machineId,
|
|
metadataOverrides: options.metadataOverrides
|
|
})
|
|
|
|
const sessionInfo = await api.getOrCreateSession({
|
|
tag: sessionTag,
|
|
metadata,
|
|
state: agentState,
|
|
model: options.model,
|
|
modelReasoningEffort: options.modelReasoningEffort,
|
|
effort: options.effort
|
|
})
|
|
|
|
const session = api.sessionSyncClient(sessionInfo)
|
|
|
|
await reportSessionStarted(sessionInfo.id, metadata)
|
|
|
|
return {
|
|
api,
|
|
session,
|
|
sessionInfo,
|
|
metadata,
|
|
machineId,
|
|
startedBy,
|
|
workingDirectory
|
|
}
|
|
}
|