diff --git a/AGENTS.md b/AGENTS.md index 730e6b6e..5bb7b2c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ OpenNest is a .NET 8 Windows CNC-nesting application with cross-platform librari - Prefer Roslyn Bridge MCP for symbols, references and diagnostics when available; fall back to text search. - Use `var` for locals and namespaces matching project directories. Follow `.editorconfig`; format only changed C# files with `dotnet format OpenNest.sln --include `, then repeat with `--verify-no-changes`. On Linux, prefix both commands with `EnableWindowsTargeting=true`. -- Keep instructions concise: commands, boundaries and non-obvious safeguards, not class inventories or session history. Update affected instructions and user-facing docs with behavior/build changes; put detailed contracts in `docs/`. +- Keep instructions concise: commands, boundaries and non-obvious safeguards, not class inventories or session history. Update affected instructions and user-facing docs with behavior/build changes; put detailed contracts in `docs/`. User guides and their screenshots live in the separate `ajisaacs/opennest-help` repo: update or recapture them when a UI change alters a documented screen, and never rename a `HelpTopics` ID. - Never commit design specs, implementation plans, progress notes or temporary benchmark reports. Keep working records under local, ignored `.hermes/plans/` or `.hermes/progress/`; retain reusable verification procedures in `docs/`. - Keep vendor manuals/full-text extracts out of source control unless redistribution is authorized. Write project-specific behavior summaries with citations, separating controller rules, machine macros and unconfirmed behavior. @@ -68,3 +68,4 @@ Read the relevant contract before changing its behavior: - [Cincinnati CL](docs/cincinnati-post-output.md) and [CI Fiber](docs/cincinnati-ci-fiber-post-output.md) - [Fill verification](docs/performance/fill-verification.md): opt-in benchmarks, frozen oracles, Debug-only counters and predictor initialization. Zero Release counters do not prove work removal. - [Desktop auto-update](docs/auto-update.md): Velopack feed, `UpdateFeedUrl` setting and `Deploy-OpenNest.ps1`. +- [Desktop help](docs/desktop-help.md): WebView2 help window, F1 topic IDs and the pinned help release both packaging scripts install. diff --git a/OpenNest.Core/CNC/CuttingPlanning/ReleasedContourState.cs b/OpenNest.Core/CNC/CuttingPlanning/ReleasedContourState.cs index 383c78bd..70570b65 100644 --- a/OpenNest.Core/CNC/CuttingPlanning/ReleasedContourState.cs +++ b/OpenNest.Core/CNC/CuttingPlanning/ReleasedContourState.cs @@ -95,7 +95,7 @@ public sealed class ReleasedContourState Finish(); if (reportMissingLeadIns && !cutoff && !hasLead) Add(new(PostVerificationKind.MissingLeadIn, plate, part, null, - "A break cut has no nonzero placed lead-in motion.") + "A break cut is missing lead-in geometry.") { Location = move.Curve.Start }, owned); inBreakCut = true; hasLead = false; @@ -179,7 +179,7 @@ public sealed class ReleasedContourState contourNumber++; if (reportMissingLeadIns && !cutoff && !hasLead) Add(new(PostVerificationKind.MissingLeadIn, plate, part, null, - $"Cutting contour {contourNumber} has no nonzero placed lead-in motion.") + $"Cutting contour {contourNumber} is missing lead-in geometry.") { Location = move.Curve.Start }, owned); hasLead = false; // A rapid can pause/reposition without leaving any material gap. diff --git a/OpenNest.WinForms.Tests/HelpTopicsTests.cs b/OpenNest.WinForms.Tests/HelpTopicsTests.cs new file mode 100644 index 00000000..32390646 --- /dev/null +++ b/OpenNest.WinForms.Tests/HelpTopicsTests.cs @@ -0,0 +1,40 @@ +using OpenNest.Help; + +namespace OpenNest.WinForms.Tests; + +public class HelpTopicsTests : IDisposable +{ + private readonly string directory = Directory.CreateTempSubdirectory("opennest-help-").FullName; + + public void Dispose() => Directory.Delete(directory, recursive: true); + + private void WriteTopics(string json) => File.WriteAllText(Path.Combine(directory, "topics.json"), json); + + [Fact] + public void MapsTopicToItsPageAndAnchor() + { + WriteTopics("""{ "topics": { "home": "index.html", "auto-nest": "first-nest.html#run-auto-nest" } }"""); + + Assert.Equal("first-nest.html#run-auto-nest", HelpTopics.ResolvePage(directory, HelpTopics.AutoNest)); + } + + [Fact] + public void UnknownTopicOpensTheHomeTopic() + { + WriteTopics("""{ "topics": { "home": "welcome.html" } }"""); + + Assert.Equal("welcome.html", HelpTopics.ResolvePage(directory, "not-a-topic")); + } + + [Theory] + [InlineData(null)] + [InlineData("not json")] + [InlineData("""{ "pages": {} }""")] + public void MissingOrUnreadableTopicsFallBackToIndex(string json) + { + if (json != null) + WriteTopics(json); + + Assert.Equal("index.html", HelpTopics.ResolvePage(directory, HelpTopics.Post)); + } +} diff --git a/OpenNest/Forms/AutoNestForm.cs b/OpenNest/Forms/AutoNestForm.cs index e2fabcf5..229435b8 100644 --- a/OpenNest/Forms/AutoNestForm.cs +++ b/OpenNest/Forms/AutoNestForm.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using System.Windows.Forms; using OpenNest.Controls; using OpenNest.Engine; +using OpenNest.Help; namespace OpenNest.Forms { @@ -29,6 +30,7 @@ namespace OpenNest.Forms LoadDrawings(nest); LoadDefaultPlateOptions(); SetPlateOptimizerVisible(false); + HelpTopics.Attach(this, HelpTopics.AutoNest); partsGrid.DataError += PartsGrid_DataError; } diff --git a/OpenNest/Forms/CadConverterForm.cs b/OpenNest/Forms/CadConverterForm.cs index 0839e593..282f4469 100644 --- a/OpenNest/Forms/CadConverterForm.cs +++ b/OpenNest/Forms/CadConverterForm.cs @@ -13,6 +13,7 @@ using OpenNest.CNC; using OpenNest.Controls; using OpenNest.Converters; using OpenNest.Geometry; +using OpenNest.Help; using OpenNest.IO; using OpenNest.IO.Bending; using OpenNest.TabbedCutouts; @@ -44,6 +45,7 @@ namespace OpenNest.Forms public CadConverterForm() { InitializeComponent(); + HelpTopics.Attach(this, HelpTopics.ImportDrawings); fileList.SelectedIndexChanged += OnFileSelected; filterPanel.FilterChanged += OnFilterChanged; diff --git a/OpenNest/Forms/MainForm.cs b/OpenNest/Forms/MainForm.cs index bf8a00e3..d308325a 100644 --- a/OpenNest/Forms/MainForm.cs +++ b/OpenNest/Forms/MainForm.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using OpenNest.Engine.BestFit; using OpenNest.Engine.Jobs; using OpenNest.Forms.Commands; +using OpenNest.Help; using OpenNest.IO; using OpenNest.Properties; @@ -119,6 +120,7 @@ namespace OpenNest.Forms mnuFile.DropDownItems.Insert(mnuFile.DropDownItems.IndexOf(mnuFileExport), exportNestMenu); mnuFile.DropDownItems.Insert(mnuFile.DropDownItems.IndexOf(mnuFileExit), storageModeMenu); InitializeAlignMenu(); + InitializeHelpMenu(); UpdateOverlapMenu(); MainWindowSettings.Load(this); @@ -160,6 +162,17 @@ namespace OpenNest.Forms private UpdaterStatus updaterStatus; + private void InitializeHelpMenu() + { + var contents = new ToolStripMenuItem("OpenNest &Help") { ShortcutKeys = Keys.F1 }; + contents.Click += (_, _) => HelpTopics.Show(this, HelpTopics.Home); + var firstNest = new ToolStripMenuItem("&Your First Nest"); + firstNest.Click += (_, _) => HelpTopics.Show(this, HelpTopics.FirstNest); + var help = new ToolStripMenuItem("&Help"); + help.DropDownItems.AddRange(new ToolStripItem[] { contents, firstNest }); + menuStrip1.Items.Add(help); + } + private static ToolStripButton CreateActionButton(string name, string text, Image image, EventHandler click) { diff --git a/OpenNest/Help/HelpForm.cs b/OpenNest/Help/HelpForm.cs new file mode 100644 index 00000000..b2277baf --- /dev/null +++ b/OpenNest/Help/HelpForm.cs @@ -0,0 +1,167 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; +using Microsoft.Web.WebView2.Core; +using Microsoft.Web.WebView2.WinForms; + +namespace OpenNest.Help +{ + /// + /// Single help window hosting the bundled HTML in WebView2. The help folder is served + /// from a private virtual host so the site's search and scripts run as on a web server. + /// The window runs its own UI thread, so modal dialogs in the app never disable it: + /// F1 in a dialog opens help that can be scrolled and searched while the dialog is open. + /// + public sealed class HelpForm : Form + { + private const string Host = "help.opennest.local"; + private static readonly string Origin = $"https://{Host}/"; + private static readonly TimeSpan StartTimeout = TimeSpan.FromSeconds(10); + + private static readonly object Sync = new(); + private static HelpForm instance; + + private readonly WebView2 browser = new() { Dock = DockStyle.Fill }; + private string pendingPage; + private bool ready; + + private HelpForm(string page) + { + pendingPage = page; + Text = "OpenNest Help"; + Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); + StartPosition = FormStartPosition.Manual; + var area = Screen.FromPoint(Cursor.Position).WorkingArea; + Size = new Size(System.Math.Min(1100, area.Width), System.Math.Min(900, area.Height)); + Location = new Point(area.Right - Width, area.Top); + Controls.Add(browser); + } + + /// Shows (relative to the help folder) in the help window. + public static void ShowPage(string page) + { + lock (Sync) + { + var open = instance; + if (open != null && !open.IsDisposed) + { + try + { + open.BeginInvoke(() => open.Reveal(page)); + return; + } + catch (InvalidOperationException) + { + // Closed between the check and the call: start a new window below. + } + } + + using var started = new ManualResetEventSlim(); + var thread = new Thread(() => + { + var form = new HelpForm(page); + form.HandleCreated += (_, _) => started.Set(); + instance = form; + Application.Run(form); + }) + { + IsBackground = true, + Name = "OpenNest Help", + }; + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + started.Wait(StartTimeout); + } + } + + private void Reveal(string page) + { + if (WindowState == FormWindowState.Minimized) + WindowState = FormWindowState.Normal; + Activate(); + Navigate(page); + } + + protected override async void OnLoad(EventArgs e) + { + base.OnLoad(e); + try + { + var dataFolder = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "OpenNest", "WebView2"); + var environment = await CoreWebView2Environment.CreateAsync(null, dataFolder); + await browser.EnsureCoreWebView2Async(environment); + } + catch (Exception ex) when (ex is WebView2RuntimeNotFoundException or COMException or IOException + or UnauthorizedAccessException) + { + MessageBox.Show(this, + "OpenNest Help needs the Microsoft Edge WebView2 Runtime, which could not be started.\n\n" + + ex.Message, + "OpenNest Help", MessageBoxButtons.OK, MessageBoxIcon.Warning); + Close(); + return; + } + + var core = browser.CoreWebView2; + core.SetVirtualHostNameToFolderMapping(Host, HelpTopics.Directory, + CoreWebView2HostResourceAccessKind.DenyCors); + core.Settings.AreDevToolsEnabled = false; + core.Settings.IsStatusBarEnabled = false; + core.NavigationStarting += Core_NavigationStarting; + core.NewWindowRequested += Core_NewWindowRequested; + // Site page titles already end in "OpenNest Help". + core.DocumentTitleChanged += (_, _) => Text = core.DocumentTitle; + + ready = true; + if (pendingPage != null) + Navigate(pendingPage); + } + + private void Navigate(string page) + { + if (!ready) + { + pendingPage = page; + return; + } + + pendingPage = null; + browser.CoreWebView2.Navigate(Origin + page.TrimStart('/')); + } + + // Help pages stay in this window; anything off-site opens in the user's browser. + private static void Core_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) + { + if (IsHelpPage(e.Uri)) + return; + e.Cancel = true; + OpenExternally(e.Uri); + } + + private void Core_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e) + { + e.Handled = true; + if (IsHelpPage(e.Uri)) + browser.CoreWebView2.Navigate(e.Uri); + else + OpenExternally(e.Uri); + } + + private static bool IsHelpPage(string uri) => + uri.StartsWith(Origin, StringComparison.OrdinalIgnoreCase) || uri.StartsWith("about:", StringComparison.Ordinal); + + private static void OpenExternally(string uri) + { + if (!Uri.TryCreate(uri, UriKind.Absolute, out var parsed) + || (parsed.Scheme != Uri.UriSchemeHttps && parsed.Scheme != Uri.UriSchemeHttp)) + return; + Process.Start(new ProcessStartInfo(parsed.AbsoluteUri) { UseShellExecute = true }); + } + } +} diff --git a/OpenNest/Help/HelpTopics.cs b/OpenNest/Help/HelpTopics.cs new file mode 100644 index 00000000..e6c03ae1 --- /dev/null +++ b/OpenNest/Help/HelpTopics.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Windows.Forms; + +namespace OpenNest.Help +{ + /// + /// Opens the bundled help (built from the ajisaacs/opennest-help repository) at a topic. + /// Topic IDs are a stable contract: the help's topics.json maps each ID to a page, + /// so pages can move without app changes. Never rename an ID the app uses. + /// + public static class HelpTopics + { + public const string Home = "home"; + public const string FirstNest = "first-nest"; + public const string ImportDrawings = "import-drawings"; + public const string AutoNest = "auto-nest"; + public const string Post = "post"; + + /// Overrides the help folder, e.g. a local opennest-help site/ build. + public const string DirectoryVariable = "OPENNEST_HELP_DIR"; + + public static string Directory + { + get + { + var overridden = Environment.GetEnvironmentVariable(DirectoryVariable); + return string.IsNullOrWhiteSpace(overridden) + ? Path.Combine(Application.StartupPath, "Help") + : overridden; + } + } + + public static bool IsInstalled => File.Exists(Path.Combine(Directory, "index.html")); + + /// Opens when F1 is pressed anywhere in . + public static void Attach(Form form, string topic) + { + form.HelpRequested += (_, e) => + { + e.Handled = true; + Show(form, topic); + }; + } + + public static void Show(IWin32Window owner, string topic) + { + if (!IsInstalled) + { + MessageBox.Show(owner, + $"Help is not installed. Expected it in:\n{Directory}", + "OpenNest Help", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + HelpForm.ShowPage(ResolvePage(Directory, topic)); + } + + /// Maps a topic ID to a site-relative page, falling back to the home page. + public static string ResolvePage(string helpDirectory, string topic) + { + var topics = LoadTopics(helpDirectory); + if (topics.TryGetValue(topic, out var page)) + return page; + return topics.TryGetValue(Home, out var home) ? home : "index.html"; + } + + private static Dictionary LoadTopics(string helpDirectory) + { + var path = Path.Combine(helpDirectory, "topics.json"); + try + { + using var document = JsonDocument.Parse(File.ReadAllText(path)); + var topics = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var property in document.RootElement.GetProperty("topics").EnumerateObject()) + topics[property.Name] = property.Value.GetString(); + return topics; + } + catch (Exception ex) when (ex is IOException or JsonException or KeyNotFoundException + or InvalidOperationException or UnauthorizedAccessException) + { + return new Dictionary(); + } + } + } +} diff --git a/OpenNest/OpenNest.csproj b/OpenNest/OpenNest.csproj index 44aaf7b2..a7ad4e59 100644 --- a/OpenNest/OpenNest.csproj +++ b/OpenNest/OpenNest.csproj @@ -31,6 +31,7 @@ + diff --git a/docs/desktop-help.md b/docs/desktop-help.md new file mode 100644 index 00000000..014a8834 --- /dev/null +++ b/docs/desktop-help.md @@ -0,0 +1,40 @@ +# Desktop help + +User guides live in [ajisaacs/opennest-help](https://github.com/ajisaacs/opennest-help): +Markdown pages plus annotated screenshots, built with MkDocs into offline HTML. This repo +holds only the code that shows that HTML and the pin of which help release ships. + +## In the app + +- **Help > OpenNest Help** (F1 in the main window) opens the home topic; + **Help > Your First Nest** opens the tutorial. +- A dialog opts in to context help with `HelpTopics.Attach(this, HelpTopics.)`; + F1 anywhere in it opens that topic. Auto Nest and the CAD Converter do this today. +- `HelpForm` is a single WebView2 window on its own STA thread, so modal dialogs never + disable it. It serves the help folder from the private virtual host + `https://help.opennest.local/`; off-site links open in the default browser. WebView2 + data goes to `%LOCALAPPDATA%\OpenNest\WebView2`. +- The help folder is `Help\` beside `OpenNest.exe`. Set `OPENNEST_HELP_DIR` to a local + opennest-help `site\` build to preview unreleased pages. Without either, the menu + explains that help is not installed. + +## Topic IDs + +`HelpTopics` constants are IDs, not file names. The help's `topics.json` maps each ID +to a page or `page.html#anchor`, and its build fails if a mapped page is missing. An +unknown ID falls back to the home page. Add the ID to `topics.json` (in the help repo) +before using a new constant here, and never rename an existing ID. + +## Packaging + +`scripts/help.json` pins one opennest-help release (tag and SHA-256 of its +`opennest-help.zip`). `scripts/Install-Help.ps1` downloads it, refuses a hash mismatch +and expands it into the package's `Help\` folder; both `Publish-Windows.ps1` and +`Deploy-OpenNest.ps1` call it, and `build-info.json` records the help version. Pass +`-HelpDirectory ` to either script to package a local build instead. + +To ship new help: tag the help repo `vX.Y.Z`, wait for its release, then update `tag` +and `sha256` here (the release attaches `opennest-help.zip.sha256`). + +When a UI change alters a documented screen or workflow, update or recapture the +affected opennest-help pages (its README covers capture and markup). diff --git a/docs/releasing.md b/docs/releasing.md index 0b4c1c61..25f43418 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -23,7 +23,9 @@ pulls from GitHub every hour; it refuses pushes. 4. Download the `OpenNest-X.Y.Z-win-x64` artifact and verify its `.sha256`. It contains `OpenNest.vX.Y.Z.win-x64.zip`, with the .NET runtime, native dependencies, shipped configurations, all three post-processors, license, - and `build-info.json` identifying the exact source commit. The nesting engines + the `Help` folder from the opennest-help release pinned in `scripts/help.json` + (see [desktop help](desktop-help.md)), and `build-info.json` identifying the exact + source commit and help version. The nesting engines are built into `OpenNest.Engine.dll`; no external engine repository or plug-in DLL is packaged. `scripts/ReleaseSmoke` loads the packaged engine assembly and checks that every built-in engine instantiates from it, that the renamed diff --git a/scripts/Deploy-OpenNest.ps1 b/scripts/Deploy-OpenNest.ps1 index 9356de68..bcf6a691 100644 --- a/scripts/Deploy-OpenNest.ps1 +++ b/scripts/Deploy-OpenNest.ps1 @@ -22,7 +22,9 @@ Param( [string]$FeedHost, [string]$FeedUser = "aj", [Parameter(Mandatory)] - [string]$RemoteDataDir + [string]$RemoteDataDir, + # A built opennest-help site/ folder to package instead of the release pinned in help.json. + [string]$HelpDirectory ) Set-StrictMode -Version Latest @@ -55,6 +57,9 @@ Write-Host "Publishing self-contained build..." & dotnet publish $ProjectPath -c $PublishConfiguration -r win-x64 --self-contained true -o $PublishDir if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed with exit code $LASTEXITCODE" } +$helpVersion = & (Join-Path $ScriptDir 'Install-Help.ps1') -Destination (Join-Path $PublishDir 'Help') -HelpDirectory $HelpDirectory +Write-Host "Packaged help $helpVersion" + Write-Host "Packing Velopack release v$Version..." & vpk pack -u OpenNest -v $Version -p $PublishDir -e OpenNest.exe -o $ReleasesDir if ($LASTEXITCODE -ne 0) { throw "vpk pack failed with exit code $LASTEXITCODE" } diff --git a/scripts/Install-Help.ps1 b/scripts/Install-Help.ps1 new file mode 100644 index 00000000..8d5f848d --- /dev/null +++ b/scripts/Install-Help.ps1 @@ -0,0 +1,41 @@ +<# +Put the OpenNest help site into a package's Help folder. + +By default this downloads the opennest-help release pinned in scripts/help.json and +refuses it unless its SHA-256 matches. Pass -HelpDirectory to use a locally built +site/ folder instead (e.g. while writing new help pages). Returns a short +description of the help version for build-info.json. + +Example: + ./scripts/Install-Help.ps1 -Destination artifacts/OpenNest/Help + ./scripts/Install-Help.ps1 -Destination bin/publish/Help -HelpDirectory ../opennest-help/site +#> +[CmdletBinding()] +param( + [Parameter(Mandatory)] [string] $Destination, + [string] $HelpDirectory +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +if (Test-Path $Destination) { throw "Refusing to overwrite existing help folder: $Destination" } + +if ($HelpDirectory) { + if (-not (Test-Path (Join-Path $HelpDirectory 'index.html'))) { throw "No help site in $HelpDirectory (index.html missing)." } + New-Item -ItemType Directory -Path $Destination | Out-Null + Copy-Item (Join-Path $HelpDirectory '*') $Destination -Recurse + return "local:$([IO.Path]::GetFullPath($HelpDirectory))" +} + +$pin = Get-Content (Join-Path $PSScriptRoot 'help.json') -Raw | ConvertFrom-Json +$version = "$($pin.repository)@$($pin.tag)" +$zip = Join-Path ([IO.Path]::GetTempPath()) "opennest-help-$([guid]::NewGuid().ToString('N')).zip" +try { + Invoke-WebRequest "https://github.com/$($pin.repository)/releases/download/$($pin.tag)/opennest-help.zip" -OutFile $zip -UseBasicParsing + $hash = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLowerInvariant() + if ($hash -ne $pin.sha256) { throw "Help $version hash $hash does not match scripts/help.json." } + Expand-Archive -Path $zip -DestinationPath $Destination +} +finally { Remove-Item $zip -ErrorAction SilentlyContinue } +return $version diff --git a/scripts/Publish-Windows.ps1 b/scripts/Publish-Windows.ps1 index 2d740aac..eaa84702 100644 --- a/scripts/Publish-Windows.ps1 +++ b/scripts/Publish-Windows.ps1 @@ -3,7 +3,9 @@ param( [Parameter(Mandatory)] [ValidatePattern('^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$')] [string] $Version, - [string] $OutputDirectory = 'artifacts' + [string] $OutputDirectory = 'artifacts', + # A built opennest-help site/ folder to package instead of the release pinned in help.json. + [string] $HelpDirectory ) $ErrorActionPreference = 'Stop' @@ -39,6 +41,9 @@ try { if ($name -eq 'GravographIS') { Copy-Item "$staging/System.IO.Ports.dll" $package } } + # Help ships as the opennest-help release pinned in help.json, verified against its hash. + $helpVersion = & (Join-Path $PSScriptRoot 'Install-Help.ps1') -Destination (Join-Path $package 'Help') -HelpDirectory $HelpDirectory + New-Item -ItemType Directory -Path (Join-Path $package 'Schemes') -Force | Out-Null Copy-Item LICENSE $package @{ @@ -46,6 +51,7 @@ try { sourceCommit = $commit runtime = 'win-x64' selfContained = $true + help = $helpVersion } | ConvertTo-Json | Set-Content (Join-Path $package 'build-info.json') -Encoding utf8NoBOM $required = @( @@ -54,7 +60,8 @@ try { 'onnxruntime.dll', 'System.IO.Ports.dll', 'Configurations/PipeFlangeShape.json', 'Posts/OpenNest.Posts.Cincinnati.dll', 'Posts/OpenNest.Posts.Cincinnati.json', 'Posts/OpenNest.Posts.CincinnatiCIFiber.dll', 'Posts/OpenNest.Posts.CincinnatiCIFiber.json', - 'Posts/OpenNest.Posts.GravographIS.dll', 'LICENSE', 'build-info.json' + 'Posts/OpenNest.Posts.GravographIS.dll', 'Help/index.html', 'Help/topics.json', + 'LICENSE', 'build-info.json' ) foreach ($file in $required) { if (-not (Test-Path (Join-Path $package $file) -PathType Leaf)) { throw "Package missing $file" } diff --git a/scripts/help.json b/scripts/help.json new file mode 100644 index 00000000..21e72539 --- /dev/null +++ b/scripts/help.json @@ -0,0 +1,5 @@ +{ + "repository": "ajisaacs/opennest-help", + "tag": "v0.1.0", + "sha256": "" +}