485ed50b26
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (push) Has been cancelled
## 背景 净月潭案例(2026-09-19 21:53 → 09-20 01:26,3 小时 33 分)的问题不是模型慢,而是环境未就绪、验收靠模型自述、预算只约束单个工具入口、工具调用被 SDK 全局串行闸门卡住。本 PR 落地确认后的七项交付效率合同,并把捆绑 Codex 升到当前 npm latest。 ## 结果 - 新建 Web 游戏在正式生成前由宿主自动预检:捆绑 Node/npm、真实 Vite 构建、受限浏览器桌面/移动截图;失败不启动生成或付费素材。 - 首个副作用前冻结交付合同,宿主保存权威证据与预算;证据齐全后先封口、排空并取得执行器完整退出证明,再产出交付报告,模型回复不再当作验收。 - 原生 shell、内置浏览器与托管命令、第三方 MCP 共用同一执行许可和累计执行时间;`validation.maxRuns` 改为执行/返修批次语义,另设 `maxTurnSeconds` 墙钟上限。 - 所有工具可并发:移除 SDK 全局串行的 `apply_patch`/`update_plan` 注册,改由宿主 `agc_apply_patch`(官方 parser + 当前回合写许可 + 受控进程树 + 短项目事务)和 `agc_update_plan` 提供等价能力;真实请求目录里已无串行注册,长 MCP 与补丁/计划实测在同一响应内重叠。 - 付费提交与本地写入绑定原回合原租约:容量与同动作锁等待可取消,封口、取消或预算耗尽后零新增提交;已越过提交边界的请求保留 operation ID 走 GET 对账,不自动重放。 - 新增请求与工具分段计时、有界并行批读和首轮上下文预取,未知耗时不补零。 - 捆绑 Codex 0.147.0 → 0.155.1:固定版本收敛到 `build_support/codex_bundle.rs` 单一声明,vendor 解析源码按 `rust-v0.155.1` 逐字节重取并更新 UPSTREAM 证据,适配 0.155 统一 exec(`exec_command`/`write_stdin`);macOS 侧车最小系统版本仍为 15.0。 ## 验证 - 生产 CLI → 捆绑 Codex 0.155.1 → 本地 Responses/MCP 夹具 9/9:补丁、完成收尾、批次、只读/可写 MCP 并发、原生命令并发、原生资源并发、统一 exec 会话、期限终止(真实重叠 775 / 764 / 999 ms)。 - 真实模型目录 2/2;vendor 上游库 111 项;宿主定向与回归 106 项;真实 Windows 进程与取消 21 项;Node 侧门禁 52 项。 - 发行载荷:artifact-only 重建 NSIS,解包验证侧车清单 `codex-cli 0.155.1`、6 个组件哈希、打包后 `bin/codex.exe --version`、Node 运行时 2130 文件与双端 PNG、`--environment-check` ready。 - `check-config`、TypeScript、编码(4991 文件)、文档索引、`git diff --check`、`cargo fmt --check` 全部通过。 ## 未覆盖 - 真实陶泥儿登录态 Provider 生成尚未执行(本机 `--llm-status` 返回 `authentication-required`)。 - macOS 侧车只在本机做静态 Mach-O 与清单解析,未在 macOS 上跑 `check-macos-bundle.mjs`。 - 全仓库聚合套件在本机仍因负载敏感的后台 mock-provider 用例而红,与本次改动无关:改动前的旧二进制同样失败,换单线程后相关用例 3/3 通过。 --------- Co-authored-by: kdletters <61648117+kdletters@users.noreply.github.com> Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/439
96 lines
5.5 KiB
PowerShell
96 lines
5.5 KiB
PowerShell
# 只读取 Windows Installer 已登记的同版本 Node.js 缓存;不执行安装、不访问网络。
|
|
$ErrorActionPreference = 'Stop'
|
|
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
|
|
$expectedVersion = $env:AGC_STAGING_NODE_VERSION
|
|
if ($expectedVersion -notmatch '^\d+\.\d+\.\d+$') { throw 'Invalid Node version' }
|
|
|
|
# WinVerifyTrust 强制仅使用本地证书缓存,禁止吊销/证书 URL 网络检索。
|
|
Add-Type -TypeDefinition @'
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
public static class AgcOfflineSignature {
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct FileInfo { public uint Size; public IntPtr Path; public IntPtr File; public IntPtr Subject; }
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct TrustData {
|
|
public uint Size; public IntPtr Policy; public IntPtr Sip; public uint Ui;
|
|
public uint Revocation; public uint Choice; public IntPtr File;
|
|
public uint StateAction; public IntPtr State; public IntPtr Url;
|
|
public uint Flags; public uint Context;
|
|
}
|
|
[DllImport("wintrust.dll", ExactSpelling=true, PreserveSig=true)]
|
|
static extern int WinVerifyTrust(IntPtr window, ref Guid action, ref TrustData data);
|
|
public static bool Verify(string path) {
|
|
IntPtr name = Marshal.StringToCoTaskMemUni(path);
|
|
IntPtr file = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FileInfo)));
|
|
try {
|
|
var info = new FileInfo { Size=(uint)Marshal.SizeOf(typeof(FileInfo)), Path=name };
|
|
Marshal.StructureToPtr(info, file, false);
|
|
var data = new TrustData { Size=(uint)Marshal.SizeOf(typeof(TrustData)), Ui=2, Choice=1, File=file, Flags=0x1000|0x10 };
|
|
var action = new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE");
|
|
return WinVerifyTrust(new IntPtr(-1), ref action, ref data) == 0;
|
|
} finally { Marshal.FreeHGlobal(file); Marshal.FreeCoTaskMem(name); }
|
|
}
|
|
}
|
|
'@
|
|
|
|
function Read-Property($database, [string]$name) {
|
|
$view = $database.OpenView("SELECT ``Value`` FROM ``Property`` WHERE ``Property`` = '$name'")
|
|
try {
|
|
[void]$view.Execute()
|
|
$record = $view.Fetch()
|
|
if ($null -ne $record) { return $record.StringData(1) }
|
|
return ''
|
|
} finally { [void]$view.Close() }
|
|
}
|
|
|
|
$installer = New-Object -ComObject WindowsInstaller.Installer
|
|
$cacheRoot = [System.IO.Path]::GetFullPath((Join-Path ([Environment]::GetFolderPath('Windows')) 'Installer'))
|
|
$registrations = @(
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
)
|
|
$products = Get-ItemProperty $registrations -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.DisplayName -eq 'Node.js' -and $_.DisplayVersion -eq $expectedVersion -and $_.PSChildName -match '^\{[0-9A-Fa-f-]{36}\}$' } |
|
|
Select-Object -ExpandProperty PSChildName -Unique
|
|
foreach ($product in $products) {
|
|
try {
|
|
if ($installer.ProductInfo($product, 'ProductName') -ne 'Node.js') { continue }
|
|
if ($installer.ProductInfo($product, 'VersionString') -ne $expectedVersion) { continue }
|
|
$package = [System.IO.Path]::GetFullPath($installer.ProductInfo($product, 'LocalPackage'))
|
|
if (-not [string]::Equals([System.IO.Path]::GetDirectoryName($package), $cacheRoot, [StringComparison]::OrdinalIgnoreCase)) { continue }
|
|
if ([System.IO.Path]::GetExtension($package) -ne '.msi') { continue }
|
|
$entry = Get-Item -LiteralPath $package -Force
|
|
$cache = Get-Item -LiteralPath $cacheRoot -Force
|
|
if (($entry.Attributes -band [IO.FileAttributes]::ReparsePoint) -or ($cache.Attributes -band [IO.FileAttributes]::ReparsePoint)) { continue }
|
|
if (-not [AgcOfflineSignature]::Verify($package)) { continue }
|
|
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new([System.Security.Cryptography.X509Certificates.X509Certificate]::CreateFromSignedFile($package))
|
|
if ($certificate.Subject -notmatch '(^|,\s*)O=OpenJS Foundation(,|$)') { continue }
|
|
$database = $installer.OpenDatabase($package, 0)
|
|
if ((Read-Property $database 'ProductName') -ne 'Node.js') { continue }
|
|
if ((Read-Property $database 'ProductVersion') -ne $expectedVersion) { continue }
|
|
if ((Read-Property $database 'ProductCode') -ne $product) { continue }
|
|
$manufacturer = Read-Property $database 'Manufacturer'
|
|
if ($manufacturer -notin @('Node.js Foundation', 'OpenJS Foundation')) { continue }
|
|
$view = $database.OpenView('SELECT `Text` FROM `Control` WHERE `Dialog_` = ''LicenseAgreementDlg'' AND `Control` = ''LicenseText''')
|
|
try {
|
|
[void]$view.Execute()
|
|
$record = $view.Fetch()
|
|
if ($null -eq $record) { continue }
|
|
$content = $record.StringData(1)
|
|
} finally { [void]$view.Close() }
|
|
if (-not $content.StartsWith('{\rtf') -or $content.Length -gt 1048576) { continue }
|
|
if (-not $content.Contains('Node.js') -or -not $content.Contains('Permission is hereby granted')) { continue }
|
|
[pscustomobject]@{
|
|
productName = 'Node.js'; version = $expectedVersion; manufacturer = $manufacturer
|
|
signatureVerified = $true; signer = 'OpenJS Foundation'; format = 'rtf'; content = $content
|
|
} | ConvertTo-Json -Compress
|
|
exit 0
|
|
} catch {
|
|
# 单个损坏/无权限缓存不能绕过验证;继续查找其它已登记候选。
|
|
continue
|
|
}
|
|
}
|
|
throw 'No matching trusted installed Node.js license'
|