@zerwiz/ymir 0.1.33 → 0.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/apps/README.md +4 -0
- package/apps/hlidskjalf/README.md +68 -0
- package/apps/hlidskjalf/android/app/build.gradle +73 -0
- package/apps/hlidskjalf/android/app/capacitor.build.gradle +19 -0
- package/apps/hlidskjalf/android/app/proguard-rules.pro +21 -0
- package/apps/hlidskjalf/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +26 -0
- package/apps/hlidskjalf/android/app/src/main/AndroidManifest.xml +41 -0
- package/apps/hlidskjalf/android/app/src/main/java/org/zerwiz/ymir/MainActivity.java +5 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +34 -0
- package/apps/hlidskjalf/android/app/src/main/res/layout/activity_main.xml +12 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/apps/hlidskjalf/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
- package/apps/hlidskjalf/android/app/src/main/res/values/strings.xml +7 -0
- package/apps/hlidskjalf/android/app/src/main/res/values/styles.xml +22 -0
- package/apps/hlidskjalf/android/app/src/main/res/xml/file_paths.xml +5 -0
- package/apps/hlidskjalf/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +18 -0
- package/apps/hlidskjalf/android/build.gradle +29 -0
- package/apps/hlidskjalf/android/capacitor.settings.gradle +3 -0
- package/apps/hlidskjalf/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/apps/hlidskjalf/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/apps/hlidskjalf/android/gradle.properties +22 -0
- package/apps/hlidskjalf/android/gradlew +248 -0
- package/apps/hlidskjalf/android/gradlew.bat +92 -0
- package/apps/hlidskjalf/android/settings.gradle +5 -0
- package/apps/hlidskjalf/android/variables.gradle +16 -0
- package/apps/hlidskjalf/capacitor.config.ts +26 -0
- package/apps/hlidskjalf/dist/apple-touch-icon.png +0 -0
- package/apps/hlidskjalf/dist/assets/index-BWmNIyaG.css +1 -0
- package/apps/hlidskjalf/dist/assets/index-k7QEfNto.js +88 -0
- package/apps/hlidskjalf/dist/assets/index-k7QEfNto.js.map +1 -0
- package/apps/hlidskjalf/dist/icon.svg +7 -0
- package/apps/hlidskjalf/dist/index.html +64 -0
- package/apps/hlidskjalf/dist/manifest.webmanifest +31 -0
- package/apps/hlidskjalf/dist/og.jpg +0 -0
- package/apps/hlidskjalf/dist/og.png +0 -0
- package/apps/hlidskjalf/dist/og.svg +64 -0
- package/apps/hlidskjalf/dist/sw.js +39 -0
- package/apps/hlidskjalf/dist/ymir-icon.png +0 -0
- package/apps/hlidskjalf/dist/ymir-mark.svg +62 -0
- package/apps/hlidskjalf/electron/icon.png +0 -0
- package/apps/hlidskjalf/electron/main.cjs +236 -0
- package/apps/hlidskjalf/electron/preload.cjs +8 -0
- package/apps/hlidskjalf/electron/smidja-icon.png +0 -0
- package/apps/hlidskjalf/electron/ymir-hlidskjalf.desktop.in +12 -0
- package/apps/hlidskjalf/electron/ymir-smidja.desktop.in +12 -0
- package/apps/hlidskjalf/index.html +63 -0
- package/apps/hlidskjalf/package-lock.json +5398 -0
- package/apps/hlidskjalf/package.json +55 -0
- package/apps/hlidskjalf/public/apple-touch-icon.png +0 -0
- package/apps/hlidskjalf/public/icon.svg +7 -0
- package/apps/hlidskjalf/public/manifest.webmanifest +31 -0
- package/apps/hlidskjalf/public/og.jpg +0 -0
- package/apps/hlidskjalf/public/og.png +0 -0
- package/apps/hlidskjalf/public/og.svg +64 -0
- package/apps/hlidskjalf/public/sw.js +39 -0
- package/apps/hlidskjalf/public/ymir-icon.png +0 -0
- package/apps/hlidskjalf/public/ymir-mark.svg +62 -0
- package/apps/hlidskjalf/server/accounts.ts +159 -0
- package/apps/hlidskjalf/server/index.ts +2045 -0
- package/apps/hlidskjalf/src/app/App.tsx +116 -0
- package/apps/hlidskjalf/src/app/BottomStream.tsx +128 -0
- package/apps/hlidskjalf/src/app/MobileNav.tsx +87 -0
- package/apps/hlidskjalf/src/app/Rail.tsx +106 -0
- package/apps/hlidskjalf/src/app/Shell.tsx +135 -0
- package/apps/hlidskjalf/src/app/Topbar.tsx +130 -0
- package/apps/hlidskjalf/src/components/AccentPicker.tsx +207 -0
- package/apps/hlidskjalf/src/components/AccountMenu.tsx +115 -0
- package/apps/hlidskjalf/src/components/AgentCard.tsx +75 -0
- package/apps/hlidskjalf/src/components/EmberBackground.tsx +36 -0
- package/apps/hlidskjalf/src/components/Emblem.tsx +48 -0
- package/apps/hlidskjalf/src/components/Halls.tsx +155 -0
- package/apps/hlidskjalf/src/components/LoginModal.tsx +329 -0
- package/apps/hlidskjalf/src/components/Markdown.tsx +10 -0
- package/apps/hlidskjalf/src/components/MetricTile.tsx +40 -0
- package/apps/hlidskjalf/src/components/ModelPicker.tsx +100 -0
- package/apps/hlidskjalf/src/components/Overlay.tsx +134 -0
- package/apps/hlidskjalf/src/components/PRCard.tsx +154 -0
- package/apps/hlidskjalf/src/components/RecallPanel.tsx +116 -0
- package/apps/hlidskjalf/src/components/RuneTag.tsx +23 -0
- package/apps/hlidskjalf/src/components/Status.tsx +35 -0
- package/apps/hlidskjalf/src/components/TaskChip.tsx +23 -0
- package/apps/hlidskjalf/src/components/TraceRow.tsx +28 -0
- package/apps/hlidskjalf/src/data/lore.ts +127 -0
- package/apps/hlidskjalf/src/data/metadata.ts +147 -0
- package/apps/hlidskjalf/src/data/mythology.ts +95 -0
- package/apps/hlidskjalf/src/data/realms.ts +167 -0
- package/apps/hlidskjalf/src/gates/Cron.tsx +77 -0
- package/apps/hlidskjalf/src/gates/Decisions.tsx +67 -0
- package/apps/hlidskjalf/src/gates/Files.tsx +138 -0
- package/apps/hlidskjalf/src/gates/Fleet.tsx +184 -0
- package/apps/hlidskjalf/src/gates/Forge.tsx +486 -0
- package/apps/hlidskjalf/src/gates/OmniChat.tsx +217 -0
- package/apps/hlidskjalf/src/gates/Processes.tsx +162 -0
- package/apps/hlidskjalf/src/gates/Profile.tsx +225 -0
- package/apps/hlidskjalf/src/gates/Reviews.tsx +33 -0
- package/apps/hlidskjalf/src/gates/Runes.tsx +116 -0
- package/apps/hlidskjalf/src/gates/Runtime.tsx +106 -0
- package/apps/hlidskjalf/src/gates/Sessions.tsx +109 -0
- package/apps/hlidskjalf/src/gates/Stats.tsx +268 -0
- package/apps/hlidskjalf/src/gates/Tasks.tsx +173 -0
- package/apps/hlidskjalf/src/gates/Trace.tsx +155 -0
- package/apps/hlidskjalf/src/gates/Well.tsx +154 -0
- package/apps/hlidskjalf/src/gates/Worktrees.tsx +48 -0
- package/apps/hlidskjalf/src/hooks/useTenantDef.ts +13 -0
- package/apps/hlidskjalf/src/main.tsx +31 -0
- package/apps/hlidskjalf/src/services/api.ts +404 -0
- package/apps/hlidskjalf/src/services/auth.ts +107 -0
- package/apps/hlidskjalf/src/services/stream.ts +35 -0
- package/apps/hlidskjalf/src/state/store.ts +648 -0
- package/apps/hlidskjalf/src/state/ui.ts +62 -0
- package/apps/hlidskjalf/src/styles/auth.css +485 -0
- package/apps/hlidskjalf/src/styles/components.css +1259 -0
- package/apps/hlidskjalf/src/styles/forge.css +115 -0
- package/apps/hlidskjalf/src/styles/global.css +167 -0
- package/apps/hlidskjalf/src/styles/menus.css +175 -0
- package/apps/hlidskjalf/src/styles/mobile.css +298 -0
- package/apps/hlidskjalf/src/styles/overlays.css +205 -0
- package/apps/hlidskjalf/src/styles/shell.css +641 -0
- package/apps/hlidskjalf/src/types.ts +251 -0
- package/apps/hlidskjalf/src/vite-env.d.ts +9 -0
- package/apps/hlidskjalf/static/landing.md +6 -0
- package/apps/hlidskjalf/tsconfig.json +25 -0
- package/apps/hlidskjalf/vite.config.ts +49 -0
- package/apps/hlidskjalf-mobile/App.tsx +93 -0
- package/apps/hlidskjalf-mobile/app.json +13 -0
- package/apps/hlidskjalf-mobile/index.ts +4 -0
- package/apps/hlidskjalf-mobile/package.json +35 -0
- package/apps/hlidskjalf-mobile/public/icon.svg +7 -0
- package/apps/hlidskjalf-mobile/tsconfig.json +4 -0
- package/apps/odrerir/.astro/content.d.ts +159 -0
- package/apps/odrerir/.astro/dev.json +24 -0
- package/apps/odrerir/.astro/settings.json +5 -0
- package/apps/odrerir/.astro/types.d.ts +2 -0
- package/apps/odrerir/astro.config.mjs +79 -0
- package/apps/odrerir/dist/apple-touch-icon.png +0 -0
- package/apps/odrerir/dist/favicon-192.png +0 -0
- package/apps/odrerir/dist/favicon-32.png +0 -0
- package/apps/odrerir/dist/favicon-512.png +0 -0
- package/apps/odrerir/dist/favicon.svg +53 -0
- package/apps/odrerir/dist/icon.svg +7 -0
- package/apps/odrerir/dist/index.html +837 -0
- package/apps/odrerir/dist/og-square.png +0 -0
- package/apps/odrerir/dist/og-story.png +0 -0
- package/apps/odrerir/dist/og.png +0 -0
- package/apps/odrerir/dist/safari-pinned-tab.svg +7 -0
- package/apps/odrerir/dist/site.webmanifest +16 -0
- package/apps/odrerir/dist/styles/cloth.css +112 -0
- package/apps/odrerir/dist/styles/livehall.css +278 -0
- package/apps/odrerir/electron/icon.png +0 -0
- package/apps/odrerir/electron/main.cjs +183 -0
- package/apps/odrerir/electron/ymir-odrerir.desktop.in +12 -0
- package/apps/odrerir/package-lock.json +4195 -0
- package/apps/odrerir/package.json +30 -0
- package/apps/odrerir/public/apple-touch-icon.png +0 -0
- package/apps/odrerir/public/favicon-192.png +0 -0
- package/apps/odrerir/public/favicon-32.png +0 -0
- package/apps/odrerir/public/favicon-512.png +0 -0
- package/apps/odrerir/public/favicon.svg +53 -0
- package/apps/odrerir/public/icon.svg +7 -0
- package/apps/odrerir/public/og-square.png +0 -0
- package/apps/odrerir/public/og-story.png +0 -0
- package/apps/odrerir/public/og.png +0 -0
- package/apps/odrerir/public/safari-pinned-tab.svg +7 -0
- package/apps/odrerir/public/site.webmanifest +16 -0
- package/apps/odrerir/scripts/extract-cloth.mjs +101 -0
- package/apps/odrerir/src/index.html +837 -0
- package/apps/odrerir/src/styles/cloth.css +112 -0
- package/apps/odrerir/src/styles/livehall.css +278 -0
- package/apps/sessrumnir/.github/ISSUE_TEMPLATE/bug_report.yml +99 -0
- package/apps/sessrumnir/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/apps/sessrumnir/.github/ISSUE_TEMPLATE/feature_request.yml +46 -0
- package/apps/sessrumnir/.github/PULL_REQUEST_TEMPLATE.md +56 -0
- package/apps/sessrumnir/.github/SUPPORT.md +18 -0
- package/apps/sessrumnir/.github/workflows/build.yml +133 -0
- package/apps/sessrumnir/AGENTS.md +540 -0
- package/apps/sessrumnir/CLA.md +63 -0
- package/apps/sessrumnir/CONTRIBUTING.md +233 -0
- package/apps/sessrumnir/LICENSE +200 -0
- package/apps/sessrumnir/NOTICE +33 -0
- package/apps/sessrumnir/README.md +329 -0
- package/apps/sessrumnir/bin/sessrumnir-web.sh +117 -0
- package/apps/sessrumnir/bin/sessrumnir.js +169 -0
- package/apps/sessrumnir/docs/CNAME +1 -0
- package/apps/sessrumnir/docs/favicon.ico +0 -0
- package/apps/sessrumnir/docs/icon-512.png +0 -0
- package/apps/sessrumnir/docs/index.html +441 -0
- package/apps/sessrumnir/docs/robots.txt +4 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_181929.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182005.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182020.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182039.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182117.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182225.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182248.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182322.png +0 -0
- package/apps/sessrumnir/docs/screenshots/Screenshot_20260824_182340.png +0 -0
- package/apps/sessrumnir/docs/sitemap.xml +9 -0
- package/apps/sessrumnir/electron.vite.config.ts +49 -0
- package/apps/sessrumnir/eslint.config.mjs +75 -0
- package/apps/sessrumnir/i18next.config.ts +33 -0
- package/apps/sessrumnir/install.sh +144 -0
- package/apps/sessrumnir/out/main/index.js +10881 -0
- package/apps/sessrumnir/out/preload/index.js +722 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-400-normal-C8QS47vb.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-400-normal-D3EsxgFc.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-500-normal-B7dJQtg-.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-500-normal-BLlg2W5x.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-600-normal-BcIsDXzC.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-600-normal-CBymlcNF.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-400-normal-Bgrpe4p1.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-400-normal-BlcaxZtM.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-500-normal-CdQuyvtc.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-500-normal-pZw22qtS.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-600-normal-Dr-wLyOm.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-cyrillic-ext-600-normal-dLR2-a_v.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-400-normal-BGH8Vunh.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-400-normal-C3_-2Ua-.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-500-normal-Dj3SQ6fR.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-500-normal-EBdSCOD3.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-600-normal-B254Xisw.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-600-normal-DUW-TI76.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-400-normal-DuQ88yz3.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-400-normal-DuXFa1Dr.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-500-normal-AH9qog1s.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-500-normal-DAuUCO41.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-600-normal-CD-dlDpD.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-latin-ext-600-normal-D3T6BBXG.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-400-normal-C-RiYxEf.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-400-normal-DmUuA7Y2.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-500-normal-DsPuwQHi.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-500-normal-tGBW_mI7.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-600-normal-Dar_cCT6.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/cormorant-vietnamese-600-normal-GIs8CF2x.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-300-normal-Ba-HN6uq.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-300-normal-ByB2hQUF.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-300-normal-B8O3uHbr.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-300-normal-BbtBtHoB.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-300-normal-BPU54Tw3.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-300-normal-BRS-C4KA.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-300-normal-BEtQ2wm2.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-300-normal-CQbCaAQ4.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-300-normal-B6fSpYYV.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-300-normal-CpdbWO_2.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/apps/sessrumnir/out/renderer/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/index-BxqsRq2x.css +4858 -0
- package/apps/sessrumnir/out/renderer/assets/index-TaD69rFk.js +99435 -0
- package/apps/sessrumnir/out/renderer/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-latin-ext-wght-italic-DFS986qL.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-latin-ext-wght-normal-C-3rgBeH.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-latin-wght-italic-Bxi8ein9.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-latin-wght-normal-CCVVNp6i.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-vietnamese-wght-italic-xAqemagA.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/newsreader-vietnamese-wght-normal-Czsa-EzN.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/openmoji-color-9qo_2DLG.woff2 +0 -0
- package/apps/sessrumnir/out/renderer/assets/pi-logo-B6SVnhuS.svg +7 -0
- package/apps/sessrumnir/out/renderer/index.html +19 -0
- package/apps/sessrumnir/out/renderer/theme-boot.js +30 -0
- package/apps/sessrumnir/package-lock.json +10636 -0
- package/apps/sessrumnir/package.json +183 -0
- package/apps/sessrumnir/public/apple-touch-icon.png +0 -0
- package/apps/sessrumnir/public/icon.svg +7 -0
- package/apps/sessrumnir/resources/icons/generate_icons.py +38 -0
- package/apps/sessrumnir/resources/icons/icon-128.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-16.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-256.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-32.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-48.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-512.png +0 -0
- package/apps/sessrumnir/resources/icons/icon-64.png +0 -0
- package/apps/sessrumnir/resources/icons/icon.icns +0 -0
- package/apps/sessrumnir/resources/icons/icon.ico +0 -0
- package/apps/sessrumnir/resources/icons/icon.png +0 -0
- package/apps/sessrumnir/resources/icons/icon.svg +7 -0
- package/apps/sessrumnir/resources/linux/after-install.sh +23 -0
- package/apps/sessrumnir/resources/linux/after-remove.sh +18 -0
- package/apps/sessrumnir/resources/locales/en/translation.json +1735 -0
- package/apps/sessrumnir/resources/permission-prompt-text.test.ts +111 -0
- package/apps/sessrumnir/resources/permission-prompt-text.ts +84 -0
- package/apps/sessrumnir/resources/permission-rules.test.ts +351 -0
- package/apps/sessrumnir/resources/permission-rules.ts +293 -0
- package/apps/sessrumnir/resources/pi-desktop-permissions.ts +62 -0
- package/apps/sessrumnir/resources/ymir-sessrumnir.desktop.in +12 -0
- package/apps/sessrumnir/scripts/check-semantic-colors.mjs +57 -0
- package/apps/sessrumnir/src/main/activity-stats.test.ts +240 -0
- package/apps/sessrumnir/src/main/activity-stats.ts +596 -0
- package/apps/sessrumnir/src/main/agent-detection.test.ts +25 -0
- package/apps/sessrumnir/src/main/agent-detection.ts +114 -0
- package/apps/sessrumnir/src/main/app-data-paths.test.ts +90 -0
- package/apps/sessrumnir/src/main/app-data-paths.ts +95 -0
- package/apps/sessrumnir/src/main/app-log.test.ts +114 -0
- package/apps/sessrumnir/src/main/app-log.ts +210 -0
- package/apps/sessrumnir/src/main/archived-sessions.test.ts +50 -0
- package/apps/sessrumnir/src/main/archived-sessions.ts +95 -0
- package/apps/sessrumnir/src/main/attachment-reader.test.ts +56 -0
- package/apps/sessrumnir/src/main/attachment-reader.ts +52 -0
- package/apps/sessrumnir/src/main/auto-tag.test.ts +38 -0
- package/apps/sessrumnir/src/main/auto-tag.ts +75 -0
- package/apps/sessrumnir/src/main/autostart-linux.test.ts +56 -0
- package/apps/sessrumnir/src/main/autostart-linux.ts +58 -0
- package/apps/sessrumnir/src/main/cmd-escape.test.ts +424 -0
- package/apps/sessrumnir/src/main/cmd-escape.ts +186 -0
- package/apps/sessrumnir/src/main/council-manager.test.ts +167 -0
- package/apps/sessrumnir/src/main/council-manager.ts +265 -0
- package/apps/sessrumnir/src/main/diagnostics-report.test.ts +140 -0
- package/apps/sessrumnir/src/main/diagnostics-report.ts +91 -0
- package/apps/sessrumnir/src/main/diagnostics.ts +111 -0
- package/apps/sessrumnir/src/main/editor-guard.test.ts +59 -0
- package/apps/sessrumnir/src/main/editor-guard.ts +50 -0
- package/apps/sessrumnir/src/main/extension-ui-ipc.test.ts +299 -0
- package/apps/sessrumnir/src/main/extension-ui-ipc.ts +117 -0
- package/apps/sessrumnir/src/main/file-service.test.ts +279 -0
- package/apps/sessrumnir/src/main/file-service.ts +652 -0
- package/apps/sessrumnir/src/main/fs-errors.ts +42 -0
- package/apps/sessrumnir/src/main/get-messages-trim.test.ts +77 -0
- package/apps/sessrumnir/src/main/get-messages-trim.ts +97 -0
- package/apps/sessrumnir/src/main/git-conveyor.test.ts +305 -0
- package/apps/sessrumnir/src/main/git-conveyor.ts +338 -0
- package/apps/sessrumnir/src/main/git-worktree.test.ts +101 -0
- package/apps/sessrumnir/src/main/git-worktree.ts +201 -0
- package/apps/sessrumnir/src/main/i18n.ts +31 -0
- package/apps/sessrumnir/src/main/index.ts +619 -0
- package/apps/sessrumnir/src/main/ipc/active-engine.ts +15 -0
- package/apps/sessrumnir/src/main/ipc/context.ts +58 -0
- package/apps/sessrumnir/src/main/ipc/council-handlers.ts +126 -0
- package/apps/sessrumnir/src/main/ipc/diagnostics-handlers.ts +8 -0
- package/apps/sessrumnir/src/main/ipc/file-handlers.ts +96 -0
- package/apps/sessrumnir/src/main/ipc/git-conveyor-handlers.ts +55 -0
- package/apps/sessrumnir/src/main/ipc/model-handlers.ts +33 -0
- package/apps/sessrumnir/src/main/ipc/models-config-handlers.ts +80 -0
- package/apps/sessrumnir/src/main/ipc/notes-handlers.ts +65 -0
- package/apps/sessrumnir/src/main/ipc/package-handlers.ts +330 -0
- package/apps/sessrumnir/src/main/ipc/permission-rules-handlers.ts +223 -0
- package/apps/sessrumnir/src/main/ipc/pi-handlers.ts +136 -0
- package/apps/sessrumnir/src/main/ipc/pi-start-options.ts +150 -0
- package/apps/sessrumnir/src/main/ipc/run-pi-cli.ts +53 -0
- package/apps/sessrumnir/src/main/ipc/session-handlers.ts +491 -0
- package/apps/sessrumnir/src/main/ipc/settings.ts +120 -0
- package/apps/sessrumnir/src/main/ipc/skills-mcp-handlers.ts +192 -0
- package/apps/sessrumnir/src/main/ipc/system-handlers.ts +131 -0
- package/apps/sessrumnir/src/main/ipc/tag-handlers.ts +69 -0
- package/apps/sessrumnir/src/main/ipc/terminal-handlers.ts +41 -0
- package/apps/sessrumnir/src/main/ipc/theme-handlers.ts +131 -0
- package/apps/sessrumnir/src/main/ipc/update-handlers.ts +61 -0
- package/apps/sessrumnir/src/main/ipc/validation.ts +45 -0
- package/apps/sessrumnir/src/main/ipc/workflow-handlers.ts +108 -0
- package/apps/sessrumnir/src/main/ipc/workspace-activity-wiring.ts +179 -0
- package/apps/sessrumnir/src/main/ipc/workspace-handlers.ts +133 -0
- package/apps/sessrumnir/src/main/ipc-handlers.ts +98 -0
- package/apps/sessrumnir/src/main/map-concurrent.test.ts +80 -0
- package/apps/sessrumnir/src/main/map-concurrent.ts +30 -0
- package/apps/sessrumnir/src/main/models-file.test.ts +114 -0
- package/apps/sessrumnir/src/main/models-file.ts +89 -0
- package/apps/sessrumnir/src/main/notes-manager.test.ts +64 -0
- package/apps/sessrumnir/src/main/notes-manager.ts +183 -0
- package/apps/sessrumnir/src/main/notify-decision.test.ts +39 -0
- package/apps/sessrumnir/src/main/notify-decision.ts +25 -0
- package/apps/sessrumnir/src/main/omp-fork-points.test.ts +119 -0
- package/apps/sessrumnir/src/main/omp-fork-points.ts +105 -0
- package/apps/sessrumnir/src/main/omp-plugin-list.test.ts +94 -0
- package/apps/sessrumnir/src/main/omp-plugin-list.ts +103 -0
- package/apps/sessrumnir/src/main/package-catalog.test.ts +157 -0
- package/apps/sessrumnir/src/main/package-catalog.ts +166 -0
- package/apps/sessrumnir/src/main/package-updates.test.ts +149 -0
- package/apps/sessrumnir/src/main/package-updates.ts +185 -0
- package/apps/sessrumnir/src/main/path-authorization.test.ts +64 -0
- package/apps/sessrumnir/src/main/path-authorization.ts +31 -0
- package/apps/sessrumnir/src/main/pi-binary-resolution.test.ts +582 -0
- package/apps/sessrumnir/src/main/pi-binary-resolution.ts +649 -0
- package/apps/sessrumnir/src/main/pi-event-router.test.ts +388 -0
- package/apps/sessrumnir/src/main/pi-event-router.ts +290 -0
- package/apps/sessrumnir/src/main/pi-paths.test.ts +134 -0
- package/apps/sessrumnir/src/main/pi-paths.ts +74 -0
- package/apps/sessrumnir/src/main/pi-rpc-manager.test.ts +467 -0
- package/apps/sessrumnir/src/main/pi-rpc-manager.ts +1319 -0
- package/apps/sessrumnir/src/main/process-tree.test.ts +94 -0
- package/apps/sessrumnir/src/main/renderer-origin.test.ts +33 -0
- package/apps/sessrumnir/src/main/renderer-origin.ts +35 -0
- package/apps/sessrumnir/src/main/session-lineage-reader.test.ts +317 -0
- package/apps/sessrumnir/src/main/session-lineage-reader.ts +111 -0
- package/apps/sessrumnir/src/main/session-metadata.test.ts +508 -0
- package/apps/sessrumnir/src/main/session-metadata.ts +526 -0
- package/apps/sessrumnir/src/main/session-name.test.ts +71 -0
- package/apps/sessrumnir/src/main/session-name.ts +69 -0
- package/apps/sessrumnir/src/main/session-paths.test.ts +110 -0
- package/apps/sessrumnir/src/main/session-paths.ts +88 -0
- package/apps/sessrumnir/src/main/session-tags.test.ts +61 -0
- package/apps/sessrumnir/src/main/session-tags.ts +253 -0
- package/apps/sessrumnir/src/main/session-trash.test.ts +66 -0
- package/apps/sessrumnir/src/main/session-trash.ts +65 -0
- package/apps/sessrumnir/src/main/settings-logic.ts +66 -0
- package/apps/sessrumnir/src/main/skills-discovery.test.ts +149 -0
- package/apps/sessrumnir/src/main/skills-discovery.ts +179 -0
- package/apps/sessrumnir/src/main/startup-launch.ts +63 -0
- package/apps/sessrumnir/src/main/terminal-service.ts +96 -0
- package/apps/sessrumnir/src/main/theme-store.test.ts +440 -0
- package/apps/sessrumnir/src/main/theme-store.ts +495 -0
- package/apps/sessrumnir/src/main/tray-decision.test.ts +46 -0
- package/apps/sessrumnir/src/main/tray-decision.ts +49 -0
- package/apps/sessrumnir/src/main/tray-manager.ts +220 -0
- package/apps/sessrumnir/src/main/tsconfig.json +20 -0
- package/apps/sessrumnir/src/main/window-background.test.ts +29 -0
- package/apps/sessrumnir/src/main/window-background.ts +16 -0
- package/apps/sessrumnir/src/main/workflow-discovery.test.ts +252 -0
- package/apps/sessrumnir/src/main/workflow-monitor.test.ts +371 -0
- package/apps/sessrumnir/src/main/workflow-monitor.ts +1020 -0
- package/apps/sessrumnir/src/main/workspace-activity.test.ts +227 -0
- package/apps/sessrumnir/src/main/workspace-activity.ts +215 -0
- package/apps/sessrumnir/src/main/workspace-manager.test.ts +680 -0
- package/apps/sessrumnir/src/main/workspace-manager.ts +1199 -0
- package/apps/sessrumnir/src/main/workspace-trust.test.ts +78 -0
- package/apps/sessrumnir/src/main/workspace-trust.ts +84 -0
- package/apps/sessrumnir/src/preload/index.ts +358 -0
- package/apps/sessrumnir/src/preload/tsconfig.json +20 -0
- package/apps/sessrumnir/src/renderer/index.html +18 -0
- package/apps/sessrumnir/src/renderer/public/theme-boot.js +30 -0
- package/apps/sessrumnir/src/renderer/src/app.tsx +194 -0
- package/apps/sessrumnir/src/renderer/src/assets/openmoji-color.woff2 +0 -0
- package/apps/sessrumnir/src/renderer/src/assets/pi-logo.svg +7 -0
- package/apps/sessrumnir/src/renderer/src/assets/ymir-mark.svg +55 -0
- package/apps/sessrumnir/src/renderer/src/assets.d.ts +7 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-code-highlight.ts +239 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-file-link.ts +140 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-input.tsx +729 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-panel-widths.test.ts +175 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-panel-widths.ts +100 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-panel.tsx +523 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-project-picker.tsx +193 -0
- package/apps/sessrumnir/src/renderer/src/components/chat-search.tsx +251 -0
- package/apps/sessrumnir/src/renderer/src/components/code-editor-highlight.ts +85 -0
- package/apps/sessrumnir/src/renderer/src/components/code-editor-language.test.ts +19 -0
- package/apps/sessrumnir/src/renderer/src/components/code-editor-language.ts +88 -0
- package/apps/sessrumnir/src/renderer/src/components/code-editor.tsx +128 -0
- package/apps/sessrumnir/src/renderer/src/components/command-palette.tsx +315 -0
- package/apps/sessrumnir/src/renderer/src/components/command-results.tsx +80 -0
- package/apps/sessrumnir/src/renderer/src/components/composer-permission-menu.tsx +91 -0
- package/apps/sessrumnir/src/renderer/src/components/context-menu.tsx +457 -0
- package/apps/sessrumnir/src/renderer/src/components/copy-button.tsx +36 -0
- package/apps/sessrumnir/src/renderer/src/components/council-panels.tsx +193 -0
- package/apps/sessrumnir/src/renderer/src/components/custom-models-editor.tsx +330 -0
- package/apps/sessrumnir/src/renderer/src/components/diagnostics-panel.tsx +380 -0
- package/apps/sessrumnir/src/renderer/src/components/diff-viewer.tsx +318 -0
- package/apps/sessrumnir/src/renderer/src/components/ember-background.tsx +113 -0
- package/apps/sessrumnir/src/renderer/src/components/error-boundary.tsx +38 -0
- package/apps/sessrumnir/src/renderer/src/components/extension-ui-dialog-helpers.test.ts +43 -0
- package/apps/sessrumnir/src/renderer/src/components/extension-ui-dialog-helpers.ts +51 -0
- package/apps/sessrumnir/src/renderer/src/components/extension-ui-dialog.tsx +486 -0
- package/apps/sessrumnir/src/renderer/src/components/file-tree.tsx +784 -0
- package/apps/sessrumnir/src/renderer/src/components/git-conveyor-actions.tsx +246 -0
- package/apps/sessrumnir/src/renderer/src/components/home-screen.tsx +396 -0
- package/apps/sessrumnir/src/renderer/src/components/image-viewer.tsx +100 -0
- package/apps/sessrumnir/src/renderer/src/components/line-numbered-code.tsx +58 -0
- package/apps/sessrumnir/src/renderer/src/components/markdown-renderer.tsx +237 -0
- package/apps/sessrumnir/src/renderer/src/components/message-bubble.tsx +1006 -0
- package/apps/sessrumnir/src/renderer/src/components/mission-control.tsx +341 -0
- package/apps/sessrumnir/src/renderer/src/components/model-selector.tsx +219 -0
- package/apps/sessrumnir/src/renderer/src/components/note-picker.tsx +155 -0
- package/apps/sessrumnir/src/renderer/src/components/notes-panel.tsx +437 -0
- package/apps/sessrumnir/src/renderer/src/components/package-browser.tsx +604 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-mode.test.ts +22 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-mode.ts +49 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-rules-editor-helpers.test.ts +44 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-rules-editor-helpers.ts +35 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-rules-editor.tsx +226 -0
- package/apps/sessrumnir/src/renderer/src/components/permission-selector.tsx +104 -0
- package/apps/sessrumnir/src/renderer/src/components/resize-handle.tsx +51 -0
- package/apps/sessrumnir/src/renderer/src/components/review-rail.tsx +194 -0
- package/apps/sessrumnir/src/renderer/src/components/session-menu-position.test.ts +22 -0
- package/apps/sessrumnir/src/renderer/src/components/session-menu-position.ts +34 -0
- package/apps/sessrumnir/src/renderer/src/components/session-panel.tsx +711 -0
- package/apps/sessrumnir/src/renderer/src/components/session-runtime-indicator.tsx +43 -0
- package/apps/sessrumnir/src/renderer/src/components/settings-panel.tsx +1360 -0
- package/apps/sessrumnir/src/renderer/src/components/sidebar-activity.test.ts +47 -0
- package/apps/sessrumnir/src/renderer/src/components/sidebar-activity.ts +76 -0
- package/apps/sessrumnir/src/renderer/src/components/sidebar-session-labels.test.ts +73 -0
- package/apps/sessrumnir/src/renderer/src/components/sidebar-session-labels.ts +47 -0
- package/apps/sessrumnir/src/renderer/src/components/sidebar.tsx +1045 -0
- package/apps/sessrumnir/src/renderer/src/components/skills-panel.tsx +159 -0
- package/apps/sessrumnir/src/renderer/src/components/stats-panel.tsx +368 -0
- package/apps/sessrumnir/src/renderer/src/components/status-bar.tsx +274 -0
- package/apps/sessrumnir/src/renderer/src/components/status-popover.tsx +481 -0
- package/apps/sessrumnir/src/renderer/src/components/streaming-bubble.tsx +128 -0
- package/apps/sessrumnir/src/renderer/src/components/subagent-progress.tsx +254 -0
- package/apps/sessrumnir/src/renderer/src/components/task-launcher.tsx +168 -0
- package/apps/sessrumnir/src/renderer/src/components/terminal.tsx +203 -0
- package/apps/sessrumnir/src/renderer/src/components/theme-editor-helpers.test.ts +35 -0
- package/apps/sessrumnir/src/renderer/src/components/theme-editor-helpers.ts +35 -0
- package/apps/sessrumnir/src/renderer/src/components/theme-editor.tsx +440 -0
- package/apps/sessrumnir/src/renderer/src/components/theme-gallery.tsx +373 -0
- package/apps/sessrumnir/src/renderer/src/components/thinking-level-selector.tsx +85 -0
- package/apps/sessrumnir/src/renderer/src/components/timeline.tsx +289 -0
- package/apps/sessrumnir/src/renderer/src/components/tool-call-icon.ts +32 -0
- package/apps/sessrumnir/src/renderer/src/components/workflow-navigator.tsx +901 -0
- package/apps/sessrumnir/src/renderer/src/components/workspace-tabs.tsx +241 -0
- package/apps/sessrumnir/src/renderer/src/global.d.ts +8 -0
- package/apps/sessrumnir/src/renderer/src/hooks/use-folder-drop.ts +101 -0
- package/apps/sessrumnir/src/renderer/src/hooks.test.ts +88 -0
- package/apps/sessrumnir/src/renderer/src/hooks.ts +574 -0
- package/apps/sessrumnir/src/renderer/src/i18n.test.ts +54 -0
- package/apps/sessrumnir/src/renderer/src/i18n.ts +89 -0
- package/apps/sessrumnir/src/renderer/src/index.css +425 -0
- package/apps/sessrumnir/src/renderer/src/main.tsx +42 -0
- package/apps/sessrumnir/src/renderer/src/message-grouping.test.ts +422 -0
- package/apps/sessrumnir/src/renderer/src/message-grouping.ts +410 -0
- package/apps/sessrumnir/src/renderer/src/message-parsing.test.ts +86 -0
- package/apps/sessrumnir/src/renderer/src/message-parsing.ts +166 -0
- package/apps/sessrumnir/src/renderer/src/store-external-prompts.test.ts +161 -0
- package/apps/sessrumnir/src/renderer/src/store-session-transitions.test.ts +2090 -0
- package/apps/sessrumnir/src/renderer/src/store-timeline.test.ts +52 -0
- package/apps/sessrumnir/src/renderer/src/store-turn-error.test.ts +136 -0
- package/apps/sessrumnir/src/renderer/src/store.ts +3726 -0
- package/apps/sessrumnir/src/renderer/src/subagent-detection.test.ts +55 -0
- package/apps/sessrumnir/src/renderer/src/theme/engine.test.ts +29 -0
- package/apps/sessrumnir/src/renderer/src/theme/engine.ts +20 -0
- package/apps/sessrumnir/src/renderer/src/themes/breeze-claudius.json +69 -0
- package/apps/sessrumnir/src/renderer/src/themes/breeze-dark.json +69 -0
- package/apps/sessrumnir/src/renderer/src/themes/breeze-light.json +69 -0
- package/apps/sessrumnir/src/renderer/src/themes/builtin-themes.test.ts +95 -0
- package/apps/sessrumnir/src/renderer/src/themes/dark.json +46 -0
- package/apps/sessrumnir/src/renderer/src/themes/fensalir.json +82 -0
- package/apps/sessrumnir/src/renderer/src/themes/gruvbox.json +69 -0
- package/apps/sessrumnir/src/renderer/src/themes/index.ts +60 -0
- package/apps/sessrumnir/src/renderer/src/themes/light.json +46 -0
- package/apps/sessrumnir/src/renderer/src/themes/nord.json +69 -0
- package/apps/sessrumnir/src/renderer/src/themes/sessrumnir.json +82 -0
- package/apps/sessrumnir/src/renderer/src/utils/debounced-buffer.test.ts +81 -0
- package/apps/sessrumnir/src/renderer/src/utils/debounced-buffer.ts +57 -0
- package/apps/sessrumnir/src/renderer/src/utils/format-relative-time.test.ts +62 -0
- package/apps/sessrumnir/src/renderer/src/utils/format-relative-time.ts +28 -0
- package/apps/sessrumnir/src/renderer/src/utils/heatmap-grid.test.ts +57 -0
- package/apps/sessrumnir/src/renderer/src/utils/heatmap-grid.ts +41 -0
- package/apps/sessrumnir/src/renderer/src/utils/ipc-error.test.ts +22 -0
- package/apps/sessrumnir/src/renderer/src/utils/ipc-error.ts +12 -0
- package/apps/sessrumnir/src/renderer/src/utils/model-search.test.ts +63 -0
- package/apps/sessrumnir/src/renderer/src/utils/model-search.ts +20 -0
- package/apps/sessrumnir/src/renderer/src/utils/planning-prompt.test.ts +31 -0
- package/apps/sessrumnir/src/renderer/src/utils/planning-prompt.ts +27 -0
- package/apps/sessrumnir/src/renderer/src/utils/preview-load-error.test.ts +15 -0
- package/apps/sessrumnir/src/renderer/src/utils/preview-load-error.ts +22 -0
- package/apps/sessrumnir/src/renderer/src/utils/process-status-label.test.ts +13 -0
- package/apps/sessrumnir/src/renderer/src/utils/process-status-label.ts +19 -0
- package/apps/sessrumnir/src/renderer/src/utils/quick-switcher.test.ts +68 -0
- package/apps/sessrumnir/src/renderer/src/utils/quick-switcher.ts +52 -0
- package/apps/sessrumnir/src/renderer/src/utils/rank-file-results.test.ts +46 -0
- package/apps/sessrumnir/src/renderer/src/utils/rank-file-results.ts +23 -0
- package/apps/sessrumnir/src/renderer/src/utils/relative-time.tsx +25 -0
- package/apps/sessrumnir/src/renderer/src/utils/session-title.test.ts +98 -0
- package/apps/sessrumnir/src/renderer/src/utils/session-title.ts +58 -0
- package/apps/sessrumnir/src/renderer/src/utils/stale-guard.test.ts +29 -0
- package/apps/sessrumnir/src/renderer/src/utils/stale-guard.ts +20 -0
- package/apps/sessrumnir/src/renderer/src/utils/theme.test.ts +174 -0
- package/apps/sessrumnir/src/renderer/src/utils/theme.ts +159 -0
- package/apps/sessrumnir/src/renderer/src/utils/workflow-runs.test.ts +130 -0
- package/apps/sessrumnir/src/renderer/src/utils/workflow-runs.ts +84 -0
- package/apps/sessrumnir/src/renderer/tsconfig.json +24 -0
- package/apps/sessrumnir/src/shared/agent-engine-label.test.ts +45 -0
- package/apps/sessrumnir/src/shared/agent-engine-label.ts +53 -0
- package/apps/sessrumnir/src/shared/app-settings.test.ts +25 -0
- package/apps/sessrumnir/src/shared/app-settings.ts +23 -0
- package/apps/sessrumnir/src/shared/bridge-http.ts +341 -0
- package/apps/sessrumnir/src/shared/bridge.ts +337 -0
- package/apps/sessrumnir/src/shared/council-config.test.ts +300 -0
- package/apps/sessrumnir/src/shared/council-config.ts +356 -0
- package/apps/sessrumnir/src/shared/default-settings.ts +39 -0
- package/apps/sessrumnir/src/shared/folder-drop.test.ts +118 -0
- package/apps/sessrumnir/src/shared/folder-drop.ts +74 -0
- package/apps/sessrumnir/src/shared/fork-point.test.ts +30 -0
- package/apps/sessrumnir/src/shared/fork-point.ts +24 -0
- package/apps/sessrumnir/src/shared/i18n/i18next.d.ts +10 -0
- package/apps/sessrumnir/src/shared/i18n/index.test.ts +51 -0
- package/apps/sessrumnir/src/shared/i18n/index.ts +50 -0
- package/apps/sessrumnir/src/shared/i18n/languages.ts +12 -0
- package/apps/sessrumnir/src/shared/i18n/locale-checks.ts +98 -0
- package/apps/sessrumnir/src/shared/i18n/locales.test.ts +92 -0
- package/apps/sessrumnir/src/shared/i18n/pseudo.test.ts +39 -0
- package/apps/sessrumnir/src/shared/i18n/pseudo.ts +44 -0
- package/apps/sessrumnir/src/shared/i18n/resolve.test.ts +43 -0
- package/apps/sessrumnir/src/shared/i18n/resolve.ts +41 -0
- package/apps/sessrumnir/src/shared/i18n/resources.ts +11 -0
- package/apps/sessrumnir/src/shared/ipc-contracts.ts +1539 -0
- package/apps/sessrumnir/src/shared/models-config.test.ts +124 -0
- package/apps/sessrumnir/src/shared/models-config.ts +167 -0
- package/apps/sessrumnir/src/shared/package-filter.ts +19 -0
- package/apps/sessrumnir/src/shared/package-spec.test.ts +51 -0
- package/apps/sessrumnir/src/shared/package-spec.ts +25 -0
- package/apps/sessrumnir/src/shared/path-compare.test.ts +38 -0
- package/apps/sessrumnir/src/shared/path-compare.ts +76 -0
- package/apps/sessrumnir/src/shared/permission-mode.ts +8 -0
- package/apps/sessrumnir/src/shared/pi-command.test.ts +165 -0
- package/apps/sessrumnir/src/shared/pi-command.ts +139 -0
- package/apps/sessrumnir/src/shared/product-name.ts +7 -0
- package/apps/sessrumnir/src/shared/session-lineage.test.ts +103 -0
- package/apps/sessrumnir/src/shared/session-lineage.ts +50 -0
- package/apps/sessrumnir/src/shared/session-preview.test.ts +93 -0
- package/apps/sessrumnir/src/shared/session-preview.ts +56 -0
- package/apps/sessrumnir/src/shared/sidebar-width.test.ts +58 -0
- package/apps/sessrumnir/src/shared/sidebar-width.ts +37 -0
- package/apps/sessrumnir/src/shared/theme/builtin-ids.ts +16 -0
- package/apps/sessrumnir/src/shared/theme/resolve.test.ts +66 -0
- package/apps/sessrumnir/src/shared/theme/resolve.ts +29 -0
- package/apps/sessrumnir/src/shared/theme/syntax-defaults.ts +24 -0
- package/apps/sessrumnir/src/shared/theme/theme-file.test.ts +88 -0
- package/apps/sessrumnir/src/shared/theme/theme-file.ts +132 -0
- package/apps/sessrumnir/src/shared/theme/tokens.test.ts +35 -0
- package/apps/sessrumnir/src/shared/theme/tokens.ts +86 -0
- package/apps/sessrumnir/src/shared/tsconfig.json +17 -0
- package/apps/sessrumnir/src/shared/untrusted-data.test.ts +32 -0
- package/apps/sessrumnir/src/shared/untrusted-data.ts +22 -0
- package/apps/sessrumnir/src/shared/version-compare.test.ts +33 -0
- package/apps/sessrumnir/src/shared/version-compare.ts +50 -0
- package/apps/sessrumnir/src/shared/workflow-control.ts +33 -0
- package/apps/sessrumnir/src/web-server.ts +315 -0
- package/apps/sessrumnir/tsconfig.json +26 -0
- package/apps/smidja/smidja_build.py +45 -0
- package/apps/smidja/smidja_build_review.py +76 -0
- package/apps/smidja/smidja_build_test.py +79 -0
- package/apps/smidja/smidja_document.py +76 -0
- package/apps/smidja/smidja_modules/agent_cc.py +15 -0
- package/apps/smidja/smidja_modules/agent_opencode.py +194 -0
- package/apps/smidja/smidja_modules/agent_pi.py +392 -0
- package/apps/smidja/smidja_modules/agents.py +993 -0
- package/apps/smidja/smidja_modules/changes.py +103 -0
- package/apps/smidja/smidja_modules/console.py +131 -0
- package/apps/smidja/smidja_modules/data_types.py +447 -0
- package/apps/smidja/smidja_modules/gates.py +108 -0
- package/apps/smidja/smidja_modules/git_helper.py +120 -0
- package/apps/smidja/smidja_modules/lm_local.py +144 -0
- package/apps/smidja/smidja_modules/permissions.py +194 -0
- package/apps/smidja/smidja_modules/prompts.py +21 -0
- package/apps/smidja/smidja_modules/quality.py +240 -0
- package/apps/smidja/smidja_modules/runner.py +155 -0
- package/apps/smidja/smidja_modules/session.py +50 -0
- package/apps/smidja/smidja_modules/stall_watch.py +149 -0
- package/apps/smidja/smidja_modules/tracer.py +271 -0
- package/apps/smidja/smidja_modules/utils.py +77 -0
- package/apps/smidja/smidja_orchestrate.py +162 -0
- package/apps/smidja/smidja_plan.py +45 -0
- package/apps/smidja/smidja_plan_build.py +55 -0
- package/apps/smidja/smidja_plan_build_test.py +86 -0
- package/apps/smidja/smidja_plan_build_test_quality.py +98 -0
- package/apps/smidja/smidja_prompt.py +44 -0
- package/apps/smidja/smidja_quality.py +49 -0
- package/apps/smidja/smidja_recon_iv.py +202 -0
- package/apps/smidja/smidja_scout.py +45 -0
- package/apps/smidja/smidja_simple_sdlc.py +183 -0
- package/apps/smidja/smidja_smidja_config/smidja.config.yaml +143 -0
- package/apps/smidja-factory/AGENTS.md +165 -0
- package/apps/smidja-factory/README.md +3 -0
- package/apps/smidja-factory/SKILL.md +18 -0
- package/apps/smidja-factory/apps/visualizer/.oxlintrc.json +18 -0
- package/apps/smidja-factory/apps/visualizer/bun.lock +269 -0
- package/apps/smidja-factory/apps/visualizer/desktop/icon.png +0 -0
- package/apps/smidja-factory/apps/visualizer/desktop/main.js +140 -0
- package/apps/smidja-factory/apps/visualizer/desktop/package-lock.json +871 -0
- package/apps/smidja-factory/apps/visualizer/desktop/package.json +18 -0
- package/apps/smidja-factory/apps/visualizer/desktop/preload.js +19 -0
- package/apps/smidja-factory/apps/visualizer/index.html +28 -0
- package/apps/smidja-factory/apps/visualizer/package.json +31 -0
- package/apps/smidja-factory/apps/visualizer/public/icon.svg +7 -0
- package/apps/smidja-factory/apps/visualizer/public/models/claude.png +0 -0
- package/apps/smidja-factory/apps/visualizer/public/models/gemini.png +0 -0
- package/apps/smidja-factory/apps/visualizer/public/models/kimi.png +0 -0
- package/apps/smidja-factory/apps/visualizer/public/models/openai.png +0 -0
- package/apps/smidja-factory/apps/visualizer/public/models/zai.png +0 -0
- package/apps/smidja-factory/apps/visualizer/server/chat.ts +425 -0
- package/apps/smidja-factory/apps/visualizer/server/db.ts +1050 -0
- package/apps/smidja-factory/apps/visualizer/server/index.ts +648 -0
- package/apps/smidja-factory/apps/visualizer/server/model-catalog.ts +90 -0
- package/apps/smidja-factory/apps/visualizer/server/roster-api.ts +75 -0
- package/apps/smidja-factory/apps/visualizer/server/roster_resolve.py +170 -0
- package/apps/smidja-factory/apps/visualizer/server/settings.ts +106 -0
- package/apps/smidja-factory/apps/visualizer/shared/types.ts +630 -0
- package/apps/smidja-factory/apps/visualizer/src/App.vue +379 -0
- package/apps/smidja-factory/apps/visualizer/src/components/ChatInput.vue +155 -0
- package/apps/smidja-factory/apps/visualizer/src/components/ChatThread.vue +219 -0
- package/apps/smidja-factory/apps/visualizer/src/components/ChatView.vue +335 -0
- package/apps/smidja-factory/apps/visualizer/src/components/DecisionsView.vue +177 -0
- package/apps/smidja-factory/apps/visualizer/src/components/DetailSection.vue +76 -0
- package/apps/smidja-factory/apps/visualizer/src/components/MemoryView.vue +397 -0
- package/apps/smidja-factory/apps/visualizer/src/components/PhaseDetail.vue +1354 -0
- package/apps/smidja-factory/apps/visualizer/src/components/PhaseDots.vue +55 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionCard.vue +583 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionMiniCard.vue +58 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionPanel.vue +272 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionStartForm.vue +152 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionTrace.vue +1157 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SessionsList.vue +96 -0
- package/apps/smidja-factory/apps/visualizer/src/components/SettingsView.vue +152 -0
- package/apps/smidja-factory/apps/visualizer/src/components/StatChip.vue +98 -0
- package/apps/smidja-factory/apps/visualizer/src/components/StatsView.vue +382 -0
- package/apps/smidja-factory/apps/visualizer/src/components/StatusChip.vue +73 -0
- package/apps/smidja-factory/apps/visualizer/src/components/ToolCallCard.vue +156 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/api.ts +177 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/chat-api.ts +95 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/chat-store.ts +351 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/events.ts +131 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/format.ts +92 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/highlight.ts +54 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/markdown.ts +120 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/models.ts +42 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/router.ts +67 -0
- package/apps/smidja-factory/apps/visualizer/src/lib/types.ts +61 -0
- package/apps/smidja-factory/apps/visualizer/src/main.ts +13 -0
- package/apps/smidja-factory/apps/visualizer/src/style.css +592 -0
- package/apps/smidja-factory/apps/visualizer/tsconfig.json +30 -0
- package/apps/smidja-factory/apps/visualizer/vite.config.js +32 -0
- package/apps/smidja-factory/apps/visualizer/vite.config.ts +31 -0
- package/apps/smidja-factory/cookbooks/create_config.md +61 -0
- package/apps/smidja-factory/cookbooks/create_smidja.md +120 -0
- package/apps/smidja-factory/cookbooks/how_to_prompt_for_the_eng.md +110 -0
- package/apps/smidja-factory/cookbooks/install.md +56 -0
- package/apps/smidja-factory/cookbooks/run_smidja.md +122 -0
- package/apps/smidja-factory/cookbooks/smidja_overview.md +88 -0
- package/apps/smidja-factory/cookbooks/update_config.md +103 -0
- package/apps/smidja-factory/cookbooks/update_modules.md +100 -0
- package/apps/smidja-factory/cookbooks/update_smidja.md +90 -0
- package/apps/smidja-factory/docs/enhancement-plan.md +420 -0
- package/apps/smidja-factory/references/config.md +202 -0
- package/apps/smidja-factory/references/handoff.md +161 -0
- package/apps/smidja-factory/references/observability.md +166 -0
- package/apps/smidja-factory/scripts/install.py +113 -0
- package/apps/smidja-factory/scripts/make_config.py +35 -0
- package/apps/smidja-factory/scripts/make_smidja.py +119 -0
- package/apps/smidja-factory/skills/add-or-edit-ai-models/SKILL.md +151 -0
- package/apps/smidja-factory/skills/create-new-agent/SKILL.md +125 -0
- package/apps/smidja-factory/skills/create-new-teams/SKILL.md +151 -0
- package/apps/smidja-factory/skills/git-ops/README.md +25 -0
- package/apps/smidja-factory/skills/git-ops/SKILL.md +18 -0
- package/apps/smidja-factory/skills/git-ops/create_branch.sh +79 -0
- package/apps/smidja-factory/skills/git-ops/safe_commit.sh +82 -0
- package/apps/smidja-factory/skills/git-ops/sync_upstream.sh +94 -0
- package/apps/smidja-factory/skills/how-to-run-agent-teams/SKILL.md +117 -0
- package/apps/smidja-factory/skills/smidja-instructions/SKILL.md +168 -0
- package/apps/smidja-factory/skills/smidja-launcher/SKILL.md +155 -0
- package/apps/smidja-factory/skills/smidja-start/SKILL.md +266 -0
- package/apps/smidja-factory/skills/volundr/SKILL.md +232 -0
- package/apps/smidja-factory/skills/volundr/prompt/dispatch-prompt.md +91 -0
- package/apps/smidja-factory/skills/volundr/prompt/volundr-system.md +63 -0
- package/apps/smidja-factory/skills/volundr/scripts/volundr-observe.py +52 -0
- package/apps/smidja-factory/skills/volundr/scripts/volundr-recall.py +54 -0
- package/apps/smidja-factory/skills/volundr/scripts/volundr-status.py +51 -0
- package/apps/smidja-factory/skills/volundr/scripts/volundr-teach.py +47 -0
- package/apps/smidja-factory/templates/env.sample +28 -0
- package/apps/smidja-factory/templates/harness_engineering/subagents.ts +706 -0
- package/apps/smidja-factory/templates/harness_engineering/themeMap.ts +145 -0
- package/apps/smidja-factory/templates/justfile +89 -0
- package/apps/smidja-factory/templates/prompt_engineering/builder/system.md +13 -0
- package/apps/smidja-factory/templates/prompt_engineering/builder/user.md +34 -0
- package/apps/smidja-factory/templates/prompt_engineering/documenter/system.md +17 -0
- package/apps/smidja-factory/templates/prompt_engineering/documenter/user.md +48 -0
- package/apps/smidja-factory/templates/prompt_engineering/orchestrator/system.md +55 -0
- package/apps/smidja-factory/templates/prompt_engineering/orchestrator/user.md +39 -0
- package/apps/smidja-factory/templates/prompt_engineering/planner/system.md +21 -0
- package/apps/smidja-factory/templates/prompt_engineering/planner/user.md +45 -0
- package/apps/smidja-factory/templates/prompt_engineering/recon_orchestrator/system.md +51 -0
- package/apps/smidja-factory/templates/prompt_engineering/recon_orchestrator/user.md +26 -0
- package/apps/smidja-factory/templates/prompt_engineering/reviewer/system.md +16 -0
- package/apps/smidja-factory/templates/prompt_engineering/reviewer/user.md +44 -0
- package/apps/smidja-factory/templates/prompt_engineering/scout/system.md +32 -0
- package/apps/smidja-factory/templates/prompt_engineering/scout/user.md +34 -0
- package/apps/smidja-factory/templates/smidja/smidja_build.py +45 -0
- package/apps/smidja-factory/templates/smidja/smidja_build_review.py +76 -0
- package/apps/smidja-factory/templates/smidja/smidja_build_test.py +79 -0
- package/apps/smidja-factory/templates/smidja/smidja_document.py +76 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/agent_cc.py +15 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/agent_opencode.py +194 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/agent_pi.py +392 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/agents.py +993 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/changes.py +103 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/console.py +131 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/data_types.py +447 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/gates.py +108 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/git_helper.py +120 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/lm_local.py +144 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/permissions.py +194 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/prompts.py +21 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/quality.py +240 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/runner.py +155 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/session.py +50 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/stall_watch.py +149 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/tracer.py +271 -0
- package/apps/smidja-factory/templates/smidja/smidja_modules/utils.py +77 -0
- package/apps/smidja-factory/templates/smidja/smidja_orchestrate.py +162 -0
- package/apps/smidja-factory/templates/smidja/smidja_plan.py +45 -0
- package/apps/smidja-factory/templates/smidja/smidja_plan_build.py +55 -0
- package/apps/smidja-factory/templates/smidja/smidja_plan_build_test.py +86 -0
- package/apps/smidja-factory/templates/smidja/smidja_plan_build_test_quality.py +98 -0
- package/apps/smidja-factory/templates/smidja/smidja_prompt.py +44 -0
- package/apps/smidja-factory/templates/smidja/smidja_quality.py +49 -0
- package/apps/smidja-factory/templates/smidja/smidja_recon_iv.py +202 -0
- package/apps/smidja-factory/templates/smidja/smidja_scout.py +45 -0
- package/apps/smidja-factory/templates/smidja/smidja_simple_sdlc.py +183 -0
- package/apps/smidja-factory/templates/smidja.config.yaml +143 -0
- package/bin/app-build.sh +36 -0
- package/bin/electron-lib.sh +25 -0
- package/bin/sessrumnir.sh +1 -1
- package/bin/ymir-install.sh +7 -0
- package/install.sh +88 -0
- package/package.json +16 -7
- package/scripts/electron.sh +6 -2
- package/.agents/bus/messages.json +0 -1
- package/.agents/config/agents.machine.example.yaml +0 -16
- package/.pi/mcp.json +0 -16
- package/assets/reference/state/.branch-eligible-owner +0 -4
- package/assets/reference/state/.branch-mirror-cursor +0 -1
- package/assets/reference/state/.branch-outcomes-cursor +0 -1
- package/assets/reference/state/.branch-session +0 -1
- package/assets/reference/state/.count-default_wF_p5 +0 -1
- package/assets/reference/state/.count-default_wF_p6 +0 -1
- package/assets/reference/state/.count-default_wR_p2 +0 -1
- package/assets/reference/state/.count-default_wS_p2 +0 -1
- package/assets/reference/state/.count-firstmate_fm-server-knowledge +0 -1
- package/assets/reference/state/.hash-default_wF_p5 +0 -1
- package/assets/reference/state/.hash-default_wF_p6 +0 -1
- package/assets/reference/state/.hash-default_wR_p2 +0 -1
- package/assets/reference/state/.hash-default_wS_p2 +0 -1
- package/assets/reference/state/.hash-firstmate_fm-server-knowledge +0 -1
- package/assets/reference/state/.heartbeat-streak +0 -1
- package/assets/reference/state/.inactive-outcome-reconcile +0 -2
- package/assets/reference/state/.lock +0 -1
- package/assets/reference/state/.pi-branch-extension-loaded +0 -1
- package/assets/reference/state/.pi-turnend-extension-loaded +0 -2
- package/assets/reference/state/.pi-watch-extension-loaded +0 -2
- package/assets/reference/state/.seen-server-knowledge_turn-ended +0 -1
- package/assets/reference/state/.session-start-agents-baseline +0 -2
- package/assets/reference/state/.session-start-complete +0 -1
- package/assets/reference/state/.stale-default_wF_p5 +0 -1
- package/assets/reference/state/.stale-default_wR_p2 +0 -1
- package/assets/reference/state/.stale-firstmate_fm-server-knowledge +0 -1
- package/assets/reference/state/.stale-since-default_wF_p5 +0 -1
- package/assets/reference/state/.stale-since-default_wR_p2 +0 -1
- package/assets/reference/state/.stale-since-firstmate_fm-server-knowledge +0 -1
- package/assets/reference/state/.startup-network.delivered +0 -1
- package/assets/reference/state/.startup-network.report +0 -1
- package/assets/reference/state/.startup-network.status +0 -10
- package/assets/reference/state/.startup-network.timings +0 -6
- package/assets/reference/state/.trace-context-effective +0 -1
- package/assets/reference/state/.wake-queue +0 -0
- package/assets/reference/state/.wake-queue.seq +0 -1
- package/assets/reference/state/.wake-rows.consume.BcqXSq +0 -0
- package/assets/reference/state/.wake-rows.consume.NDZZei +0 -0
- package/assets/reference/state/.wake-rows.consume.VGkhYm +0 -0
- package/assets/reference/state/.wake-rows.consume.tR2rTy +0 -0
- package/assets/reference/state/.watch-arm-output.3581p6 +0 -0
- package/assets/reference/state/.watch-arm-output.3ciDNP +0 -0
- package/assets/reference/state/.watch-arm-output.SksR6k +0 -0
- package/assets/reference/state/.watch-cycle-exits.log +0 -22
- package/assets/reference/state/.watch-deliveries.log +0 -19
- package/assets/reference/state/.watch-triage.log +0 -38
- package/assets/reference/state/.watch.lock/fm-home +0 -1
- package/assets/reference/state/.watch.lock/pid +0 -1
- package/assets/reference/state/.watch.lock/pid-identity +0 -1
- package/assets/reference/state/.watch.lock/watcher-path +0 -1
- package/assets/reference/state/.watch.lock.owner.qqbxmS/fm-home +0 -1
- package/assets/reference/state/.watch.lock.owner.qqbxmS/pid +0 -1
- package/assets/reference/state/.watch.lock.owner.qqbxmS/pid-identity +0 -1
- package/assets/reference/state/.watch.lock.owner.qqbxmS/watcher-path +0 -1
- package/assets/reference/state/.watcher-down +0 -1
- package/assets/reference/state/branch-outcomes.jsonl +0 -1
- package/assets/reference/state/branch-session/2026-09-04T16-49-38-671Z_01a06d53-6b6f-7619-930d-e6dfd9a4a29e.jsonl +0 -211
- package/assets/reference/state/home-summary.json +0 -42
- package/assets/reference/state/server-knowledge.busy-gen +0 -1
- package/assets/reference/state/server-knowledge.busy-state +0 -1
- package/assets/reference/state/server-knowledge.herdr-presentation +0 -12
- package/assets/reference/state/server-knowledge.meta +0 -18
- package/assets/reference/state/server-knowledge.pi-ext.ts +0 -26
- package/assets/reference/state/server-knowledge.turn-ended +0 -0
- /package/{assets/reference/state/.last-check → apps/hlidskjalf/src/app/.gitkeep} +0 -0
- /package/{assets/reference/state/.last-heartbeat → apps/hlidskjalf/src/components/.gitkeep} +0 -0
- /package/{assets/reference/state/.last-watcher-beat → apps/hlidskjalf/src/services/.gitkeep} +0 -0
- /package/{assets/reference/state/.main-eligible-rows.tmp.p2HMKo → apps/smidja/smidja_modules/__init__.py} +0 -0
- /package/{assets/reference/state/.main-eligible-rows.tmp.Exxm82 → apps/smidja-factory/templates/smidja/smidja_modules/__init__.py} +0 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { test } from 'node:test'
|
|
3
|
+
import { mkdir, mkdtemp, readFile, writeFile, access } from 'fs/promises'
|
|
4
|
+
import { existsSync } from 'fs'
|
|
5
|
+
import { spawnSync } from 'child_process'
|
|
6
|
+
import { tmpdir } from 'os'
|
|
7
|
+
import { join, resolve } from 'path'
|
|
8
|
+
import type {
|
|
9
|
+
PiProcessStatus,
|
|
10
|
+
PiStartOptions,
|
|
11
|
+
SessionRuntimeCloseResult,
|
|
12
|
+
SessionRuntimeInfo,
|
|
13
|
+
} from '../shared/ipc-contracts'
|
|
14
|
+
import { configureGuiDataDir, getGuiDataPath } from './app-data-paths'
|
|
15
|
+
import { isPathWithin } from './path-authorization'
|
|
16
|
+
import { getOmpSessionsRoot, getSessionsRoot } from './pi-paths'
|
|
17
|
+
import { PiRpcManager } from './pi-rpc-manager'
|
|
18
|
+
import { isDisposableSessionFile, MAX_LIVE_SESSION_RUNTIMES, WorkspaceManager } from './workspace-manager'
|
|
19
|
+
|
|
20
|
+
async function freshDataDir(): Promise<void> {
|
|
21
|
+
configureGuiDataDir(await mkdtemp(join(tmpdir(), 'pi-ws-')))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function project(): Promise<string> {
|
|
25
|
+
return mkdtemp(join(tmpdir(), 'pi-proj-'))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Run with each engine's session store redirected into its own temp tree, so a
|
|
30
|
+
* fixture can be placed in the store that decides which engine owns it.
|
|
31
|
+
*/
|
|
32
|
+
async function withSessionStores(
|
|
33
|
+
fn: (roots: { pi: string; omp: string }) => Promise<void>
|
|
34
|
+
): Promise<void> {
|
|
35
|
+
const saved = {
|
|
36
|
+
pi: process.env.PI_CODING_AGENT_DIR,
|
|
37
|
+
omp: process.env.OMP_CODING_AGENT_DIR,
|
|
38
|
+
}
|
|
39
|
+
process.env.PI_CODING_AGENT_DIR = await mkdtemp(join(tmpdir(), 'pi-agent-'))
|
|
40
|
+
process.env.OMP_CODING_AGENT_DIR = await mkdtemp(join(tmpdir(), 'omp-agent-'))
|
|
41
|
+
try {
|
|
42
|
+
await fn({ pi: getSessionsRoot(), omp: getOmpSessionsRoot() })
|
|
43
|
+
} finally {
|
|
44
|
+
for (const [key, value] of [
|
|
45
|
+
['PI_CODING_AGENT_DIR', saved.pi],
|
|
46
|
+
['OMP_CODING_AGENT_DIR', saved.omp],
|
|
47
|
+
] as const) {
|
|
48
|
+
if (value === undefined) delete process.env[key]
|
|
49
|
+
else process.env[key] = value
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Write a session file into one engine's store, laid out the way it lays them out. */
|
|
55
|
+
async function storedSession(root: string, name: string, ...records: object[]): Promise<string> {
|
|
56
|
+
const projectDir = join(root, '--tmp-app--')
|
|
57
|
+
await mkdir(projectDir, { recursive: true })
|
|
58
|
+
const path = join(projectDir, name)
|
|
59
|
+
await writeFile(path, records.map((record) => JSON.stringify(record)).join('\n') + '\n', 'utf-8')
|
|
60
|
+
return path
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Make the manager's get_state report the session file the agent wrote. */
|
|
64
|
+
function reportsSessionFile(manager: PiRpcManager, sessionPath: string, sessionId: string): void {
|
|
65
|
+
manager.sendCommand = async () => ({
|
|
66
|
+
type: 'response',
|
|
67
|
+
command: 'get_state',
|
|
68
|
+
success: true,
|
|
69
|
+
data: { sessionFile: sessionPath, sessionId },
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Initialize a manager and guarantee its watchers are stopped afterward. */
|
|
74
|
+
async function withManager(fn: (mgr: WorkspaceManager) => Promise<void>): Promise<void> {
|
|
75
|
+
const mgr = new WorkspaceManager()
|
|
76
|
+
await mgr.initialize()
|
|
77
|
+
try {
|
|
78
|
+
await fn(mgr)
|
|
79
|
+
} finally {
|
|
80
|
+
mgr.stopAll()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface FakePiProcess {
|
|
85
|
+
stopped: boolean
|
|
86
|
+
starts: number
|
|
87
|
+
/** Options the manager was last started with, for asserting on the argv. */
|
|
88
|
+
lastStartOptions: PiStartOptions | null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Give a manager the observable behaviour of a live Pi child process without
|
|
93
|
+
* spawning one: a status that flips on start/stop, and the status-change event
|
|
94
|
+
* the real manager emits from setStatus().
|
|
95
|
+
*/
|
|
96
|
+
function fakePiProcess(
|
|
97
|
+
manager: PiRpcManager,
|
|
98
|
+
pid: number,
|
|
99
|
+
initial: PiProcessStatus = 'running'
|
|
100
|
+
): FakePiProcess {
|
|
101
|
+
const state: FakePiProcess = { stopped: false, starts: 0, lastStartOptions: null }
|
|
102
|
+
let status = initial
|
|
103
|
+
const setStatus = (next: PiProcessStatus): void => {
|
|
104
|
+
if (status === next) return
|
|
105
|
+
status = next
|
|
106
|
+
manager.emit('status-change', status)
|
|
107
|
+
}
|
|
108
|
+
manager.getStatus = () => ({ status, pid: status === 'stopped' ? null : pid, error: null })
|
|
109
|
+
manager.stop = (): void => {
|
|
110
|
+
state.stopped = true
|
|
111
|
+
setStatus('stopped')
|
|
112
|
+
}
|
|
113
|
+
manager.start = async (options: PiStartOptions = {}) => {
|
|
114
|
+
state.starts += 1
|
|
115
|
+
state.lastStartOptions = options
|
|
116
|
+
setStatus('running')
|
|
117
|
+
return manager.getStatus()
|
|
118
|
+
}
|
|
119
|
+
return state
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** How many runtimes currently hold a Pi child process. */
|
|
123
|
+
function liveRuntimeCount(mgr: WorkspaceManager): number {
|
|
124
|
+
return mgr.getSessionRuntimes()
|
|
125
|
+
.filter((runtime) => runtime.status === 'running' || runtime.status === 'starting')
|
|
126
|
+
.length
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Create a session runtime, then give it a fake live process. */
|
|
130
|
+
async function liveRuntime(
|
|
131
|
+
mgr: WorkspaceManager,
|
|
132
|
+
workspaceId: string,
|
|
133
|
+
pid: number,
|
|
134
|
+
initial: PiProcessStatus = 'running'
|
|
135
|
+
): Promise<{ runtime: SessionRuntimeInfo; process: FakePiProcess }> {
|
|
136
|
+
const runtime = await mgr.createNewSessionRuntime(workspaceId)
|
|
137
|
+
const manager = mgr.getActivePiManager()
|
|
138
|
+
assert.ok(manager, 'a new session runtime owns the active Pi manager')
|
|
139
|
+
return { runtime, process: fakePiProcess(manager, pid, initial) }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Initialize a Git repository and return a runner bound to it. */
|
|
143
|
+
function gitRepo(repo: string): (args: string[], cwd?: string) => string {
|
|
144
|
+
const git = (args: string[], cwd = repo): string => {
|
|
145
|
+
const result = spawnSync('git', args, { cwd, encoding: 'utf-8' })
|
|
146
|
+
assert.equal(result.status, 0, result.stderr || `git ${args.join(' ')} failed`)
|
|
147
|
+
return result.stdout.trim()
|
|
148
|
+
}
|
|
149
|
+
git(['init'])
|
|
150
|
+
git(['config', 'user.email', 'pi-desktop@example.test'])
|
|
151
|
+
git(['config', 'user.name', 'Sessrúmnir Tests'])
|
|
152
|
+
git(['add', '.'])
|
|
153
|
+
git(['commit', '-m', 'initial'])
|
|
154
|
+
return git
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
test('saveWorkspaces writes atomically (no leftover .tmp) and round-trips', async () => {
|
|
158
|
+
await freshDataDir()
|
|
159
|
+
const cfg = getGuiDataPath('workspaces.json')
|
|
160
|
+
|
|
161
|
+
await withManager(async (mgr) => {
|
|
162
|
+
await mgr.createWorkspace('Alpha', await project())
|
|
163
|
+
const saved = JSON.parse(await readFile(cfg, 'utf-8'))
|
|
164
|
+
assert.ok(
|
|
165
|
+
saved.workspaces.some((w: { name: string }) => w.name === 'Alpha'),
|
|
166
|
+
'created workspace should be persisted'
|
|
167
|
+
)
|
|
168
|
+
await assert.rejects(() => access(`${cfg}.tmp`), 'temp file must not linger after an atomic write')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
await withManager(async (reloaded) => {
|
|
172
|
+
assert.ok(
|
|
173
|
+
reloaded.getWorkspaces().some((w) => w.name === 'Alpha'),
|
|
174
|
+
'reloaded manager should see the persisted workspace'
|
|
175
|
+
)
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('workspaceIdFor reverse-maps a manager to its owning workspace', async () => {
|
|
180
|
+
await freshDataDir()
|
|
181
|
+
|
|
182
|
+
await withManager(async (mgr) => {
|
|
183
|
+
const alpha = await mgr.createWorkspace('Alpha', await project())
|
|
184
|
+
const beta = await mgr.createWorkspace('Beta', await project())
|
|
185
|
+
const alphaManager = mgr.getPiManager(alpha.id)
|
|
186
|
+
const betaManager = mgr.getPiManager(beta.id)
|
|
187
|
+
assert.ok(alphaManager && betaManager, 'each workspace should own a Pi manager')
|
|
188
|
+
assert.equal(mgr.workspaceIdFor(alphaManager), alpha.id)
|
|
189
|
+
assert.equal(mgr.workspaceIdFor(betaManager), beta.id)
|
|
190
|
+
assert.equal(mgr.workspaceIdFor(new PiRpcManager()), null, 'an unowned manager must map to nothing')
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
test('multiple session runtimes share a project cwd without sharing a Pi process', async () => {
|
|
195
|
+
await freshDataDir()
|
|
196
|
+
|
|
197
|
+
await withManager(async (mgr) => {
|
|
198
|
+
const ws = await mgr.createWorkspace('Alpha', await project())
|
|
199
|
+
const fallback = mgr.getPiManager(ws.id)
|
|
200
|
+
const first = await mgr.createNewSessionRuntime(ws.id)
|
|
201
|
+
const second = await mgr.createNewSessionRuntime(ws.id)
|
|
202
|
+
|
|
203
|
+
assert.notEqual(first.runtimeId, second.runtimeId)
|
|
204
|
+
assert.notEqual(mgr.getActivePiManager(), fallback, 'the active session runtime replaces the workspace fallback')
|
|
205
|
+
assert.equal(mgr.getSessionRuntimes(ws.id).length, 2)
|
|
206
|
+
assert.equal(mgr.workspaceIdFor(mgr.getActivePiManager()!), ws.id)
|
|
207
|
+
|
|
208
|
+
const existingPath = join(await project(), 'session.jsonl')
|
|
209
|
+
await writeFile(existingPath, '{}\n', 'utf-8')
|
|
210
|
+
const activated = await mgr.activateSession(ws.id, existingPath)
|
|
211
|
+
assert.equal(activated.sessionPath, existingPath)
|
|
212
|
+
assert.equal(mgr.getSessionRuntimeForPath(existingPath)?.runtimeId, activated.runtimeId)
|
|
213
|
+
assert.equal(mgr.getActiveSessionRuntime()?.runtimeId, activated.runtimeId)
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
test('changeWorkspacePath stops the workspace Pi so it cannot keep the old cwd', async () => {
|
|
218
|
+
await freshDataDir()
|
|
219
|
+
|
|
220
|
+
await withManager(async (mgr) => {
|
|
221
|
+
const ws = await mgr.createWorkspace('Alpha', await project())
|
|
222
|
+
const piManager = mgr.getPiManager(ws.id)
|
|
223
|
+
assert.ok(piManager, 'the workspace should own a Pi manager')
|
|
224
|
+
let stopped = false
|
|
225
|
+
piManager.stop = () => {
|
|
226
|
+
stopped = true
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
await mgr.changeWorkspacePath(ws.id, await project())
|
|
230
|
+
|
|
231
|
+
assert.equal(stopped, true, "Pi's cwd is bound at spawn; a repoint must stop it")
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('creates and removes a clean managed worktree tab', async () => {
|
|
236
|
+
await freshDataDir()
|
|
237
|
+
const repo = await project()
|
|
238
|
+
await writeFile(join(repo, 'README.md'), 'worktree test\\n', 'utf-8')
|
|
239
|
+
const git = gitRepo(repo)
|
|
240
|
+
|
|
241
|
+
await withManager(async (mgr) => {
|
|
242
|
+
await mgr.createWorkspace('Repo', repo)
|
|
243
|
+
const tab = await mgr.createWorktreeWorkspace()
|
|
244
|
+
|
|
245
|
+
assert.equal(tab.kind, 'worktree')
|
|
246
|
+
assert.equal(tab.branch, 'pi/repo-tab-' + tab.id.replace(/^ws-/, ''))
|
|
247
|
+
assert.equal(existsSync(tab.path), true)
|
|
248
|
+
assert.equal(git(['branch', '--show-current'], tab.path), tab.branch)
|
|
249
|
+
|
|
250
|
+
const result = await mgr.removeWorkspace(tab.id)
|
|
251
|
+
assert.equal(result.worktreeRemoved, true)
|
|
252
|
+
assert.equal(result.preservedWorktreePath, undefined)
|
|
253
|
+
assert.equal(existsSync(tab.path), false)
|
|
254
|
+
|
|
255
|
+
await writeFile(join(repo, 'source-dirty.txt'), 'stays in source\\n', 'utf-8')
|
|
256
|
+
const dirtySourceTab = await mgr.createWorktreeWorkspace()
|
|
257
|
+
assert.equal(dirtySourceTab.sourceWasDirty, true)
|
|
258
|
+
assert.equal(existsSync(join(dirtySourceTab.path, 'source-dirty.txt')), false)
|
|
259
|
+
await mgr.removeWorkspace(dirtySourceTab.id)
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
test('reuses the same managed worktree for the same task', async () => {
|
|
264
|
+
await freshDataDir()
|
|
265
|
+
const repo = await project()
|
|
266
|
+
await writeFile(join(repo, 'README.md'), 'task reuse\n', 'utf-8')
|
|
267
|
+
gitRepo(repo)
|
|
268
|
+
|
|
269
|
+
await withManager(async (mgr) => {
|
|
270
|
+
const source = await mgr.createWorkspace('Repo', repo)
|
|
271
|
+
const task = 'Fix the task reuse test'
|
|
272
|
+
const first = await mgr.createWorktreeWorkspace({
|
|
273
|
+
sourceWorkspaceId: source.id,
|
|
274
|
+
name: 'Fix task reuse',
|
|
275
|
+
taskPrompt: task,
|
|
276
|
+
})
|
|
277
|
+
const second = await mgr.createWorktreeWorkspace({
|
|
278
|
+
sourceWorkspaceId: source.id,
|
|
279
|
+
name: 'Should not create another tab',
|
|
280
|
+
taskPrompt: task,
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
assert.equal(second.id, first.id)
|
|
284
|
+
assert.equal(mgr.getWorkspaces().filter((workspace) => workspace.kind === 'worktree').length, 1)
|
|
285
|
+
await mgr.removeWorkspace(first.id)
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
test('adopts an explicitly named leftover worktree without deleting it on close', async () => {
|
|
290
|
+
await freshDataDir()
|
|
291
|
+
const repo = await project()
|
|
292
|
+
await writeFile(join(repo, 'README.md'), 'leftover worktree\n', 'utf-8')
|
|
293
|
+
const git = gitRepo(repo)
|
|
294
|
+
// A worktree left behind under the app's own root, e.g. one preserved because
|
|
295
|
+
// it was still dirty when its tab closed. Only this root is reusable.
|
|
296
|
+
const leftover = join(getGuiDataPath('worktrees'), 'leftover-checkout')
|
|
297
|
+
git(['worktree', 'add', '-b', 'feature/existing', leftover])
|
|
298
|
+
|
|
299
|
+
await withManager(async (mgr) => {
|
|
300
|
+
const source = await mgr.createWorkspace('Repo', repo)
|
|
301
|
+
const adopted = await mgr.createWorktreeWorkspace({
|
|
302
|
+
sourceWorkspaceId: source.id,
|
|
303
|
+
taskPrompt: 'Continue work in feature/existing',
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
assert.equal(adopted.path.replaceAll('\\', '/'), leftover.replaceAll('\\', '/'))
|
|
307
|
+
assert.equal(adopted.branch, 'feature/existing')
|
|
308
|
+
assert.equal(adopted.managed, false)
|
|
309
|
+
const result = await mgr.removeWorkspace(adopted.id)
|
|
310
|
+
assert.equal(result.worktreeRemoved, undefined)
|
|
311
|
+
assert.equal(existsSync(leftover), true)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
git(['worktree', 'remove', leftover])
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
test('never reuses the main checkout or a worktree the user made', async () => {
|
|
318
|
+
await freshDataDir()
|
|
319
|
+
const repo = await project()
|
|
320
|
+
await writeFile(join(repo, 'README.md'), 'main checkout\n', 'utf-8')
|
|
321
|
+
const git = gitRepo(repo)
|
|
322
|
+
// The user's primary checkout sits on a group/name branch, and they keep a
|
|
323
|
+
// second checkout of their own outside the app's worktree root.
|
|
324
|
+
git(['checkout', '-b', 'feature/main-work'])
|
|
325
|
+
const userWorktree = join(await project(), 'user-checkout')
|
|
326
|
+
git(['worktree', 'add', '-b', 'feature/user-side', userWorktree])
|
|
327
|
+
|
|
328
|
+
await withManager(async (mgr) => {
|
|
329
|
+
const repoWorkspace = await mgr.createWorkspace('Repo', repo)
|
|
330
|
+
// Run the task from a managed tab, so the source is itself a linked
|
|
331
|
+
// worktree and the main checkout is just another entry in the list.
|
|
332
|
+
const sourceTab = await mgr.createWorktreeWorkspace({ sourceWorkspaceId: repoWorkspace.id })
|
|
333
|
+
|
|
334
|
+
const fromMainBranch = await mgr.createWorktreeWorkspace({
|
|
335
|
+
sourceWorkspaceId: sourceTab.id,
|
|
336
|
+
taskPrompt: 'Continue work in feature/main-work',
|
|
337
|
+
})
|
|
338
|
+
assert.notEqual(fromMainBranch.id, repoWorkspace.id, 'a task must never hand back the source project tab')
|
|
339
|
+
assert.notEqual(resolve(fromMainBranch.path), resolve(repo), 'the main checkout must never be reused')
|
|
340
|
+
assert.equal(
|
|
341
|
+
isPathWithin(getGuiDataPath('worktrees'), fromMainBranch.path),
|
|
342
|
+
true,
|
|
343
|
+
'the task must get a fresh worktree under the app root instead'
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
const fromUserWorktree = await mgr.createWorktreeWorkspace({
|
|
347
|
+
sourceWorkspaceId: sourceTab.id,
|
|
348
|
+
taskPrompt: 'Continue work in feature/user-side',
|
|
349
|
+
})
|
|
350
|
+
assert.notEqual(
|
|
351
|
+
resolve(fromUserWorktree.path),
|
|
352
|
+
resolve(userWorktree),
|
|
353
|
+
'a worktree outside the app root belongs to the user'
|
|
354
|
+
)
|
|
355
|
+
assert.equal(isPathWithin(getGuiDataPath('worktrees'), fromUserWorktree.path), true)
|
|
356
|
+
|
|
357
|
+
// Both user checkouts are untouched: same branch, same files.
|
|
358
|
+
assert.equal(git(['branch', '--show-current'], repo), 'feature/main-work')
|
|
359
|
+
assert.equal(git(['branch', '--show-current'], userWorktree), 'feature/user-side')
|
|
360
|
+
|
|
361
|
+
await mgr.removeWorkspace(fromUserWorktree.id)
|
|
362
|
+
await mgr.removeWorkspace(fromMainBranch.id)
|
|
363
|
+
await mgr.removeWorkspace(sourceTab.id)
|
|
364
|
+
assert.equal(existsSync(repo), true)
|
|
365
|
+
assert.equal(existsSync(userWorktree), true)
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
git(['worktree', 'remove', userWorktree])
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
test('closing a session runtime removes its tab and only marks empty sessions disposable', async () => {
|
|
372
|
+
await freshDataDir()
|
|
373
|
+
|
|
374
|
+
await withManager(async (mgr) => {
|
|
375
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
376
|
+
const emptyPath = join(await project(), 'empty.jsonl')
|
|
377
|
+
await writeFile(emptyPath, JSON.stringify({ type: 'session', id: 'empty' }) + '\n', 'utf-8')
|
|
378
|
+
const emptyRuntime = await mgr.activateSession(workspace.id, emptyPath)
|
|
379
|
+
|
|
380
|
+
const contentPath = join(await project(), 'content.jsonl')
|
|
381
|
+
await writeFile(contentPath, [
|
|
382
|
+
JSON.stringify({ type: 'session', id: 'content' }),
|
|
383
|
+
JSON.stringify({ type: 'message', message: { role: 'user', content: [{ type: 'text', text: 'keep me' }] } }),
|
|
384
|
+
].join('\n') + '\n', 'utf-8')
|
|
385
|
+
const contentRuntime = await mgr.activateSession(workspace.id, contentPath)
|
|
386
|
+
const pruned = await mgr.pruneEmptySessionRuntimes()
|
|
387
|
+
const contentResult = await mgr.closeSessionRuntime(contentRuntime.runtimeId)
|
|
388
|
+
|
|
389
|
+
assert.equal(pruned.some((result) => result.runtimeId === emptyRuntime.runtimeId && result.empty), true)
|
|
390
|
+
assert.equal(mgr.getSessionRuntime(emptyRuntime.runtimeId), null)
|
|
391
|
+
assert.equal(contentResult?.empty, false)
|
|
392
|
+
assert.equal(existsSync(contentPath), true)
|
|
393
|
+
|
|
394
|
+
const imagePath = join(await project(), 'image-only.jsonl')
|
|
395
|
+
await writeFile(imagePath, [
|
|
396
|
+
JSON.stringify({ type: 'session', id: 'image-only' }),
|
|
397
|
+
JSON.stringify({ type: 'message', message: { role: 'user', content: [{ type: 'image', source: { data: 'AAAA' } }] } }),
|
|
398
|
+
].join('\n') + '\n', 'utf-8')
|
|
399
|
+
const imageRuntime = await mgr.activateSession(workspace.id, imagePath)
|
|
400
|
+
const imageResult = await mgr.closeSessionRuntime(imageRuntime.runtimeId)
|
|
401
|
+
assert.equal(imageResult?.empty, false)
|
|
402
|
+
assert.equal(existsSync(imagePath), true)
|
|
403
|
+
})
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
test('a session starts on the engine that owns its store, not the configured default', async () => {
|
|
407
|
+
await freshDataDir()
|
|
408
|
+
|
|
409
|
+
await withSessionStores(async (roots) => {
|
|
410
|
+
await withManager(async (mgr) => {
|
|
411
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
412
|
+
|
|
413
|
+
// Opened from the session list, the way session-handlers starts it.
|
|
414
|
+
const ompPath = await storedSession(roots.omp, 'omp.jsonl', { type: 'session', id: 'omp' })
|
|
415
|
+
const ompRuntime = await mgr.activateSession(workspace.id, ompPath)
|
|
416
|
+
const ompManager = mgr.getActivePiManager()
|
|
417
|
+
assert.ok(ompManager, 'the activated session owns the active manager')
|
|
418
|
+
const ompProcess = fakePiProcess(ompManager, 601, 'stopped')
|
|
419
|
+
await mgr.startSessionRuntime(ompRuntime.runtimeId, { sessionPath: ompPath })
|
|
420
|
+
assert.equal(ompProcess.lastStartOptions?.engine, 'omp')
|
|
421
|
+
assert.equal(ompProcess.lastStartOptions?.sessionPath, ompPath)
|
|
422
|
+
|
|
423
|
+
// Restarting an evicted tab passes no session path, so the engine has to
|
|
424
|
+
// survive on the runtime's own remembered file.
|
|
425
|
+
const piPath = await storedSession(roots.pi, 'pi.jsonl', { type: 'session', id: 'pi' })
|
|
426
|
+
const piRuntime = await mgr.activateSession(workspace.id, piPath)
|
|
427
|
+
const piManager = mgr.getActivePiManager()
|
|
428
|
+
assert.ok(piManager)
|
|
429
|
+
const piProcess = fakePiProcess(piManager, 602, 'stopped')
|
|
430
|
+
await mgr.startSessionRuntime(piRuntime.runtimeId)
|
|
431
|
+
assert.equal(piProcess.lastStartOptions?.engine, 'pi')
|
|
432
|
+
|
|
433
|
+
// A brand-new session belongs to no store yet, so it uses the engine the
|
|
434
|
+
// user configured.
|
|
435
|
+
const fresh = await mgr.createNewSessionRuntime(workspace.id)
|
|
436
|
+
const freshManager = mgr.getActivePiManager()
|
|
437
|
+
assert.ok(freshManager)
|
|
438
|
+
const freshProcess = fakePiProcess(freshManager, 603, 'stopped')
|
|
439
|
+
await mgr.startSessionRuntime(fresh.runtimeId)
|
|
440
|
+
assert.equal(freshProcess.lastStartOptions?.engine, undefined)
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
test('a closed tab is only disposable when this run created its session file', async () => {
|
|
446
|
+
await freshDataDir()
|
|
447
|
+
|
|
448
|
+
await withSessionStores(async (roots) => {
|
|
449
|
+
await withManager(async (mgr) => {
|
|
450
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
451
|
+
|
|
452
|
+
// A header-only file the user opened from the list. It reads empty, but
|
|
453
|
+
// it is theirs — closing the tab must never delete it.
|
|
454
|
+
const adopted = await storedSession(roots.pi, 'adopted.jsonl', { type: 'session', id: 'adopted' })
|
|
455
|
+
const adoptedRuntime = await mgr.activateSession(workspace.id, adopted)
|
|
456
|
+
const adoptedClose = await mgr.closeSessionRuntime(adoptedRuntime.runtimeId)
|
|
457
|
+
assert.ok(adoptedClose)
|
|
458
|
+
assert.equal(adoptedClose.empty, true)
|
|
459
|
+
assert.equal(adoptedClose.appCreated, false)
|
|
460
|
+
assert.equal(isDisposableSessionFile(adoptedClose), false)
|
|
461
|
+
|
|
462
|
+
// A New Session tab whose agent wrote a fresh file: ours to discard.
|
|
463
|
+
const created = await mgr.createNewSessionRuntime(workspace.id)
|
|
464
|
+
const createdManager = mgr.getActivePiManager()
|
|
465
|
+
assert.ok(createdManager)
|
|
466
|
+
const createdProcess = fakePiProcess(createdManager, 701, 'stopped')
|
|
467
|
+
const createdPath = await storedSession(roots.pi, 'created.jsonl', { type: 'session', id: 'created' })
|
|
468
|
+
reportsSessionFile(createdManager, createdPath, 'created')
|
|
469
|
+
await mgr.startSessionRuntime(created.runtimeId)
|
|
470
|
+
|
|
471
|
+
// A permission-rules change restarts every live runtime with the resume
|
|
472
|
+
// preference applied. This tab already owns a file, so --session outranks
|
|
473
|
+
// --continue and the tab keeps both its session and its own authorship.
|
|
474
|
+
await mgr.startSessionRuntime(created.runtimeId, { continueSession: true })
|
|
475
|
+
assert.equal(createdProcess.lastStartOptions?.sessionPath, createdPath)
|
|
476
|
+
|
|
477
|
+
const createdClose = await mgr.closeSessionRuntime(created.runtimeId)
|
|
478
|
+
assert.ok(createdClose)
|
|
479
|
+
assert.equal(createdClose.sessionPath, createdPath)
|
|
480
|
+
assert.equal(createdClose.appCreated, true)
|
|
481
|
+
assert.equal(isDisposableSessionFile(createdClose), true)
|
|
482
|
+
|
|
483
|
+
// The same New Session tab with the resume preference on: --continue
|
|
484
|
+
// binds it to whatever session already existed for this cwd, so the file
|
|
485
|
+
// stops being ours the moment it starts.
|
|
486
|
+
const resumed = await mgr.createNewSessionRuntime(workspace.id)
|
|
487
|
+
const resumedManager = mgr.getActivePiManager()
|
|
488
|
+
assert.ok(resumedManager)
|
|
489
|
+
fakePiProcess(resumedManager, 702, 'stopped')
|
|
490
|
+
const resumedPath = await storedSession(roots.pi, 'resumed.jsonl', { type: 'session', id: 'resumed' })
|
|
491
|
+
reportsSessionFile(resumedManager, resumedPath, 'resumed')
|
|
492
|
+
await mgr.startSessionRuntime(resumed.runtimeId, { continueSession: true })
|
|
493
|
+
const resumedClose = await mgr.closeSessionRuntime(resumed.runtimeId)
|
|
494
|
+
assert.ok(resumedClose)
|
|
495
|
+
assert.equal(resumedClose.empty, true)
|
|
496
|
+
assert.equal(resumedClose.appCreated, false)
|
|
497
|
+
assert.equal(isDisposableSessionFile(resumedClose), false)
|
|
498
|
+
})
|
|
499
|
+
})
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
test('the auto-delete guard refuses a file it cannot prove is a throwaway', async () => {
|
|
503
|
+
await withSessionStores(async (roots) => {
|
|
504
|
+
const inStore = await storedSession(roots.pi, 'guard.jsonl', { type: 'session', id: 'guard' })
|
|
505
|
+
const base: SessionRuntimeCloseResult = {
|
|
506
|
+
runtimeId: 'rt-guard',
|
|
507
|
+
workspaceId: 'ws-guard',
|
|
508
|
+
sessionPath: inStore,
|
|
509
|
+
empty: true,
|
|
510
|
+
appCreated: true,
|
|
511
|
+
deleted: false,
|
|
512
|
+
}
|
|
513
|
+
assert.equal(isDisposableSessionFile(base), true)
|
|
514
|
+
|
|
515
|
+
// An unreadable or partial read leaves `empty` false; that is a session
|
|
516
|
+
// with content as far as this app is concerned.
|
|
517
|
+
assert.equal(isDisposableSessionFile({ ...base, empty: false }), false)
|
|
518
|
+
assert.equal(isDisposableSessionFile({ ...base, appCreated: false }), false)
|
|
519
|
+
assert.equal(isDisposableSessionFile({ ...base, sessionPath: null }), false)
|
|
520
|
+
// Outside every store: the runtime's path is reported by the agent, so a
|
|
521
|
+
// wrong or hostile one must not reach unlink.
|
|
522
|
+
assert.equal(
|
|
523
|
+
isDisposableSessionFile({ ...base, sessionPath: join(await project(), 'loose.jsonl') }),
|
|
524
|
+
false
|
|
525
|
+
)
|
|
526
|
+
assert.equal(
|
|
527
|
+
isDisposableSessionFile({ ...base, sessionPath: join(roots.pi, '--tmp-app--', 'gone.jsonl') }),
|
|
528
|
+
false
|
|
529
|
+
)
|
|
530
|
+
})
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
test('caps live Pi processes by stopping the least recently used idle runtime', async () => {
|
|
534
|
+
await freshDataDir()
|
|
535
|
+
|
|
536
|
+
await withManager(async (mgr) => {
|
|
537
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
538
|
+
const sessionPath = join(await project(), 'oldest.jsonl')
|
|
539
|
+
await writeFile(sessionPath, JSON.stringify({ type: 'session', id: 'oldest' }) + '\n', 'utf-8')
|
|
540
|
+
const oldest = await mgr.activateSession(workspace.id, sessionPath)
|
|
541
|
+
const oldestManager = mgr.getActivePiManager()
|
|
542
|
+
assert.ok(oldestManager, 'the activated session owns the active Pi manager')
|
|
543
|
+
const oldestProcess = fakePiProcess(oldestManager, 9000)
|
|
544
|
+
|
|
545
|
+
const opened = []
|
|
546
|
+
for (let index = 1; index < MAX_LIVE_SESSION_RUNTIMES; index++) {
|
|
547
|
+
opened.push(await liveRuntime(mgr, workspace.id, 9000 + index))
|
|
548
|
+
}
|
|
549
|
+
assert.equal(liveRuntimeCount(mgr), MAX_LIVE_SESSION_RUNTIMES, 'the cap is reached but not breached')
|
|
550
|
+
|
|
551
|
+
const seen: SessionRuntimeInfo[] = []
|
|
552
|
+
mgr.onSessionRuntime((runtime) => seen.push(runtime))
|
|
553
|
+
const before = seen.length
|
|
554
|
+
|
|
555
|
+
const extra = await liveRuntime(mgr, workspace.id, 9100)
|
|
556
|
+
|
|
557
|
+
assert.equal(oldestProcess.stopped, true, 'the least recently used idle runtime loses its process')
|
|
558
|
+
assert.equal(
|
|
559
|
+
opened.filter((item) => item.process.stopped).length,
|
|
560
|
+
0,
|
|
561
|
+
'exactly one runtime is evicted, not every idle one'
|
|
562
|
+
)
|
|
563
|
+
assert.equal(liveRuntimeCount(mgr), MAX_LIVE_SESSION_RUNTIMES, 'the new process fits inside the cap')
|
|
564
|
+
|
|
565
|
+
// The tab survives; only the process is gone, and the renderer is told.
|
|
566
|
+
const evicted = mgr.getSessionRuntime(oldest.runtimeId)
|
|
567
|
+
assert.equal(evicted?.status, 'stopped')
|
|
568
|
+
assert.equal(evicted?.sessionPath, sessionPath, 'an evicted runtime keeps its session')
|
|
569
|
+
assert.equal(existsSync(sessionPath), true, 'eviction must never delete the session file')
|
|
570
|
+
const emitted = seen.slice(before).filter((runtime) => runtime.runtimeId === oldest.runtimeId)
|
|
571
|
+
assert.equal(emitted.at(-1)?.status, 'stopped', 'the tab must not keep showing a dead process as live')
|
|
572
|
+
assert.equal(emitted.at(-1)?.closed, undefined, 'eviction stops a tab, it does not close it')
|
|
573
|
+
|
|
574
|
+
// Re-activating the evicted tab spawns again and stays inside the cap.
|
|
575
|
+
await mgr.activateSession(workspace.id, sessionPath)
|
|
576
|
+
const restarted = await mgr.startSessionRuntime(oldest.runtimeId)
|
|
577
|
+
|
|
578
|
+
assert.equal(restarted.runtimeId, oldest.runtimeId, 'the same tab is reused')
|
|
579
|
+
assert.equal(oldestProcess.starts, 1, 'a fresh Pi process is started for the same session file')
|
|
580
|
+
assert.equal(opened[0].process.stopped, true, 'the next least recently used runtime makes room')
|
|
581
|
+
assert.equal(extra.process.stopped, false, 'a runtime used a moment ago is not the eviction target')
|
|
582
|
+
assert.equal(liveRuntimeCount(mgr), MAX_LIVE_SESSION_RUNTIMES)
|
|
583
|
+
})
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
test('eviction spares the active, starting, and mid-turn runtimes', async () => {
|
|
587
|
+
await freshDataDir()
|
|
588
|
+
|
|
589
|
+
await withManager(async (mgr) => {
|
|
590
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
591
|
+
const working = await liveRuntime(mgr, workspace.id, 9200)
|
|
592
|
+
const approving = await liveRuntime(mgr, workspace.id, 9201)
|
|
593
|
+
const starting = await liveRuntime(mgr, workspace.id, 9202, 'starting')
|
|
594
|
+
const idleOlder = await liveRuntime(mgr, workspace.id, 9203)
|
|
595
|
+
const idleNewer = await liveRuntime(mgr, workspace.id, 9204)
|
|
596
|
+
const active = await liveRuntime(mgr, workspace.id, 9205)
|
|
597
|
+
mgr.setSessionRuntimeActivity(working.runtime.runtimeId, 'working')
|
|
598
|
+
mgr.setSessionRuntimeActivity(approving.runtime.runtimeId, 'needs-approval')
|
|
599
|
+
assert.equal(mgr.getActiveSessionRuntime()?.runtimeId, active.runtime.runtimeId)
|
|
600
|
+
|
|
601
|
+
const overflow = await liveRuntime(mgr, workspace.id, 9206)
|
|
602
|
+
|
|
603
|
+
assert.equal(idleOlder.process.stopped, true, 'the oldest idle runtime is the only valid victim')
|
|
604
|
+
for (const spared of [working, approving, starting, idleNewer, active, overflow]) {
|
|
605
|
+
assert.equal(spared.process.stopped, false, 'a protected or newer runtime must keep its process')
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// With every remaining runtime protected, the cap is exceeded on purpose:
|
|
609
|
+
// losing a turn the user waits on is worse than one extra process.
|
|
610
|
+
mgr.setSessionRuntimeActivity(idleNewer.runtime.runtimeId, 'working')
|
|
611
|
+
mgr.setSessionRuntimeActivity(active.runtime.runtimeId, 'needs-approval')
|
|
612
|
+
const beyondCap = await liveRuntime(mgr, workspace.id, 9207)
|
|
613
|
+
|
|
614
|
+
assert.equal(
|
|
615
|
+
[working, approving, starting, idleNewer, active, overflow, beyondCap]
|
|
616
|
+
.some((item) => item.process.stopped),
|
|
617
|
+
false,
|
|
618
|
+
'no unevictable runtime may be killed to honour the cap'
|
|
619
|
+
)
|
|
620
|
+
assert.equal(liveRuntimeCount(mgr), MAX_LIVE_SESSION_RUNTIMES + 1)
|
|
621
|
+
})
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
test('a live runtime never loses its session file to another runtime', async () => {
|
|
625
|
+
await freshDataDir()
|
|
626
|
+
|
|
627
|
+
await withManager(async (mgr) => {
|
|
628
|
+
const workspace = await mgr.createWorkspace('Alpha', await project())
|
|
629
|
+
const ownedPath = join(await project(), 'owned.jsonl')
|
|
630
|
+
await writeFile(ownedPath, JSON.stringify({ type: 'session', id: 'owned' }) + '\n', 'utf-8')
|
|
631
|
+
const owner = await mgr.activateSession(workspace.id, ownedPath)
|
|
632
|
+
const ownerManager = mgr.getActivePiManager()
|
|
633
|
+
assert.ok(ownerManager, 'the activated session owns the active Pi manager')
|
|
634
|
+
const ownerProcess = fakePiProcess(ownerManager, 9300)
|
|
635
|
+
|
|
636
|
+
const newcomer = await mgr.createNewSessionRuntime(workspace.id)
|
|
637
|
+
const newcomerManager = mgr.getActivePiManager()
|
|
638
|
+
assert.ok(newcomerManager, 'the new session owns the active Pi manager')
|
|
639
|
+
const newcomerProcess = fakePiProcess(newcomerManager, 9301)
|
|
640
|
+
// Pi reports a session file that already has a live writer.
|
|
641
|
+
newcomerManager.sendCommand = async () => ({
|
|
642
|
+
type: 'response',
|
|
643
|
+
command: 'get_state',
|
|
644
|
+
success: true,
|
|
645
|
+
data: { sessionFile: ownedPath, sessionId: 'owned' },
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
const refreshed = await mgr.refreshSessionRuntime(newcomer.runtimeId)
|
|
649
|
+
|
|
650
|
+
assert.equal(
|
|
651
|
+
mgr.getSessionRuntimeForPath(ownedPath)?.runtimeId,
|
|
652
|
+
owner.runtimeId,
|
|
653
|
+
'the runtime that already holds the session keeps it'
|
|
654
|
+
)
|
|
655
|
+
assert.equal(refreshed?.sessionPath, null, 'the newcomer must not claim a session it does not own')
|
|
656
|
+
assert.equal(newcomerProcess.stopped, true, 'two Pi processes must never write one session JSONL')
|
|
657
|
+
assert.equal(refreshed?.activity, 'failed', 'the renderer is told the runtime could not attach')
|
|
658
|
+
assert.equal(ownerProcess.stopped, false, 'the owning runtime keeps running')
|
|
659
|
+
assert.equal(mgr.getSessionRuntime(owner.runtimeId)?.sessionPath, ownedPath)
|
|
660
|
+
assert.equal(existsSync(ownedPath), true)
|
|
661
|
+
})
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
test('load recovers from .bak when the live workspaces file is corrupted', async () => {
|
|
665
|
+
await freshDataDir()
|
|
666
|
+
const proj = await project()
|
|
667
|
+
const cfg = getGuiDataPath('workspaces.json')
|
|
668
|
+
|
|
669
|
+
await withManager(async (mgr) => {
|
|
670
|
+
await mgr.createWorkspace('Alpha', proj) // first save: no .bak yet
|
|
671
|
+
await mgr.createWorkspace('Beta', proj) // second save: backs up the Alpha-only state
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
await writeFile(cfg, '{ not valid json', 'utf-8') // simulate external corruption
|
|
675
|
+
|
|
676
|
+
await withManager(async (recovered) => {
|
|
677
|
+
const names = recovered.getWorkspaces().map((w) => w.name)
|
|
678
|
+
assert.ok(names.includes('Alpha'), 'should fall back to the .bak instead of losing everything')
|
|
679
|
+
})
|
|
680
|
+
})
|