Conversation
- Purpose: introduce a dedicated onboarding step for internal boot setup using existing webgui behavior and endpoints. - Before: onboarding had no internal boot step, so users had to leave onboarding and configure it elsewhere. - Problem: internal boot setup was disconnected from first-run setup and could not be intentionally skipped/recorded in onboarding state. - Change: added an INTERNAL_BOOT step after core settings, hidden for partner builds, with skip support and persisted draft state. - Implementation: added internal boot template parser/submission helper, new step UI with validation (slots/devices/size/update BIOS), and modal/step registry wiring.
- Purpose: execute internal boot configuration during onboarding confirm/apply and surface reboot follow-up. - Before: summary only applied core settings/plugins/ssh; internal boot selections were not applied. - Problem: users could choose internal boot but onboarding would not run mkbootpool or reflect reboot needs. - Change: summary now calls mkbootpool endpoint without reboot, logs command output, and treats failures as warnings in best-effort flow. - Implementation: added internal boot summary card, included internal boot in apply-change detection, and switched final CTA to reboot when internal boot apply succeeds.
- Purpose: validate onboarding step routing and summary apply behavior after internal boot integration. - Before: tests assumed old step indexes and had no assertions for internal boot visibility or mkbootpool execution. - Problem: regressions in partner-step visibility and internal boot apply flow would be hard to detect. - Change: updated modal tests for INTERNAL_BOOT presence/hiding and adjusted activation-step index expectations. - Implementation: extended summary tests to mock internal boot submission, verify no-reboot payload, success flag behavior, and warning path on failures.
- Purpose: resolve remaining type-check/test/lint failures after internal-boot onboarding integration. - Before: web type-check failed on an unused loop variable, onboarding modal test used an outdated step index, and prettier check failed on touched onboarding files. - Problem: CI gates for type-check/test/lint were not green for the onboarding changes. - Change: adjusted internal-boot device loop indexing, corrected activation-step test index for ENOKEYFILE1, and applied prettier formatting updates. - Implementation: updated onboarding step/template/test files and refreshed generated component typings for new onboarding step registration.
- Purpose: use existing GraphQL array state in onboarding to decide whether internal boot setup can run.
- Before: onboarding inferred array stoppage from template presence, which could misreport when the page response was unexpected (redirect/empty shell).
- Problem: users could see the 'array must be stopped' message even when because the HTML parse path failed independently of true array state.
- Change: added query and wired to require for configurability.
- Behavior now: array-state gating comes from GraphQL; legacy parsing is retained only for webgui-specific internal-boot data (eligibility button/device options/presets/defaults).
- UX: status messaging now distinguishes array-not-stopped, array-state lookup failure, and inability to load webgui internal-boot template data.
- How it works: drives , while template fetch/parse still initializes boot-pool form options.
- Validation: ran
> unraid-monorepo@4.29.2 codegen /Users/ajitmehrotra/Projects/onboarding-internal-boot
> pnpm -r codegen
Scope: 8 of 9 workspace projects
web codegen$ graphql-codegen --config codegen.ts -r dotenv/config
web codegen: ❯ Parse Configuration
web codegen: ✔ Parse Configuration
web codegen: ❯ Generate outputs
web codegen: ❯ Generate to src/composables/gql/
web codegen: ❯ Load GraphQL schemas
web codegen: ✔ Load GraphQL schemas
web codegen: ❯ Load GraphQL documents
web codegen: ✔ Load GraphQL documents
web codegen: ❯ Generate
web codegen: ✔ Generate
web codegen: ✔ Generate to src/composables/gql/
web codegen: ✔ Generate outputs
web codegen: Done
packages/unraid-api-plugin-connect codegen$ MOTHERSHIP_GRAPHQL_LINK='https://staging.mothership.unraid.net/ws' graphql-codegen --config codegen.ts
packages/unraid-api-plugin-connect codegen: [STARTED] Parse Configuration
packages/unraid-api-plugin-connect codegen: [COMPLETED] Parse Configuration
packages/unraid-api-plugin-connect codegen: [STARTED] Generate outputs
packages/unraid-api-plugin-connect codegen: [STARTED] Generate to src/graphql/generated/client/
packages/unraid-api-plugin-connect codegen: [STARTED] Load GraphQL schemas
packages/unraid-api-plugin-connect codegen: [COMPLETED] Load GraphQL schemas
packages/unraid-api-plugin-connect codegen: [STARTED] Load GraphQL documents
packages/unraid-api-plugin-connect codegen: [COMPLETED] Load GraphQL documents
packages/unraid-api-plugin-connect codegen: [STARTED] Generate
packages/unraid-api-plugin-connect codegen: [COMPLETED] Generate
packages/unraid-api-plugin-connect codegen: [COMPLETED] Generate to src/graphql/generated/client/
packages/unraid-api-plugin-connect codegen: [COMPLETED] Generate outputs
packages/unraid-api-plugin-connect codegen: Done
api codegen$ graphql-codegen --config codegen.ts
api codegen: [STARTED] Parse Configuration
api codegen: [COMPLETED] Parse Configuration
api codegen: [STARTED] Generate outputs
api codegen: [STARTED] Generate to src/unraid-api/cli/generated/
api codegen: [STARTED] Load GraphQL schemas
api codegen: [COMPLETED] Load GraphQL schemas
api codegen: [STARTED] Load GraphQL documents
api codegen: [COMPLETED] Load GraphQL documents
api codegen: [STARTED] Generate
api codegen: [COMPLETED] Generate
api codegen: [COMPLETED] Generate to src/unraid-api/cli/generated/
api codegen: [COMPLETED] Generate outputs
api codegen: Done,
> unraid-monorepo@4.29.2 type-check /Users/ajitmehrotra/Projects/onboarding-internal-boot
> pnpm -r type-check
Scope: 8 of 9 workspace projects
unraid-ui type-check$ vue-tsc --noEmit
web type-check$ vue-tsc --noEmit
unraid-ui type-check: Done
web type-check: Done
api type-check$ tsc --noEmit
api type-check: Done,
> unraid-monorepo@4.29.2 test /Users/ajitmehrotra/Projects/onboarding-internal-boot
> pnpm -r test
Scope: 8 of 9 workspace projects
packages/unraid-api-plugin-health test$ echo "Error: no test specified" && exit 0
packages/unraid-shared test$ vitest run
plugin test$ vitest && pnpm run test:extractor && pnpm run test:shell-detection
unraid-ui test$ vitest
packages/unraid-api-plugin-health test: Error: no test specified
packages/unraid-api-plugin-health test: Done
web test$ vitest run
unraid-ui test: RUN v3.2.4 /Users/ajitmehrotra/Projects/onboarding-internal-boot/unraid-ui
packages/unraid-shared test: RUN v3.2.4 /Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared
web test: RUN v3.2.4 /Users/ajitmehrotra/Projects/onboarding-internal-boot/web
plugin test: RUN v3.2.4 /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test
packages/unraid-shared test: Server listening on Unix socket: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/test-ws-unix-1772218335390.sock
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect to Unix socket using ws+unix:// protocol
packages/unraid-shared test: Connecting to: ws+unix:///var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/test-ws-unix-1772218335390.sock:/
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect to Unix socket using ws+unix:// protocol
packages/unraid-shared test: Server: New WebSocket connection on path: /
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect to Unix socket using ws+unix:// protocol
packages/unraid-shared test: Client: Connected successfully!
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect to Unix socket using ws+unix:// protocol
packages/unraid-shared test: Server received: Test message
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect with /graphql path like SocketConfigService
packages/unraid-shared test: Testing SocketConfigService format: ws+unix:///var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/test-ws-unix-1772218335390.sock:/graphql
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect with /graphql path like SocketConfigService
packages/unraid-shared test: Server: New WebSocket connection on path: /graphql
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should connect with /graphql path like SocketConfigService
packages/unraid-shared test: Client: Connected to /graphql path
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Server: Client disconnected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Server: New WebSocket connection on path: /client-0
packages/unraid-shared test: ✓ src/util/permissions.spec.ts (21 tests) 9ms
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Client 0 connected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Server: Client disconnected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Server: New WebSocket connection on path: /client-1
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Client 1 connected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Server: New WebSocket connection on path: /client-2
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should work with multiple concurrent connections
packages/unraid-shared test: Client 2 connected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should verify the exact implementation used in BaseInternalClientService
packages/unraid-shared test: Server: Client disconnected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should verify the exact implementation used in BaseInternalClientService
packages/unraid-shared test: Server: Client disconnected
packages/unraid-shared test: stdout | src/services/ws-unix-socket-test.spec.ts > WebSocket Unix Socket - Actual Connection Test > should verify the exact implementation used in BaseInternalClientService
packages/unraid-shared test: Server: Client disconnected
packages/unraid-shared test: ✓ src/util/__tests__/key-order.test.ts (2 tests) 79ms
packages/unraid-shared test: ✓ src/util/__tests__/permissions.test.ts (25 tests) 13ms
packages/unraid-shared test: ✓ src/util/__tests__/processing.test.ts (18 tests) 231ms
packages/unraid-shared test: ✓ src/services/ws-unix-socket-test.spec.ts (5 tests) 465ms
packages/unraid-shared test: ✓ WebSocket Unix Socket - Actual Connection Test > should verify the exact implementation used in BaseInternalClientService 336ms
packages/unraid-shared test: stderr | src/util/permissions-scopes.spec.ts > convertScopesToPermissions > should handle invalid scope formats gracefully
packages/unraid-shared test: Invalid scope format (missing colon): INVALID_SCOPE
packages/unraid-shared test: Invalid scope format: :action
packages/unraid-shared test: Invalid scope format: RESOURCE:
packages/unraid-shared test: Unknown resource in scope: UNKNOWN:read:any
packages/unraid-shared test: ✓ src/util/permissions-scopes.spec.ts (5 tests) 12ms
unraid-ui test: ✓ src/lib/utils.test.ts (8 tests) 8ms
packages/unraid-shared test: ✓ src/util/__tests__/create-ttl-memoized-loader.test.ts (4 tests) 2ms
packages/unraid-shared test: ✓ src/services/internal-graphql-client-usage.spec.ts (17 tests) 22ms
packages/unraid-shared test: ✓ src/use-permissions.directive.spec.ts (24 tests) 4ms
plugin test: ✓ builder/utils/manifest-validator.test.ts (16 tests) 144ms
plugin test: stderr | builder/__tests__/cli/setup-txz-environment.spec.ts > setupTxzEnvironment > should parse and return provided environment arguments
plugin test: skipValidation is true, skipping validation
plugin test: ✓ builder/__tests__/cli/setup-txz-environment.spec.ts (4 tests) 5ms
packages/unraid-shared test: ✓ src/util/__tests__/config-definition.test.ts (7 tests) 9ms
unraid-ui test: stderr | src/composables/useTeleport.test.ts > useTeleport > should return teleportTarget ref with correct value
unraid-ui test: [Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
unraid-ui test: ✓ src/composables/useTeleport.test.ts (6 tests) 127ms
packages/unraid-shared test: ✓ src/services/socket-config.service.spec.ts (31 tests) 7ms
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > validatePluginEnv > validates required fields
plugin test: Reading txz file from: ./test.txz
plugin test: Mock readFile called with: ./test.txz undefined
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > validatePluginEnv > handles tag option in non-CI mode
plugin test: Reading txz file from: ./test.txz
plugin test: Mock readFile called with: ./test.txz undefined
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > validatePluginEnv > reads release notes when release-notes-path is provided
plugin test: Mock readFile called with: valid-release-notes.txt utf8
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > validatePluginEnv > reads release notes when release-notes-path is provided
plugin test: Reading txz file from: ./test.txz
plugin test: Mock readFile called with: ./test.txz undefined
plugin test: stderr | builder/__tests__/cli/setup-plugin-environment.spec.ts > validatePluginEnv > handles tag option in non-CI mode
plugin test: Tag is set, will generate a TAGGED build
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should generate changelog header with version
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at processTicksAndRejections (node:internal/process/task_queues:103:5)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:18:20
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > sets up environment from CLI arguments
plugin test: Plugin version: 2026.02.27.1852
plugin test: Options: {
plugin test: ci: false,
plugin test: apiVersion: '4.29.2\n' +
plugin test: '+fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git\n',
plugin test: baseUrl: 'https://example.com',
plugin test: pluginVersion: '2024.05.05.1232',
plugin test: txzPath: './test.txz'
plugin test: }
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > sets up environment from CLI arguments
plugin test: Reading txz file from: ./test.txz
plugin test: Mock readFile called with: ./test.txz undefined
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > sets up environment from CLI arguments
plugin test: Plugin environment setup successfully: {
plugin test: ci: false,
plugin test: apiVersion: '4.29.2\n' +
plugin test: '+fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git\n',
plugin test: baseUrl: 'https://example.com',
plugin test: tag: '',
plugin test: buildNumber: 1,
plugin test: txzPath: './test.txz',
plugin test: pluginVersion: '2024.05.05.1232',
plugin test: releaseNotes: 'FAST_TEST_CHANGELOG',
plugin test: txzSha256: '6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72'
plugin test: }
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should generate changelog with tag parameter
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:33:20
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > throws when required options are missing
plugin test: Plugin version: 2026.02.27.1852
plugin test: Options: {
plugin test: ci: false,
plugin test: apiVersion: '4.29.2\n' +
plugin test: '+fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git\n',
plugin test: baseUrl: 'http://localhost:5858',
plugin test: pluginVersion: '2026.02.27.1852'
plugin test: }
plugin test: TXZ path not found at: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/deploy/dynamix.unraid.net-4.29.2
plugin test: +fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: -x86_64-1.txz
plugin test: Attempting to find TXZ using apiVersion: 4.29.2
plugin test: +fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: Could not find TXZ at: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/deploy/dynamix.unraid.net-4.29.2
plugin test: +fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: -x86_64-1.txz
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > handles optional CLI arguments
plugin test: Plugin version: 2026.02.27.1852
plugin test: Options: {
plugin test: ci: true,
plugin test: apiVersion: '4.29.2\n' +
plugin test: '+fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git\n',
plugin test: baseUrl: 'https://example.com',
plugin test: pluginVersion: '2024.05.05.1232',
plugin test: txzPath: './test.txz',
plugin test: tag: 'PR1203'
plugin test: }
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > handles optional CLI arguments
plugin test: Reading txz file from: ./test.txz
plugin test: Mock readFile called with: ./test.txz undefined
plugin test: stdout | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > handles optional CLI arguments
plugin test: Plugin environment setup successfully: {
plugin test: ci: true,
plugin test: apiVersion: '4.29.2\n' +
plugin test: '+fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git\n',
plugin test: baseUrl: 'https://example.com',
plugin test: tag: 'PR1203',
plugin test: buildNumber: 1,
plugin test: txzPath: './test.txz',
plugin test: pluginVersion: '2024.05.05.1232',
plugin test: releaseNotes: 'FAST_TEST_CHANGELOG',
plugin test: txzSha256: '6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72'
plugin test: }
plugin test: stderr | builder/__tests__/cli/setup-plugin-environment.spec.ts > setupPluginEnv > handles optional CLI arguments
plugin test: Tag is set, will generate a TAGGED build
plugin test: ✓ builder/__tests__/cli/setup-plugin-environment.spec.ts (8 tests) 277ms
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should handle error gracefully and return tag
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at processTicksAndRejections (node:internal/process/task_queues:103:5)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:64:20
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should use conventional-changelog v7 API correctly
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at processTicksAndRejections (node:internal/process/task_queues:103:5)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:81:7
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
packages/unraid-shared test: ✓ src/jsonforms/__tests__/settings.test.ts (3 tests) 3ms
unraid-ui test: ✓ src/components/common/button/Button.test.ts (4 tests) 23ms
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336665/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:159:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336665/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336677/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
unraid-ui test: Test Files 3 passed (3)
unraid-ui test: Tests 18 passed (18)
unraid-ui test: Start at 13:52:14
unraid-ui test: Duration 1.86s (transform 605ms, setup 0ms, collect 2.04s, tests 159ms, environment 1.67s, prepare 230ms)
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336685/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336698/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:174:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM WARN [ConfigFileHandler:test-config.json] Migration failed. Using defaults.
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM WARN [ConfigFileHandler:test-config.json] Error: Migration failed
packages/unraid-shared test: at TestConfigDefinition.migrateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:109:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:65:54�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:174:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Invalid version: must be >= 1
packages/unraid-shared test: at TestConfigFilePersister.validate �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/__tests__/config-file.test.ts:80:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:93:34�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.loadOrMigrateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:223:20�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.onModuleInit �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:159:5�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/__tests__/config-file.test.ts:178:5
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336685/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Invalid maxRetries: must be >= 0
packages/unraid-shared test: at TestConfigDefinition.validate �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:94:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:57:36�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:204:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336701/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336721/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] SyntaxError: Expected property name or '}' in JSON at position 2 (line 1 column 3)
packages/unraid-shared test: at JSON.parse (<anonymous>)
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:92:25�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:218:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336726/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should validate changelog structure
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:95:20
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336737/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:279:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM WARN [ConfigFileHandler:test-config.json] Migration failed. Using defaults.
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM WARN [ConfigFileHandler:test-config.json] Error: Special validation failure: migration + defaults combo invalid
packages/unraid-shared test: at SpecialMigrationDefinition.validate �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:266:19�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:66:52�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:279:22
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336745/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336754/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336754/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.loadOrMigrateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:223:20�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.onModuleInit �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:159:5�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/__tests__/config-file.test.ts:295:5
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336754/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336757/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336754/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM ERROR [ConfigFileHandler:test-config.json] Error: Validation failed
packages/unraid-shared test: at TestConfigDefinition.validate �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:78:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.writeConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:105:38�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:376:41
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:155:11
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:26
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:1897:20
packages/unraid-shared test: at new Promise (<anonymous>)
packages/unraid-shared test: at runWithTimeout (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:1863:10)
packages/unraid-shared test: at runTest (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:1574:12)
packages/unraid-shared test: at runSuite (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:1729:8)
packages/unraid-shared test: Cannot write invalid config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
unraid-ui test: Done
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336770/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM WARN [ConfigFilePersister:test-config.json] Cannot persist undefined config
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336772/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336777/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.updateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:146:29�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:406:23
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336777/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336777/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM ERROR [ConfigFileHandler:test-config.json] Failed to update config
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM ERROR [ConfigFileHandler:test-config.json] Error: Invalid version: must be >= 1
packages/unraid-shared test: at TestConfigDefinition.validate �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:85:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.updateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:147:47�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:423:23
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /invalid/readonly/path/test-config.json
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM ERROR [ConfigFileHandler:test-config.json] [Error: ENOENT: no such file or directory, open '/invalid/readonly/path/test-config.json.tmp-2218336795ee3d5e'] {
packages/unraid-shared test: errno: �[33m-2�[39m,
packages/unraid-shared test: code: �[32m'ENOENT'�[39m,
packages/unraid-shared test: syscall: �[32m'open'�[39m,
packages/unraid-shared test: path: �[32m'/invalid/readonly/path/test-config.json.tmp-2218336795ee3d5e'�[39m
packages/unraid-shared test: }
packages/unraid-shared test: Error writing config to '/invalid/readonly/path/test-config.json'
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336802/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/__tests__/config-file-handler.test.ts:453:20
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336802/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
plugin test: stdout | builder/utils/changelog.test.ts > getStagingChangelogFromGit > should include actual commits when using gitRawCommitsOpts with tag
plugin test: Non-fatal error: Failed to get changelog from git: Error: fatal: invalid gitfile format: /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/.git
plugin test: at catchProcessError (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:42:13)
plugin test: at processTicksAndRejections (node:internal/process/task_queues:103:5)
plugin test: at outputStream (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@simple-libs+child-process-utils@1.0.1/node_modules/@simple-libs/child-process-utils/src/index.ts:83:17)
plugin test: at ConventionalGitClient.getTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/GitClient.ts:152:16)
plugin test: at ConventionalGitClient.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@conventional-changelog+git-client@2.5.1_conventional-commits-filter@5.0.0_conventional-commits-parser@6.2.0/node_modules/@conventional-changelog/git-client/src/ConventionalGitClient.ts:100:16)
plugin test: at ConventionalChangelog.getSemverTags (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:240:22)
plugin test: at ConventionalChangelog.write (file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/conventional-changelog@7.1.1_conventional-commits-filter@5.0.0/node_modules/conventional-changelog/src/ConventionalChangelog.ts:591:24)
plugin test: at getStagingChangelogFromGit (/Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.ts:154:22)
plugin test: at /Users/ajitmehrotra/Projects/onboarding-internal-boot/plugin/builder/utils/changelog.test.ts:115:20
plugin test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336823/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44435 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-handler-test-1772218336802/test-config.json
packages/unraid-shared test: ✓ src/util/__tests__/config-file-handler.test.ts (17 tests) 183ms
web test: ✓ __test__/components/ThemeSwitcher.test.ts (10 tests) 76ms
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336904/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336904/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.loadOrMigrateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:223:20�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.onModuleInit �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:159:5�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/__tests__/config-file.test.ts:391:5
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Writing config to /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336904/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Config is unchanged, skipping write
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFilePersister:test-config.json] Config path: /var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336914/test-config.json
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error: Config file does not exist at '/var/folders/95/f6tc2xdd2t703__z22w4lxzh0000gn/T/config-test-1772218336914/test-config.json'
packages/unraid-shared test: at ConfigFileHandler.readConfigFile �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:89:13�[90m)�[39m
packages/unraid-shared test: at ConfigFileHandler.loadConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/util/config-file-handler.ts:56:26�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.loadOrMigrateConfig �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:223:20�[90m)�[39m
packages/unraid-shared test: at TestConfigFilePersister.onModuleInit �[90m(/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/config-file.ts:159:5�[90m)�[39m
packages/unraid-shared test: at �[90m/Users/ajitmehrotra/Projects/onboarding-internal-boot/packages/unraid-shared/�[39msrc/services/__tests__/config-file.test.ts:399:5
packages/unraid-shared test: at file:///Users/ajitmehrotra/Projects/onboarding-internal-boot/node_modules/�[4m.pnpm�[24m/@vitest+runner@3.2.4/node_modules/�[4m@vitest/runner�[24m/dist/chunk-hooks.js:752:20
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM DEBUG [ConfigFileHandler:test-config.json] Error loading config. Attempting to migrate...
packages/unraid-shared test: [Nest] 44433 - 02/27/2026, 1:52:16 PM VERBOSE [ConfigFileHandler:test-config.json] Existing config unreadable, proceeding with write
packages/unraid-shared test: …
Purpose: remove fragile dependency on /Main/PoolDevices HTML parsing for internal-boot onboarding setup data. Before: onboarding fetched and parsed the legacy PoolDevices page to infer array availability, eligibility, and candidate devices. Problem: in this app context the PoolDevices page can be unavailable/redirected, causing parsing to fail and blocking setup even when server state is valid. Change: introduced GetInternalBootContext GraphQL query (array, vars.fsState, disks) and derived onboarding options directly from API state. Behavior now: array-stopped checks come from GraphQL state, candidate devices come from unassigned non-USB disks, and pool/boot-size defaults are computed locally. Simplification: removed template HTML parsing logic from internalBoot composable; it now focuses on mkbootpool submission and reboot post only. Compatibility: mkbootpool.php and Boot.php invocation paths remain unchanged for apply/reboot behavior. Validation: ran pnpm codegen, pnpm type-check, pnpm test, and pnpm lint in web successfully.
Purpose: provide onboarding with the same core boot-setup eligibility/device identity data used by webgui state files, without adding new HTTP endpoints. Before: GraphQL exposed array/fs state and system disk data, but not vars.bootEligible or devs.ini-backed disk assignment identifiers/sectors. Problem: onboarding could not reliably mirror webgui bootable-pool gating/device identity because mkbootpool expects emhttp disk IDs and webgui eligibility depends on bootEligible. Change: added bootEligible to var parsing/core type/GraphQL Vars model and surfaced emhttp devs metadata on existing Disk type (emhttpDeviceId, sectors, sectorSize). How it works: DisksService now reads store.emhttp.devices, matches entries by normalized device name, and projects emhttp assignment metadata alongside existing disk data. Tests: updated var parser snapshot and extended disks service tests to assert emhttp metadata mapping and config access. Validation: pnpm --filter ./api type-check, pnpm --filter ./api lint, and targeted vitest for var parser + disks service passed.
Purpose: switch internal-boot onboarding inputs to API-provided boot eligibility and emhttp-backed disk identity metadata. Before: onboarding inferred eligibility and device IDs from non-webgui sources and local heuristics, which could drift from mkbootpool expectations. Problem: when PoolDevices rendering is unavailable, onboarding still needs deterministic data for gating and for args[] disk IDs accepted by mkbootpool. Change: internal boot context query now requests vars.bootEligible and disk emhttp metadata; step maps selectable devices using emhttpDeviceId plus sector data and uses bootEligible for eligibility messaging. Behavior: array stopped gating uses array/vars state, eligibility uses vars.bootEligible, and boot-size math uses sectors*sectorSize (fallback to disk size). Compatibility: mkbootpool.php submission path is unchanged; selected device values now align with emhttp disk IDs expected by cmdAssignDisk flow. Validation: pnpm codegen, pnpm --filter @unraid/web type-check, pnpm --filter @unraid/web test, and pnpm --filter @unraid/web lint passed.
- Purpose: provide a dedicated onboarding query that mirrors webgui internal-boot context sourcing from emhttp state. - Before: onboarding fetched mixed GraphQL fields (array/vars/disks) and derived boot device context from system disk data. - Problem: migration parity was weaker because validation inputs and selectable boot devices were not sourced the same way as webgui. - Change: added GraphQL query with device options from (devs.ini), plus pool/share/reserved-name context and boot defaults. - Change: added resolver/service/model wiring and schema artifacts, including deterministic device sorting aligned to CacheDevices.page behavior. - Change: added service unit tests and updated emhttp state snapshot expectations for . - How it works: service reads emhttp var/disks/shares/devices, computes boot-pool defaults and constraints, and returns a single query payload consumed by onboarding.
- Purpose: port internal-boot onboarding UI logic to consume the dedicated API context with webgui-aligned inputs. - Before: the step mixed array/vars/disks queries and inferred devices/constraints client-side from generic disk metadata. - Problem: validation and selectable-device behavior could diverge from CacheDevices.page during migration. - Change: switched query consumption to onboardingInternalBoot context and regenerated typed GraphQL documents. - Change: added pool-name collision validation against reserved names, user shares, and existing pools to match webgui checks. - Change: removed HTML-parsing/system-disk derivation paths; device options now come directly from API-provided devs.ini context. - How it works: the step initializes defaults, slot limits, preset bounds, and validation rules from one query payload and persists the same draft selection flow.
- Purpose: revert the custom onboarding-specific internal boot GraphQL surface and return to existing API surfaces only. - Before: Query included with custom resolver/service/types and schema entries generated from that path. - Problem: this diverged from the migration goal of reusing existing API data and increased maintenance/behavior drift risk. - Change: removed resolver/service/model files, detached providers from , and removed schema/codegen artifacts for that field. - How it works now: API exposes no new onboarding internal-boot query; consumers must use existing /// GraphQL fields.
- Purpose: align onboarding internal-boot setup with existing API queries instead of a custom onboarding query. - Before: onboarding step read a dedicated onboardingInternalBoot GraphQL field. - Problem: extra query surface was unnecessary for this migration and made parity/debugging harder. - Change: rewired onboarding internal-boot context query to existing fields (array, vars, shares, disks), updated step logic to derive options from those fields, and regenerated web GraphQL artifacts. - How it works: onboarding now checks array state and boot eligibility from existing data, builds device options from disks, and keeps summary/apply behavior on the existing mkbootpool POST flow. - Tracking: added docs/onboarding-internal-boot-port-differences.md to keep an explicit list of current non-1:1 differences versus webgui.
- Purpose: surface the same var.ini signals webgui uses so onboarding can match visibility and validation behavior without new endpoints. - Before: GraphQL vars did not expose enableBootTransfer or reservedNames, so web had to infer/hardcode parts of webgui logic. - Problem: onboarding could not reliably hide the step when already booting internally and could not run reserved-name validation parity. - Change: added enableBootTransfer and reservedNames to Vars GraphQL model, state types/parser typing, generated schema, and API generated GraphQL types. - How it works: clients can now read vars.enableBootTransfer and vars.reservedNames directly from the existing vars query.
- Purpose: match webgui behavior for internal-boot onboarding visibility and pool-name validation. - Before: internal-boot step still appeared when already booting internally, and validation did not include reservedNames parity checks. - Problem: users on internal boot saw an unnecessary step and validation could diverge from CacheDevices.page constraints. - Change: added lightweight step-visibility query in onboarding modal using vars.enableBootTransfer, expanded internal-boot context query to include vars.reservedNames/enableBootTransfer, and aligned validation ordering/checks with webgui (reserved names, shares, pools, regex). - How it works: step is filtered out when enableBootTransfer is no; onboarding validates pool names against the same var/share/pool sources and ordering used by webgui logic. - Tracking: updated the internal-boot port differences document to remove resolved parity gaps and keep remaining deltas explicit.
- Purpose: make onboarding internal-boot submit the same device identifiers used by webgui. - Before: dropdown option value preferred GraphQL disk.id, which includes server-prefixed IDs and did not match webgui mkbootpool args. - Problem: mkbootpool requests could fail or behave unexpectedly because device args were not in emhttp devs.ini id format. - Change: updated internal boot device option mapping to use emhttpDeviceId first, with device name fallback. - How it works: submitted args[] now mirror webgui option values, improving compatibility with mkbootpool.php and downstream scripts.
- Purpose: make onboarding internal-boot apply robust when mkbootpool.php returns non-ideal payloads. - Before: onboarding expected clean JSON and surfaced a generic failure when the response body was empty or noisy. - Problem: users could see unhelpful failures even with HTTP 200, making server-side debugging difficult. - Change: added tolerant response parsing (strict JSON first, then JSON substring fallback) and parity with webgui ajax behavior. - Change: when response body is empty, onboarding now attempts and reports detailed HTTP diagnostics as fallback. - Result: failures now return actionable output instead of opaque request-failed messages.
- Purpose: keep onboarding internal-boot context aligned with fields actually consumed by the UI. - Before: the context query fetched extra disk fields that were not used by the onboarding step. - Problem: unused fields increased payload and made emhttp-derived metadata origin less explicit. - Change: removed unused disk fields from GetInternalBootContext and aliased emhttp-backed metadata to explicit names. - Change: updated the internal-boot step to consume emhttpSectors and emhttpSectorSize while preserving emhttpDeviceId selection behavior. - Change: regenerated GraphQL client artifacts for the updated query shape. - Result: smaller query surface, clearer field provenance, and no behavior change in selection/size calculations.
- Purpose: make onboarding internal-boot requests match webgui PHP post expectations. - Before: onboarding posted args to mkbootpool.php without csrf_token and relied only on same-origin cookies. - Problem: on systems enforcing CSRF checks, mkbootpool.php can return an empty HTTP 200 response instead of JSON output. - Change: append csrf_token from global csrf_token into form payload and also send x-csrf-token header when available. - Change: remove HTTP fetch fallback to /boot/config/internal_boot/output.log because that filesystem path is not generally web-served. - Result: onboarding requests now follow existing webgui request conventions and avoid noisy 404 fallback probes.
- Purpose: align onboarding internal-boot logging with the rest of onboarding and make reboot submit path reliable. - Before: successful internal-boot apply logged full script output into onboarding console, and reboot submit used a minimal form post that could land on Boot.php without executing expected reboot flow. - Problem: extra success log noise reduced signal in onboarding logs, and reboot flow could appear inert in some contexts. - Change: removed verbose success output logging from summary step; success now logs the same concise status style as other onboarding actions. - Change: reboot submit now posts directly to /plugins/dynamix/include/Boot.php, targets _top, and includes csrf_token when available. - Change: tightened empty mkbootpool-response message to concise guidance. - Change: added composable tests for mkbootpool payload csrf inclusion and reboot form construction. - Result: cleaner onboarding logs and a reboot action that follows webgui/php expectations more robustly.
WalkthroughThis PR introduces internal boot functionality across the stack. It adds boot-related fields to API state types (bootEligible, enableBootTransfer, reservedNames), disk metadata fields (emhttpDeviceId, sectors, sectorSize), a new onboarding step component for internal boot configuration, supporting store state management, GraphQL queries, and helper composables for submitting boot configurations. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Modal as OnboardingModal
participant InternalBootStep as InternalBootStep
participant GraphQL as Apollo<br/>(GraphQL)
participant API as Server
participant Store as DraftStore
User->>Modal: Navigate to Internal Boot
Modal->>GraphQL: GET_INTERNAL_BOOT_CONTEXT_QUERY
GraphQL->>API: Fetch array, vars, shares, disks
API-->>GraphQL: Return boot context
GraphQL-->>InternalBootStep: Provide context data
InternalBootStep->>Store: Load previous selection
User->>InternalBootStep: Configure pool, devices, boot size
InternalBootStep->>InternalBootStep: Validate form
User->>InternalBootStep: Submit (Next)
InternalBootStep->>Store: setInternalBootSelection()
InternalBootStep->>Modal: onComplete()
Modal->>Modal: Proceed to Summary step
User->>Modal: Review & Apply
Modal->>API: submitInternalBootCreation()
Note over API: POST to mkbootpool.php
API-->>Modal: Creation response
Modal->>Store: setInternalBootApplySucceeded(true)
Modal->>Modal: Show reboot button
User->>Modal: Reboot
Modal->>API: submitInternalBootReboot()
Note over API: POST to Boot.php
API-->>User: System reboots
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
| return null; | ||
| } | ||
|
|
||
| const poolNamePattern = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/; |
Check failure
Code scanning / CodeQL
Inefficient regular expression High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
In general, to fix inefficient regular expressions, remove ambiguous quantified subpatterns—especially something like (X*Y)* where characters can be consumed by either X* or Y—or rewrite them into simpler, unambiguous expressions. This usually means collapsing nested quantified groups, avoiding overlapping character classes in successive tokens, or adding explicit boundaries.
Here, the current regex is:
const poolNamePattern = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/;Semantically, this means:
- Start with a lowercase letter.
- Then, repeat zero or more “segments”, each consisting of:
- zero or more allowed characters
[a-z0-9~._-]* - followed by a final character
[a-z_-].
- zero or more allowed characters
This is equivalent to: “start with a letter, then any number of allowed characters, but do not end with a digit or ~.”. We can express this more simply and without nested ambiguous quantifiers as:
^[a-z][a-z0-9~._-]*[a-z_-]$This form has only simple quantifiers on character classes and no nested repetition, so backtracking is linear. It still enforces:
- First char:
[a-z](lowercase letter). - Middle: any number (possibly zero) of allowed characters.
- Last char:
[a-z_-](no trailing digit,~, or.).
To preserve current semantics exactly, we must also accept 2‑character names like aa and reject 1‑character names like a (because the original pattern requires at least one repetition of ([a-z0-9~._-]*[a-z_-])). If the original behavior is intended, we need to maintain “length ≥ 2”. For clarity and to keep the engine’s work simple, we can write:
^[a-z][a-z0-9~._-]*[a-z_-]$This already ensures a minimum length of 2 because there are two mandatory characters (first and last). Given the original pattern, this is behaviorally equivalent for all strings that fit the alphabet—they all must have at least two characters to match.
Therefore, in web/src/components/Onboarding/steps/OnboardingInternalBootStep.vue, around line 454, replace the existing poolNamePattern definition with the simplified, unambiguous regex:
const poolNamePattern = /^[a-z][a-z0-9~._-]*[a-z_-]$/;No extra imports or helper methods are needed; we only change this one line.
| @@ -451,7 +451,7 @@ | ||
| return null; | ||
| } | ||
|
|
||
| const poolNamePattern = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/; | ||
| const poolNamePattern = /^[a-z][a-z0-9~._-]*[a-z_-]$/; | ||
| if (!poolNamePattern.test(normalizedPoolName)) { | ||
| formError.value = 'Use only lowercase with no special characters or leading/trailing digits.'; | ||
| return null; |
|
This plugin has been deployed to Cloudflare R2 and is available for testing. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1881 +/- ##
==========================================
- Coverage 48.06% 47.75% -0.32%
==========================================
Files 1002 1006 +4
Lines 66511 67495 +984
Branches 6672 6727 +55
==========================================
+ Hits 31968 32229 +261
- Misses 34422 35144 +722
- Partials 121 122 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
web/src/components/Onboarding/OnboardingSteps.vue (1)
10-17: Consider centralizingStepIdin a shared type.Lines [10-17] still duplicate step IDs in this component. Exporting a single
StepIdtype from a shared onboarding module would reduce drift risk as steps evolve.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/Onboarding/OnboardingSteps.vue` around lines 10 - 17, This file defines a local StepId union type that duplicates onboarding step IDs; remove the local StepId declaration in OnboardingSteps.vue and import a single exported StepId from a shared onboarding types/module (e.g., export StepId from a new/shared onboarding types file), then update all references in this component (and any other components) to use the imported StepId type; ensure the shared module exports the same union values and update any usages of 'OVERVIEW'|'CONFIGURE_SETTINGS' etc. to the centralized StepId to prevent drift.web/src/components/Onboarding/steps/OnboardingNextStepsStep.vue (2)
83-90: Consider adding error handling for the reboot submission.
submitInternalBootReboot()is called without awaiting or handling potential errors. If the reboot request fails, the user has no feedback.♻️ Suggested approach
-const handlePrimaryAction = () => { +const handlePrimaryAction = async () => { if (showRebootButton.value) { - submitInternalBootReboot(); - return; + try { + await submitInternalBootReboot(); + } catch (error) { + console.error('Reboot request failed:', error); + } + return; } props.onComplete(); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/Onboarding/steps/OnboardingNextStepsStep.vue` around lines 83 - 90, handlePrimaryAction calls submitInternalBootReboot() without awaiting or handling failures, so add async error handling: make handlePrimaryAction async, await submitInternalBootReboot(), wrap the call in try/catch, show user feedback on error (e.g., set a local error state or call an existing notification method) and only call props.onComplete() on success; also consider disabling the primary button or showing a loading state while awaiting submitInternalBootReboot() to prevent duplicate submissions.
52-54: Hardcoded "Reboot" string should use i18n.The
primaryButtonTextuses a hardcoded'Reboot'string while other text usest()for translation. This creates an inconsistency for localized builds.♻️ Suggested fix
const primaryButtonText = computed(() => - showRebootButton.value ? 'Reboot' : t('onboarding.nextSteps.continueToDashboard') + showRebootButton.value ? t('common.reboot', 'Reboot') : t('onboarding.nextSteps.continueToDashboard') );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/Onboarding/steps/OnboardingNextStepsStep.vue` around lines 52 - 54, primaryButtonText uses a hardcoded 'Reboot' instead of the i18n helper; update the computed to call t() for the reboot label (e.g., t('onboarding.nextSteps.reboot')) when showRebootButton.value is true, and add the corresponding translation key/value to your locale files; reference primaryButtonText and showRebootButton to locate and change the conditional, and ensure existing usages of t('onboarding.nextSteps.continueToDashboard') remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/components/Onboarding/composables/internalBoot.ts`:
- Around line 46-56: The code is unsafely casting JSON.parse results to
MkbootpoolResponsePayload and coercing parsed.ok with Boolean(), bypassing
runtime validation and mis-handling string "false"; instead parse into unknown
(no "as" cast), implement a runtime type guard that checks required fields and
their types (e.g., verify the parsed object has the expected properties for
MkbootpoolResponsePayload), apply that guard both after JSON.parse(trimmed) and
after JSON.parse(trimmed.slice(firstBrace, lastBrace + 1)), and for parsed.ok
normalize it explicitly (if typeof ok === 'boolean' use it, else if typeof ok
=== 'string' accept only 'true'/'false' and convert accordingly), returning null
if validation fails; remove all "as MkbootpoolResponsePayload" casts and replace
them with validated, typed returns using the new type guard.
- Around line 85-119: The code processes the fetch result without checking HTTP
success and uses unsafe casts; update the logic to require response.ok when
deciding success (e.g., return ok: response.ok && parsed?.ok === true instead of
Boolean(parsed.ok)) and modify the parsing flow to remove "as
MkbootpoolResponsePayload" casts by moving JSON.parse/validation into a proper
type-guard or validator inside parseMkbootpoolPayload (ensure
parseMkbootpoolPayload returns a typed union or null after validating required
fields like ok, code, output) so you no longer need to cast parsed values before
using them.
In `@web/src/components/Onboarding/stepRegistry.ts`:
- Around line 38-42: INTERNAL_BOOT in the stepRegistry uses hardcoded English
strings for titleKey and descriptionKey; replace them with i18n keys (e.g., set
titleKey to a key like 'onboarding.internalBoot.title' and descriptionKey to
'onboarding.internalBoot.description') to match the project's localization
pattern used by other steps, and add the corresponding entries to the locale
resource files so the keys resolve at runtime.
In `@web/src/components/Onboarding/steps/OnboardingInternalBootStep.vue`:
- Around line 454-458: The regex assigned to poolNamePattern (used to validate
normalizedPoolName) contains nested quantifiers which can lead to ReDoS; replace
the single complex pattern with a safer two-step validation: first use a simple
allowed-character pattern (e.g., ensure it starts with a lowercase letter and
only contains allowed chars) and then separately check structural rules (e.g.,
does not end or start with a digit, disallow consecutive special characters, or
other constraints). Update the validation logic where poolNamePattern is tested
and set formError.value accordingly so the tests use the new checks instead of
the vulnerable nested-quantifier regex.
In `@web/src/composables/gql/index.ts`:
- Around line 1-2: The re-exports in web/src/composables/gql/index.ts use
extensionless relative paths which breaks ESM conventions; update the two export
statements (export * from './fragment-masking' and export * from './gql') to
include the .js extension (export * from './fragment-masking.js' and export *
from './gql.js') so they match the project's ESM style and other modules like
web/src/utils/authorizationLink.ts.
---
Nitpick comments:
In `@web/src/components/Onboarding/OnboardingSteps.vue`:
- Around line 10-17: This file defines a local StepId union type that duplicates
onboarding step IDs; remove the local StepId declaration in OnboardingSteps.vue
and import a single exported StepId from a shared onboarding types/module (e.g.,
export StepId from a new/shared onboarding types file), then update all
references in this component (and any other components) to use the imported
StepId type; ensure the shared module exports the same union values and update
any usages of 'OVERVIEW'|'CONFIGURE_SETTINGS' etc. to the centralized StepId to
prevent drift.
In `@web/src/components/Onboarding/steps/OnboardingNextStepsStep.vue`:
- Around line 83-90: handlePrimaryAction calls submitInternalBootReboot()
without awaiting or handling failures, so add async error handling: make
handlePrimaryAction async, await submitInternalBootReboot(), wrap the call in
try/catch, show user feedback on error (e.g., set a local error state or call an
existing notification method) and only call props.onComplete() on success; also
consider disabling the primary button or showing a loading state while awaiting
submitInternalBootReboot() to prevent duplicate submissions.
- Around line 52-54: primaryButtonText uses a hardcoded 'Reboot' instead of the
i18n helper; update the computed to call t() for the reboot label (e.g.,
t('onboarding.nextSteps.reboot')) when showRebootButton.value is true, and add
the corresponding translation key/value to your locale files; reference
primaryButtonText and showRebootButton to locate and change the conditional, and
ensure existing usages of t('onboarding.nextSteps.continueToDashboard') remain
unchanged.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
api/src/unraid-api/cli/generated/graphql.tsis excluded by!**/generated/**
📒 Files selected for processing (27)
api/generated-schema.graphqlapi/src/__test__/store/modules/emhttp.test.tsapi/src/__test__/store/state-parsers/var.test.tsapi/src/core/types/states/var.tsapi/src/store/state-parsers/var.tsapi/src/unraid-api/graph/resolvers/disks/disks.model.tsapi/src/unraid-api/graph/resolvers/disks/disks.service.spec.tsapi/src/unraid-api/graph/resolvers/disks/disks.service.tsapi/src/unraid-api/graph/resolvers/vars/vars.model.tsdocs/onboarding-internal-boot-port-differences.mdweb/__test__/components/Onboarding/OnboardingModal.test.tsweb/__test__/components/Onboarding/OnboardingSummaryStep.test.tsweb/__test__/components/Onboarding/internalBoot.test.tsweb/components.d.tsweb/src/components/Onboarding/OnboardingModal.vueweb/src/components/Onboarding/OnboardingSteps.vueweb/src/components/Onboarding/composables/internalBoot.tsweb/src/components/Onboarding/graphql/getInternalBootContext.query.tsweb/src/components/Onboarding/graphql/getInternalBootStepVisibility.query.tsweb/src/components/Onboarding/stepRegistry.tsweb/src/components/Onboarding/steps/OnboardingInternalBootStep.vueweb/src/components/Onboarding/steps/OnboardingNextStepsStep.vueweb/src/components/Onboarding/steps/OnboardingSummaryStep.vueweb/src/components/Onboarding/store/onboardingDraft.tsweb/src/composables/gql/gql.tsweb/src/composables/gql/graphql.tsweb/src/composables/gql/index.ts
| return JSON.parse(trimmed) as MkbootpoolResponsePayload; | ||
| } catch { | ||
| const firstBrace = trimmed.indexOf('{'); | ||
| const lastBrace = trimmed.lastIndexOf('}'); | ||
| if (firstBrace === -1 || lastBrace <= firstBrace) { | ||
| return null; | ||
| } | ||
|
|
||
| try { | ||
| return JSON.parse(trimmed.slice(firstBrace, lastBrace + 1)) as MkbootpoolResponsePayload; | ||
| } catch { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# First, let's find and read the file to see the actual code
file_path="web/src/components/Onboarding/composables/internalBoot.ts"
if [ -f "$file_path" ]; then
echo "=== File exists: $file_path ==="
echo "=== Full file content ==="
cat -n "$file_path"
else
echo "File not found at $file_path"
# Try to find it with fd
echo "=== Searching for internalBoot.ts ==="
fd -a 'internalBoot\.ts$'
fiRepository: unraid/api
Length of output: 4838
Avoid unsafe parse casts and truthy coercion for ok.
Lines 46 and 55 use as MkbootpoolResponsePayload which bypasses TypeScript's type system without runtime shape validation. Additionally, line 103's Boolean(parsed.ok) mishandles string values (e.g., "false" becomes true). Per coding guidelines, avoid casting; prefer proper typing from the start.
Proposed fix
interface MkbootpoolResponsePayload {
ok?: boolean;
code?: number;
output?: string;
}
+
+const isMkbootpoolResponsePayload = (value: unknown): value is MkbootpoolResponsePayload => {
+ if (!value || typeof value !== 'object') return false;
+ const v = value as { ok?: unknown; code?: unknown; output?: unknown };
+ return (
+ (v.ok === undefined || typeof v.ok === 'boolean') &&
+ (v.code === undefined || typeof v.code === 'number') &&
+ (v.output === undefined || typeof v.output === 'string')
+ );
+};
@@
try {
- return JSON.parse(trimmed) as MkbootpoolResponsePayload;
+ const parsed: unknown = JSON.parse(trimmed);
+ return isMkbootpoolResponsePayload(parsed) ? parsed : null;
} catch {
@@
try {
- return JSON.parse(trimmed.slice(firstBrace, lastBrace + 1)) as MkbootpoolResponsePayload;
+ const parsed: unknown = JSON.parse(trimmed.slice(firstBrace, lastBrace + 1));
+ return isMkbootpoolResponsePayload(parsed) ? parsed : null;
} catch {
return null;
}
@@
- ok: Boolean(parsed.ok),
+ ok: parsed.ok === true,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/Onboarding/composables/internalBoot.ts` around lines 46 -
56, The code is unsafely casting JSON.parse results to MkbootpoolResponsePayload
and coercing parsed.ok with Boolean(), bypassing runtime validation and
mis-handling string "false"; instead parse into unknown (no "as" cast),
implement a runtime type guard that checks required fields and their types
(e.g., verify the parsed object has the expected properties for
MkbootpoolResponsePayload), apply that guard both after JSON.parse(trimmed) and
after JSON.parse(trimmed.slice(firstBrace, lastBrace + 1)), and for parsed.ok
normalize it explicitly (if typeof ok === 'boolean' use it, else if typeof ok
=== 'string' accept only 'true'/'false' and convert accordingly), returning null
if validation fails; remove all "as MkbootpoolResponsePayload" casts and replace
them with validated, typed returns using the new type guard.
| const response = await fetch('/plugins/dynamix/include/mkbootpool.php', { | ||
| method: 'POST', | ||
| credentials: 'same-origin', | ||
| headers: { | ||
| 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', | ||
| 'X-Requested-With': 'XMLHttpRequest', | ||
| ...(csrfToken ? { 'x-csrf-token': csrfToken } : {}), | ||
| }, | ||
| body: payload.toString(), | ||
| }); | ||
|
|
||
| const raw = await response.text(); | ||
| const trimmedRaw = raw.trim(); | ||
| const parsed = parseMkbootpoolPayload(raw); | ||
|
|
||
| if (parsed) { | ||
| const parsedOutput = parsed.output?.trim() ?? ''; | ||
| return { | ||
| ok: Boolean(parsed.ok), | ||
| code: parsed.code, | ||
| output: parsedOutput.length > 0 ? parsedOutput : trimmedRaw || 'No output', | ||
| }; | ||
| } | ||
| if (trimmedRaw.length > 0) { | ||
| return { | ||
| ok: false, | ||
| output: trimmedRaw, | ||
| }; | ||
| } | ||
|
|
||
| return { | ||
| ok: false, | ||
| output: `mkbootpool returned an empty response (HTTP ${response.status}). Check /boot/config/internal_boot/output.log via server shell for script output.`, | ||
| }; | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the file
find . -name "internalBoot.ts" -type fRepository: unraid/api
Length of output: 113
🏁 Script executed:
#!/bin/bash
# Read the file to see the full context
cat -n web/src/components/Onboarding/composables/internalBoot.tsRepository: unraid/api
Length of output: 4733
🏁 Script executed:
#!/bin/bash
# Search for the parseMkbootpoolPayload function definition
rg -nP 'function\s+parseMkbootpoolPayload|const\s+parseMkbootpoolPayload' -A10 web/src/components/Onboarding/composables/Repository: unraid/api
Length of output: 1064
🏁 Script executed:
#!/bin/bash
# Find all call sites of submitInternalBootCreation
rg -nP '\bsubmitInternalBootCreation\s*\(' --type=ts --type=tsxRepository: unraid/api
Length of output: 81
🏁 Script executed:
#!/bin/bash
# Check the type definitions for InternalBootSubmitResult
rg -nP 'interface\s+InternalBootSubmitResult|type\s+InternalBootSubmitResult' -A5 web/src/components/Onboarding/Repository: unraid/api
Length of output: 516
🏁 Script executed:
#!/bin/bash
# Find all call sites - retry without tsx type issue
rg -nP '\bsubmitInternalBootCreation\s*\(' -A5 -B2 --type=tsRepository: unraid/api
Length of output: 729
🏁 Script executed:
#!/bin/bash
# Also check for any imports of this function
rg -nP 'submitInternalBootCreation' --type=ts -B2Repository: unraid/api
Length of output: 2615
🏁 Script executed:
#!/bin/bash
# Check if response.ok is checked anywhere in the codebase
rg -nP 'response\.ok' web/src/components/Onboarding/Repository: unraid/api
Length of output: 36
🏁 Script executed:
#!/bin/bash
# Examine the test file to see how the result is used
cat -n web/__test__/components/Onboarding/internalBoot.test.tsRepository: unraid/api
Length of output: 3297
🏁 Script executed:
#!/bin/bash
# Check the OnboardingSummaryStep component for actual usage
rg -nP 'submitInternalBootCreation' web/src/components/Onboarding/ -B3 -A8Repository: unraid/api
Length of output: 3846
🏁 Script executed:
#!/bin/bash
# Check if response.ok is used anywhere in response handling
rg -nP 'response\.(ok|status)' web/src/components/Onboarding/Repository: unraid/api
Length of output: 275
🏁 Script executed:
#!/bin/bash
# Search entire codebase for any other calls to submitInternalBootCreation outside Onboarding dir
rg -nP 'submitInternalBootCreation' --type=tsRepository: unraid/api
Length of output: 1091
🏁 Script executed:
#!/bin/bash
# Check context around the call in OnboardingSummaryStep to confirm try-catch is present
sed -n '655,680p' web/src/components/Onboarding/steps/OnboardingSummaryStep.vueRepository: unraid/api
Length of output: 912
🏁 Script executed:
#!/bin/bash
# Check the complete try-catch block and error handling context
sed -n '655,695p' web/src/components/Onboarding/steps/OnboardingSummaryStep.vueRepository: unraid/api
Length of output: 1421
Check response.ok before processing response body and remove unnecessary type casts.
The function doesn't check response.ok before parsing the response, allowing non-2xx HTTP responses with valid JSON bodies to return ok: true. Additionally, lines 46 and 55 use as MkbootpoolResponsePayload casts, violating the typing guideline to avoid casting.
Recommended fixes:
- Check
response.okwhen determining success (line 103 should useok: response.ok && parsed.ok === trueinstead ofBoolean(parsed.ok)) - Replace
JSON.parse(trimmed) as MkbootpoolResponsePayloadwith proper type guards or validation to eliminate casts per coding guidelines
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/Onboarding/composables/internalBoot.ts` around lines 85 -
119, The code processes the fetch result without checking HTTP success and uses
unsafe casts; update the logic to require response.ok when deciding success
(e.g., return ok: response.ok && parsed?.ok === true instead of
Boolean(parsed.ok)) and modify the parsing flow to remove "as
MkbootpoolResponsePayload" casts by moving JSON.parse/validation into a proper
type-guard or validator inside parseMkbootpoolPayload (ensure
parseMkbootpoolPayload returns a typed union or null after validating required
fields like ok, code, output) so you no longer need to cast parsed values before
using them.
| INTERNAL_BOOT: { | ||
| titleKey: 'Internal Boot', | ||
| descriptionKey: 'Configure bootable pool', | ||
| icon: 'i-heroicons-circle-stack', | ||
| }, |
There was a problem hiding this comment.
Hardcoded strings should use i18n keys for consistency.
Other steps use localization key patterns (e.g., 'onboarding.coreSettings.title'), but INTERNAL_BOOT uses hardcoded English strings. This will prevent localization of the internal boot step.
Suggested fix using i18n keys
INTERNAL_BOOT: {
- titleKey: 'Internal Boot',
- descriptionKey: 'Configure bootable pool',
+ titleKey: 'onboarding.internalBoot.title',
+ descriptionKey: 'onboarding.internalBoot.description',
icon: 'i-heroicons-circle-stack',
},📝 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.
| INTERNAL_BOOT: { | |
| titleKey: 'Internal Boot', | |
| descriptionKey: 'Configure bootable pool', | |
| icon: 'i-heroicons-circle-stack', | |
| }, | |
| INTERNAL_BOOT: { | |
| titleKey: 'onboarding.internalBoot.title', | |
| descriptionKey: 'onboarding.internalBoot.description', | |
| icon: 'i-heroicons-circle-stack', | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/Onboarding/stepRegistry.ts` around lines 38 - 42,
INTERNAL_BOOT in the stepRegistry uses hardcoded English strings for titleKey
and descriptionKey; replace them with i18n keys (e.g., set titleKey to a key
like 'onboarding.internalBoot.title' and descriptionKey to
'onboarding.internalBoot.description') to match the project's localization
pattern used by other steps, and add the corresponding entries to the locale
resource files so the keys resolve at runtime.
| const poolNamePattern = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/; | ||
| if (!poolNamePattern.test(normalizedPoolName)) { | ||
| formError.value = 'Use only lowercase with no special characters or leading/trailing digits.'; | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Potential ReDoS vulnerability in pool name regex.
The pattern ([a-z0-9~._-]*[a-z_-])* can cause exponential backtracking on inputs like "a" + "-".repeat(30). The nested quantifiers create overlapping match possibilities.
🔒 Suggested fix with a safer pattern
- const poolNamePattern = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/;
+ // Validates: starts with lowercase letter, contains allowed chars, doesn't end with digit
+ const poolNamePattern = /^[a-z][a-z0-9~._-]*[a-z_-]$|^[a-z]$/;
if (!poolNamePattern.test(normalizedPoolName)) {Alternatively, if the intent is to disallow consecutive special characters or enforce specific structure, consider validating in multiple steps:
// Check allowed characters first, then validate structure
const hasValidChars = /^[a-z][a-z0-9~._-]*$/.test(normalizedPoolName);
const endsWithDigit = /\d$/.test(normalizedPoolName);
if (!hasValidChars || endsWithDigit) {
formError.value = '...';
return null;
}🧰 Tools
🪛 GitHub Check: CodeQL
[failure] 454-454: Inefficient regular expression
This part of the regular expression may cause exponential backtracking on strings starting with 'a' and containing many repetitions of '-'.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/Onboarding/steps/OnboardingInternalBootStep.vue` around
lines 454 - 458, The regex assigned to poolNamePattern (used to validate
normalizedPoolName) contains nested quantifiers which can lead to ReDoS; replace
the single complex pattern with a safer two-step validation: first use a simple
allowed-character pattern (e.g., ensure it starts with a lowercase letter and
only contains allowed chars) and then separately check structural rules (e.g.,
does not end or start with a digit, disallow consecutive special characters, or
other constraints). Update the validation logic where poolNamePattern is tested
and set formError.value accordingly so the tests use the new checks instead of
the vulnerable nested-quantifier regex.
| export * from './fragment-masking'; | ||
| export * from './gql'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the file in question
find . -name "index.ts" -path "*/composables/gql/*" -type fRepository: unraid/api
Length of output: 119
🏁 Script executed:
# Also check for the referenced files
find . -path "*/composables/gql/*" -type fRepository: unraid/api
Length of output: 377
🏁 Script executed:
# Search for similar re-export patterns in the web directory
rg "export \* from" web/ --type ts -A 0 -B 0 | head -30Repository: unraid/api
Length of output: 372
🏁 Script executed:
cat -n web/src/composables/gql/index.tsRepository: unraid/api
Length of output: 126
🏁 Script executed:
# Check other re-export patterns in web/src to understand consistency
rg "export \* from" web/src --type ts -B 0 -A 0 | sort | uniq -cRepository: unraid/api
Length of output: 279
🏁 Script executed:
# Check if there's any build or transpilation config that might affect this
find . -name "tsconfig.json" -o -name "nuxt.config.ts" -o -name "vite.config.ts" | head -5 | xargs cat 2>/dev/nullRepository: unraid/api
Length of output: 11785
Add .js extensions to re-exports for ESM compatibility.
Lines 1-2 use extensionless relative paths, which violates the project's ESM convention. Other files in the codebase (e.g., web/src/utils/authorizationLink.ts) consistently use .js extensions in re-exports.
Suggested fix
-export * from './fragment-masking';
-export * from './gql';
+export * from './fragment-masking.js';
+export * from './gql.js';📝 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.
| export * from './fragment-masking'; | |
| export * from './gql'; | |
| export * from './fragment-masking.js'; | |
| export * from './gql.js'; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/composables/gql/index.ts` around lines 1 - 2, The re-exports in
web/src/composables/gql/index.ts use extensionless relative paths which breaks
ESM conventions; update the two export statements (export * from
'./fragment-masking' and export * from './gql') to include the .js extension
(export * from './fragment-masking.js' and export * from './gql.js') so they
match the project's ESM style and other modules like
web/src/utils/authorizationLink.ts.
Summary by CodeRabbit
New Features
Documentation