feat: add deterministic daily ops SOP and verified dev lifecycle

This commit is contained in:
Codex committed 2026-10-21 16:50:11 +09:00
1 parent dac4af53e0
commit 2aafb6f92f
16 files changed
+935 -5

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
/** Opt-in development readiness only. Never exposes a network/debug endpoint. */
import { app, type BrowserWindow } from 'electron'
import { promises as fs } from 'node:fs'
import { join, resolve } from 'node:path'
import { randomUUID } from 'node:crypto'
export function attachDevOpsHealth(window: BrowserWindow): void {
const runId = process.env.YCODE_OPS_RUN_ID
if (app.isPackaged || !runId || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(runId)) return
const root = resolve(process.cwd()), directory = join(root, '.tmp', 'ops')
const destination = join(directory, 'renderer-health.json')
let busy = false, stopped = false, responsive = true, generation = 0
let writes: Promise<void> = Promise.resolve()
const invalidate = (): void => { generation++; void publish(false).catch(() => undefined) }
function publish(ready: boolean): Promise<void> {
const expectedGeneration = generation
const operation = writes.then(async () => {
if (expectedGeneration !== generation) return
// The controller owns this directory. Do not create or follow an arbitrary linked path.
const actualDirectory = await fs.realpath(directory)
const canonical = (value: string): string => process.platform === 'win32' ? value.toLowerCase() : value
if (canonical(actualDirectory) !== canonical(directory)) return
const temporary = join(directory, `.health-${process.pid}-${randomUUID()}.tmp`)
try {
await fs.writeFile(temporary, JSON.stringify({ runId, pid: process.pid,
rendererPid: window.webContents.isDestroyed() ? 0 : window.webContents.getOSProcessId(),
checkedAt: Date.now(), ready }), { flag: 'wx', mode: 0o600 })
if (expectedGeneration === generation) await fs.rename(temporary, destination)
} finally { await fs.rm(temporary, { force: true }).catch(() => undefined) }
})
writes = operation.catch(() => undefined)
return operation
}
async function probe(): Promise<void> {
if (busy || stopped) return
busy = true
const current = generation
try {
let ready = false
if (responsive && !window.isDestroyed() && !window.webContents.isDestroyed() && !window.webContents.isLoadingMainFrame()) {
ready = await window.webContents.executeJavaScript(`(() => {
const shell = document.querySelector('.app-shell');
if (document.readyState !== 'complete' || !shell || !shell.querySelector('button')) return false;
const rect = shell.getBoundingClientRect(), style = getComputedStyle(shell);
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
})()`)
}
if (!stopped && current === generation) await publish(ready === true)
} catch { if (!stopped && current === generation) await publish(false).catch(() => undefined) }
finally { busy = false }
}
window.webContents.on('did-start-loading', invalidate)
window.webContents.on('render-process-gone', invalidate)
window.on('unresponsive', () => { responsive = false; invalidate() })
window.on('responsive', () => { responsive = true; void probe() })
const timer = setInterval(() => { void probe() }, 1000)
timer.unref()
window.on('closed', () => { stopped = true; clearInterval(timer); invalidate() })
void probe()
}
+2
View File
@@ -1,3 +1,4 @@
import { attachDevOpsHealth } from './dev-ops-health'
/**
* Electron 主进程入口。
*
@@ -109,6 +110,7 @@ function createWindow(): void {
}
})
attachDevOpsHealth(mainWindow)
mainWindow.on('ready-to-show', () => mainWindow?.show())
mainWindow.on('closed', () => {
mainWindow = null