Skip to content

fix(installer): port install.sh fixes to install.ps1 (Windows parity) - #13

Merged
lowyelling merged 4 commits into
mainfrom
lily/install-ps1-windows-parity
May 11, 2026
Merged

fix(installer): port install.sh fixes to install.ps1 (Windows parity)#13
lowyelling merged 4 commits into
mainfrom
lily/install-ps1-windows-parity

Conversation

@lowyelling

@lowyelling lowyelling commented May 1, 2026

Copy link
Copy Markdown
Contributor

Backports the install.sh portability + UX fixes that landed in PR #4 to install.ps1, so Windows users get parity with macOS/Linux. Three commits, all mine — they were sitting on eri/dev-1417 after PR #8 merged into that branch instead of being promoted to main. Re-branched cleanly under lily/ for ownership clarity.

Summary

  • Port install.sh portability patterns (sed, exec/PID, python3 fallback) to install.ps1
  • Trim duplicate / process-y comments in install.ps1

Verification

  • Manual run on Windows PowerShell (haven't tested on real Windows — flagging as judgment call; happy to do extended testing if reviewer wants)
  • install.sh unchanged on macOS — verified locally

Follow-up

None.

Linear

DEV-1417

Summary by CodeRabbit

  • Installation & Setup
    • Requires PowerShell 5.0+ and recommends running installer with elevated execution policy.
    • Looser project-directory detection so setup runs in more contexts.
    • Uses native junction creation for server plugins and provides targeted diagnostics on failure.
    • Verifies npm availability before installing dependencies and aborts with actionable troubleshooting on failure.
    • Bootstraps missing configuration by briefly starting the app and waiting for files, with logs captured.
    • Auto-enables server-plugin setting and validates success; falls back to manual instructions if needed.
  • Error Handling
    • Better detection and user-facing guidance for malformed or missing local config and API keys.

Brings install.ps1 into parity with the merged install.sh after the
DEV-1417 install-fixes series. Previously Windows users hit four silent
papercuts that macOS/Linux users were already protected from.

Ported fixes:
- ST-dir verification now requires BOTH server.js AND package.json (OR
  logic, matching install.sh); previously the PS1 check only errored if
  BOTH were missing, silently installing in the wrong dir when one was
  present.
- BUG-4: generate config.yaml by starting SillyTavern briefly when
  missing. Uses Start-Process + taskkill /F /T to manage the npm -> node
  process tree (Windows analogue of install.sh's exec npm + kill $!).
- enableServerPlugins idempotent auto-flip in config.yaml via PowerShell
  -replace with (?m) multiline regex, matching install.sh's sed semantics.
  Writes with [System.IO.File]::WriteAllText to avoid Windows PowerShell
  5.1's UTF-8 BOM injection.
- BUG-5: resolvable apiKey probe through the plugin's fallback chain
  (hosts.sillytavern.apiKey -> root apiKey) using PowerShell's native
  ConvertFrom-Json + null-propagation — cleaner than install.sh's
  python3 probe since PS .NET JSON parsing + null chaining needs no
  external runtime.

Additional:
- Junction failure message now names both remediations (Administrator
  PowerShell OR Windows Developer Mode); default Azure Windows Server
  images ship Developer Mode off, making this distinction relevant for
  any automated VM-based verification.

References merged install.sh commits: 3b09f32 (config.yaml + flip),
6ef2018 (apiKey probe), 32a90d3 (install.sh hardening), 161c3ae (usage
comment drift).

No new dependencies. Pure port — behavior is a strict superset of the
prior install.ps1 (same happy paths, now with the four additional
guards). Not yet verified on a real Windows host; see PR body for
verification plan.
Drop rationale comments that restate what the code already expresses
via named cmdlets, guards, and error messages.

Removed: #Requires directive explanation, ST-dir verify preamble,
junction-no-admin-needed preamble (same content already in the
error message), New-Item-vs-mklink JSDoc, npm install guard
rationale, Start-Process redirection novel, HasExited poll
rationale, taskkill null-guard rationale, config.yaml bootstrap
multi-line block, regex explanation multi-line block, BOM note
multi-line block, resolvable-key probe multi-line block.

Kept: one-line WHY where the invariant isn't visible in code —
the [ \t]* vs \s* .NET asymmetry, UTF-8 BOM behavior on PS 5.1
Set-Content, the config.yaml first-npm-start invariant (BUG-4
crux), the false-promise probe rationale, and the malformed-JSON
catch note.

Mirrors Eri's cleanup pass on PR #7 (eef27be).
fix(installer): port install.sh fixes to install.ps1 (Windows parity)
@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

Walkthrough

The install.ps1 installer now enforces PowerShell 5.0+, relaxes SillyTavern directory detection, creates junctions via PowerShell New-Item, validates npm install exit codes, bootstraps config.yaml by starting/polling SillyTavern, and robustly updates/validates YAML and JSON configs.

Changes

Cohort / File(s) Summary
Install Script Enhancements
install.ps1
Enforces PowerShell 5.0+; accepts either server.js or package.json for directory detection; uses New-Item -ItemType Junction and emits diagnostic messages on failure (cross-volume, network share, permissions); verifies npm.cmd availability and npm install exit code with actionable troubleshooting and verbose rerun hint; bootstraps missing config.yaml by starting SillyTavern, polling up to 60s, capturing temp logs, and killing the process if needed; rewrites enableServerPlugins precisely (multiline match, UTF-8 BOM-free) and revalidates; parses .honcho/config.json to detect malformed JSON and whether auto-populatable keys are resolvable, prompting manual entry when necessary.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Installer as install.ps1
    participant FS as Filesystem
    participant NPM as npm.exe
    participant ST as SillyTavern (process)

    User->>Installer: run install.ps1
    Installer->>Installer: check PowerShell >= 5.0
    Installer->>FS: verify `server.js` or `package.json` present
    Installer->>FS: create junction via New-Item
    alt junction fails
        Installer->>User: print diagnostics (cross-volume, network, permissions)
        Installer-->>User: exit
    end
    Installer->>NPM: resolve `npm.cmd`
    alt npm missing or install fails
        Installer->>User: print actionable npm troubleshooting and verbose rerun hint
        Installer-->>User: exit on nonzero
    end
    Installer->>FS: check `config.yaml`
    alt config missing
        Installer->>ST: start SillyTavern (background)
        Installer->>FS: poll for `config.yaml` up to 60s (capture stdout/stderr to temp logs)
        alt file appears
            Installer->>ST: kill process if needed
        else
            Installer->>User: show temp logs and exit
        end
    end
    Installer->>FS: rewrite YAML key `enableServerPlugins: true` (UTF-8 no BOM)
    Installer->>FS: validate YAML change
    alt validation fails
        Installer->>User: provide manual YAML edit instructions
    end
    Installer->>FS: parse `.honcho/config.json`
    alt malformed JSON
        Installer->>User: error and exit
    else if auto-key not resolvable
        Installer->>User: prompt to enter API key manually after restart
    end
    Installer-->>User: finish
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nudged the script, it hopped awake,
Junctions joined paths for setup's sake,
I coaxed a config from SillyTavern's nest,
Printed clues when things refused to rest,
Hooray — installs now are less of a quake! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective: porting install.sh fixes to install.ps1 for Windows parity. It is concise, specific, and clearly conveys the primary change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lily/install-ps1-windows-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.ps1`:
- Around line 130-145: The install.ps1 block currently treats a JSON parse error
the same as a valid config without keys; update the try/catch to track parse
success (e.g., set a $parseSucceeded or $malformedJson flag) so $resolvableKey
is only evaluated when ConvertFrom-Json succeeded; in the catch set the
malformed flag and later branch on that flag (instead of just $resolvableKey) to
print a distinct message when $cfg parsing failed for $HONCHO_CONFIG and avoid
implying the config simply lacks an apiKey—refer to the variables
$HONCHO_CONFIG, $cfg, $hostKey, $rootKey, and $resolvableKey when locating and
changing the logic.
- Around line 63-85: The npm install step can run when npm isn't on PATH because
$LASTEXITCODE can be stale; before calling npm (the npm install block that sets
$null = npm install --silent and reads $LASTEXITCODE) run a command availability
check using Get-Command -Name npm.cmd -ErrorAction SilentlyContinue (or npm) and
if it returns $null write a clear error and exit 1; additionally after
attempting the install check the automatic success flag ($?) as a fallback and
treat a false value the same as a non-zero $LASTEXITCODE so you don't proceed to
the Start-Process bootstrap (the Start-Process -FilePath "npm.cmd" ... block)
when npm is missing or failed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f651068-2cb8-46ae-9f70-28456fed0f80

📥 Commits

Reviewing files that changed from the base of the PR and between c7ba0f8 and 5dbe5c2.

📒 Files selected for processing (1)
  • install.ps1

Comment thread install.ps1
Comment thread install.ps1
- Preflight Get-Command npm.cmd before invoking, with $? fallback to
  catch command-not-found cases that don't set $LASTEXITCODE.
- Treat malformed ~/.honcho/config.json as a hard error rather than
  collapsing it into the missing-key branch (current behavior risks
  silent settings wipe when the plugin recreates a minimal config).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.ps1`:
- Around line 138-154: The probe logic incorrectly treats
hosts.sillytavern.apiKey (hostKey) as sufficient for "resolvable" even though
the plugin runtime first consults the SecretManager and only falls back to the
root apiKey; update the check that sets resolvableKey so it mirrors the runtime
fallback: consider a SecretManager entry as the highest-priority resolvable
source and only mark resolvableKey true if a SecretManager config exists or the
root-level apiKey (rootKey) exists, rather than relying on
hosts.sillytavern.apiKey alone; adjust the conditional that examines
hostKey/rootKey (and any secret manager field) so the Write-Host message about
auto-population for HONCHO_CONFIG accurately reflects the runtime behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3eea1581-da93-4590-b0fe-21ce933e2631

📥 Commits

Reviewing files that changed from the base of the PR and between 5dbe5c2 and 122e8d5.

📒 Files selected for processing (1)
  • install.ps1

Comment thread install.ps1
Comment on lines +138 to +154
$hostKey = $cfg.hosts.sillytavern.apiKey
$rootKey = $cfg.apiKey
if ($hostKey -or $rootKey) { $resolvableKey = $true }
} catch {
$parseFailed = $true
}
if ($parseFailed) {
Write-Host "[!] Found malformed Honcho config at $HONCHO_CONFIG"
Write-Host " Fix or remove it before re-running, or the plugin may recreate a minimal config and wipe existing settings."
exit 1
} elseif ($resolvableKey) {
Write-Host "[*] Found global Honcho config with resolvable apiKey at $HONCHO_CONFIG"
Write-Host " API key, workspace, and peer name will be auto-populated."
} else {
Write-Host "[*] Found $HONCHO_CONFIG but no resolvable apiKey."
Write-Host " (plugin checks hosts.sillytavern.apiKey, then root apiKey.)"
Write-Host " Enter your Honcho API key via the Extensions panel after restart."

@coderabbitai coderabbitai Bot May 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align apiKey probe with actual plugin fallback chain.

At Line 138 and Line 153, the script treats hosts.sillytavern.apiKey as resolvable. But the provided plugin runtime paths (plugin/index.js:88-110, plugin/index.js:201-230) use SecretManager first, then root-level apiKey. This can report “auto-populated” when runtime auth still fails.

Suggested fix
-        $hostKey = $cfg.hosts.sillytavern.apiKey
         $rootKey = $cfg.apiKey
-        if ($hostKey -or $rootKey) { $resolvableKey = $true }
+        if ($rootKey) { $resolvableKey = $true }
...
-        Write-Host "    (plugin checks hosts.sillytavern.apiKey, then root apiKey.)"
+        Write-Host "    (plugin checks SillyTavern SecretManager first, then root apiKey.)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$hostKey = $cfg.hosts.sillytavern.apiKey
$rootKey = $cfg.apiKey
if ($hostKey -or $rootKey) { $resolvableKey = $true }
} catch {
$parseFailed = $true
}
if ($parseFailed) {
Write-Host "[!] Found malformed Honcho config at $HONCHO_CONFIG"
Write-Host " Fix or remove it before re-running, or the plugin may recreate a minimal config and wipe existing settings."
exit 1
} elseif ($resolvableKey) {
Write-Host "[*] Found global Honcho config with resolvable apiKey at $HONCHO_CONFIG"
Write-Host " API key, workspace, and peer name will be auto-populated."
} else {
Write-Host "[*] Found $HONCHO_CONFIG but no resolvable apiKey."
Write-Host " (plugin checks hosts.sillytavern.apiKey, then root apiKey.)"
Write-Host " Enter your Honcho API key via the Extensions panel after restart."
$rootKey = $cfg.apiKey
if ($rootKey) { $resolvableKey = $true }
} catch {
$parseFailed = $true
}
if ($parseFailed) {
Write-Host "[!] Found malformed Honcho config at $HONCHO_CONFIG"
Write-Host " Fix or remove it before re-running, or the plugin may recreate a minimal config and wipe existing settings."
exit 1
} elseif ($resolvableKey) {
Write-Host "[*] Found global Honcho config with resolvable apiKey at $HONCHO_CONFIG"
Write-Host " API key, workspace, and peer name will be auto-populated."
} else {
Write-Host "[*] Found $HONCHO_CONFIG but no resolvable apiKey."
Write-Host " (plugin checks SillyTavern SecretManager first, then root apiKey.)"
Write-Host " Enter your Honcho API key via the Extensions panel after restart."
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)

[warning] Missing BOM encoding for non-ASCII encoded file 'install.ps1'

(PSUseBOMForUnicodeEncodedFile)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.ps1` around lines 138 - 154, The probe logic incorrectly treats
hosts.sillytavern.apiKey (hostKey) as sufficient for "resolvable" even though
the plugin runtime first consults the SecretManager and only falls back to the
root apiKey; update the check that sets resolvableKey so it mirrors the runtime
fallback: consider a SecretManager entry as the highest-priority resolvable
source and only mark resolvableKey true if a SecretManager config exists or the
root-level apiKey (rootKey) exists, rather than relying on
hosts.sillytavern.apiKey alone; adjust the conditional that examines
hostKey/rootKey (and any secret manager field) so the Write-Host message about
auto-population for HONCHO_CONFIG accurately reflects the runtime behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not fixing since SecretManager path is dead — SECRET_KEYS.HONCHO isn't in ST's enum, so readSecret(undefined) always returns ''. Real runtime fallback is hosts.sillytavern.apiKey || globalConfig.apiKey. PR #14 removes the dead branch and codifies globalConfig as SSoT.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lowyelling, understood — thanks for the clarification. Since SECRET_KEYS.HONCHO is absent from ST's enum, readSecret(undefined) is a no-op and the effective fallback chain is hosts.sillytavern.apiKey → globalConfig.apiKey, which is exactly what the current probe logic reflects. My suggestion was based on an incorrect read of the runtime path. Makes sense to keep hostKey in the check until PR #14 lands.


✏️ Learnings added
Learnt from: lowyelling
Repo: plastic-labs/sillytavern-honcho PR: 13
File: install.ps1:138-154
Timestamp: 2026-05-01T19:59:36.570Z
Learning: In the sillytavern-honcho plugin (install.ps1 and plugin/index.js), the SecretManager path for the Honcho API key is dead code: `SECRET_KEYS.HONCHO` is not in SillyTavern's enum, so `readSecret(undefined)` always returns an empty string. The real runtime apiKey fallback chain is `hosts.sillytavern.apiKey` (from `~/.honcho/config.json`) first, then root-level `apiKey` (`globalConfig.apiKey`). PR `#14` removes the dead SecretManager branch and codifies globalConfig as the Single Source of Truth.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@lowyelling
lowyelling merged commit 1e2a573 into main May 11, 2026
3 checks passed
@lowyelling
lowyelling deleted the lily/install-ps1-windows-parity branch May 11, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants