sf snapshot: uncommitted changes after 248m inactivity

This commit is contained in:
Mikael Hugo 2026-04-28 21:10:17 +02:00
parent d30d91bf2f
commit 6eaf5926ad
4 changed files with 79 additions and 6 deletions

View file

@ -98,4 +98,26 @@ const destPath = path.join(addonDir, destFilename);
fs.copyFileSync(sourcePath, destPath);
console.log(`Installed: ${destPath}`);
// Also copy into the npm platform package so `require('@singularity-forge/engine-<platform>')`
// works when the package is symlinked into node_modules during local development.
if (!isDev) {
const platformPackageMap = {
"darwin-arm64": "darwin-arm64",
"darwin-x64": "darwin-x64",
"linux-x64": "linux-x64-gnu",
"linux-arm64": "linux-arm64-gnu",
"win32-x64": "win32-x64-msvc",
};
const npmSuffix = platformPackageMap[platformTag];
if (npmSuffix) {
const npmPackageDir = path.join(nativeRoot, "npm", npmSuffix);
const npmDest = path.join(npmPackageDir, "forge_engine.node");
if (fs.existsSync(npmPackageDir)) {
fs.copyFileSync(sourcePath, npmDest);
console.log(`Installed npm package binary: ${npmDest}`);
}
}
}
console.log("Build complete.");

View file

@ -88,5 +88,12 @@
"files": [
"dist"
],
"optionalDependencies": {
"@singularity-forge/engine-darwin-arm64": ">=2.75.0",
"@singularity-forge/engine-darwin-x64": ">=2.75.0",
"@singularity-forge/engine-linux-x64-gnu": ">=2.75.0",
"@singularity-forge/engine-linux-arm64-gnu": ">=2.75.0",
"@singularity-forge/engine-win32-x64-msvc": ">=2.75.0"
},
"license": "MIT"
}

View file

@ -87,3 +87,37 @@ for (const dir of packageDirs) {
if (linked > 0) process.stderr.write(` Linked ${linked} workspace package${linked !== 1 ? 's' : ''}\n`)
if (copied > 0) process.stderr.write(` Copied ${copied} workspace package${copied !== 1 ? 's' : ''} (symlinks unavailable)\n`)
// Platform-specific native engine packages live under native/npm/<suffix>/, not packages/.
// Wire them into node_modules/@singularity-forge/ so native.ts can require() them without
// a registry install. Only link platforms where the binary (forge_engine.node) is present.
const nativeNpmDir = join(root, 'native', 'npm')
const engineSuffixes = ['darwin-arm64', 'darwin-x64', 'linux-x64-gnu', 'linux-arm64-gnu', 'win32-x64-msvc']
for (const suffix of engineSuffixes) {
const source = join(nativeNpmDir, suffix)
const binaryPath = join(source, 'forge_engine.node')
if (!existsSync(source) || !existsSync(binaryPath)) continue
const target = join(scopeDir, `engine-${suffix}`)
if (existsSync(target)) {
try {
const stat = lstatSync(target)
if (stat.isSymbolicLink()) {
const linkTarget = readlinkSync(target)
if (resolve(join(scopeDir, linkTarget)) === source || linkTarget === source) continue
unlinkSync(target)
} else {
continue
}
} catch {
continue
}
}
try {
symlinkSync(source, target, 'junction')
process.stderr.write(` Linked native engine: @singularity-forge/engine-${suffix}\n`)
} catch {
try { cpSync(source, target, { recursive: true }) } catch { /* non-fatal */ }
}
}

View file

@ -1860,7 +1860,7 @@ function rowToSlice(row: Record<string, unknown>): SliceRow {
title: row["title"] as string,
status: row["status"] as string,
risk: row["risk"] as string,
depends: JSON.parse((row["depends"] as string) || "[]"),
depends: safeParseJsonArray<string>(row["depends"]),
demo: (row["demo"] as string) ?? "",
created_at: row["created_at"] as string,
completed_at: (row["completed_at"] as string) ?? null,
@ -1943,6 +1943,16 @@ export interface TaskRow {
verification_status?: string;
}
function safeParseJsonArray<T = unknown>(raw: unknown, fallback: T[] = []): T[] {
if (typeof raw !== "string" || raw.trim() === "") return fallback;
try {
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? (parsed as T[]) : fallback;
} catch {
return fallback;
}
}
function parseTaskArrayColumn(raw: unknown): string[] {
if (typeof raw !== "string" || raw.trim() === "") return [];
@ -2112,18 +2122,18 @@ function rowToMilestone(row: Record<string, unknown>): MilestoneRow {
id: row["id"] as string,
title: row["title"] as string,
status: row["status"] as string,
depends_on: JSON.parse((row["depends_on"] as string) || "[]"),
depends_on: safeParseJsonArray<string>(row["depends_on"]),
created_at: row["created_at"] as string,
completed_at: (row["completed_at"] as string) ?? null,
vision: (row["vision"] as string) ?? "",
success_criteria: JSON.parse((row["success_criteria"] as string) || "[]"),
key_risks: JSON.parse((row["key_risks"] as string) || "[]"),
proof_strategy: JSON.parse((row["proof_strategy"] as string) || "[]"),
success_criteria: safeParseJsonArray<string>(row["success_criteria"]),
key_risks: safeParseJsonArray<{ risk: string; whyItMatters: string }>(row["key_risks"]),
proof_strategy: safeParseJsonArray<{ riskOrUnknown: string; retireIn: string; whatWillBeProven: string }>(row["proof_strategy"]),
verification_contract: (row["verification_contract"] as string) ?? "",
verification_integration: (row["verification_integration"] as string) ?? "",
verification_operational: (row["verification_operational"] as string) ?? "",
verification_uat: (row["verification_uat"] as string) ?? "",
definition_of_done: JSON.parse((row["definition_of_done"] as string) || "[]"),
definition_of_done: safeParseJsonArray<string>(row["definition_of_done"]),
requirement_coverage: (row["requirement_coverage"] as string) ?? "",
boundary_map_markdown: (row["boundary_map_markdown"] as string) ?? "",
vision_meeting: parseVisionMeeting(row["vision_meeting_json"]),