From 52e924d103e3879a2a5a9447c1ddbf5245bb7d98 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 13 Sep 2026 20:15:13 -0400 Subject: [PATCH 1/2] feat: infrastructure retirement and lock restructure (#1098) Retire dead fork infrastructure and restructure opencode.lock.json: - Delete overlay-sync, overlay-promotion, extract_overlay, opencode_dev - Strip drift_gate to committed-overlay-only check - Restructure lock: drop repo/tag/ref/platforms, add base_commit/overlay_hash - Migrate all lock consumers to new schema - Remove AMICODE_OPENCODE_SRC and DEFAULT_OPENCODE_PATH from functional code - Update i18n placeholders and manifest hashes - Update test fixtures for the new world Part of fork-absorption campaign #1091. --- packages/app-bundle/manifest.json | 1874 ++++++++--------- .../settings-v2/developer-tools-controller.ts | 6 +- .../overlay/packages/app/src/i18n/ar.ts | 2 +- .../overlay/packages/app/src/i18n/br.ts | 2 +- .../overlay/packages/app/src/i18n/bs.ts | 2 +- .../overlay/packages/app/src/i18n/da.ts | 2 +- .../overlay/packages/app/src/i18n/de.ts | 2 +- .../overlay/packages/app/src/i18n/en.ts | 2 +- .../overlay/packages/app/src/i18n/es.ts | 2 +- .../overlay/packages/app/src/i18n/fr.ts | 2 +- .../overlay/packages/app/src/i18n/ja.ts | 2 +- .../overlay/packages/app/src/i18n/ko.ts | 2 +- .../overlay/packages/app/src/i18n/no.ts | 2 +- .../overlay/packages/app/src/i18n/pl.ts | 2 +- .../overlay/packages/app/src/i18n/ru.ts | 2 +- .../overlay/packages/app/src/i18n/th.ts | 2 +- .../overlay/packages/app/src/i18n/tr.ts | 2 +- .../overlay/packages/app/src/i18n/uk.ts | 2 +- .../overlay/packages/app/src/i18n/zh.ts | 2 +- .../overlay/packages/app/src/i18n/zht.ts | 2 +- packages/app-bundle/package.json | 4 +- packages/app-bundle/scripts/drift_gate.mjs | 56 +- .../app-bundle/scripts/extract_overlay.mjs | 199 -- .../app-bundle/scripts/overlay-promotion.mjs | 315 --- packages/app-bundle/scripts/overlay-sync.mjs | 378 ---- packages/extension/opencode.lock.json | 21 +- packages/extension/package.json | 4 +- packages/extension/scripts/build_binary.mjs | 2 +- packages/extension/scripts/fetch_opencode.mjs | 314 +-- packages/extension/scripts/opencode_dev.mjs | 225 -- .../scripts/record_amicode_fixtures.mjs | 2 +- packages/extension/src/opencode_binary.ts | 4 +- .../src/rebuild/main_source_resolver.ts | 157 +- packages/extension/src/rebuild_errors.ts | 27 +- .../test/amicode_service_contract.test.ts | 16 +- .../test/download_robustness.test.ts | 114 +- .../extension/test/fetch_opencode.test.ts | 247 +-- .../test/main_source_resolver.test.ts | 118 +- packages/extension/test/opencode_dev.test.ts | 143 +- .../extension/test/overlay_promotion.test.ts | 135 -- packages/extension/test/overlay_sync.test.ts | 352 ---- .../test/rebuild_coordinator.test.ts | 12 +- .../extension/test/rebuild_errors.test.ts | 4 +- 43 files changed, 1155 insertions(+), 3610 deletions(-) delete mode 100644 packages/app-bundle/scripts/extract_overlay.mjs delete mode 100644 packages/app-bundle/scripts/overlay-promotion.mjs delete mode 100644 packages/app-bundle/scripts/overlay-sync.mjs delete mode 100755 packages/extension/scripts/opencode_dev.mjs delete mode 100644 packages/extension/test/overlay_promotion.test.ts delete mode 100644 packages/extension/test/overlay_sync.test.ts diff --git a/packages/app-bundle/manifest.json b/packages/app-bundle/manifest.json index a2a673ab5..79bcc3ab3 100644 --- a/packages/app-bundle/manifest.json +++ b/packages/app-bundle/manifest.json @@ -1,940 +1,940 @@ { - "schema": 5, - "scope": "complete fork-vs-base delta of packages/{app,ui,session-ui,schema,core,sdk,opencode}", - "fork_ref": "local/amicode", - "fork_tag": "v1.18.29-amicode.30-11-g0667bccd6d", - "fork_sha": "517921eecaa56eb9861a7b96a5bd2ee36ee42e86", - "upstream_base": "7fe993879f98aa17cecc70f70d3f40d6f0f11689", - "upstream_base_sha": "7fe993879f98aa17cecc70f70d3f40d6f0f11689", - "promoted_at": "2026-09-13T22:15:25.839Z", - "files": { - "packages/app/CONTEXT.md": "7dc4bf176a32ee578a54593a58a6b97907ffc5a9baf7ae7c16a8fa920d8e6e86", - "packages/app/docs/adr/0001-chat-first-landing.md": "d19c42a8aa56f585f92a3e0ffd072c55804ca029c6d19fb7d772c69d7e5de3be", - "packages/app/docs/adr/0002-brain-as-chat-background.md": "bda9bc065e16684e1daffdc3f7d8ac5b3c81a82de5c27fa1ba7d6268659c32c1", - "packages/app/docs/adr/0003-context-tree-top-panel.md": "693f19dd5c155b881dd35b85412ad62fef0683a6934d7cf1c59c9a679d1a8eeb", - "packages/app/docs/adr/0004-context-tree-to-side-panel.md": "271f31a677547be2e11c0c19364ae97b04a2ea353a9ab22c87bde1afab64babc", - "packages/app/docs/adr/0005-reconfigurable-titlebar-controls.md": "82c386143ca45f0fd2af3b3e1ffedb47db21e57ac9b7eede661f843eb5655a1b", - "packages/app/docs/design/agentic-surfaces.md": "94a117b2790ff0157ee01684fd49dcb32d241b3572e9df77f81f721967dc52bf", - "packages/app/e2e/regression/chrome-surfaces.spec.ts": "c7ff1b82bf84e577fee0e765b0c357c040d4d7cdefdd537702d7dbd186bfedf6", - "packages/app/e2e/regression/home-open-chat-empty-projects.spec.ts": "b0debddea5051defd859b9c8db2439801592d984fa89ddaf880494722ef2cb21", - "packages/app/e2e/regression/new-session-panel-corner.spec.ts": "df11b094012f8206117575c63fd9ac0475d14b54ea4f9d719c6b21aac04d1c4b", - "packages/app/e2e/regression/openai-browser-oauth.spec.ts": "7df4521d1d82a186e383afd9351eef64f33f2adf8a3dce86dd5915b5f4828b68", - "packages/app/e2e/regression/pane-boot-watch.spec.ts": "3aa869f8b1d9881797e14dceb9854c4408f768f490d4db8722e29e511bca1833", - "packages/app/e2e/regression/preview-baseline-contract.spec.ts": "78c23b9e52496a779ee10aabf5bfad6900afb9b905d82ddedfa954031ce633f5", - "packages/app/e2e/regression/project-picker-recent-search.spec.ts": "64f4249f29cfce29d5e755a544c5aa2f27599d9fd874d363628f696f5f0e02b9", - "packages/app/e2e/regression/review-line-comment.spec.ts": "953e9c67ed4cee91968369088237cf2288558eaa55e55b61f385571bccad7003", - "packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts": "00bfd4f6199c1b350d14a9eda5e3a4c546b020df32e3604609326281869d6d4f", - "packages/app/e2e/regression/session-timeline-tool-projection.spec.ts": "c0bb866b113d38ddec084e04027030cf5b7c81f1fe4e6ee88fcd7b1b161296c3", - "packages/app/e2e/regression/tab-dblclick-close.spec.ts": "7bf9490c2f39281c7751c39747bb720ec1b5571d7b7ddc803686071aa8ad55aa", - "packages/app/e2e/regression/tab-navigate-mousedown.spec.ts": "8521d43183f0df624449edbba8ee4dc646f0ecb84a9c5a04d275613f9da875ae", - "packages/app/e2e/regression/workbench-drops.spec.ts": "0188f4f1ff07a40945a4900bfa85e21a4f578be9f18257a803200a18ce41ac05", - "packages/app/e2e/regression/workbench-panes.spec.ts": "e0dfb84bd1b8be00a89cf48387aeaab5ec75845e8efbc8e4fa8252204fb27e8f", - "packages/app/e2e/smoke/session-timeline.spec.ts": "4006274a5001e36502e16b11ef7b9caee5dfdad2280766380470c72118b7fd90", - "packages/app/e2e/utils/pdf-fixture.ts": "86c6c0d11a3c78180133d9e0cd7b87ba4c639f34ccf50a417429e23f80042b87", - "packages/app/e2e/utils/text-selection.ts": "bb4ada9ee7faa07eb792c5550d244dfef31c089a944d0411a5749eb9a74ba859", - "packages/app/e2e/utils/waits.ts": "53959eeae1e6562a2e6c578b261140c74fe9fc30e1e4c46295d3252b6d274a74", - "packages/app/index.html": "fa38026be3b7e7ec38958a558d7b4d059140b2aff998c3ac862601543702584d", - "packages/app/package.json": "3c9bf3d487052d4834b7fd3ce93fcf6b7fc358de92b8be4b0e84fc424a971f74", - "packages/app/playwright.config.ts": "b7dae0b39248b4ddf7cba829af96ac7fe3cc919add9711ecb5292d9bd52e1805", - "packages/app/public/amico.svg": "a14b9d543d895bcdf0758f7b9ef5908ee0acaac794446494af059b159247db8f", - "packages/app/public/assets/Aero-Regular.ttf": "0ebf14f80d05c3a82c766124ab31196c310014744333d397425ac82a1e3537c4", - "packages/app/public/assets/DMSans-Variable.woff2": "aa530716b0d351866af7dbfa3eee4120fb36f2d071baff8c234185141865c7ff", - "packages/app/public/assets/JuliaMono-Regular.woff2": "43f5dfca02a03035f89799da5af150f28d5c4aff729753076094c687fc61b063", - "packages/app/public/assets/RacingSansOne-Regular.woff2": "2ff92c8abe7a35962922c54da215d68690f8502463698b1b595bed597b63e3ff", - "packages/app/public/oc-theme-preload.js": "27227e802b3494e7c545da903e679efdb30ccc754cd4eb5cdf08005a40d560b6", - "packages/app/src/amicode/inspector/device-inspector.tsx": "5ab63709e88176bb4dad1072ffe28fd59ad67d414c9d844ee6c55353df50df79", - "packages/app/src/amicode/inspector/inspector-bridge.ts": "460dbf4509b4e56a8eacd6cac7adcb3a63c6cd3e417d851df5f3e3b259095d3e", - "packages/app/src/amicode/inspector/inspector-context.tsx": "ac81b9e0e2a4035f85b6af68b7f0cefcb9f256a175b244ba13136f3a307c0c77", - "packages/app/src/amicode/inspector/run-inspector.tsx": "63a6351fad12a8377550eb87f7602a712bae586fe482ff46cd847c8544fc6e8a", - "packages/app/src/app-desktop-commands.test.ts": "1d2057f238dc14e4407ff5c4e53afe091784790bc0fd0dbfde0eacd91e2bd968", - "packages/app/src/app.tsx": "c32eae50e48492404aa2057f37fc0ce229e24640d26ce9a81c3b64066483f62f", - "packages/app/src/components/amicode-default-model-value.ts": "416bb4a7cf051c678bdfc5246ddc5796a9a6efe48d1e5c2e933756800cfdae8d", - "packages/app/src/components/amicode-default-model.test.ts": "941750d074706bd5f4e433c9737b19ebc0ac0f9ba9cd1faaa599a24b22126e05", - "packages/app/src/components/amicode-default-model.tsx": "16a2de1feb12e07416fe5fbb25879391f912ee0909b553c868c1b531f2ed1f2d", - "packages/app/src/components/amicode-defaults-capsule.tsx": "94dc081bc47abb7e50566fcd8e9e53124f9d7632d61f93eff4f1627e0c2efb2d", - "packages/app/src/components/amicode-file-ref-bridge.tsx": "11c17d7fdb29d16530e188b13ee8af728f37d9adfbb518084106ce50cc0c527a", - "packages/app/src/components/connection-banner.tsx": "c793966e1f9d6f307af697032b235c2ff65afaa04f6cc232e40ce45e5745ded4", - "packages/app/src/components/dialog-command-palette-v2.css": "85984957adaf15efcc0828310f3a0b438cedaaba776a9fec2eddb3ad83487fa2", - "packages/app/src/components/dialog-command-palette-v2.tsx": "e12da3e5e9e503089dd9139b20e04f6b566cf74fa445f23a2e193f5883f7c5f3", - "packages/app/src/components/dialog-connect-provider-harmoniqs.test.ts": "7c16914afe3e77ad09691bbfa8223981eda0c2faf3616ed6db2e4e5fa9ce9fdd", - "packages/app/src/components/dialog-connect-provider-harmoniqs.ts": "2f070abc5d0274ed1403f963ae0cb0af6e0f635f3732414d757d1b7ba06ea313", - "packages/app/src/components/dialog-connect-provider.tsx": "6f23cb5edda411c12606659109c3943f0cd218b9bcba29310f4ea3cda4eea98c", - "packages/app/src/components/dialog-edit-project-v2.tsx": "f34aaed28604facd9d8a46a4934e2b331421d5f60902a2b160ddcec11af03bd9", - "packages/app/src/components/dialog-edit-project.tsx": "5371da3de3a643d4347629af55c0adc2476bffe7b2f061535a92fd67e756e562", - "packages/app/src/components/dialog-new-project.tsx": "102fc33e8eeaf3c76ddd1b953b7b97995d30c02a3579f8b7036e47448a1582a8", - "packages/app/src/components/dialog-release-notes.tsx": "0ea5b049786787643a7f6b54d4ccf84c4f8ffa4e8272426c0d32f60d445b6890", - "packages/app/src/components/dialog-select-directory-v2.css": "2e2f18abdca77f9fe85da157c40f288f3b1641ca92845208749e16455fd58637", - "packages/app/src/components/dialog-select-file.tsx": "e6278ee35dd27d203e00ad73f70c709c44a6c06f81ffbd931edfaa0c986b9e03", - "packages/app/src/components/external-link.tsx": "7130044026ad3ec417de4ba7389cc6059de46f21b370047046269c772aa7a4bb", - "packages/app/src/components/help-button.tsx": "780d533f776a784660cfed072a131198bc6fcc8e8fe332e8e1a220d516c9684e", - "packages/app/src/components/pane-bridge.tsx": "756b3306b51c963fac6778716f6c6c4626f0f3bf75c93b7cb4cab58ea0bf3d4e", - "packages/app/src/components/profile-popover.tsx": "eff742e90544455f13234a9351bb1b82189663cba2cd3172bdcea1a8a37284e8", - "packages/app/src/components/prompt-input-clipboard-structure.test.ts": "946b718c2164da394602f26e4d9919d752da0d0b9bee714f345ba16c274542da", - "packages/app/src/components/prompt-input-v2.tsx": "5f15ed441bc267cbdf9ef211bced384d7d9bb3c0b2fffb6a1020b34584a4f5ce", - "packages/app/src/components/prompt-input.tsx": "1bc71d585a5ada2caf6d190d702dcabbfb56642e740a08ad6aedf078809b60e5", - "packages/app/src/components/prompt-input/attachments.ts": "c3c28df0d2f18378d39e17147a4c64e8ea01d63b97c39e1874ed9445ca671bb1", - "packages/app/src/components/prompt-input/clipboard-bridge.test.ts": "15f76dca1a25d024128718e4099220b79ca029263410aab55502cf9caf9b2914", - "packages/app/src/components/prompt-input/clipboard-bridge.ts": "4b5a1edf59d4c85268d6ff72aa9f9d66f82d4fdb887121fb978c09caf4c5be65", - "packages/app/src/components/prompt-input/context-items.tsx": "027b02e394ccd14849052bf3fcacdae1e090c71d164fa8955addfe3f7abf1758", - "packages/app/src/components/prompt-input/image-attachments.tsx": "30cdea4285884b4c257670b57ade4266f5861e8a303d3355a591f302ed4bf965", - "packages/app/src/components/prompt-input/placeholder.test.ts": "d3cee5e2c758faf5fda626e270adad81129622bbc2bf2c335c2bffe1544165c3", - "packages/app/src/components/prompt-input/placeholder.ts": "6b2af23a0588e7970cd0dd059fc60c3671c907a76ba3db660483a932f1dce79d", - "packages/app/src/components/prompt-input/slash-popover.tsx": "a1800173edebcd419802796470f7270acaf0ef689a72f1b81a1cedfd8968337d", - "packages/app/src/components/prompt-input/submit.ts": "c00dc83e3e45d589963b38ea7b9ad8c437fb229a9b4dfa67abcf74e537e09724", - "packages/app/src/components/prompt-project-selector.tsx": "0157c954b938bce2b5aca9a82f4a72338e361f4c9027e55a7fd5a14a1654d294", - "packages/app/src/components/report-bug-button.css": "909809b6241d53c386aa4c8ea34539ba162a8998fff755834c783025bc53a5fd", - "packages/app/src/components/report-bug-button.stories.tsx": "82aed22bd3fcca448841205dee759ca0f0de92562a99d07c696eee5bd29e807b", - "packages/app/src/components/report-bug-button.tsx": "a1beb8c94b4faaa4c7db3ab68de349f8a8a03cb3a058ce447f552aed35848d43", - "packages/app/src/components/session-context-usage.tsx": "cd25a9af91c73d0cb53000261e066dc16385e1a3ea13e92392fd3a5ca7b33032", - "packages/app/src/components/session/context-warning-banner.tsx": "f5fab4d7a9536238b70d64488fc30d44f6a4948fdcffd910a9666f4b6c296019", - "packages/app/src/components/session/index.ts": "21473290d4a1a3d0670fd878372ddf21ff22d4a0b30d1aef6c81ea906c1488b4", - "packages/app/src/components/session/panel-menu.tsx": "42f323046b7375ae158023a51506038eb15f2e1545c407f45acd47446a8ef3e0", - "packages/app/src/components/session/pdf-canvas-view.tsx": "89a2c67262d16f262a185bf9c20a44038c6e97abb72c8206d12e720efa4ec6bb", - "packages/app/src/components/session/preview-file-view.tsx": "7dad448cf6a166ede82b8908efd028eeb649139b59c7b996780c3f61c6a860ee", - "packages/app/src/components/session/session-chats-dropdown.test.ts": "2003d2a15781337ea6bff2c68e730cc5b6df38697f15d927ab26913936444db7", - "packages/app/src/components/session/session-context-tab.tsx": "227243b178b517f067d9ae0ae0eec3c559beeb6681828158b0600a17e98e7f81", - "packages/app/src/components/session/session-header.tsx": "a46591ed1097d0fdcff61fb0c5529396955e8857cbef748747c51e472d5564c5", - "packages/app/src/components/session/session-new-view.tsx": "9510a4f550a3f0d4791e98e8025666f09d70a60fb66f193e48ee61feddae5a57", - "packages/app/src/components/session/session-preview-tab.tsx": "8c17771e40a0385b394ea0ea1a6034f475b6f9ca1a348604b6ef507595017d9c", - "packages/app/src/components/session/session-preview-tabs.test.ts": "773fc0116c5f61302eaa4a09fd5f91e6b26dee978c89e29c21714243ae3a5653", - "packages/app/src/components/session/session-preview-tabs.ts": "672d147a6f1f46a7ac2eff7aff9da6cc069c476ff918e5ff4aed3a997310e6fe", - "packages/app/src/components/session/session-preview-tree.test.ts": "6d1677caa56ec89fa5fcc8fc2f26fdcc1bc0a23217ce9c6d92888b272523c00a", - "packages/app/src/components/session/session-preview-tree.ts": "13930fcd8a8ae9df4c37ba9ea306e162fd08f0e429249ddea21d937675d3ad7e", - "packages/app/src/components/session/session-sortable-tab.tsx": "a015277347fe679ac1afa1372202de49fc98a0930ac10682c8897f70a0300909", - "packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx": "08db0e378c3e07d243121f40c77e153bafe897e5e2ececd48a3e00786793032b", - "packages/app/src/components/session/use-context-warning.ts": "af7a6d0159a5541aa02ad4d08fd694af1cc4853fc1c0a70763bc264a634d1c53", - "packages/app/src/components/session/vscode-explorer-file-icon.test.tsx": "f1d38aaf0ca1cbffe696d054bbb422aa94cb56387393e014bec3ba6e79b5037f", - "packages/app/src/components/session/vscode-explorer-file-icon.tsx": "b5ba0cafe61594dd2afe45ef6e070e512861162933c85e9545db2ec697d50f17", - "packages/app/src/components/settings-dialog.tsx": "da3bc01dad4ece4214c14083ae4e7dea87ef64ef9829b315b867fdafccdb6916", - "packages/app/src/components/settings-providers.tsx": "c86c9bf4a6f6e198dc7b0995a69d5b76e851144987bbe601802b1b0120ee4ac4", - "packages/app/src/components/settings-v2/data-storage-controller.ts": "fa5d143cc101f3a3b9d5ad445edddc981e0d02783021d52dbfed6c8d8bf62498", - "packages/app/src/components/settings-v2/data-storage.tsx": "a56b423b32c952c4379688d88d13a9f43b163a4169b9393f8c35b18a763a1180", - "packages/app/src/components/settings-v2/developer-tools-controller.ts": "892426d39057e47192fd4d54c36253d6024253f0901f243ba7b861779376616a", - "packages/app/src/components/settings-v2/developer-tools-rebuild-flags.test.ts": "4d11815fe5acfa930bc418d0be82602f03821997300d0deef0aa2da2a743b3b0", - "packages/app/src/components/settings-v2/developer-tools-rebuild-flags.ts": "561a75fa456b832d4af6f782c7ecf5269ce768fc2adc59c15a79197a2dde84c0", - "packages/app/src/components/settings-v2/developer-tools-request-state.test.ts": "29711b3bc17fddbb8d046e104bc78e775a9ec7c5aa0ee2e181fbcd8b2b5e2135", - "packages/app/src/components/settings-v2/developer-tools-request-state.ts": "e9678ed32e7c2562b18143f39a51c0a94dbf0a0884d056653c6c77e4cd07a9bd", - "packages/app/src/components/settings-v2/developer-tools.tsx": "ee2d586cfa1202f5fc253b502dd8752256166192541e7addab6bb5da18d1d0f5", - "packages/app/src/components/settings-v2/dialog-settings-v2.tsx": "a1e1fb7eea7bbad7708b97a721b54a4897c8cb6f582b71d6bb7c8ca7f44930db", - "packages/app/src/components/settings-v2/general.tsx": "2abf6c9c7b4b9bf020ed224dbc7fff4574db47711956fc08e1b8e84e781d395a", - "packages/app/src/components/settings-v2/permission-scope-relocation.test.ts": "39539c4fc4b7433f08b913100f48a7fa75d6ab47615ba697aa9ae8eee09d316b", - "packages/app/src/components/settings-v2/permissions.tsx": "5746c8ef02da833ff72fee1375dab2a7ee241bb111e8ef15b21ae70c49349543", - "packages/app/src/components/settings-v2/providers.tsx": "e15f23a40058abb4299ad7444df2845e3c24b5da3ca58a731e0cbafe58de2a76", - "packages/app/src/components/settings-v2/settings-v2.css": "38818ab5349cf637023379d2b1ee62081d456676020bdb445576865327858162", - "packages/app/src/components/settings-v2/skills-controller.ts": "2c7344d144da0eec1c25083ead45f5afb2a8c6fd759541ad719cae9a09fcd19b", - "packages/app/src/components/settings-v2/skills.tsx": "42deb0c11fcba158abad857b9644ffb551aed5ba9e00dbfd1584a7ffaaba5aa0", - "packages/app/src/components/solver-switch-banner.tsx": "ec7edeec6dc05a4a06b39241b4f3a8e7534da97722dd8ec6f26ff782025802e9", - "packages/app/src/components/split-frame.tsx": "44c53737f72027b461097c03df48a4f411d04a82d02b1fce4901813c73dfcc72", - "packages/app/src/components/status-popover-body.tsx": "a78d557256283fd05657d999b2a6babc0bcb5ae3dcfa2cb07f770ebb602a94a1", - "packages/app/src/components/status-popover-indicator.test.ts": "9afc7b49d9021a94d74f3f777178230ae13bd26e5749da0cee4d3378eacacacd", - "packages/app/src/components/status-popover-indicator.ts": "887b3e659ff49fd0d2a8715fad6562dc7e9402b80d06442058502306bdb108f5", - "packages/app/src/components/status-popover-model.test.ts": "10634035bab0f31de24564e0d6c8413a0f7434fb2c08ac3ef722981a69dd08e7", - "packages/app/src/components/status-popover-model.ts": "ec5a5a3caf9344fe617c7bc668af81d96ad4290378c34186cd4cd959821f1c85", - "packages/app/src/components/status-popover.tsx": "663b3ab44218780b3415120c42d89a2a410ba0054231e8fdd0887a97a1b75b23", - "packages/app/src/components/terminal.tsx": "2ce242034ae129c1f475c7a24fdec3facdd9bb1f49ba8c6b503643b07ae241e5", - "packages/app/src/components/titlebar-channel.test.ts": "184238871c46f586dcc21081f710e37a77914c983fccf250665c7317212e41d8", - "packages/app/src/components/titlebar-channel.ts": "385ace91d3c69c92f5b442bf15d2040e35df855f1d4ece47312c1ff8e1b01780", - "packages/app/src/components/titlebar-layout.test.ts": "52912f37fab4e7d0d5b7403371060651597f4c4904fefb802ff9e3333facdeed", - "packages/app/src/components/titlebar-layout.ts": "a375c238ab632421a6505dce3a41fd3894865729e921e68eb32249478c18a286", - "packages/app/src/components/titlebar-tab-nav.css": "90930c2f9476fb0eace8692424a029b3510781c88d1ee61f7f2edba559526832", - "packages/app/src/components/titlebar-tab-nav.tsx": "2304e936af56c24f27f1549f4f8751a600ed274123d7a3973ecfa6a5bb28102c", - "packages/app/src/components/titlebar-tab-popover.css": "d731db2d7d49838004089a3d82ff68c22214b0ca636bf3b8e02498c14dadbf8d", - "packages/app/src/components/titlebar-tab-strip.tsx": "932a2d01e6673d283a48d704b580f7a7b88ba000061d11f6df5efe994dbd4ee3", - "packages/app/src/components/titlebar.css": "50c262603ba1140db9e4fefe8f03e9c6ae3bf64dc7a917e55586bfd67a5e3011", - "packages/app/src/components/titlebar.tsx": "c53f438701e97cbe3fbf2eaa67fb584a0b8b3a91f2d4f8016542156e17cd598c", - "packages/app/src/components/ui/drawer.tsx": "76574ca4c6997209f37a766a61000d707332a9a857f6ea8100a3cee1be58d65c", - "packages/app/src/components/vault-browser-model.test.ts": "7ca11eae3574033d58081bc4126b1ec772a5b496573c70159f05497a1365f4cd", - "packages/app/src/components/vault-browser-model.ts": "d9ef6ff588a96ae79b13c3ae0c2a442a42b59021dd501b3a17bd810dda6f7b20", - "packages/app/src/components/vault-browser.tsx": "509efa874d69bcd07ef2495a025bc8de2b2fa582736003ff709b4ca76096274b", - "packages/app/src/components/vault-panel.tsx": "1d9f06f42b94ffb94a28bfd6d2693a36c75ceb969bcd434081b4cd2fbf99665c", - "packages/app/src/components/windows-app-menu.tsx": "460669a129e9be61ab2d5f51fe6ecad73579a395295d5f724f235b988cdc667e", - "packages/app/src/components/workbench-panel.tsx": "d16f477044098842a214a2e16f9be719e7688a04bcb575889ca544988f23c690", - "packages/app/src/context/command.tsx": "388d6cb12b6dc43ecb0827e3fb918370cb9d16d96161a5990dec10fff05af172", - "packages/app/src/context/directory-sync.ts": "a3921044097f3fbcfb20eaec500f24344f12a43e137417c86f15d39dcc6e4b2b", - "packages/app/src/context/global-sync/bootstrap.test.ts": "149c0241b378b6ce837aef45e1ba257dbfed88de37c70affa13f513e9c72338d", - "packages/app/src/context/global-sync/child-store.ts": "b13a513c93b8fec7b656593d842e9cfa30f346a0911dc0f516783ccc5fa4c07d", - "packages/app/src/context/global-sync/event-reducer.test.ts": "600cd7654854b910f25c61b20d8ae69f043f52ed544e6bf9be5ee9e5bbd6c96e", - "packages/app/src/context/global-sync/event-reducer.ts": "667fbae1259f6deed77573edd2b742beee4f825b4306b6d861670443e381a55f", - "packages/app/src/context/global-sync/session-cache.test.ts": "c66d790c6336794b2b1d707e2739fe0992ccad7ed3b96187b124b5c783ef332a", - "packages/app/src/context/global-sync/session-cache.ts": "1849408caba0f114809f37153e7d531bf2776572433880a96c5ebd31d7b30aa3", - "packages/app/src/context/global-sync/types.ts": "901c9bd1fda63dab676d33dc1a8582a29f8ee00aa20458e843aed5f93414fa84", - "packages/app/src/context/language.tsx": "cb545e04c128bf981b2b72ac407f9220cf9e80337fe8c87482ffe85407e0cf9a", - "packages/app/src/context/layout-side-panel-tabs.test.ts": "47425bbed0ada18d3fcb67a76b63de3b9e1f827cd63a61ffe4eb45430fc5814e", - "packages/app/src/context/layout-side-panel-tabs.ts": "e8426fadbdf9e7c49bf457e00ec92793475b44bcc11548e8b5ef9a9fa461be76", - "packages/app/src/context/layout-tabs.test.ts": "4d9fdbe963306f164b2f48eac3b6a28c5a703c1758bf14b2cc4796720d8fa72c", - "packages/app/src/context/layout-tabs.ts": "741506ce165f68cdb0b8f2931a2dad3e26c05880f9286c3daf04ec979bac21c5", - "packages/app/src/context/layout.tsx": "7767c8b5f64efd63390cbe99128686bec2f1da7e8f2b21530df4c3fd67d171bb", - "packages/app/src/context/local-agent.test.ts": "a5a9d60bb4401d409218cc247c1cc06ede8b7878ddf01dc6080328f54eb9cade", - "packages/app/src/context/local-agent.ts": "0aab67e695dc3bb45a733ac0df80a0a5e14cfe29b2375b6dc3cd07fbccea33e2", - "packages/app/src/context/local.tsx": "3ab8b9fc2db082df4ba485373679f00a95d0ffe3c691a0afee1dc53db7eabd9e", - "packages/app/src/context/models.tsx": "8904525767b36ed5ba93e85a0fddb9bf737a8d066dfff084380ce1a67182f535", - "packages/app/src/context/platform.tsx": "edd9b1773feb5c084b922a57b6914f6a473eed558b44f9de0eeb1c4d4e2b49da", - "packages/app/src/context/server-sdk.test.ts": "5cd22962c8ea1e4374915508a765281ceb9f808ad8bbf241c06b00b48621c816", - "packages/app/src/context/server-sdk.tsx": "b3450d9bdafde6ed1a95d7dc970fc9f33bef81531b05245c36b789878d09d186", - "packages/app/src/context/server-session.ts": "a9e1f089ad328a705848d11ba25e890c5e374bb3a33066ffe67b6f09bd48ed16", - "packages/app/src/context/server-sync.tsx": "43154ffe6227203d778378d190af3c46d7f49098619721fea5e6263e8794dc84", - "packages/app/src/context/server.tsx": "08e978e4b4b3094221a2a0b92e069f39cbedb6d6cf95935881e21cde52265ee2", - "packages/app/src/context/settings.tsx": "53025fbfbd7eb641cdb0e7c49e21ced3617050f4f98ee45c745affdd8ab17b48", - "packages/app/src/context/split.tsx": "891aeb290b369b327a63ce548dcaab1daca08e41fab430648787be7f84e53ec0", - "packages/app/src/context/tabs.tsx": "eb494b5785defdd3a4901874be355ba8ddd7bab4c009359b558c413f9ee63ffa", - "packages/app/src/context/vault-panel.ts": "f91cb5fb49a9f0d46bd2a1b131f9a218b30147e2ad3617d2a2dc4f1e14599a53", - "packages/app/src/context/workbench.tsx": "69a44da2b69989bd2c67ebffdb49941841f3f4718d6a70d659c828b57928d9eb", - "packages/app/src/context/zoom-keybind.test.ts": "a1385c93639687a7dac7d21f8f02841d82a55e42465ce3836b97b16c82b52469", - "packages/app/src/design-polish.css": "6b860316d2d57a4a9a89c1ff2772de45eca0d0cef2bd3e2ea8572d817e1d1910", - "packages/app/src/desktop-menu.ts": "55481604f4fd5dcb74b0678347076c42fda7f928590d90bc2c3d1633bea8bc36", - "packages/app/src/entry.tsx": "f35e1017f4c9d478d254b2a38043e5750064b6bef25169c3e07ae9f72ff1049c", - "packages/app/src/i18n/ar.ts": "82497504fda12f005b8225ee4a0eed0a1741256f6c4ebbb5f27af9832c267ab1", - "packages/app/src/i18n/br.ts": "396f9edd949fc8e8de56d3b0d903915245f2ff4b373e052d69e3f7c328a189be", - "packages/app/src/i18n/bs.ts": "9b6c8cbac3878719350a4e0c336e26cc32ca8792ffa91631b5d3f685c1c3b965", - "packages/app/src/i18n/da.ts": "4fcc2137327497227abd9f3725e264f876157ad8399d49faa15964cca27d1651", - "packages/app/src/i18n/de.ts": "f50fdc572312ec36bdd1fc12ec8d7d4c644ef5d233ba798c850a455c8d6fc49a", - "packages/app/src/i18n/en.ts": "c3fa62962833f33fb4734b90dd8a24e01b6cbb63becc2906a0e05484a0e6691d", - "packages/app/src/i18n/es.ts": "88833e6030e2f76e1e8b147924f210c639d664c043fcd675998d42ef32da09cb", - "packages/app/src/i18n/fr.ts": "f07d36e5d5692fa820a4ee6ec8f8d78eb9b178466adc84cc2a2c54e6316c0e0a", - "packages/app/src/i18n/ja.ts": "aa5f49228283d01c252f92f2271d526605644b465e58ca63e7f29611387f22f0", - "packages/app/src/i18n/ko.ts": "124bfcf65566d9c6e1e8c6c115476d136060c1b893dfd48ca870b33129b10c46", - "packages/app/src/i18n/no.ts": "7837b5e039306ccf77fc218c0acef6c2e2d74d7d14cecba7e968c6971a0980ae", - "packages/app/src/i18n/pl.ts": "204641a31670184fb635ae9c494cad426cf408755d09a226a3f01b85245b99ae", - "packages/app/src/i18n/rebuild-label-rename.test.ts": "c9ad20e491a5c9c6b8f6d56858271988e827398afe8b7cbe333e5f970fe76142", - "packages/app/src/i18n/ru.ts": "f1298ba64c48ccb20a7fa6502478c7f84543fcdfde3046357c79dda00bcd2885", - "packages/app/src/i18n/th.ts": "01fb3f97dbce851e86d130ec83acbdd2d3dc96607a29ef7dac6176ef46b51032", - "packages/app/src/i18n/tr.ts": "91fc95eb5f4488ce91ea24a0bbdcd17286af08a4ecef0d93d5251edd015ff3b0", - "packages/app/src/i18n/uk.ts": "1799b28b4e4829012d5790252d231e99f16f941814214e39b2a40f57f5d262f2", - "packages/app/src/i18n/zh.ts": "6a5787af0507b7e350a273a5193fae4bc2963c522c72bd7c87bc133e442b5c17", - "packages/app/src/i18n/zht.ts": "1b9942df0e71fe98e0c45da8c7e0904d7b8f51ffc4058866d13067f27d794daa", - "packages/app/src/index.css": "2c11df3dcebb381358e06626094b5dda3c35688ad7940d643b2cbb6cff1ea9e9", - "packages/app/src/pages/error.tsx": "db9ba0847cfb205100ad6133cce30c6ea2ce983802af44947e6d2b746c2a6ec5", - "packages/app/src/pages/home-projects.test.ts": "a90155c37210a0e5b7a095bbfc3ba2d40681f02927d9726148a706bed5ba7891", - "packages/app/src/pages/home-projects.ts": "d55124578dc839b98e2084b488d818e30e4a1abf1ae264499b83e403c2aabca7", - "packages/app/src/pages/home-session-archive.test.ts": "e8f1126287a3e9daa455efcc378e5d72aebdd092158bf8526f7779669b72e850", - "packages/app/src/pages/home-session-archive.ts": "1b56c173f37f4a4dfd54088ef5fdb0dbcd3d9b62aeb08de4bfa0ed34f07d7ad5", - "packages/app/src/pages/home.tsx": "06fb5c7718aacfd29b35e730e05d45076b39d6cd5d936d1270fb1bd9424c32fa", - "packages/app/src/pages/home/home-projects-view.tsx": "074f1cdd7926db9574164824666cd63f1f5bd0f8e8dfb65453f6fe8f2dca0ec8", - "packages/app/src/pages/home/home-sessions-view.tsx": "5b73b18e4349a628a15e09a3810ecf2319bde222e18fe8de5d08373ac91fb37c", - "packages/app/src/pages/layout-new.tsx": "3ef477634cb6d7de0c32d3572c5ff699e07efff47e6e75458583456eb1ff8b27", - "packages/app/src/pages/layout.tsx": "eaf8bed869b5ec53582db732119fb903b223d749ebda354b1e388de3be02dc52", - "packages/app/src/pages/layout/helpers.test.ts": "3a77cfe018ce2867cccded2c726f556e53a9895a77baa944a4878714b9b2b59e", - "packages/app/src/pages/layout/helpers.ts": "ba476894857aefd2172e3d31fa1aaf52ca030183d3fbf180050bd3b10fe4b524", - "packages/app/src/pages/layout/notification-toasts.test.ts": "6a95bd3dccb03be894b5d2adb4bc1f7531a9ec704e4d0eae1eba4ec89bbc9846", - "packages/app/src/pages/layout/notification-toasts.ts": "11256e25f2bcc20d3520e81aa50b53db2a7f8dea8047b17e99deb1f9f061e43d", - "packages/app/src/pages/layout/project-avatar-state.ts": "7aadb235d27dc45799411c724f0fd1282af82d091cbcefb0344deb7c5d0659d4", - "packages/app/src/pages/layout/session-tab-avatar.tsx": "89e83e239d513f91b31f16473be531eaf82768cefe637ea5f10d752cea4ef887", - "packages/app/src/pages/layout/session-tab-status.test.ts": "d6e62365948450c0acda628bc5d03233e5e6ead69649c2d2fb7e20c906007e74", - "packages/app/src/pages/layout/session-tab-status.tsx": "0960d24e581e5cdd38d1bea5e745039542e5ab5268f5540cf8fa87d84717922b", - "packages/app/src/pages/layout/sidebar-items.tsx": "daf940fc66f34e5f83410a8580f7bb1790bedc599ab4d64fcda2301537b24865", - "packages/app/src/pages/layout/sidebar-workspace.tsx": "a0f8e3fbd16d09e783db2a7a09c686d3aa993436d882425d3436a59ec4adf94b", - "packages/app/src/pages/layout/worktree-auto-rename.test.ts": "fb6fac363b8bee1225bbcff8098019c02f19b095b5cd96c29f7e673acb1e4e89", - "packages/app/src/pages/layout/worktree-auto-rename.ts": "2ef3e506b96b972cb55799a89aa54ca6453fc31c80bc022aa16db6ecfe9cdced", - "packages/app/src/pages/new-session-landing.test.ts": "c0f47e4096e6a20fa59dac2b10f7285d3ef45e9289bf6f0ad75c1d9e4dd1117f", - "packages/app/src/pages/new-session-landing.ts": "528d27cd5d441b521674328fb7812fb2acf77233e9e436d081c98ce611e8b268", - "packages/app/src/pages/new-session.tsx": "c060bbb15569b6da2f67146e6af0879ccb5444345df03dbc2f9b39cb98b9db78", - "packages/app/src/pages/new-session/new-session-draft-controller.ts": "3607771a22b6855afd0b0d666de662c9070a2dcd56ae96ba51d89c9e11018e81", - "packages/app/src/pages/new-session/new-session-view.test.ts": "615110d1a956bb2321ca77c998d6f5da434756d166ee61cf71ca232cc9efb0c4", - "packages/app/src/pages/new-session/new-session-view.tsx": "30b0b048f88ce741215e642b0760758638ad36696d2eb8770bc8e6b8b8f3fc29", - "packages/app/src/pages/session.tsx": "8f4375e9f2682cb36fd7b68a57e677252c4b2c8a30dd476265122847249329b1", - "packages/app/src/pages/session/amicode-session-relay.integration.test.ts": "4991e775d3a6c63a514072ccfa5aad190c586383b77ef41689c853fb271d3bf4", - "packages/app/src/pages/session/composer/bug-dock-controller.test.ts": "fe3d68f2f2bb41b04ee5567cd95a9c01671a98fd21585788be9d4cbb01a4bc22", - "packages/app/src/pages/session/composer/bug-dock-controller.ts": "ab2c72a761e1992f300b6a0cecc9d0351b00a56e4be08567bcb22d3fcece78f7", - "packages/app/src/pages/session/composer/bug-dock.ts": "11eb1a1c911df8764162d47f07e5f135d94fcb622f8a2ad9b41a23233131ba58", - "packages/app/src/pages/session/composer/report-bug.test.ts": "d4dc012309c2171298852501a14a077c6fe8cdf5d25538dc84ddd1f8195d3a8c", - "packages/app/src/pages/session/composer/report-bug.ts": "bdc3b3dec38b11c7bfa5b867a246db2717e60e1d50692d6bddb3983c9e95e02b", - "packages/app/src/pages/session/composer/session-bug-dock.stories.tsx": "a5730bb3699751d63629134924ce8dea021b264722c40f5f6bb98236dc15eda7", - "packages/app/src/pages/session/composer/session-bug-dock.tsx": "e7fed3c5ab80527d69a106440833f795bbbafc5deeba3883902ede9fba612605", - "packages/app/src/pages/session/composer/session-composer-controls.ts": "7ba9d56c81b1547acbdd47c4f9371ddc37c9a92059f5785f7286fc68e0cb4483", - "packages/app/src/pages/session/composer/session-composer-region-controller.ts": "979d2e28d9734581f88e7cb3e0a51c8a8c204f81e644f7a3b5766f60ddf88938", - "packages/app/src/pages/session/composer/session-composer-region.tsx": "415cd5c3a77b625a3142b828b6458687e1a35b382d3a208d90ff1555cc7098b1", - "packages/app/src/pages/session/composer/session-composer-state.ts": "fcffa11d801309cf58f42a174143bf6eb3ea2b14f860ad91a8ffa4e097df5c16", - "packages/app/src/pages/session/composer/session-question-dock.helpers.test.ts": "a1fe31fe4dfdf2914bc184030a0427bcbdfae0f3e7b146e1d6ee29ce31d85b64", - "packages/app/src/pages/session/composer/session-question-dock.helpers.ts": "b16282d0cf5d39152bd76f4ef8bac32f964f68143a3067765ae0827a5f90deed", - "packages/app/src/pages/session/composer/session-question-dock.tsx": "44c0814284ef4a5273c8034b8d1f5cd45306406d04e2f4f6646000facae47d7e", - "packages/app/src/pages/session/composer/session-revert-dock.stories.tsx": "0310ce448c1f8feaf4732e66429654fe3602d470f3121835cf6435084c455c36", - "packages/app/src/pages/session/composer/session-revert-dock.tsx": "3f2d030126a4c673731bac65406fd48797464ddc515444b891e39b0eb538e002", - "packages/app/src/pages/session/composer/session-tour.test.ts": "147473505d54466417b6b34fa672d280b71e1b9577e8bd41fbf9870035d1083e", - "packages/app/src/pages/session/composer/session-tour.tsx": "da5d807c7efe7aed1140d65d7eddd7982a8c17348d928f5d0a887d1b2a8d3a50", - "packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx": "70a8267c725af320d78d266b85fd0ff005d067c4d09a21bef824126602e831e7", - "packages/app/src/pages/session/helpers.test.ts": "09fd272c286c7746db5ce635e1c453c8943e46111d030b4892af9145a89401db", - "packages/app/src/pages/session/helpers.ts": "0311f52b7cc34c2c38950512c01397e9672c89a9e61fdfa0e4696192da114f34", - "packages/app/src/pages/session/review-tab.tsx": "3c90e6b11fad40ea19a258966c374ee12c05bd0e7891fcea561ba0b965ddc9f5", - "packages/app/src/pages/session/session-panel-width.test.ts": "9482afba7fbce254cbbd21ef885e9e9620b981616681635376f466478f611155", - "packages/app/src/pages/session/session-panel-width.ts": "02ee3a02ed78db2eac47c2528055cf78aef95f389641e929ddc56c17471dcbe2", - "packages/app/src/pages/session/session-side-panel-structure.test.ts": "b2d1d007d9200d0ac4a0889e45c2dbe57a324a10cb26ae9ab8f420d3c890402b", - "packages/app/src/pages/session/session-side-panel.tsx": "c3f3fb553be21dcbde98c389a09c66582bddbcaa94ce303d80f8e5158cd3dbda", - "packages/app/src/pages/session/terminal-panel-v2.tsx": "68dad9307f1d2abf3ff9248e451bd08005acf01ddc46b30a6d01b58f4a90dce0", - "packages/app/src/pages/session/timeline/last-prompt-bubble.test.ts": "83753b3ec7227570523c2e0b9e82401fae7a20f3a23980bb40deaeb13304327b", - "packages/app/src/pages/session/timeline/message-timeline.tsx": "718264c48becae24f8c55b0ef61684a26a9a12762edad9526c0b8caf9f6b097f", - "packages/app/src/pages/session/timeline/model-pure.ts": "50be4ba12d747dd8df9932044ceee29c5f3b6fa6d6ac36791207f91a91067cd4", - "packages/app/src/pages/session/timeline/model.test.ts": "459e0694409ffcf2530252a65491e1006f982b8f5c78a15573ed41646b2c85cf", - "packages/app/src/pages/session/timeline/model.ts": "76cbb00ef94133db33b69851ae8eb5cc974b5f2414551cb48ba7b61f3cfa025e", - "packages/app/src/pages/session/timeline/projection.test.ts": "68655f29c382640fc281780166aa528ea26d28d953f3376e1e062be7a0e13749", - "packages/app/src/pages/session/timeline/projection.ts": "36ab006523de7b695b33d26a0a03b59db9e148b7e979c36f63970cbcb8bcaca2", - "packages/app/src/pages/session/timeline/rows-current.test.ts": "b6a2d9671cfba970990b36d9ef0d1f107efcee59f0a9863f1280526116299095", - "packages/app/src/pages/session/timeline/rows.ts": "68581190ff5e51d2dc398298c705fbb5dfdefb7eb4cecf98f1da6ae0bd171f18", - "packages/app/src/pages/session/timeline/smooth-scroll.test.ts": "79d3bba42ad83c3ab80df907e0acf08665a38c4809468e6c12ac9fcf5e94682f", - "packages/app/src/pages/session/timeline/smooth-scroll.ts": "a7c16860aa68917b74f5c5c46d239e9a5d7a9a952233407e2ed856b534059828", - "packages/app/src/pages/session/timeline/thought-rail-pure.ts": "886c10b0de61b0ab64baf8a284758dab8154f279fd9cd509b7b1d8ecc155ad02", - "packages/app/src/pages/session/timeline/thought-rail.test.ts": "21960365e57d61de047440c386a18a06607bca74554e89881ef53cb7c00c4519", - "packages/app/src/pages/session/timeline/thought-rail.tsx": "d42be90ccb75c2efef3a3a2718763165a10336d08f8d48f8b33ba7dbb696128f", - "packages/app/src/pages/session/timeline/timeline-row.ts": "91576b8ba89a2882881bf4e8a0019431cb118a487e1160810e0c51bf23cbccf7", - "packages/app/src/pages/session/timeline/travelling-dot.test.ts": "c32a66e0d188d84d6b9693f35f29efb3ff1b2ecf30077f8250782fbf563d19b8", - "packages/app/src/pages/session/use-amicode-commands.test.ts": "65671d054c404edd2b799b0f6591a9c055e6ecb454a674fa0bd9a7fa6f68e111", - "packages/app/src/pages/session/use-amicode-commands.tsx": "88bfdad9ae6dfd920b8e6a14ffebd2cf9e52b8f67bb9284cb358ad940643ca67", - "packages/app/src/pages/session/use-composer-commands.test.ts": "cc970bec6b208786987a4179e86b63ece1031c71c00d65bcba8fb08e2a5d2237", - "packages/app/src/pages/session/use-composer-commands.tsx": "4a8c20f706385071bfddefa245cc71a84459d0a38da9aaa6896aa101f4de5c3d", - "packages/app/src/pages/session/use-session-commands.tsx": "7af9a112ae60415572ab7c9b5d4e73b2f8ed9115858c695be675ffdf07c3df2b", - "packages/app/src/pages/session/v2/accumulate-diffs.test.ts": "289ef80e26c9e85d3121d3705cefd467d147d4872410fce7309d9b7a382020fa", - "packages/app/src/pages/session/v2/accumulate-diffs.ts": "a4d5ee94b31db8def04d4b1e5efc909a8c5e0e14368af0e37414e98d4d819936", - "packages/app/src/pages/session/v2/review-panel-v2-state.test.ts": "ac0cf1939c164948d9a0c54cc15076b30413612d872237e0fbd0912804c1ced0", - "packages/app/src/pages/session/v2/review-panel-v2-state.ts": "e27c3aa236d2862e3cbd87128c4e03e6d810974faaaadb12a7e04cdd3b531e1c", - "packages/app/src/pages/session/v2/review-panel-v2.tsx": "a3cd899538a738d0236ecbe9e292928ff14e48d3646f2b045dc25880bc7f3ee3", - "packages/app/src/theme-preload.test.ts": "d9e4e96dd39a3491493637682611bedf6ddf4b6e4dbdddcb60bf006211b137a1", - "packages/app/src/utils/amicode-bridge.ts": "5104a04c7822f80dc0c564619e7dd2d850ba50035dbc86ea875604ecd97df05f", - "packages/app/src/utils/amicode-bug-report.test.ts": "b1bbf49230ff3aa6d1a43ffa9165ba5a84ca4ee18a6d49f52ee5cd887c3e6444", - "packages/app/src/utils/amicode-bug-report.ts": "d55d9cecfe17719c0d4a0ca498345c7eff6fca1de6b645e4bc3fecb40f2f4645", - "packages/app/src/utils/amicode-developer.ts": "b5cecd598b7e50631d2a441d7c72d1a012a2a77bdee3629fcfe9400a36312ad6", - "packages/app/src/utils/amicode-fetch.ts": "ec62b502e6b8688cef0a2aa249715e847032265fd0e150d73ab3021a63db0e33", - "packages/app/src/utils/amicode-hidden-project.test.ts": "333ce7e13a2940268448db06fcfc8bf1733110b5311932820ade1dc9ab573180", - "packages/app/src/utils/amicode-hidden-project.ts": "d845a80ecad2d497528a5071f55cffab72e7b451f16d106cdb594f5bbd62c0ee", - "packages/app/src/utils/amicode-pane.ts": "46c18a2dc47c5db154f70272d25031e6834539ad03f6ab25613f082426f7c642", - "packages/app/src/utils/amicode-route-info.ts": "a0268a223e8de09fae9d4de8bee6a7774c14c87c6254cb4ed1d921db18587f44", - "packages/app/src/utils/amicode-session-relay.test.ts": "6723b5da04b30564e913883f1324e84ce92ed6028e0b02ef122bd3a7d54b2b3c", - "packages/app/src/utils/amicode-session-relay.ts": "b718d3285594e15ab563a556fa1cea75f280150cb271fc57f308e4ee577c43f8", - "packages/app/src/utils/amicode-workspace-projects.test.ts": "8b5c32172e2039b3d9c52f2257023263fc846132e7c185e4a63ae014bc2e2bfb", - "packages/app/src/utils/amicode-workspace-projects.ts": "cbe091c463177375c93cb43676c202bd7bf06baf36fdec779f7d641558ff6bee", - "packages/app/src/utils/chrome-dropdown.ts": "f8b878c5df4e1afd96b0751c73daaad0a8127411030724cb8f9a5089ebb29eac", - "packages/app/src/utils/global-clipboard.test.ts": "18ac0ea486d36eed00597f2718f03bffce70a6e6a8f77c79aefe0795790d8771", - "packages/app/src/utils/global-clipboard.ts": "b26373289d7402c88e8038575703b11fa5e4ef5a7f50ee05bceb45488022ab26", - "packages/app/src/utils/pane-bridge.ts": "a8a8a40dc60a367086f3c4e4c561a289fb85d8b2086a8d62c2b66102de652ce4", - "packages/app/src/utils/project-type-helpers.test.ts": "602ed23d5719729d1e3b5241a155857775a7a855897a87986964e83fc1b249ec", - "packages/app/src/utils/project-type-helpers.ts": "5b9eb86b6fa271186e49d380249f7dce13879106a2e68a503aeaacee2f7d6ba0", - "packages/app/src/utils/provider-disconnect.test.ts": "809971964ed28564d379dce2e590bd4727f45eb597e46234c28d25dd2485df26", - "packages/app/src/utils/provider-disconnect.ts": "209c9b44970cfa3cd150cc20bf7bff34b773b148739e3d6beb314969b6bb1bbc", - "packages/app/src/utils/serialize-session.test.ts": "f8fe318f195dca251eae3f4899f4a5881c3523522f59e02fef208588391f4048", - "packages/app/src/utils/serialize-session.ts": "c303c678500cdb64c7aa6928a0bd984c441a36705fe8152368a0e575cbcb459f", - "packages/app/src/utils/server-compat.ts": "01413e13b87485770eb3dbec0b882aec4c8247dafc4dc74b7b4669fa5b20cf1a", - "packages/app/src/utils/start-prompt.ts": "809d8ad0ab6de76a97503f8368ade25f771431be3f92eb8f039a2c65244ab20f", - "packages/app/src/utils/vscode-explorer-icon-theme.test.ts": "351deb0ff77e62d2585858105aaf34ab621298511798fcb626abee97bd644fe6", - "packages/app/src/utils/vscode-explorer-icon-theme.ts": "0d700027004f4a08265682e19364bd931313d0658b3d75d7874397b407ade2ab", - "packages/app/src/utils/web-zoom.test.ts": "f373618138add504faa44dd6d2c9e3489b6e8dd0093ac6bb4f00f55307864e3d", - "packages/app/src/utils/web-zoom.ts": "d5119a07e9fc61880b7294fadd23801933d99a9d3dbd0fadcafed1f786bd7d7a", - "packages/app/src/utils/webview-context-menu.ts": "876b532fc9c00156f722d6424c28476f34b2db1bd0bc3cff3c9866152600e7c3", - "packages/app/src/wsl/dialog-add-server.tsx": "a80a19cfc3590539026a11846d56e0d3cf7eb4ed7360dedab71412da58827247", - "packages/app/src/wsl/dialog-add-wsl-server.css": "a9c2f13e8823fe51989bec945ed1e36274eb0ad363f55cd91714fc91ca4d91de", - "packages/app/src/wsl/settings-model.test.ts": "3304797c2779ca573f44eb25b758b67d66b2d7897432252375606680021390c3", - "packages/app/src/wsl/settings-model.ts": "35481fe3029714becf30b07024e0f849438c99c369a41b437b5208e48095cbf4", - "packages/app/src/wsl/settings.tsx": "1d6bb448f5f7e574ddd2efb2fdb0b6cdafb7a2ca4af9bdd210f2f58da9d9b984", - "packages/app/test-browser/keybind-migration.test.ts": "192418880d432ff62d15fd80f6250ece6233e43d0dbe11d5a4fbb5f4d9e45a06", - "packages/core/schema.json": "79ef4e2f0dd8103ac7a4b6ff3ddb0fd10764655f1dc678c1c401dfc43be9a1aa", - "packages/core/src/config.ts": "0b6b81bea6a3a09285daa4bd70757e6bbe93cf2508121e1062b71bb24654d692", - "packages/core/src/database/database.ts": "9406173aa6cac6acd1c3ec306ae71942e12c8e2d68b7cd3d58a9a094539bc32f", - "packages/core/src/database/migration.gen.ts": "689da2c4e571629ba207420c8f31f604c653059ef1b3846683c46d02f1c02c12", - "packages/core/src/database/migration/20260813162312_shocking_karnak.ts": "f4e901f79e3f660b3809e336599a5ba7da7794ff595e6accf6218739c046ab68", - "packages/core/src/database/migration/20260820000001_add_session_directories.ts": "bd8ab86f36281b8ccd6d02a6971b81a0a1e877544fac68f969a9a16b559f3f91", - "packages/core/src/database/migration/20260828201050_normal_stryfe.ts": "cbf63b27785b76d64d83e4c7fea341278c736985a6e21e4bd6cc816360a84154", - "packages/core/src/database/schema.gen.ts": "784fadc53281588f15edebef7a6362d025ed3fa15f7b86b6451f1cf27292f0f0", - "packages/core/src/filesystem/watcher.ts": "8600768eb5250fd9e26e4404e4f18c2b823c452bf967da8e4c5085347c918c65", - "packages/core/src/flag/flag.ts": "3cefd0a4d803268910d265a27bf24ed8ca354ab28449380c6f1cbd7708a8d4b5", - "packages/core/src/location-mutation.ts": "5fa852c48e98cec513346f848b422c2d5d6d4b753b39da851c73be073a03511a", - "packages/core/src/location.ts": "16325cfecf6c83bd4e653a0f1313d78172a31fb93cd28672f180053ae4719aef", - "packages/core/src/models-dev.ts": "dbbbe33f470e219d5fdaa6ec8e4998be95356e80756f29c18e3656562523923c", - "packages/core/src/observability/otlp.ts": "be20b97f84b2a5b4a1663fa3bed0b31c6c387950f7c28b76fbaa8525cd24d6e8", - "packages/core/src/permission.ts": "8c46b08adc9edd6bbfb90481b592ea6f00c40743d1ea0ee6a8b2e185dfd2de66", - "packages/core/src/permission/provider-saved.ts": "029f02a7120fde4ca1d499294f73f22ca8f0dbaba030a901f94093fb36674025", - "packages/core/src/permission/sql.ts": "c8c44e00cf957511282e35cbb192c0be36ed33d41d6b15e98d79eab4378661cd", - "packages/core/src/provider-permission.ts": "a672c1f40fa2efb0cd8923b0b7827b6debe770308bcaef692ad8589ba9b40685", - "packages/core/src/session.ts": "9b0942acb81373bd177ec544eaba74815369c0be55ad35c76a48b7676f2ce315", - "packages/core/src/session/runner/llm.ts": "e1c9da5f568cab64ebd49a467bff8e11a685306240b3faf672127663f1b02444", - "packages/core/src/session/sql.ts": "30267b6bd6f291051942cc1cc870267c073d6866f5dfd984fd7e9777e4c38c0e", - "packages/core/src/system-context/builtins.ts": "c5cba75156723c9f8e670c9ab578e95d0be6f81808000d6f0b854eb883a7c1a3", - "packages/core/src/tool/bash.ts": "4b56de5f3f7ad3ddbcf1ba756caff49f0a65f0fbc73811cbfc312ea716e0e447", - "packages/core/src/tool/edit.ts": "b1bd6df76da2c04681aef1c0d6e90e16e929b2c1ed09f6367a2bb9c655dc1d68", - "packages/core/src/tool/glob.ts": "3da75d862c37d35aafadf6d54b5d7ef3a61eefae049ac8c3ffe9cadfec818006", - "packages/core/src/tool/grep.ts": "db323a91b27727abcee372bf5403f322458ce456c9b581d4f905ab241bea6dd6", - "packages/core/src/tool/question.ts": "9b32d02d3d8e18adaeb86a2b344fff0a21fff1955fcacf91b4c79f93c93fd28f", - "packages/core/src/tool/read.ts": "ceb37f787cc78a9973dec7c0f8c5fd647baeac979619741d0ff15167e13c6f29", - "packages/core/src/tool/webfetch.ts": "904846f51dbee2579a36c4856efbfe1442d4ce6a31d6a280cc387c390fd22bef", - "packages/core/src/tool/websearch.ts": "bd0502eeb9d6deeea975a21a592040b5b48abd6f2613e39dd6cfbd1a959c950a", - "packages/core/src/tool/write.ts": "4759d89e4b6cd5fa7d7de4ba091d2bf859d830cb15038828a15751c80fd9b0ec", - "packages/core/src/v1/config/config.ts": "6eece12da68ac65a2c8b2fe19b1f2509f397cb63d004dca3998cf6dcc772293e", - "packages/core/src/v1/config/migrate.ts": "6c960e1245db9a4bb830f0c1ebd6174e50570b4282d4ce5d7bff3333277abcf4", - "packages/core/src/v1/session.ts": "53714b7754a3adecbed4e28d511f5c1ef97ae2fa379e3a07cc68714e1de8469e", - "packages/core/test/filesystem/watcher.test.ts": "ade83f34270bc33c0a8cfd91766d5400a29927818f9b7f33e364bc26132ef7d9", - "packages/core/test/fixture/location.ts": "8e93d87c20305911dc4583ab1717766b1f70eed3e687dac040ad2c646c25ceea", - "packages/core/test/location-mutation.test.ts": "2c4c8faa220cc8fabfe12d57bd74ec8dd8aac8485d0ecafd2761cdee1806d6b0", - "packages/core/test/system-context/builtins.test.ts": "2331a35ab10b3e69f5f5d2dd462ec56000246a747bccec77db783144a91ebbea", - "packages/core/test/tool-question.test.ts": "4df41393f15104a1d3a9c3d06e30cef515108490b41fcf4d9a7d9399fd4ed945", - "packages/opencode/package.json": "01d9338ee64108d0bd6af80b971fa2da4c7bf63e7efae59cc97cd58a9cfce55c", - "packages/opencode/pasqal-live-test.mjs": "2ff0edf222ce29660ef8d901c0b6f10951943ef01824d2d264339f8d720206f1", - "packages/opencode/pasqal-live-test.sh": "0bb0089eb413956f0252939f933a139c2f11520466887ad91fcae362f1698e41", - "packages/opencode/script/build.ts": "876e7d569aa71ce060c1d4b24c96e9bf13245cbf4ca743828d645560a95aa641", - "packages/opencode/script/httpapi-exercise.ts": "772bd2cf5748ca90c5d5790c2d044237518cc8ede0411fc4ba28b9d7440ba28c", - "packages/opencode/src/agent/agent.ts": "512372a4c62997e9565266638ada19b9dc0a3685b0c0483fd28fede2abdb5c9b", - "packages/opencode/src/cli/cmd/run/footer.question.tsx": "c9a1b335c9c7d8446d15c58c8808ea857f8f238c8a4047121f49599296922f39", - "packages/opencode/src/cli/cmd/run/question.shared.ts": "f4b8ab69c18e66d3efea505f3d2c8c5476bba78d46b0f30bc52da4386b19e478", - "packages/opencode/src/mcp/browser.ts": "ecdda42cbd55a97b8d14050aa15c6e6450a1d63b0a641c8c8e5b81e50f957c87", - "packages/opencode/src/plugin/openai/codex.ts": "7f4342ee6a25eca6b66a47732a154449fbf318f6ce70ed446cf3e6788833954b", - "packages/opencode/src/project/instance-context.ts": "65a35792e50e96a50ea14cd9f928045c0e2fc15eb49506f5bbceee38c4af1457", - "packages/opencode/src/project/instance-store.ts": "c22d3e2499e63dd8d9395d58189df75444d306774df833e746f22e327edcf2ab", - "packages/opencode/src/provider/auth.ts": "b0ab1322c1039e27176bf9e3500603eae27506065ac141a69710220f3361f6b8", - "packages/opencode/src/provider/provider.ts": "671f6d8de83f919ddaa69b8240cacd82e2b8202ab505d4334175f2858bbd8c32", - "packages/opencode/src/server/amicode/connections.ts": "4498adc8a1ba0d81f92a2a23cc36641597b738bb0ac81d658bd21e10c35e39fc", - "packages/opencode/src/server/amicode/credentials.ts": "f3a15c82496f9a3b6e8c1006a6a4ab419a02156e9a93a43c6c2319632c30063f", - "packages/opencode/src/server/amicode/dashboard.ts": "031a4f40bfdc847984a1deecfefbe0fd27f42cbd1caf8823dc43c7eb5bcb9af0", - "packages/opencode/src/server/amicode/file-resolve.ts": "3f0548fc97aad431d3f7707fd0b911e66fb4fd68ac4f643da71a2f00a73beffe", - "packages/opencode/src/server/amicode/library.ts": "36013b19f7c57afaa1bab63e5ff34d79f09ec42640e2a8c4a40cb14c97c4b859", - "packages/opencode/src/server/amicode/pasqal-secret.ts": "a0b53498bb7415c96e14b435367ffa93bd3d298fe12f7584cd401e649312fd69", - "packages/opencode/src/server/amicode/problems.ts": "d56513cff90193ab436dcca379f065a4ce963eeb45c22178cf9a0151b49c9487", - "packages/opencode/src/server/amicode/profile.ts": "521338a7990deb8d0f352ed96d0f0a96fd56daeeec407c3ae133b02dfb2ed5c1", - "packages/opencode/src/server/amicode/project.ts": "7f0a8a15aea0ef367a00ab31ba4329ecf2344282965afce553005b5355be63c3", - "packages/opencode/src/server/amicode/run-terminal.ts": "c6857036c1dca90e8b462e916f49df707757f227d0ed74f072b8e94d08d74cd0", - "packages/opencode/src/server/amicode/toml-lite.ts": "0001fb071c53c1a3ab330e40550ccfba497b78e2a0cc45084e1c016d8f215831", - "packages/opencode/src/server/amicode/vault-browser.ts": "8a8252fb0b46583c75e9475d7c89e68c092f5255b21476f3c3d0b9d379ea2d48", - "packages/opencode/src/server/amicode/vaults.ts": "e48c90c64de27abe24a510f188def6b56297d9bb1fa1ae08cbcc94888d42044a", - "packages/opencode/src/server/amicode/warrants.ts": "13ef47a676245d577617f6e5af2c8a2beb3102346d2dbb43076159f3f43c01a7", - "packages/opencode/src/server/amicode/widget-frame-html.ts": "3df10eeeccbb81d2b163195ceaa1d5abc24e90506471ff6d6b2a5fc40e52db52", - "packages/opencode/src/server/amicode/widget-manifest.ts": "5753daf16ef4c1e74c97d4a515b30d123f7afbfee29bb07381c6f10ecc14cebf", - "packages/opencode/src/server/amicode/widget-runtime.ts": "a5fe95eba46df87c4b4c54bc07bb91587b73e88eb90db889bc87358ece4b3f27", - "packages/opencode/src/server/amicode/widgets-src/jump-back-in.ts": "a82bf11004b71c7ac6e0357c45a0d7532aad4ee6af16e048ae86ef9bf3799fef", - "packages/opencode/src/server/amicode/widgets.ts": "d15481086c41b365c28937f002bfcdeb8c2a9f68066413da695fbac8b7acdb61", - "packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts": "944a0aee215a917e867fd9482f3c2bd40f49082bd3174c8a7d967ca40e34ec15", - "packages/opencode/src/server/routes/instance/httpapi/groups/file.ts": "ed165131c62eeb29375db39edf89db8f87488e24ef99fc6f2cf19705ba35751a", - "packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts": "34c6f1ab1a085d1b047c220bbff32a36032dc5e924784e9272cda166cf0ec84b", - "packages/opencode/src/server/routes/instance/httpapi/groups/session.ts": "1421f8c07948b121c7e2005bd9b0fcd6b2c456565ddd1da32d8e6c35d03fac9c", - "packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts": "69ca3dd48d95157fc822e1f76eb42ac873df50f22616b85194619ca658613867", - "packages/opencode/src/server/routes/instance/httpapi/handlers/file.ts": "10bcb79b117beebee04184fb48c1ad789e782e2f7ae4b0c68603edc00f03aee9", - "packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts": "8baf16cad0992c5351b61b0c0fb27903bb25b17e1b25fc7c5d77f807c24413a6", - "packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts": "b37ff4136c4aea85b23083bf441f03e09820e3e4cdd95e4118ca570d8435b94f", - "packages/opencode/src/server/routes/instance/httpapi/server.ts": "85c200797fed41c0cd08e7aa699ce13aeb8a3d23aa2b9eddc4d72e72b8b5082c", - "packages/opencode/src/server/server.ts": "56b3c2047917aa80d1dfb29bfa9839bcc2ad7f5a6f4db12103cd962a98fba866", - "packages/opencode/src/server/shared/public-ui.ts": "a843b4e84673d9a5e34f36eb7cffbb499850f7588154c23061fc8a81cd1369ef", - "packages/opencode/src/server/shared/ui.ts": "eba93fdd47c786d723d2593e788f6b7278b072548acb916d19eeb2e9616a4197", - "packages/opencode/src/server/shared/workspace-routing.ts": "3704b6cf218fc165ce9c1cdad0ee42fc9cf604976e4a552478200f85db80876a", - "packages/opencode/src/session/compaction.ts": "fd6159a8b04050706b6968c7a1b091f79d06e6e4aa988a12629a7616b8128e94", - "packages/opencode/src/session/external-diff.ts": "8f40051b3791551d3811045e4060884266687ec2208465ea2cc116aad939f819", - "packages/opencode/src/session/instruction.ts": "19640d02c96b8ec764edd49b0ce74879432fd2d2cbb4d2ad0076caa200dd4797", - "packages/opencode/src/session/llm/request.ts": "248db5d00c4513fa7101b4631950ed39fe8fe6de8228c2f527c57ca72e0b55f0", - "packages/opencode/src/session/message-v2.ts": "7c5bcf4f68ffd8b5e7f637b7a7550dd154d79e69c8939e4a172446ea2cce2240", - "packages/opencode/src/session/prompt.ts": "65f53031ee84f8e16e6295b5c8aaf9f63f9411f30799a4323f53e2c19eebe05a", - "packages/opencode/src/session/prompt/anthropic.txt": "e3e1a55159f0104ceec69098620eb281cd8927cfa808ab5feaa753719af27f05", - "packages/opencode/src/session/prompt/communicating.txt": "e14e1daf86eb4fa2fc1222cc941145913d540827bde3d27ebfe0fe30181f3e97", - "packages/opencode/src/session/prompt/default.txt": "bfb0d6ab93fb82a8edad591101bd84839565a0fb401770ceb0045b1fd3b081bc", - "packages/opencode/src/session/prompt/gemini.txt": "d24815ea833b058b304d95d3212ad2e091bc07064a22a6af9401872cdc3871a9", - "packages/opencode/src/session/prose-guard.ts": "dd6f8dfdc41b9cad3406ac586db9a60f7ee0a040b41550d6c55da2d040dc7c13", - "packages/opencode/src/session/session.ts": "260a27d72fb53b11c272987a921d3c2099b1e009afb943106336d7f190752c62", - "packages/opencode/src/session/summary.ts": "09f546db362a992156bdb4901cce58e495bd38bab6ba41b4386cca77bebab7f3", - "packages/opencode/src/session/system.ts": "c91d00de07d6d4e3910561d59a598579eeafb725583a9d6475a158abdd4a17c4", - "packages/opencode/src/session/turn-output.ts": "889624ca54a8149d35f200c7efa732771dfca36984e8a322a9781b1a25434762", - "packages/opencode/src/snapshot/index.ts": "4d76a78c48597bda2379e2c3396f4a53828b21c6ce03e1975d2911150822c6de", - "packages/opencode/src/tool/apply_patch.ts": "37535a783d115ac2032def7a28cce56e304f4e7c75d3ecac05b9a37054ae5b4f", - "packages/opencode/src/tool/edit.ts": "38aa4ce0751ff99bbb0807bcda52f8b9a1d32b6e342df4cc2aedab1f03d342b1", - "packages/opencode/src/tool/question.txt": "49bbecb33a825620c2ed14ec9b61faa294359c3673c33277e32f57c1070d2806", - "packages/opencode/src/tool/registry.ts": "2b0e8546f01643e78b9dee504357bfc33f2d7075ec45f8a1462d8c3ee8e7aff5", - "packages/opencode/src/tool/truncate.ts": "92c59d83c4a660116d6ecc48e900aeb16bde93962bfae9f520193fda18273379", - "packages/opencode/src/tool/widget-author.ts": "912be8636b162adca8796a501e927019c2449393c14bb5f3ff478b02083b73a9", - "packages/opencode/src/tool/widget-author.txt": "a2572913debbbbd2d4a644dcdf4576accbc7efdcc8217c0fc9f5a011e7a15ec4", - "packages/opencode/src/tool/write.ts": "094661a3bdd3fab2cd439c0b6cb942b6a2653d3e9451420523b33acbc762d1a7", - "packages/opencode/src/worktree/index.ts": "a86f542b579ef40f2940d36e2c8011ce5592d4811cd5ed437bafe614789fb87e", - "packages/opencode/test/amicode-release-workflow.test.ts": "f6dfcb3ed9c572ca8e8b21ff82e038872b635b25c68f9580f6d6f51ee2813189", - "packages/opencode/test/cli/run/question.shared.test.ts": "fbb3bdb20fae7d77f0e54444847c658c721b132feca9ad939a963721d2ddd772", - "packages/opencode/test/cli/run/run-process.test.ts": "13e6386bf1919688cff2f6f9f68bcddcfbbec822ef8fc271ee68347a542827b8", - "packages/opencode/test/event-manifest.test.ts": "e2f1542c3ee8e981934044bb14cb87a58a676f3b6eb5d160f6e854f136ba445c", - "packages/opencode/test/fixture/fixture.ts": "357bdaa06c6233a91069db20cc5f1cbb2d6eafa3bc7ba3e89b019859d195d6ef", - "packages/opencode/test/lib/cli-process.ts": "110c43d247930e834ffffb9068682c5ab2e1b95460ec1ac3d0a75cafbdee60ff", - "packages/opencode/test/preload.ts": "5a3c7e7a8341dc735513b0cbeac6029ee406ad64767a1b883bdcb3e99269dd7e", - "packages/opencode/test/project/worktree-rename.test.ts": "3ec168c9f8595249b75832895a251483ec1f3641ce44ad0bd5a664b5bbd6dad1", - "packages/opencode/test/provider/harmoniqs-no-tools.test.ts": "ac455d754c1a61791fa45b18db5322ec2d472ff71778fbed1d412ec749b4b7b9", - "packages/opencode/test/provider/provider.test.ts": "5b2cbed8994d3bbc968a72d01459460c1de72b6117a0795c2bc6a10abbf02926", - "packages/opencode/test/server/amicode-connections-routes.test.ts": "2852289427fadaf6133b556af02f7e7b369b2a4df53ababc39531fe85bcc9d17", - "packages/opencode/test/server/amicode-connections.test.ts": "0d916321a42e321d44e0db13a6966985deaf77cea48470d11eb8b434a464b7cd", - "packages/opencode/test/server/amicode-credentials.test.ts": "ba77d064fd2be799930524510ce6e32c6f6a0d144d3cdf41673a8283dbe95bf6", - "packages/opencode/test/server/amicode-dashboard.test.ts": "e25b284b9eb434da7f07dfa8b72b7919a0cd1ffaed275a6725d9cd44cd1298c0", - "packages/opencode/test/server/amicode-file-resolve.test.ts": "39db84780125c8fd4551137e4f6a0ea6b0a9dce45b04e26ed15f649efe251311", - "packages/opencode/test/server/amicode-library.test.ts": "87b986c43390e1f94d6bcded0bb5d22be24beaab2c336773bb438ed1fc6a2d95", - "packages/opencode/test/server/amicode-problems.test.ts": "4a8a9011f3796df4d6cde9999b86b507a8126fdc9138cc3ba305f930968c3392", - "packages/opencode/test/server/amicode-profile.test.ts": "5e5dcfd2b3db5cb8d7aba2cf1f74ed2d76716af6e4f761f54b94e77174b314de", - "packages/opencode/test/server/amicode-project.test.ts": "18991a015b5b8fd5c25b7f9d875d7ff8fbb28fe8b8df02bde390420be9189841", - "packages/opencode/test/server/amicode-toml-lite.test.ts": "3c10b68cde693e27cbb6520f7d40c283d78c5ce30ca6e47871072b6db59600fa", - "packages/opencode/test/server/amicode-vault-browser.test.ts": "03347a6a9b6ba250b7a1150449cbe44b8817dbc0ebc433c89a703f4818492a5a", - "packages/opencode/test/server/amicode-vaults.test.ts": "3f7c8ecfdc250ff360c0ed66d9cc6354d9069e66001281b3f6e30981b9f71c35", - "packages/opencode/test/server/amicode-warrants.test.ts": "a7ad74da87f77f4488f334debf8c126671d563839891eb3a19b3d1a134dbc504", - "packages/opencode/test/server/amicode-widget-frame.test.ts": "c96818aadd94711a2f435d98fe9fcabd95bf4202d695899956c6e74d90c6c531", - "packages/opencode/test/server/amicode-widget-manifest.test.ts": "ac404d1737bdde8ea3464cf0b5fa12f0a6f9e630a0698ca5fdec38449cb66d0f", - "packages/opencode/test/server/amicode-widgets-src.test.ts": "fa95521084f95e0c421e7f7f13bf61de7e6b5cc9f42aa9fade486f5c1b53a65d", - "packages/opencode/test/server/amicode-widgets.test.ts": "14fc6ccff4e83a5b005a724936e9f0d7ce411fab74109f319e8bc748665f7ab8", - "packages/opencode/test/server/fixtures/credentials/cloud.json": "431bdf114031da38975538384e21ab0ec7206a0859859f0bf87345b8c360829e", - "packages/opencode/test/server/fixtures/credentials/pasqal.json": "d3c775cc498fe3029d9ac234d9eaa9eaffa1ad8656e12a5aca1355c733276736", - "packages/opencode/test/server/httpapi-compression.test.ts": "5f7603d7018e0b95f1c2f36c01dd297c01770bfcdd91ce29778e03b7d6143f75", - "packages/opencode/test/server/httpapi-exercise/index.ts": "59048fa30e60348240de62cca862a5c6abbe2e9e0f6340b77b0a9bbd997bec27", - "packages/opencode/test/server/httpapi-file.test.ts": "d3386129bc81467ecbcc57a3861f53767ee56ac41b4ff6ad58d8b168fb3b3373", - "packages/opencode/test/server/httpapi-instance-route-auth.test.ts": "4b73a89d2431c02bc3b665d93f9002914e51eb1add979dc1867efbcbc0c36e25", - "packages/opencode/test/server/httpapi-provider.test.ts": "9e8b3e085b478e3f99b689ffff600e10c0b4b50b3cabdbd749f88dae19bf5904", - "packages/opencode/test/server/httpapi-ui.test.ts": "d029e959cfd9347fff4cf17c5686dd125b0bd3a41afb3408a23b31418f12e3b0", - "packages/opencode/test/server/pasqal-secret.test.ts": "54be8c666160dad22cd37bbf041f5bd40aec120271818f3c56c94107d987b9fb", - "packages/opencode/test/server/session-diff-missing-patch.test.ts": "70526ca7fb86741843fd167f8f2f9c6f6d7e5e415a20a5448d17d24229bdd65b", - "packages/opencode/test/server/session-diff-scoped.test.ts": "4d062ab6881fe6c10f656b363405828b6ebc4c0c66d55f5e694e058f61370e03", - "packages/opencode/test/server/workspace-routing.test.ts": "2574731ac379c540f450edc15f8750ac5360e8c33b4a0dad7c61e8eb686137bb", - "packages/opencode/test/session/instruction.test.ts": "8b4d954eb10afa852a671e6c0a94d19604deacc9a62f9c3651c7456cc32736b7", - "packages/opencode/test/session/llm-native-recorded.test.ts": "7139b58569af0172862af521e8f8d7a78132f40f06dcceb4baf8ca3a2f07d3bd", - "packages/opencode/test/session/message-v2.test.ts": "9edc16ae57b7f2d34aaed7378d82fcf9d07a82075a05730bfb3caae39d70ac7f", - "packages/opencode/test/session/prompt.test.ts": "d9654be772eed1e73191b3a693190674eb087cf7f545385351c0917114bac9cb", - "packages/opencode/test/session/prose-guard.test.ts": "7239a758cbf27df4c3879fa9ee0374964559c1461773c2f5a85196f64632e6c4", - "packages/opencode/test/session/session.test.ts": "e2870fe0a4d759d4c467f45b1903e48ac5ee5aefc6dcd9ae6b6da20714d03646", - "packages/opencode/test/session/turn-output.test.ts": "3e92f545d10054e501ad2c8857b43719f5a8f768065643d343c0c37c2e6fb60c", - "packages/opencode/test/share/share-next.test.ts": "d94076118b558644c06de3ef315041a6fd8895098377da843e98530311e9e609", - "packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap": "e1b0c536581dd36599aebcb5562ffe49923b09629cc8fe5d64ba0a2d7fe43630", - "packages/opencode/test/tool/apply_patch.test.ts": "4a22d83eead95e6b9eb26d42dae3b421bf07d5ac9ab3e1fdcb396c2941262c25", - "packages/opencode/test/tool/edit.test.ts": "ec1ed35002b1af4e2ff508aeac456c3edbb2e1dde3f6df4abd957eda9ef6d056", - "packages/opencode/test/tool/question.test.ts": "75760ba6ed98f2fdfd75945c3b492342dfe91026f99cde86db19cf52444260c2", - "packages/opencode/test/tool/registry-schema.test.ts": "053cb9732299ea6554db007bad873d8d61cd3769aa9514d66c70c3bf0d405b90", - "packages/opencode/test/tool/truncation.test.ts": "582ef7199b3f294b1c1588fadda8a1c0ea43ca9af0424a97f48747ade1654ad1", - "packages/opencode/test/tool/write.test.ts": "820d36fde2314abbd939ce43ca5bcc4cfa0139d12a4c669716249060d9a955ff", - "packages/schema/src/index.ts": "007e8bc04cc91c2c0aba3a78212c47c4fed6a8edd0d4be05286667d303448d11", - "packages/schema/src/location.ts": "078649bbc39b8e3413311b5af85392437873597d8954494016943cfb13564805", - "packages/schema/src/prompt.ts": "eb3b42b98ef856f85f32154482b19de546272f1eabe552ee9207db030346291b", - "packages/schema/src/provider-permission.ts": "382d3b8c8e7bac64816d6a8cb0a84dff6e9a4bd1a921a653ebb20b23d4580e14", - "packages/schema/src/question.ts": "538b73b25f8993700d7836b915ff27a1aff63cb6a6ef42e77b90bfbef83a5558", - "packages/schema/src/v1/question.ts": "3ba37742dbd5ef322b7edb42fea0dacf43a1322747dfe997af909bf564bffd35", - "packages/schema/src/v1/session.ts": "5804deda9cfcf2a015c759a6905b5bdfac74897239994c7facb246a60dbcf285", - "packages/schema/src/worktree-event.ts": "833b689b3636335d00a60cbed521f05dc02b467f7ee757de48291a602fac55b3", - "packages/schema/test/question.test.ts": "511f4fabf2841ed89e1fed9594f2e3a1be8eea5bcb50b680d762c49d6ef572d9", - "packages/sdk/js/src/v2/gen/sdk.gen.ts": "6610638b4fb71bac498da98d232ef9adcd4b011b63e5e81a63fc6dc20d311b17", - "packages/sdk/js/src/v2/gen/types.gen.ts": "0c23b262085d1e14b89bd03292a380c9ec8b52e66c4308304a05173362b79339", - "packages/sdk/js/test/session-history.test.ts": "f10913af3157694465273d54e05c03cf96a0002df0e34898d9808f92977b11fd", - "packages/session-ui/bunfig.toml": "468114e9b52c3cf926d2385c12d93385992cd70c97ea9e32ed22154617b7799d", - "packages/session-ui/happydom.ts": "d81d6b14e988f058fa502c841df34b55307c57fc94a26fb4f8a5deb6aa0d4834", - "packages/session-ui/package.json": "15edfe2287a76b544bb359c809da056087bf00e71684a34d22cdcc405a77868a", - "packages/session-ui/preload-worker-mock.ts": "b53280029a042575734d7bfdf27713f6c5cd6a6665599dc429d839a3e3372bd1", - "packages/session-ui/src/components/basic-tool.css": "0bcf0592ce8af0d902bd69da26ecad2f00f5a7890275392abbffe6f4d80c7853", - "packages/session-ui/src/components/basic-tool.stories.tsx": "059c4bdce6a9ddc93c69949f5baf7323631ef0d5e69f04030fde0f2771a9fc09", - "packages/session-ui/src/components/basic-tool.tsx": "ff2678cc17510e1b39657469f6dd1a0311843664cfd5161d385256e617b4e759", - "packages/session-ui/src/components/build-trace.test.ts": "6259c529fa667a3514bfee1c771e8f623bcb8c69e37ceb17ea541aa42e207451", - "packages/session-ui/src/components/build-trace.ts": "153e3182c3a37e4aca9c88bf0e2052b0ff4ec117a60d74d2c81567ab91180066", - "packages/session-ui/src/components/group-parts.test.ts": "a31ce19009e1d62e75e83b682190a4613da0eed334420409ed73a9e21834ae84", - "packages/session-ui/src/components/line-comment-styles.ts": "2077836c13bd3c3f1c39c67722119e448a2dfa123377f94bfd3676634e955d00", - "packages/session-ui/src/components/markdown-file-refs.test.ts": "e2b1bed33629d3ab53c521f33266814088ea4122b6e64d6ab294eacc4cf15070", - "packages/session-ui/src/components/markdown-file-refs.ts": "b75bddeb565dc0163635fab8f84bdd26723742f9f82d06b6fd5991777b311032", - "packages/session-ui/src/components/markdown-shiki.worker.ts": "2748ddbfcd625bf696b27d9b64895e64ee47a3f316c88930010e260b4ba37f4b", - "packages/session-ui/src/components/markdown-stream.test.ts": "b73b1a15ffa2cfea5358b2d6313ce17d26a5a11302b0e3b7d823cde0c98cbc83", - "packages/session-ui/src/components/markdown-stream.ts": "50e38abd5d4ff919564655799678be10463dec58502fc5487c1c97a9a8db5399", - "packages/session-ui/src/components/markdown.css": "24e7c19218620386647656a5d27e116cdeca911f1916c5d5b8609edca11ff165", - "packages/session-ui/src/components/markdown.tsx": "89e132e62d20c873311c9781d0ca4d7cd1a7ff882d99f19c8696aafaf4a8f298", - "packages/session-ui/src/components/message-part-css.test.ts": "ffab7d2c94e8d40ca35e4a8d4383cc6efd805b133764176b70046fba874a5f06", - "packages/session-ui/src/components/message-part-groups.ts": "37be069bf46e926fcde83d3744ee706911ff002e6b532e279290d841aeee96da", - "packages/session-ui/src/components/message-part-skill.test.ts": "453bdcb25e4df91ad1004635b8766070a60421355adf18ee53f43cd2fa7d0486", - "packages/session-ui/src/components/message-part-skill.ts": "d65a15dc39b8c0dece13aebe5e308426ae2dd758b07740251525ba9257654cf7", - "packages/session-ui/src/components/message-part-task.test.ts": "f5896e3f5eeeed2dcc55d690be56483902ecc06f047cb44cecb2dad31ee6c405", - "packages/session-ui/src/components/message-part-task.ts": "4276091c6f8ea2c31819c72b82747871e4548b3d402b7d1b7b06603ae69b2d5a", - "packages/session-ui/src/components/message-part-text.ts": "e38d68224f1743ccc5e0e0a8023e11977e3b761ec67dd5364cde9cb34e97ea4b", - "packages/session-ui/src/components/message-part-user.ts": "1f2c8cb4efff5274863a133f369a7397cac804678e953740f356ae03b71d475c", - "packages/session-ui/src/components/message-part.css": "ae592deb33739738f6a7fc6a3460b7146803bdd05cbbf46f1cfd2c5cec421392", - "packages/session-ui/src/components/message-part.test.ts": "7c66430837fa3d2607657e57e35720ae68dc5e84662e12826713a938301eeb7b", - "packages/session-ui/src/components/message-part.tsx": "89c6d920516e3c991b81ace10b14cc75df1dcf130723e87af6bec448688a7612", - "packages/session-ui/src/components/session-retry.tsx": "2cb1513d73275a269894f601e8c1d29bc790b14927134fe36177f2b371888721", - "packages/session-ui/src/components/session-review.css": "ec8c5b359dd4b7ff80d7fad8906359678adade9ce62c9d74aedc000b646db341", - "packages/session-ui/src/components/session-review.tsx": "d2015c9f7419279f08e84523439a0b73e83bd5d06587ad56b85ea53b66ecaee4", - "packages/session-ui/src/components/session-turn.css": "792915f3373134eadf3cd51e1d4bfa88ec347e6b037b6caf60b639ec5e74fbd8", - "packages/session-ui/src/components/session-turn.tsx": "9cbc0d7a35f42e32dad53ace7b3c7d92623fa2d3108edb49e0b7bc868f5c1966", - "packages/session-ui/src/components/tool-count-label.test.ts": "c62bbe2c662f6740794d25bd7c33fb3b9b46394a1b41d01d6568a8a2ee2b4e75", - "packages/session-ui/src/components/tool-count-label.tsx": "6c0f42d2c3fdc8c63bff3ca5a51aaa6ebcac9dc773f971884cbc2696246502a8", - "packages/session-ui/src/components/tool-error-card.tsx": "e27b89836b7c709120ac15fbffd2200038944058ea3506e61e5897ffb3537503", - "packages/session-ui/src/components/tool-status-title.tsx": "ae4561b58f55985d2294a352802e723b18943ac9a6551d97f1c4a6cc95368c8a", - "packages/session-ui/src/pierre/worker.ts": "7f210f931777956567eaeea15f2f5478befc7874a64a4b685504c59c66503fee", - "packages/session-ui/src/util/clipboard.ts": "c37ba53914714ed04135e5a254e8ea90186f097d7470fa0873a83de82f3fef2d", - "packages/session-ui/src/v2/components/attachment-card-v2.css": "3b4b9c23d69e76b35488bc3a65fb51211038c3e8aac015df3f531b4e97e96359", - "packages/session-ui/src/v2/components/basic-tool-v2.css": "55d3aa179704deddda7149342a951229ff5561127f786dd551e5df9aea8a7835", - "packages/session-ui/src/v2/components/basic-tool-v2.tsx": "ece46d761f7d51a7a0925b3df00a5c289d891e9a514ee721016eb723d87fb406", - "packages/session-ui/src/v2/components/diff-gutter-extension.test.ts": "7c3a9d541f8cc2cdb537cc6630d8902a17647f0df063439a93e8d563cd4a97b2", - "packages/session-ui/src/v2/components/diff-gutter-extension.ts": "aed07587c0c9a5f110f9ea91aa42679d6f9f66b2ec4de9043d6e2233a375acb8", - "packages/session-ui/src/v2/components/editable-diff-view-core.ts": "f01a341c4c1cdb4a9522f9ccd3c856bd3b9b7310c01d87327b3ce777052c8c59", - "packages/session-ui/src/v2/components/editable-diff-view.test.ts": "ab206fa17779e6e9015d343ae37e3067dfc1821a93b6ba566b7a0dce0fc19acb", - "packages/session-ui/src/v2/components/editable-diff-view.tsx": "f682e398ece864b5b854ca36698581c7e1cc5964eed96e7b45cabfcb64748b24", - "packages/session-ui/src/v2/components/editor-core.test.ts": "bd6552c0e7080afd554cb57ad690cc1504555712274c8b02702c64bb09460234", - "packages/session-ui/src/v2/components/editor-core.ts": "a03da4863d0dc4333772b8369a63822dd730bfd84dfa876f965cdd594292484b", - "packages/session-ui/src/v2/components/file-name-picker.test.tsx": "1ce9741e315b549165d390c74b5885a43580aa70e24de987f9ba8388cd521b41", - "packages/session-ui/src/v2/components/markdown-utils.test.ts": "10e1034293bf385cf50d860bf1667d8370abc61dcee0c5a93295f21f5f55876a", - "packages/session-ui/src/v2/components/markdown-utils.ts": "3bc47cfed5b99ab23f857d5324be3189f3a7e800d991103d72ef1c2f970b910b", - "packages/session-ui/src/v2/components/preview-editor.test.ts": "b8da9320a594aaa680ed3848612fcea66f41c0a046a673f0cf6155c2a0b697dd", - "packages/session-ui/src/v2/components/preview-editor.tsx": "d356ff168919abc8446c5fac2836791338fb3b9124f558c43ea7d3d5a1bcc5f4", - "packages/session-ui/src/v2/components/preview-file-routing.test.ts": "fca02a21261b291fd94001baa2294e7b2fa45b18b0c0403848f045763b41bf15", - "packages/session-ui/src/v2/components/preview-nav-state.test.ts": "cec09a8b3c08ab16581d3d5b6ff704584b3c87d81c25e8af20f6f00272f3593f", - "packages/session-ui/src/v2/components/preview-nav-state.ts": "ccaeb94d1ab39271f5dcd49c935c8fc7b54d4ffbd66e1352e4d797c9205553fc", - "packages/session-ui/src/v2/components/prompt-input/attachments.ts": "ff66078f2edc9a67a4df0d7dfd76a49be5eab27ac332b303f3412721ef7268ea", - "packages/session-ui/src/v2/components/prompt-input/index.tsx": "6cbd3a1e3a4fd789284526e5981c6fd2d4952f3926c5a1be0609bb6832453997", - "packages/session-ui/src/v2/components/session-review-file-preview-v2.tsx": "fc06f46ed3c92c8066744da1f6ac97db7d8b7d2aeec5ef776d743dd93b317936", - "packages/session-ui/src/v2/components/session-review-v2.css": "bb306f226fda8f8ba6cf0ae706843ba9f2b48f3a3446433515e8a8dd1f9dc626", - "packages/session-ui/src/v2/components/session-review-v2.tsx": "4151286efb6e0e148246ee3eebae24a2e5d4eac2603fd5ea8546d0839a694161", - "packages/session-ui/src/v2/components/shiki-highlight-decorations.test.ts": "f50e8156b708f3e0ddbc509abf71751778a74923dac9d7e65385b178f6346718", - "packages/session-ui/src/v2/components/shiki-highlight-decorations.ts": "57fee1804df78c627f7ddfd092a55d71afe041baa153d0d5ed7c7d8781e30206", - "packages/session-ui/src/v2/components/shiki-highlight-integration.test.ts": "c3f62945f0258d7462bf9936a8b78294c4295f445e2a75fca186432f241443dc", - "packages/session-ui/src/v2/components/shiki-highlight-plugin.ts": "85b01203590f6de0af75b1cb4f35d1b87dea92989a950dbe6a9cf10aac19ffaf", - "packages/session-ui/src/v2/components/shiki-highlight-worker.ts": "0f9628b9e0d3ec9ff49d53d05cb77259e1762f66daf7b0e1f2403649385e66e4", - "packages/session-ui/src/v2/components/shiki-theme-state.test.ts": "b305c3f669b2083851fb574bacccab4f311228ce842f18465443b7807226e619", - "packages/session-ui/src/v2/components/shiki-theme-state.ts": "5ab15c15f4a32afce2279068adda732846404133bbc2a44b90779a4da88d123a", - "packages/session-ui/src/v2/components/tool-error-card-v2.css": "9eb0bf8b583a18159f3855465118ff6a853d0193ea783037d5c90a868fdb3ff1", - "packages/ui/package.json": "b1d168d0371e9094faae1107fc6c00be197f09bc69daa2247a3890d607f4b629", - "packages/ui/src/amicode/amico-presence.css": "b3f345b607e318dcfbefcdc677fe21cc7d387b9946b0f9d625b0a842fe7e31b9", - "packages/ui/src/amicode/amico-presence.stories.tsx": "6012506c946a18460f8a6105c5860a050e47e7708818b0408b516370f50b7094", - "packages/ui/src/amicode/amico-presence.test.ts": "c7ea8c840004d06e231a7368b3c10e11b7dd7efcbcaca4867b0f30167bd2e2bb", - "packages/ui/src/amicode/amico-presence.ts": "b4708117445d3fa5cf9be8c9b2f51bfb1f6b01a76e2fac114cde93107a075e26", - "packages/ui/src/amicode/amico-wave.stories.tsx": "fed064c5202bd772308e2c6165c9d63182661fe6ce590c75cac1fd0e9deadf94", - "packages/ui/src/amicode/amico-wave.tsx": "478cd8b19a87679016d9dbb0aa494ba7d1f1ef67b3da1d09fb35d28e33de9017", - "packages/ui/src/amicode/amicode.css": "a7b8e410dad9ee66190cc31d4a4782efa44e8f759d89d701c7525e67002b98c8", - "packages/ui/src/amicode/approval-bridge.test.ts": "5b5e5a41c827b7a3cdaf455dbf488cfa7b8d339f46e64f5a35a0ba9226eb0ebf", - "packages/ui/src/amicode/approval-bridge.ts": "ceaa6024916794ece1bc80a004b79c36406d2bc512f82e003c25d919c9050e48", - "packages/ui/src/amicode/approval-card.tsx": "f55bd13bfded569020ad0ce0d385da3018aee8e833ec573cb45447114658a11b", - "packages/ui/src/amicode/approval.test.ts": "d1a9eb383112234d750d07229e347a464bcccc1d633d90ebf653937ae0653773", - "packages/ui/src/amicode/approval.ts": "ebee2a1302c27e1f74d2892b3d84158dbaf672e13d4300ffc01ad8ce9a1ed644", - "packages/ui/src/amicode/ask-bridge.ts": "8ab7f64eefe55ae0968b9b960718a1f4ceaf6813102bbda42349a06a3638610f", - "packages/ui/src/amicode/ask-card.tsx": "0e2fe53c747cc9aa7f65536b73cceaac30f6bdb864424c87997dcb13325e7584", - "packages/ui/src/amicode/ask.test.ts": "1daa4ccf6cc41f17039c5ffb0a09243ba364b5af6e174ecd1040787afb7907e2", - "packages/ui/src/amicode/ask.ts": "5081435a8b09b2eba12240a9914bbe222303460bd21044bbf8482bc190ff2efe", - "packages/ui/src/amicode/brain-data.ts": "f23483cda811e148748d4f47435c6d01c03d52e9a65ad74cae2c0ea30ce0b8dc", - "packages/ui/src/amicode/brain-engine.test.ts": "3b244fbe15ac87529655acd688da9181af53a1dfeb3f9f87e5f77000db3aada6", - "packages/ui/src/amicode/brain-engine.ts": "500b03cd43d4cdbd76a575f4517a4aaac788167e1d41a396d6dc6bce3cdfb8dc", - "packages/ui/src/amicode/brain-ref.ts": "9d8aaa8b24fb0b74acc0c4cdafc265c1808c28c95d4ac9b815fd2e54ea89f46d", - "packages/ui/src/amicode/bridge.ts": "e7b93a15060a0cb1ab0be2b367f73e926d74b990a8af917a9966b451ee303b5b", - "packages/ui/src/amicode/calibration-view.tsx": "bc4193104fea43ac3e5476df0f9a91a55465b48ffffc80e4170047872a141812", - "packages/ui/src/amicode/card.stories.tsx": "b1591abb4af426b0eb08588ea1585336a392d755b5d308cb31f17cb65acf5a3e", - "packages/ui/src/amicode/card.tsx": "e5198e40923a77c3ed6a7aa235401bdeb20db6fbdb81f1ffeb847962dd1122e1", - "packages/ui/src/amicode/connection-icon.tsx": "2b36c05209a3b5091c6407d59add58fb51ec34724ae6411af85c3dcc797a9987", - "packages/ui/src/amicode/connection-picker.tsx": "12cc6f142ee109580442a278286f06118a2a35239cabeaef6d60c0dac1a7ed3f", - "packages/ui/src/amicode/connections-paths.test.ts": "07c86e8e04700cdbd55bff8db342a8400d85114d76bc73fee8205e9162953f2a", - "packages/ui/src/amicode/connections-tab.tsx": "06489a47bbd6d482ba4d2dc2cf4e9e8e9c648be774f78cd76e2abc87451116e5", - "packages/ui/src/amicode/connections.stories.tsx": "fda54a41c4b46f5cab5278278f92c01d1fea70610f7b8641fa5855be6bd9d486", - "packages/ui/src/amicode/connections.test.ts": "a718b1b698178087fdac5294c1661ca2eb200491e2a076465a09ab52c70b8910", - "packages/ui/src/amicode/connections.ts": "c44875ae2a95aae3f62a95fcf59517178039d09d51ca84e816ea725ba965e408", - "packages/ui/src/amicode/context-tree-data.test.ts": "bd51dc84d6c14c64f38c8f467ef29d9d8f45dcb77cc83ec92bffc8aaa983b463", - "packages/ui/src/amicode/context-tree-data.ts": "d623578b957b9a49d6f7b930a2264b7bf0ea71fabf1a485d9666706c7b77485d", - "packages/ui/src/amicode/context-tree-engine.test.ts": "afa3199c18c7ca05a19fdf0663a5b4d6e1fd2303e038cf25641c29e254e610f4", - "packages/ui/src/amicode/context-tree-engine.ts": "2177d01855d58c5ee7c164c2ed1dac6f4a8a5cc04daea67566f195b02ed1ca06", - "packages/ui/src/amicode/device-view.tsx": "1842053e9e25cd5c8076598449e44abf06008940a8f3f39403cbf435b1b8aa8d", - "packages/ui/src/amicode/devtools-header-alignment.test.ts": "8506411132e142d54a27e551f2dd3806166824a777dc002be6fb5477c77af5a3", - "packages/ui/src/amicode/edit-row.test.ts": "7c68fcf083d3854bfb70768b648110e001843a290dcfdc25869c1a4681445b94", - "packages/ui/src/amicode/edit-row.ts": "28d5f39470376968e7eabc3f50807a779177e9c9f2081302e4b5eb15306aef1b", - "packages/ui/src/amicode/entity-rail.tsx": "fee936650d0f05ab00e46ebb70333b2c92a57ab0da1e7fcee942d7e6b64004b7", - "packages/ui/src/amicode/entity-view.tsx": "e181575c8bd66a7cbdf89411d0cc1d12173a74a3bac9122163f2e27331e3becc", - "packages/ui/src/amicode/facets.test.ts": "e89bd4e49276f52ac0af4990b202919331a48302b4b34c1ec1d8406fa4fccabf", - "packages/ui/src/amicode/facets.ts": "074f7843a105961da3b4b89c67ea20de106968b4524f9094a5f57d1ecb0acee0", - "packages/ui/src/amicode/fixtures/formulation-migration.json": "e573355a5eeb29f1611e52f0fb716697281b16f899331fa7fb5ada9eac4e74bc", - "packages/ui/src/amicode/footer.tsx": "481c839d72fadc03cb6a5d92da52c8a36110b0ca5946481e38c3fa4eb6e72fa1", - "packages/ui/src/amicode/formulation-projection.test.ts": "bcf40f30a977268c1e0c009d94c16141d6d2957dd59abfaf8741014db7c9fc7e", - "packages/ui/src/amicode/formulation-view.tsx": "7064837eb1fd7118b49312c0697cfb0f4b96541e2c0a3f3e763441c16c64d8d5", - "packages/ui/src/amicode/frontier.test.ts": "229eb8e3f187113fcfc73f0a30f2690bab4266cb12c1c6c3802522dd7eb4af9c", - "packages/ui/src/amicode/frontier.ts": "78cd89deb26a2c6c4b8a18230012455b7aecd5f23eb007dbd0cd440b6b6ec36c", - "packages/ui/src/amicode/getting-started.tsx": "9cdb8df438521d33cf7732fd0ba64e21b4ba9d63de0c823e59d0dcd21ea90a7f", - "packages/ui/src/amicode/harmonic-dot.tsx": "e8439d64453a885aaaec76686d7984674cc53b50b86dc2dde104c0013082cf0f", - "packages/ui/src/amicode/harmonic-geometry.test.ts": "393b9dcdb9de917dc5715cc135c4ab8a221fcb69dc3cb5b269306f860e4bfe51", - "packages/ui/src/amicode/harmonic-geometry.ts": "165f1ac46050c5fdce1d54d2f52eea32c5027b385ead589ad7e214fe45bff26c", - "packages/ui/src/amicode/home-cards.tsx": "019069f82e0a29baa392b7609ce0825d0c036ce31112bbd1efd375ce1b077a9c", - "packages/ui/src/amicode/institution-lookup.ts": "3edf90b0778ea50b048975cc317a18a1aa82290cd4f5241cf9df74fd17866fe9", - "packages/ui/src/amicode/onboarding-wizard.test.ts": "268df538ea99280c5297f9b1dc06a236da2fb82830c2d49a107feca3f610279f", - "packages/ui/src/amicode/onboarding-wizard.tsx": "75db623f8f50fd875f1bde8942841fbb5167c77a34fe3c6dbfa80732841b53e8", - "packages/ui/src/amicode/problem.test.ts": "e7a15928df883fbed424744953a87ad0b5ba8a0c1039dc190ed00bfefe85eeee", - "packages/ui/src/amicode/problem.ts": "d40ca9f4f411b112d97c7d1067b5834ff22f763456df17df7fa0ad31768a3a51", - "packages/ui/src/amicode/project-type-icons.test.ts": "1db755e2818a5e97d018e7133ae329b9ce1ff63fc347a06bcac7b9f4d0784969", - "packages/ui/src/amicode/rail-gate.test.ts": "7cf0ff5add76f27eb4022224a0f18532a7bc419dd5368788e7a0667f9913dcae", - "packages/ui/src/amicode/rail-gate.ts": "c24f99d8285a5484863078acedc5ed36d8de67084c2baaf2bb2f7b6d87e657cb", - "packages/ui/src/amicode/receipt-currency.test.ts": "7b6518fc7eb1f789540ed3b7f9f761e496ab09648f22d967d2f1a260099db09a", - "packages/ui/src/amicode/receipt-currency.ts": "379c6ff09b170a0dbb85fb093ee7a334339066db83e268534918967010469876", - "packages/ui/src/amicode/receipt-runs.test.ts": "2c25968b2ba9eaa7fe70ed4cf767aae88d3db9595e01d880215514fef7a4563f", - "packages/ui/src/amicode/receipt-runs.ts": "4aa31624ea3d61ab352bfda7cd0da48f7d367f123cf7929f52f4da84629a190b", - "packages/ui/src/amicode/receipt.test.ts": "7065899d0efd4b2b712bf412053d1b3071e6aee4be163f38a3e0a7dcdbbb45fa", - "packages/ui/src/amicode/receipt.ts": "cc5e452b229b29386f474772cd27caf6a83a13862540de9035cff610ef06e929", - "packages/ui/src/amicode/run-card.test.ts": "e0b3a7c94bbdddfa1cdcc81898404bad17319862f3c3a9f47255d17db1fe75fa", - "packages/ui/src/amicode/run-card.tsx": "b074e95fd8fe8b1907d1527fa88ff85b5dd6ec2ffaa30f749969f9130e83e592", - "packages/ui/src/amicode/run-gallery.tsx": "80100e808f9e8e46bfca8daf927b1e149fafcb757cc2ab2ee5fdec3339625b9b", - "packages/ui/src/amicode/run-plot.test.ts": "64ac70e7ff5784ef6c1c224136df2a4e8a43b4187d3ac0fc4382cb0464eb2953", - "packages/ui/src/amicode/run-plot.ts": "b4bc50f279cb864f7720e56ba69b993c7a4e599a71047162173b1b93a63598ac", - "packages/ui/src/amicode/run-series.test.ts": "2e7aec7cdf7eb056efbe52d180ff316482e3010e2442611daaf4bda444c82705", - "packages/ui/src/amicode/run-series.ts": "c94496068ae05f4600b9dd9fab4247b678dae7aaba31ef48e4389b0e7fefc52c", - "packages/ui/src/amicode/run-view.tsx": "5098ef006cec0f354dde8589df1a730b5663c05300c1cf298569e62eb633f1be", - "packages/ui/src/amicode/run-window.tsx": "411abb6064ca76a1866b91914be1788f78173844f5e963562733348f92d982b4", - "packages/ui/src/amicode/shell-row.test.ts": "48ec6f0786edf81f163e350904bc2a93b1a55375b8115e688237ce8c2f1a7e64", - "packages/ui/src/amicode/shell-row.ts": "b39dc05d2b77ba6d44456248782b31f6219c891d56700203186a65ccb48319ad", - "packages/ui/src/amicode/solver-switch.test.ts": "c9cc10d657d7adf0c388e56cb6058affed5a255bdeb9b8f2fea5c02f4daff1fe", - "packages/ui/src/amicode/solver-switch.ts": "041c2ad3cfa63770cdc09ee5fb2cda0c7d09c55e7e53c83927822476716c6b92", - "packages/ui/src/amicode/solver-toggle.test.ts": "2c5ede8eff8a60f1b5e6bb4423545438ebed6d5d60306d5bdc6f557144ede5e6", - "packages/ui/src/amicode/solver-toggle.tsx": "2d3f05bed264526b439e53be9897862d1dc1098d37d530bd26606ae6da804ddc", - "packages/ui/src/amicode/spinner.tsx": "f76ae9b6a3945017b854d35ea0e6b2f4a08ca7f01e0f77236dbe1ba33d244fd7", - "packages/ui/src/amicode/splash.tsx": "4d5485f48065d2c88a3ce41cc1abd81d5b58338dfd4ae240b1c211444fc689aa", - "packages/ui/src/amicode/stage.test.ts": "b1a82d5ddf216f6e6ce09b42d0850cea3622792ac33bac5b2eaf64d850372a37", - "packages/ui/src/amicode/stage.ts": "8f9c07187ddb2ab0aeab26a6287529059a363131ba0140fcefec360f6522500b", - "packages/ui/src/amicode/system-render.test.ts": "0e1e30063445a464cf5f4db2b4b6333136b971d942606afb578b0248da8f44bd", - "packages/ui/src/amicode/system-render.ts": "8e0e5287f9a3d6b166c65e999aeb5cdc002cea566f1543c616459878aad10427", - "packages/ui/src/amicode/system-view.tsx": "42d5232e69dbf446b9039fe966e53eb579253915f22c5b161595e938b83bfea1", - "packages/ui/src/amicode/tagline.tsx": "251fe67f072f6590049f58e4174c1da90e1fc1ef8814e5d3c06ce246035d868f", - "packages/ui/src/amicode/thinking-line.stories.tsx": "3bf821de97d2b58487466c44e17bf6e46c0309ce4b563cc8e4a725f1757190d2", - "packages/ui/src/amicode/thinking-line.tsx": "d08e8525a3caf9a5c5bd954374f9219ac3b1fc5c2aae4f25412663fe7036e81f", - "packages/ui/src/amicode/thinking.test.ts": "ee926e4971e1af78d4317e90f28550b7d0be57cb7363f7b3c0d6869f10fb2167", - "packages/ui/src/amicode/thinking.ts": "ce2529285621620df168eaaa845cd2957b4fe5e61729fdfa736a8702ccf059b7", - "packages/ui/src/amicode/ui-bridge.ts": "5ed07b8e595e9650a27a32fbc72e7a076b885614ef07cf955d340578342943e2", - "packages/ui/src/amicode/upload.ts": "9a3a59541ba056a5069f5145cc10bbcc8d44caeb7cfce7a59d97415de2e4a149", - "packages/ui/src/amicode/vaults-tab.tsx": "9e93b7424f0d885250cf999a115b1801d5973f3fdb9095a5c29d74e7093af7e6", - "packages/ui/src/amicode/vaults.test.ts": "24826e6b8b083b0a7478e469f3d4fd7319c973da281cb569e3d885d83d3d46d4", - "packages/ui/src/amicode/vaults.ts": "6250b08a8d6493bd42c5407bfcb581a300757b273a587247e3666ddbe25c00af", - "packages/ui/src/amicode/wave-geometry.test.ts": "3a89a89310b8c9ce15b402ced6dec83d691bc4ccf50448f2a89e4c0ff1c80cc7", - "packages/ui/src/amicode/wave-geometry.ts": "79fcd8ce75e280f6de3fae108ae5db4b992e28a8826735a33dbbbebfa68c8f24", - "packages/ui/src/amicode/widget-allowlist.ts": "53c6554561fc694756cac154e1db5520e806dfe6dfb2ffa41ee77bafd18536fe", - "packages/ui/src/amicode/widget-bridge.test.ts": "67ef016e90aef247c16b5dea1362a549f36a5ec44faa5457357b4646d57ff110", - "packages/ui/src/amicode/widget-bridge.ts": "91f5949af16ae3d6c3e5acf3e6853518b9cf7cec19a2534c3636e30270d1e536", - "packages/ui/src/amicode/widget-config-form.tsx": "b62f99deed3abebf14e17788218e9583d277e759f01721d9c7ec9b1377b3c04d", - "packages/ui/src/amicode/widget-frame.tsx": "f4082458ecc50a43d48dc558d16dae5b4b14bf7c19500fc5807e4488ca564753", - "packages/ui/src/amicode/widget-grid.tsx": "075005dae4f54f45598a4aabe9e1cde1aa4f767a574dde3ce7e82a524f61fb7f", - "packages/ui/src/amicode/widget-preview-card.tsx": "ed022fda6f0e4838d8d8e98680ac6b77979fa8e0987becac1c0d8ad35bf22ecd", - "packages/ui/src/amicode/widget-preview.test.ts": "3ba95ada8fa9ce742a3246c52e1b1f5b4df1a9e0d8ad453f41e4468fec3b7e54", - "packages/ui/src/amicode/widget-preview.ts": "21fa605139b96f45675b11a73fa0e8e974be3444feed0f024b8003e96e44927b", - "packages/ui/src/amicode/widget-schema.test.ts": "b24049aeeda3fd2a922b5ce6601d99df9c8d3aa44b3e69dc8510a13120c7353a", - "packages/ui/src/amicode/widget-schema.ts": "e8a0efa3c86ccfae34d2a6feead87b556a2030c1a4e1bbd4b7c5839e116376a6", - "packages/ui/src/amicode/widget-tokens.test.ts": "426064638b322a421f794bedf5dbf41ad75fc30b3da6e2d02dcf6ed2f85d5f45", - "packages/ui/src/amicode/widget-tokens.ts": "397edcfa18882b2b6b6abef0a8783d72323f793e974d0bd440ca240a10b2f737", - "packages/ui/src/assets/favicon/amico.svg": "7c64b145bdd063bacd53318336a423f0654ec702de2b4e0c4a4a384694052804", - "packages/ui/src/assets/favicon/site.webmanifest": "beee758dd8811f9c76c27cbfa3801f92fc2eff537068b51c555aca4d90804550", - "packages/ui/src/components/amico-spinner.tsx": "75114d38aac924a37fee563e35375ebfd5e96cf3771690d01ad484f91df1c563", - "packages/ui/src/components/amicode-brain-ref.tsx": "e08345bdf064fccf7a0d0f7eab5b269c7eda47aad7d17b17ec91e14a613bb931", - "packages/ui/src/components/amicode-bridge.tsx": "c00ab12a45b9d092abc63a9b259e71bdf3582132aa1c288dcf8a2a520e5a5e80", - "packages/ui/src/components/amicode-card.tsx": "a09c4a734c55bf6fef0d04dcc0f0d4fce437e44a8745aa2ac2c936442d9a7d6e", - "packages/ui/src/components/amicode-connections-tab.tsx": "d184dfcd5c645332c2cc1c79356e551cd53b67a6b61ed16e78d041de5d13fafe", - "packages/ui/src/components/amicode-edit-row.tsx": "99c8c4e90ea02be21f74603c5a5ac1e2c030f487d62ce9da972c99dff505d892", - "packages/ui/src/components/amicode-entity-rail.tsx": "5377561b952d9e6bd9bd6a16cec91a37770f14195bb7bd1cd294eb20a1e78a3d", - "packages/ui/src/components/amicode-entity-view.tsx": "1ff46b6abdca65992606755e0d5e516483bbd8f3f8cef54b81cb6faa08d895dc", - "packages/ui/src/components/amicode-footer.tsx": "d7d7344613c7acbf2d4b0dd3f33c89f67fae6ac065bcea047e7dc26d13bca5a0", - "packages/ui/src/components/amicode-getting-started.tsx": "219524d12d3b7e35a3e6ac4a112c64b8a54ce1b695bb61dc4a0bcc64a7f37e2e", - "packages/ui/src/components/amicode-harmonic-dot.tsx": "3f459b3e579e5d8fc3de5562593ec4236d22878f1da59ba46b74e524559542dc", - "packages/ui/src/components/amicode-home-cards.tsx": "1551d6832131782c26e0ff0fe89d3a56777958ba764df9ff754821c412471e4a", - "packages/ui/src/components/amicode-onboarding-wizard.tsx": "9e93fc0a1ff1e4c7ce02444c27924f0073b675d07752032c37f52a4c45f94536", - "packages/ui/src/components/amicode-problem-switcher.tsx": "1dcf478871344108eb25e194f6c1a95e9977944d7f170627d46108ba3a07f1f3", - "packages/ui/src/components/amicode-rail-gate.tsx": "2850e9dda4adba54324be7e88f6fe47fdcda51507771ed2f6599b5773411ca9e", - "packages/ui/src/components/amicode-receipt-runs.tsx": "5c285c7b3bc1e164fdc24ac6f2daf1765a8b74998577b3868fe43b00adb00d26", - "packages/ui/src/components/amicode-receipt.tsx": "bd37403867623f81c8092660df10df7fb7b08e96e80271b492e03e8c36fb662e", - "packages/ui/src/components/amicode-run-card.tsx": "e9295cf59d46a71de0ee5b91c74eea3b4e42b70a9358f39a9a28c2578627f6b3", - "packages/ui/src/components/amicode-run-gallery.tsx": "366919dc8b1fc48d4aeb454bc8f92e5e23621a4570c9084a2889c88952d6f692", - "packages/ui/src/components/amicode-run-window.tsx": "5e5c623adc5d4e3fd35740e9b9cb5bae77e6f3f694850c5828f06a2616b4181f", - "packages/ui/src/components/amicode-shell-row.tsx": "0ce6525dd2cb8c1b04c7779ae477417a7776ec83768b8b028d52817e734587a9", - "packages/ui/src/components/amicode-solver-switch.tsx": "ea1e5d187fcbd505046af8c2bdcddeb7b30dd98a7d2ee9a4775e25be2c581270", - "packages/ui/src/components/amicode-solver-toggle.tsx": "b09c870bab880bfdf2557fb870fb6af13a065f90353f59d609f37a6054db858d", - "packages/ui/src/components/amicode-splash.tsx": "0f69ebdd0e4e6595f38b1492c31a28bd1320706c7f1e26411ec4d25d1ab2921f", - "packages/ui/src/components/amicode-thinking.tsx": "2734da9851aaf49f9c31929ee0092ffb19d40a945ff760fe0635c06812b04357", - "packages/ui/src/components/amicode-vaults-tab.tsx": "9ad6262db994e2ecc7d7068c95f4a31c6fbb178c531364b0dc3c8fec427a9a0c", - "packages/ui/src/components/amicode-widget-grid.tsx": "df589de093bca703e9fdbbffc6a13020e96ee0ef43e545718f91277ec0b7cd24", - "packages/ui/src/components/brain-engine.tsx": "955723ad42c6abfb785313f62277143142f1248987c45da30eadaf28d5137072", - "packages/ui/src/components/brain-ref.tsx": "c97a0ac0dad470c9b9e194d6ba94d1f1cfbb774bdbea3f798bece4a2a9968a60", - "packages/ui/src/components/context-menu.css": "7c701902c852f205a178ded4fe8c6181ba43cb4d1c42c6ad9a39ae368738aa1a", - "packages/ui/src/components/context-menu.stories.tsx": "0542961bd9db8e191e122b901519452217a410ea5339e8d3ee09a73258ba59a9", - "packages/ui/src/components/context-tree-data.tsx": "ca261e7a5eeed09130af14bb755fc2258833d2ac9efd995418cb32927de05d86", - "packages/ui/src/components/context-tree-engine.tsx": "92ca28c968cb0c1c346c1693163abd4e604287f875b1d53a434966f1c48cef97", - "packages/ui/src/components/dialog.css": "f66f34aa3488b53e2ce1ad19d697a31c3f7cead0307adabaede0d710b17c7401", - "packages/ui/src/components/dock-surface.css": "bc8945d4e19eb122078f98e5700e0b542e9e80901782ec927340a048fa0d3be1", - "packages/ui/src/components/dropdown-menu.css": "35d1e136a03fb3b59fd5801645de2870c20ecae6810488f69f01595b6abf5a3c", - "packages/ui/src/components/favicon.tsx": "809fd1d2621b0e28e69f8ac8092405b89a11fb7a6dbad2938121f7c0f2f5938d", - "packages/ui/src/components/hover-card.css": "b6cf61d45ba88cc4252923fb6fb4643659410596eaf3f7456ee5a856dd22dc8f", - "packages/ui/src/components/icon.tsx": "1d25faf5031ce28f12d3bdc4067b51377b5dc538e1b2495cc5d1983097615a04", - "packages/ui/src/components/image-preview.css": "fdb49ad0314cc89d95be7d905d9d1d50628e25cd07d536104c8b3d0ef5132beb", - "packages/ui/src/components/list.stories.tsx": "ba1302be7924b850a1ba2e8e7f3247fb10fa9a5e5f433164e56cbd1a457ab938", - "packages/ui/src/components/logo.css": "f788db461b78bbe33ca2df8d8ff92104fe5c569c7feae124b43c24a5e7e9ab86", - "packages/ui/src/components/logo.tsx": "de12f1af573c8bdee867a4c4c2ac40ba0064b5ffb0f2a0c72f89aea6446ebc63", - "packages/ui/src/components/popover.css": "cf73a22ed5fb53e6ce235126e0e7e877e611a9da87a0c982df5a8959729b82bc", - "packages/ui/src/components/resize-handle.stories.tsx": "c5624be901cbeb1c4658e65d22dae5659b2b2d4f53c93e619a8ac4d2c6611c55", - "packages/ui/src/components/select.css": "487d276d8398b94650505954f99393f8d7d2630510931206d4aee8b35131e5cc", - "packages/ui/src/components/tabs.css": "57d12ea6b52fb499ba39e6e1ae5a325fbc20b9d218b2a88fdd907e5ecf3871a9", - "packages/ui/src/components/text-field.tsx": "5ad1870d4858cc582a0cc7bc0fd1c5332b5e5c96901131639d7bc8f2a38350cf", - "packages/ui/src/components/text-reveal.stories.tsx": "393d45b149299dacac37e688dfd8f0bb2eef0294aacb700f50a9416ac6fcaaa9", - "packages/ui/src/components/text-strikethrough.stories.tsx": "5117a3b4ed59c18063720f47affcc52f210dcf769934b24ede0ef14a2cbc5c43", - "packages/ui/src/components/thinking-heading.stories.tsx": "53e63e5106f8f2dad93c5b44e0f22d2a27174a153a0666016f333fa97c2f8a92", - "packages/ui/src/components/thinking-line.tsx": "956e483aa21029161c26830544cbc2df23fb20a3f342d1618675b6f238d87709", - "packages/ui/src/components/toast.css": "60c06eda9f0ccc5641c03c002a6080db99c00d797dbdf7511c789089efc1c546", - "packages/ui/src/components/tooltip.css": "a615df9b86e64c1565384baa8054c2f80ebad11856d33f5e6f53902541eacef2", - "packages/ui/src/context/dialog.tsx": "876f8a5dc26ebb98f1f5e9e528e7d0bd7aa79c0a107b62027dd9fe78ed2cc620", - "packages/ui/src/context/marked-math.test.ts": "0fe460c09956335a469b382ff631809381875465cbcaf7e7c599f86240b0227c", - "packages/ui/src/context/marked.tsx": "b4f693cba3f8020596f860a00293e43855ec75d0bd214e379e36250d02e2be4c", - "packages/ui/src/i18n/ar.ts": "8113d320fe4a5300f1bd70150ae1695d68cb783e1c6e2be43b8a429b7dbdb711", - "packages/ui/src/i18n/br.ts": "cbde2da43ef820fe2664cb96cb973fd722156a6c8a3c5e16d18638bf014e5196", - "packages/ui/src/i18n/bs.ts": "23ea0ae34a4edaa4599b13f63f481be861e28da3b0d898987e291c7e91a9f11e", - "packages/ui/src/i18n/da.ts": "e8083f8a7ab01f73990a1eabcba817afdc663858d524e56e652ea69238cefc47", - "packages/ui/src/i18n/de.ts": "eb854fdd43f16fc2346ec43d7d1629d2714709991b3e5f7ac5ee99011324aa43", - "packages/ui/src/i18n/en.ts": "1b412a1cd0ea8f7d0ce6069d3bd94dc40778cc38c23c60191cd90071d4187ac8", - "packages/ui/src/i18n/es.ts": "a34d132adc2ad68ae3da98b6afd5070be48a0cd6cb15c4866cc7ea99deefc4ab", - "packages/ui/src/i18n/fr.ts": "4a8296dec41894e6ecb209e44564ac79c04cae73035b5447eb233cd984ef4bae", - "packages/ui/src/i18n/ja.ts": "6c13f118491c8badfac33baf449bee55779f6058792b6a54973bfe975e4c25c3", - "packages/ui/src/i18n/ko.ts": "b97f70d80c9ab7561c05ab91d461e9323c4c846d6a27bed0a41ad5fbcdf0c1db", - "packages/ui/src/i18n/no.ts": "120e5d11f5aebde00822def6fda9ae12db47cd020bdd04114cdb098d5ba67449", - "packages/ui/src/i18n/pl.ts": "8133cedc013364bf84a3902399b431f4029d6c1d57acf23f12a739127d4583e9", - "packages/ui/src/i18n/ru.ts": "11d79d60f2f678597ee2b33b51fa666f38f1e78b7ed051a686229ae0dd8aac72", - "packages/ui/src/i18n/th.ts": "afa5a46ff445461db8f069338aae760cb9cac09b370c47ced5542549c92c9235", - "packages/ui/src/i18n/tr.ts": "fac27e4bec327ff83976d9cdd8f54c2a241cb26b44c644a93c591e99f09290ed", - "packages/ui/src/i18n/uk.ts": "3531fcf92efaec359381fcc2f0cdbb644d52936a20037067451b057ef327ea1c", - "packages/ui/src/i18n/zh.ts": "6aac9e8c8973fb538effee075740035ce58a631615d39c0c8fb49375d45a56e5", - "packages/ui/src/i18n/zht.ts": "d50b7119139f53180eac64a6317341f54efc87ff76d56961a3e86ef74e3ad29b", - "packages/ui/src/solid-dnd.d.ts": "f1faf22b0773252852ff0865f68a00fa479777f5d0b4602ea4d1660c366793ff", - "packages/ui/src/styles/index.css": "2eae4e3d82e992c3d99f4a91ff25b3d6e9e514b38e9bebd232e6c41009cdc1fd", - "packages/ui/src/styles/theme.css": "0dc88bf675df5cdf08cfe0cc53c11eaf030a1bc0cf8b36cbeb3977367c2b362b", - "packages/ui/src/theme/context.tsx": "93b0b3f8a258bc8a33d4b6a4cda7016e91f6d999bd32c60a43aaaf45eadd1227", - "packages/ui/src/theme/default-themes.ts": "878f3e9cb45803dfa740890ea2240e246b05833f2d7f1345c67909c1000d8761", - "packages/ui/src/theme/themes/harmoniqs.json": "a20f6bb71df08a150a096bdd13f3aa347177f51858dba9bc9af6e25c2dcd848e", - "packages/ui/src/theme/themes/oc-2.json": "539a59886cbee9f2e54362075486d47ac69884ef8a9282f767f7cfd3f1f598a8", - "packages/ui/src/util/clipboard.ts": "218d321e1b0567b76514057ef22cfd23cb843fefc36bed7aab91f072e3233ad0", - "packages/ui/src/v2/components/badge-v2.css": "32135a9df5bad856a10138e00a2cb3ede7a6fc0cc2398797ad6bed9335d1f845", - "packages/ui/src/v2/components/dialog-v2.css": "ae6f7b1de755929ba529b9dbb0e837c80f620f00a77188b9d2c59f10b0f28bbd", - "packages/ui/src/v2/components/icon-button-v2.tsx": "966e535e3efe503f054045be4476fc20d2fad36092410b52f75e4cf8de6fce6f", - "packages/ui/src/v2/components/icon.tsx": "9f702e9c307524f79dfa9cad70f9bea32bda85672f917ffdb0871bb14cf13437", - "packages/ui/src/v2/components/menu-v2.css": "2f262a6c456a8e3cb9027f0b8b3bb3c4327794bd80cadd3cf8c16d08e6125d4d", - "packages/ui/src/v2/components/menu-v2.stories.tsx": "4ed1498d7e4cd51ce9c7459061f3540efdfae71751ff618901c78ee413951559", - "packages/ui/src/v2/components/radio-v2.css": "bf6eb3457a7fc13e48356f5a7dcf3cbf462382580250a3144a745402ff88e2e6", - "packages/ui/src/v2/components/select-v2.css": "4dd4104bee8f661c30ad08ec806e5bddec21d75be6a5d09b693dd297ea10a24c", - "packages/ui/src/v2/components/switch-v2.css": "96406f51a412f931c99c005ecd6a889898ad80160143cca0a81cacfa13714f8f", - "packages/ui/src/v2/components/toast-v2.css": "9b652d908f39e35cdf1764f1675e4db3dea1d7abf43cb792cfa2d27b699f2723", - "packages/ui/src/v2/components/tooltip-v2.css": "7cbd2523d9f183b7e24bfbc1f523c370abf8e32836f8be90cfdf75e1c70f05a9", - "packages/ui/src/v2/components/wordmark-v2.tsx": "6037a68db862ddd67235cbae8dae5a95c9f7403e7c5f268b78fdaaf013950166", - "packages/ui/src/v2/styles/theme.css": "3b6fc14460c39ed8b48c71f7527ab510282c014fc385ed6a08cae3686fd145bc" - }, - "symlinks": [ - "packages/app/public/amico.svg" - ], - "deletions": [ - "packages/app/src/components/debug-bar.tsx", - "packages/ui/src/components/text-shimmer.css", - "packages/ui/src/components/text-shimmer.stories.tsx", - "packages/ui/src/components/text-shimmer.tsx", - "packages/ui/src/v2/components/text-shimmer-v2.css", - "packages/ui/src/v2/components/text-shimmer-v2.stories.tsx", - "packages/ui/src/v2/components/text-shimmer-v2.tsx" - ], - "exceptions": [ - { - "path": "packages/app/src/components/posture-indicator-view.tsx", - "sha256": "1bd7903838926b21609c08460ff06683c6e0f378ae968e8b497de041d0f09bdd", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" + "schema": 5, + "scope": "complete fork-vs-base delta of packages/{app,ui,session-ui,schema,core,sdk,opencode}", + "fork_ref": "local/amicode", + "fork_tag": "v1.18.29-amicode.30-11-g0667bccd6d", + "fork_sha": "517921eecaa56eb9861a7b96a5bd2ee36ee42e86", + "upstream_base": "7fe993879f98aa17cecc70f70d3f40d6f0f11689", + "upstream_base_sha": "7fe993879f98aa17cecc70f70d3f40d6f0f11689", + "promoted_at": "2026-09-13T22:15:25.839Z", + "files": { + "packages/app/CONTEXT.md": "7dc4bf176a32ee578a54593a58a6b97907ffc5a9baf7ae7c16a8fa920d8e6e86", + "packages/app/docs/adr/0001-chat-first-landing.md": "d19c42a8aa56f585f92a3e0ffd072c55804ca029c6d19fb7d772c69d7e5de3be", + "packages/app/docs/adr/0002-brain-as-chat-background.md": "bda9bc065e16684e1daffdc3f7d8ac5b3c81a82de5c27fa1ba7d6268659c32c1", + "packages/app/docs/adr/0003-context-tree-top-panel.md": "693f19dd5c155b881dd35b85412ad62fef0683a6934d7cf1c59c9a679d1a8eeb", + "packages/app/docs/adr/0004-context-tree-to-side-panel.md": "271f31a677547be2e11c0c19364ae97b04a2ea353a9ab22c87bde1afab64babc", + "packages/app/docs/adr/0005-reconfigurable-titlebar-controls.md": "82c386143ca45f0fd2af3b3e1ffedb47db21e57ac9b7eede661f843eb5655a1b", + "packages/app/docs/design/agentic-surfaces.md": "94a117b2790ff0157ee01684fd49dcb32d241b3572e9df77f81f721967dc52bf", + "packages/app/e2e/regression/chrome-surfaces.spec.ts": "c7ff1b82bf84e577fee0e765b0c357c040d4d7cdefdd537702d7dbd186bfedf6", + "packages/app/e2e/regression/home-open-chat-empty-projects.spec.ts": "b0debddea5051defd859b9c8db2439801592d984fa89ddaf880494722ef2cb21", + "packages/app/e2e/regression/new-session-panel-corner.spec.ts": "df11b094012f8206117575c63fd9ac0475d14b54ea4f9d719c6b21aac04d1c4b", + "packages/app/e2e/regression/openai-browser-oauth.spec.ts": "7df4521d1d82a186e383afd9351eef64f33f2adf8a3dce86dd5915b5f4828b68", + "packages/app/e2e/regression/pane-boot-watch.spec.ts": "3aa869f8b1d9881797e14dceb9854c4408f768f490d4db8722e29e511bca1833", + "packages/app/e2e/regression/preview-baseline-contract.spec.ts": "78c23b9e52496a779ee10aabf5bfad6900afb9b905d82ddedfa954031ce633f5", + "packages/app/e2e/regression/project-picker-recent-search.spec.ts": "64f4249f29cfce29d5e755a544c5aa2f27599d9fd874d363628f696f5f0e02b9", + "packages/app/e2e/regression/review-line-comment.spec.ts": "953e9c67ed4cee91968369088237cf2288558eaa55e55b61f385571bccad7003", + "packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts": "00bfd4f6199c1b350d14a9eda5e3a4c546b020df32e3604609326281869d6d4f", + "packages/app/e2e/regression/session-timeline-tool-projection.spec.ts": "c0bb866b113d38ddec084e04027030cf5b7c81f1fe4e6ee88fcd7b1b161296c3", + "packages/app/e2e/regression/tab-dblclick-close.spec.ts": "7bf9490c2f39281c7751c39747bb720ec1b5571d7b7ddc803686071aa8ad55aa", + "packages/app/e2e/regression/tab-navigate-mousedown.spec.ts": "8521d43183f0df624449edbba8ee4dc646f0ecb84a9c5a04d275613f9da875ae", + "packages/app/e2e/regression/workbench-drops.spec.ts": "0188f4f1ff07a40945a4900bfa85e21a4f578be9f18257a803200a18ce41ac05", + "packages/app/e2e/regression/workbench-panes.spec.ts": "e0dfb84bd1b8be00a89cf48387aeaab5ec75845e8efbc8e4fa8252204fb27e8f", + "packages/app/e2e/smoke/session-timeline.spec.ts": "4006274a5001e36502e16b11ef7b9caee5dfdad2280766380470c72118b7fd90", + "packages/app/e2e/utils/pdf-fixture.ts": "86c6c0d11a3c78180133d9e0cd7b87ba4c639f34ccf50a417429e23f80042b87", + "packages/app/e2e/utils/text-selection.ts": "bb4ada9ee7faa07eb792c5550d244dfef31c089a944d0411a5749eb9a74ba859", + "packages/app/e2e/utils/waits.ts": "53959eeae1e6562a2e6c578b261140c74fe9fc30e1e4c46295d3252b6d274a74", + "packages/app/index.html": "fa38026be3b7e7ec38958a558d7b4d059140b2aff998c3ac862601543702584d", + "packages/app/package.json": "3c9bf3d487052d4834b7fd3ce93fcf6b7fc358de92b8be4b0e84fc424a971f74", + "packages/app/playwright.config.ts": "b7dae0b39248b4ddf7cba829af96ac7fe3cc919add9711ecb5292d9bd52e1805", + "packages/app/public/amico.svg": "a14b9d543d895bcdf0758f7b9ef5908ee0acaac794446494af059b159247db8f", + "packages/app/public/assets/Aero-Regular.ttf": "0ebf14f80d05c3a82c766124ab31196c310014744333d397425ac82a1e3537c4", + "packages/app/public/assets/DMSans-Variable.woff2": "aa530716b0d351866af7dbfa3eee4120fb36f2d071baff8c234185141865c7ff", + "packages/app/public/assets/JuliaMono-Regular.woff2": "43f5dfca02a03035f89799da5af150f28d5c4aff729753076094c687fc61b063", + "packages/app/public/assets/RacingSansOne-Regular.woff2": "2ff92c8abe7a35962922c54da215d68690f8502463698b1b595bed597b63e3ff", + "packages/app/public/oc-theme-preload.js": "27227e802b3494e7c545da903e679efdb30ccc754cd4eb5cdf08005a40d560b6", + "packages/app/src/amicode/inspector/device-inspector.tsx": "5ab63709e88176bb4dad1072ffe28fd59ad67d414c9d844ee6c55353df50df79", + "packages/app/src/amicode/inspector/inspector-bridge.ts": "460dbf4509b4e56a8eacd6cac7adcb3a63c6cd3e417d851df5f3e3b259095d3e", + "packages/app/src/amicode/inspector/inspector-context.tsx": "ac81b9e0e2a4035f85b6af68b7f0cefcb9f256a175b244ba13136f3a307c0c77", + "packages/app/src/amicode/inspector/run-inspector.tsx": "63a6351fad12a8377550eb87f7602a712bae586fe482ff46cd847c8544fc6e8a", + "packages/app/src/app-desktop-commands.test.ts": "1d2057f238dc14e4407ff5c4e53afe091784790bc0fd0dbfde0eacd91e2bd968", + "packages/app/src/app.tsx": "c32eae50e48492404aa2057f37fc0ce229e24640d26ce9a81c3b64066483f62f", + "packages/app/src/components/amicode-default-model-value.ts": "416bb4a7cf051c678bdfc5246ddc5796a9a6efe48d1e5c2e933756800cfdae8d", + "packages/app/src/components/amicode-default-model.test.ts": "941750d074706bd5f4e433c9737b19ebc0ac0f9ba9cd1faaa599a24b22126e05", + "packages/app/src/components/amicode-default-model.tsx": "16a2de1feb12e07416fe5fbb25879391f912ee0909b553c868c1b531f2ed1f2d", + "packages/app/src/components/amicode-defaults-capsule.tsx": "94dc081bc47abb7e50566fcd8e9e53124f9d7632d61f93eff4f1627e0c2efb2d", + "packages/app/src/components/amicode-file-ref-bridge.tsx": "11c17d7fdb29d16530e188b13ee8af728f37d9adfbb518084106ce50cc0c527a", + "packages/app/src/components/connection-banner.tsx": "c793966e1f9d6f307af697032b235c2ff65afaa04f6cc232e40ce45e5745ded4", + "packages/app/src/components/dialog-command-palette-v2.css": "85984957adaf15efcc0828310f3a0b438cedaaba776a9fec2eddb3ad83487fa2", + "packages/app/src/components/dialog-command-palette-v2.tsx": "e12da3e5e9e503089dd9139b20e04f6b566cf74fa445f23a2e193f5883f7c5f3", + "packages/app/src/components/dialog-connect-provider-harmoniqs.test.ts": "7c16914afe3e77ad09691bbfa8223981eda0c2faf3616ed6db2e4e5fa9ce9fdd", + "packages/app/src/components/dialog-connect-provider-harmoniqs.ts": "2f070abc5d0274ed1403f963ae0cb0af6e0f635f3732414d757d1b7ba06ea313", + "packages/app/src/components/dialog-connect-provider.tsx": "6f23cb5edda411c12606659109c3943f0cd218b9bcba29310f4ea3cda4eea98c", + "packages/app/src/components/dialog-edit-project-v2.tsx": "f34aaed28604facd9d8a46a4934e2b331421d5f60902a2b160ddcec11af03bd9", + "packages/app/src/components/dialog-edit-project.tsx": "5371da3de3a643d4347629af55c0adc2476bffe7b2f061535a92fd67e756e562", + "packages/app/src/components/dialog-new-project.tsx": "102fc33e8eeaf3c76ddd1b953b7b97995d30c02a3579f8b7036e47448a1582a8", + "packages/app/src/components/dialog-release-notes.tsx": "0ea5b049786787643a7f6b54d4ccf84c4f8ffa4e8272426c0d32f60d445b6890", + "packages/app/src/components/dialog-select-directory-v2.css": "2e2f18abdca77f9fe85da157c40f288f3b1641ca92845208749e16455fd58637", + "packages/app/src/components/dialog-select-file.tsx": "e6278ee35dd27d203e00ad73f70c709c44a6c06f81ffbd931edfaa0c986b9e03", + "packages/app/src/components/external-link.tsx": "7130044026ad3ec417de4ba7389cc6059de46f21b370047046269c772aa7a4bb", + "packages/app/src/components/help-button.tsx": "780d533f776a784660cfed072a131198bc6fcc8e8fe332e8e1a220d516c9684e", + "packages/app/src/components/pane-bridge.tsx": "756b3306b51c963fac6778716f6c6c4626f0f3bf75c93b7cb4cab58ea0bf3d4e", + "packages/app/src/components/profile-popover.tsx": "eff742e90544455f13234a9351bb1b82189663cba2cd3172bdcea1a8a37284e8", + "packages/app/src/components/prompt-input-clipboard-structure.test.ts": "946b718c2164da394602f26e4d9919d752da0d0b9bee714f345ba16c274542da", + "packages/app/src/components/prompt-input-v2.tsx": "5f15ed441bc267cbdf9ef211bced384d7d9bb3c0b2fffb6a1020b34584a4f5ce", + "packages/app/src/components/prompt-input.tsx": "1bc71d585a5ada2caf6d190d702dcabbfb56642e740a08ad6aedf078809b60e5", + "packages/app/src/components/prompt-input/attachments.ts": "c3c28df0d2f18378d39e17147a4c64e8ea01d63b97c39e1874ed9445ca671bb1", + "packages/app/src/components/prompt-input/clipboard-bridge.test.ts": "15f76dca1a25d024128718e4099220b79ca029263410aab55502cf9caf9b2914", + "packages/app/src/components/prompt-input/clipboard-bridge.ts": "4b5a1edf59d4c85268d6ff72aa9f9d66f82d4fdb887121fb978c09caf4c5be65", + "packages/app/src/components/prompt-input/context-items.tsx": "027b02e394ccd14849052bf3fcacdae1e090c71d164fa8955addfe3f7abf1758", + "packages/app/src/components/prompt-input/image-attachments.tsx": "30cdea4285884b4c257670b57ade4266f5861e8a303d3355a591f302ed4bf965", + "packages/app/src/components/prompt-input/placeholder.test.ts": "d3cee5e2c758faf5fda626e270adad81129622bbc2bf2c335c2bffe1544165c3", + "packages/app/src/components/prompt-input/placeholder.ts": "6b2af23a0588e7970cd0dd059fc60c3671c907a76ba3db660483a932f1dce79d", + "packages/app/src/components/prompt-input/slash-popover.tsx": "a1800173edebcd419802796470f7270acaf0ef689a72f1b81a1cedfd8968337d", + "packages/app/src/components/prompt-input/submit.ts": "c00dc83e3e45d589963b38ea7b9ad8c437fb229a9b4dfa67abcf74e537e09724", + "packages/app/src/components/prompt-project-selector.tsx": "0157c954b938bce2b5aca9a82f4a72338e361f4c9027e55a7fd5a14a1654d294", + "packages/app/src/components/report-bug-button.css": "909809b6241d53c386aa4c8ea34539ba162a8998fff755834c783025bc53a5fd", + "packages/app/src/components/report-bug-button.stories.tsx": "82aed22bd3fcca448841205dee759ca0f0de92562a99d07c696eee5bd29e807b", + "packages/app/src/components/report-bug-button.tsx": "a1beb8c94b4faaa4c7db3ab68de349f8a8a03cb3a058ce447f552aed35848d43", + "packages/app/src/components/session-context-usage.tsx": "cd25a9af91c73d0cb53000261e066dc16385e1a3ea13e92392fd3a5ca7b33032", + "packages/app/src/components/session/context-warning-banner.tsx": "f5fab4d7a9536238b70d64488fc30d44f6a4948fdcffd910a9666f4b6c296019", + "packages/app/src/components/session/index.ts": "21473290d4a1a3d0670fd878372ddf21ff22d4a0b30d1aef6c81ea906c1488b4", + "packages/app/src/components/session/panel-menu.tsx": "42f323046b7375ae158023a51506038eb15f2e1545c407f45acd47446a8ef3e0", + "packages/app/src/components/session/pdf-canvas-view.tsx": "89a2c67262d16f262a185bf9c20a44038c6e97abb72c8206d12e720efa4ec6bb", + "packages/app/src/components/session/preview-file-view.tsx": "7dad448cf6a166ede82b8908efd028eeb649139b59c7b996780c3f61c6a860ee", + "packages/app/src/components/session/session-chats-dropdown.test.ts": "2003d2a15781337ea6bff2c68e730cc5b6df38697f15d927ab26913936444db7", + "packages/app/src/components/session/session-context-tab.tsx": "227243b178b517f067d9ae0ae0eec3c559beeb6681828158b0600a17e98e7f81", + "packages/app/src/components/session/session-header.tsx": "a46591ed1097d0fdcff61fb0c5529396955e8857cbef748747c51e472d5564c5", + "packages/app/src/components/session/session-new-view.tsx": "9510a4f550a3f0d4791e98e8025666f09d70a60fb66f193e48ee61feddae5a57", + "packages/app/src/components/session/session-preview-tab.tsx": "8c17771e40a0385b394ea0ea1a6034f475b6f9ca1a348604b6ef507595017d9c", + "packages/app/src/components/session/session-preview-tabs.test.ts": "773fc0116c5f61302eaa4a09fd5f91e6b26dee978c89e29c21714243ae3a5653", + "packages/app/src/components/session/session-preview-tabs.ts": "672d147a6f1f46a7ac2eff7aff9da6cc069c476ff918e5ff4aed3a997310e6fe", + "packages/app/src/components/session/session-preview-tree.test.ts": "6d1677caa56ec89fa5fcc8fc2f26fdcc1bc0a23217ce9c6d92888b272523c00a", + "packages/app/src/components/session/session-preview-tree.ts": "13930fcd8a8ae9df4c37ba9ea306e162fd08f0e429249ddea21d937675d3ad7e", + "packages/app/src/components/session/session-sortable-tab.tsx": "a015277347fe679ac1afa1372202de49fc98a0930ac10682c8897f70a0300909", + "packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx": "08db0e378c3e07d243121f40c77e153bafe897e5e2ececd48a3e00786793032b", + "packages/app/src/components/session/use-context-warning.ts": "af7a6d0159a5541aa02ad4d08fd694af1cc4853fc1c0a70763bc264a634d1c53", + "packages/app/src/components/session/vscode-explorer-file-icon.test.tsx": "f1d38aaf0ca1cbffe696d054bbb422aa94cb56387393e014bec3ba6e79b5037f", + "packages/app/src/components/session/vscode-explorer-file-icon.tsx": "b5ba0cafe61594dd2afe45ef6e070e512861162933c85e9545db2ec697d50f17", + "packages/app/src/components/settings-dialog.tsx": "da3bc01dad4ece4214c14083ae4e7dea87ef64ef9829b315b867fdafccdb6916", + "packages/app/src/components/settings-providers.tsx": "c86c9bf4a6f6e198dc7b0995a69d5b76e851144987bbe601802b1b0120ee4ac4", + "packages/app/src/components/settings-v2/data-storage-controller.ts": "fa5d143cc101f3a3b9d5ad445edddc981e0d02783021d52dbfed6c8d8bf62498", + "packages/app/src/components/settings-v2/data-storage.tsx": "a56b423b32c952c4379688d88d13a9f43b163a4169b9393f8c35b18a763a1180", + "packages/app/src/components/settings-v2/developer-tools-controller.ts": "8888e7da23d0e092c531c706470edb7ae410aef1aa8f3067729b3f7dfec5f48d", + "packages/app/src/components/settings-v2/developer-tools-rebuild-flags.test.ts": "4d11815fe5acfa930bc418d0be82602f03821997300d0deef0aa2da2a743b3b0", + "packages/app/src/components/settings-v2/developer-tools-rebuild-flags.ts": "561a75fa456b832d4af6f782c7ecf5269ce768fc2adc59c15a79197a2dde84c0", + "packages/app/src/components/settings-v2/developer-tools-request-state.test.ts": "29711b3bc17fddbb8d046e104bc78e775a9ec7c5aa0ee2e181fbcd8b2b5e2135", + "packages/app/src/components/settings-v2/developer-tools-request-state.ts": "e9678ed32e7c2562b18143f39a51c0a94dbf0a0884d056653c6c77e4cd07a9bd", + "packages/app/src/components/settings-v2/developer-tools.tsx": "ee2d586cfa1202f5fc253b502dd8752256166192541e7addab6bb5da18d1d0f5", + "packages/app/src/components/settings-v2/dialog-settings-v2.tsx": "a1e1fb7eea7bbad7708b97a721b54a4897c8cb6f582b71d6bb7c8ca7f44930db", + "packages/app/src/components/settings-v2/general.tsx": "2abf6c9c7b4b9bf020ed224dbc7fff4574db47711956fc08e1b8e84e781d395a", + "packages/app/src/components/settings-v2/permission-scope-relocation.test.ts": "39539c4fc4b7433f08b913100f48a7fa75d6ab47615ba697aa9ae8eee09d316b", + "packages/app/src/components/settings-v2/permissions.tsx": "5746c8ef02da833ff72fee1375dab2a7ee241bb111e8ef15b21ae70c49349543", + "packages/app/src/components/settings-v2/providers.tsx": "e15f23a40058abb4299ad7444df2845e3c24b5da3ca58a731e0cbafe58de2a76", + "packages/app/src/components/settings-v2/settings-v2.css": "38818ab5349cf637023379d2b1ee62081d456676020bdb445576865327858162", + "packages/app/src/components/settings-v2/skills-controller.ts": "2c7344d144da0eec1c25083ead45f5afb2a8c6fd759541ad719cae9a09fcd19b", + "packages/app/src/components/settings-v2/skills.tsx": "42deb0c11fcba158abad857b9644ffb551aed5ba9e00dbfd1584a7ffaaba5aa0", + "packages/app/src/components/solver-switch-banner.tsx": "ec7edeec6dc05a4a06b39241b4f3a8e7534da97722dd8ec6f26ff782025802e9", + "packages/app/src/components/split-frame.tsx": "44c53737f72027b461097c03df48a4f411d04a82d02b1fce4901813c73dfcc72", + "packages/app/src/components/status-popover-body.tsx": "a78d557256283fd05657d999b2a6babc0bcb5ae3dcfa2cb07f770ebb602a94a1", + "packages/app/src/components/status-popover-indicator.test.ts": "9afc7b49d9021a94d74f3f777178230ae13bd26e5749da0cee4d3378eacacacd", + "packages/app/src/components/status-popover-indicator.ts": "887b3e659ff49fd0d2a8715fad6562dc7e9402b80d06442058502306bdb108f5", + "packages/app/src/components/status-popover-model.test.ts": "10634035bab0f31de24564e0d6c8413a0f7434fb2c08ac3ef722981a69dd08e7", + "packages/app/src/components/status-popover-model.ts": "ec5a5a3caf9344fe617c7bc668af81d96ad4290378c34186cd4cd959821f1c85", + "packages/app/src/components/status-popover.tsx": "663b3ab44218780b3415120c42d89a2a410ba0054231e8fdd0887a97a1b75b23", + "packages/app/src/components/terminal.tsx": "2ce242034ae129c1f475c7a24fdec3facdd9bb1f49ba8c6b503643b07ae241e5", + "packages/app/src/components/titlebar-channel.test.ts": "184238871c46f586dcc21081f710e37a77914c983fccf250665c7317212e41d8", + "packages/app/src/components/titlebar-channel.ts": "385ace91d3c69c92f5b442bf15d2040e35df855f1d4ece47312c1ff8e1b01780", + "packages/app/src/components/titlebar-layout.test.ts": "52912f37fab4e7d0d5b7403371060651597f4c4904fefb802ff9e3333facdeed", + "packages/app/src/components/titlebar-layout.ts": "a375c238ab632421a6505dce3a41fd3894865729e921e68eb32249478c18a286", + "packages/app/src/components/titlebar-tab-nav.css": "90930c2f9476fb0eace8692424a029b3510781c88d1ee61f7f2edba559526832", + "packages/app/src/components/titlebar-tab-nav.tsx": "2304e936af56c24f27f1549f4f8751a600ed274123d7a3973ecfa6a5bb28102c", + "packages/app/src/components/titlebar-tab-popover.css": "d731db2d7d49838004089a3d82ff68c22214b0ca636bf3b8e02498c14dadbf8d", + "packages/app/src/components/titlebar-tab-strip.tsx": "932a2d01e6673d283a48d704b580f7a7b88ba000061d11f6df5efe994dbd4ee3", + "packages/app/src/components/titlebar.css": "50c262603ba1140db9e4fefe8f03e9c6ae3bf64dc7a917e55586bfd67a5e3011", + "packages/app/src/components/titlebar.tsx": "c53f438701e97cbe3fbf2eaa67fb584a0b8b3a91f2d4f8016542156e17cd598c", + "packages/app/src/components/ui/drawer.tsx": "76574ca4c6997209f37a766a61000d707332a9a857f6ea8100a3cee1be58d65c", + "packages/app/src/components/vault-browser-model.test.ts": "7ca11eae3574033d58081bc4126b1ec772a5b496573c70159f05497a1365f4cd", + "packages/app/src/components/vault-browser-model.ts": "d9ef6ff588a96ae79b13c3ae0c2a442a42b59021dd501b3a17bd810dda6f7b20", + "packages/app/src/components/vault-browser.tsx": "509efa874d69bcd07ef2495a025bc8de2b2fa582736003ff709b4ca76096274b", + "packages/app/src/components/vault-panel.tsx": "1d9f06f42b94ffb94a28bfd6d2693a36c75ceb969bcd434081b4cd2fbf99665c", + "packages/app/src/components/windows-app-menu.tsx": "460669a129e9be61ab2d5f51fe6ecad73579a395295d5f724f235b988cdc667e", + "packages/app/src/components/workbench-panel.tsx": "d16f477044098842a214a2e16f9be719e7688a04bcb575889ca544988f23c690", + "packages/app/src/context/command.tsx": "388d6cb12b6dc43ecb0827e3fb918370cb9d16d96161a5990dec10fff05af172", + "packages/app/src/context/directory-sync.ts": "a3921044097f3fbcfb20eaec500f24344f12a43e137417c86f15d39dcc6e4b2b", + "packages/app/src/context/global-sync/bootstrap.test.ts": "149c0241b378b6ce837aef45e1ba257dbfed88de37c70affa13f513e9c72338d", + "packages/app/src/context/global-sync/child-store.ts": "b13a513c93b8fec7b656593d842e9cfa30f346a0911dc0f516783ccc5fa4c07d", + "packages/app/src/context/global-sync/event-reducer.test.ts": "600cd7654854b910f25c61b20d8ae69f043f52ed544e6bf9be5ee9e5bbd6c96e", + "packages/app/src/context/global-sync/event-reducer.ts": "667fbae1259f6deed77573edd2b742beee4f825b4306b6d861670443e381a55f", + "packages/app/src/context/global-sync/session-cache.test.ts": "c66d790c6336794b2b1d707e2739fe0992ccad7ed3b96187b124b5c783ef332a", + "packages/app/src/context/global-sync/session-cache.ts": "1849408caba0f114809f37153e7d531bf2776572433880a96c5ebd31d7b30aa3", + "packages/app/src/context/global-sync/types.ts": "901c9bd1fda63dab676d33dc1a8582a29f8ee00aa20458e843aed5f93414fa84", + "packages/app/src/context/language.tsx": "cb545e04c128bf981b2b72ac407f9220cf9e80337fe8c87482ffe85407e0cf9a", + "packages/app/src/context/layout-side-panel-tabs.test.ts": "47425bbed0ada18d3fcb67a76b63de3b9e1f827cd63a61ffe4eb45430fc5814e", + "packages/app/src/context/layout-side-panel-tabs.ts": "e8426fadbdf9e7c49bf457e00ec92793475b44bcc11548e8b5ef9a9fa461be76", + "packages/app/src/context/layout-tabs.test.ts": "4d9fdbe963306f164b2f48eac3b6a28c5a703c1758bf14b2cc4796720d8fa72c", + "packages/app/src/context/layout-tabs.ts": "741506ce165f68cdb0b8f2931a2dad3e26c05880f9286c3daf04ec979bac21c5", + "packages/app/src/context/layout.tsx": "7767c8b5f64efd63390cbe99128686bec2f1da7e8f2b21530df4c3fd67d171bb", + "packages/app/src/context/local-agent.test.ts": "a5a9d60bb4401d409218cc247c1cc06ede8b7878ddf01dc6080328f54eb9cade", + "packages/app/src/context/local-agent.ts": "0aab67e695dc3bb45a733ac0df80a0a5e14cfe29b2375b6dc3cd07fbccea33e2", + "packages/app/src/context/local.tsx": "3ab8b9fc2db082df4ba485373679f00a95d0ffe3c691a0afee1dc53db7eabd9e", + "packages/app/src/context/models.tsx": "8904525767b36ed5ba93e85a0fddb9bf737a8d066dfff084380ce1a67182f535", + "packages/app/src/context/platform.tsx": "edd9b1773feb5c084b922a57b6914f6a473eed558b44f9de0eeb1c4d4e2b49da", + "packages/app/src/context/server-sdk.test.ts": "5cd22962c8ea1e4374915508a765281ceb9f808ad8bbf241c06b00b48621c816", + "packages/app/src/context/server-sdk.tsx": "b3450d9bdafde6ed1a95d7dc970fc9f33bef81531b05245c36b789878d09d186", + "packages/app/src/context/server-session.ts": "a9e1f089ad328a705848d11ba25e890c5e374bb3a33066ffe67b6f09bd48ed16", + "packages/app/src/context/server-sync.tsx": "43154ffe6227203d778378d190af3c46d7f49098619721fea5e6263e8794dc84", + "packages/app/src/context/server.tsx": "08e978e4b4b3094221a2a0b92e069f39cbedb6d6cf95935881e21cde52265ee2", + "packages/app/src/context/settings.tsx": "53025fbfbd7eb641cdb0e7c49e21ced3617050f4f98ee45c745affdd8ab17b48", + "packages/app/src/context/split.tsx": "891aeb290b369b327a63ce548dcaab1daca08e41fab430648787be7f84e53ec0", + "packages/app/src/context/tabs.tsx": "eb494b5785defdd3a4901874be355ba8ddd7bab4c009359b558c413f9ee63ffa", + "packages/app/src/context/vault-panel.ts": "f91cb5fb49a9f0d46bd2a1b131f9a218b30147e2ad3617d2a2dc4f1e14599a53", + "packages/app/src/context/workbench.tsx": "69a44da2b69989bd2c67ebffdb49941841f3f4718d6a70d659c828b57928d9eb", + "packages/app/src/context/zoom-keybind.test.ts": "a1385c93639687a7dac7d21f8f02841d82a55e42465ce3836b97b16c82b52469", + "packages/app/src/design-polish.css": "6b860316d2d57a4a9a89c1ff2772de45eca0d0cef2bd3e2ea8572d817e1d1910", + "packages/app/src/desktop-menu.ts": "55481604f4fd5dcb74b0678347076c42fda7f928590d90bc2c3d1633bea8bc36", + "packages/app/src/entry.tsx": "f35e1017f4c9d478d254b2a38043e5750064b6bef25169c3e07ae9f72ff1049c", + "packages/app/src/i18n/ar.ts": "b4f9ca56ed157c34f6248bc053f09c1ce565159a30eb971570c77884b780e686", + "packages/app/src/i18n/br.ts": "1bef54ba8796b2c94ff6e6b1c40f924a130f203da919b096c1ea6d363ee28e50", + "packages/app/src/i18n/bs.ts": "1317264cf4bd5f6ae1fb0636209c6f169978eb62685ea3c1f7ab80c34c3bf499", + "packages/app/src/i18n/da.ts": "dea807e84b8cc7f9410dd492682523f51966bc79d0f8f47fbc83afd47cad52ea", + "packages/app/src/i18n/de.ts": "fa9a91f52895e4dc421847595bf2ed0a8e88d4ca8afd7c50c4fcb063979f3512", + "packages/app/src/i18n/en.ts": "da4fde0a74423baca743182041a4028e6b18650e01b6dc8d5b81974d75e7ace2", + "packages/app/src/i18n/es.ts": "d16b85c3b53558f74dbbc16866c253102920438c4df5488a7b1ff9ba431f733a", + "packages/app/src/i18n/fr.ts": "9f6871fe2556b6ef864a84a285d95793a242f92c94b8b6a8f3774cb045aea929", + "packages/app/src/i18n/ja.ts": "46f8392f5de380a3212afd73d879837a6e1c70b986188de7ee6c1fd3ae7dca96", + "packages/app/src/i18n/ko.ts": "fdc97342c447915cbf5d6387c07d4c445c53f54d4bb669f876d7344876ca8bd4", + "packages/app/src/i18n/no.ts": "6e1a75c32e3ea0d7576da0255316a8ab450e1e3d963db3d5b92d25c55971b987", + "packages/app/src/i18n/pl.ts": "cbbdb0bd13405da313bba396a91356500bcc95d3a68f68060689773200b49442", + "packages/app/src/i18n/rebuild-label-rename.test.ts": "c9ad20e491a5c9c6b8f6d56858271988e827398afe8b7cbe333e5f970fe76142", + "packages/app/src/i18n/ru.ts": "43f38453f2192102dace0690bce8b81a60e376bfa44f62133cb99ae55a392125", + "packages/app/src/i18n/th.ts": "527fd9de237b2397063c3ee39de62856d9c174af4b62afc48b53f266cd2ab533", + "packages/app/src/i18n/tr.ts": "08f8794e6858898ec0dcdd8b0c9ae7dae218ef3f0878354b1b0f1282c3727877", + "packages/app/src/i18n/uk.ts": "7b534484e8abd0f3efcd0447efa414cdf7c2694c59e614767477d5578c570d8c", + "packages/app/src/i18n/zh.ts": "d31d243ecaf762b747a67354c7f929317fd340cf6896b6cbd2b402e55ca0bf9a", + "packages/app/src/i18n/zht.ts": "e21b1f58be6482bcd3121861b3ed6620acc8878ae1729fdff2b05cce92eedac4", + "packages/app/src/index.css": "2c11df3dcebb381358e06626094b5dda3c35688ad7940d643b2cbb6cff1ea9e9", + "packages/app/src/pages/error.tsx": "db9ba0847cfb205100ad6133cce30c6ea2ce983802af44947e6d2b746c2a6ec5", + "packages/app/src/pages/home-projects.test.ts": "a90155c37210a0e5b7a095bbfc3ba2d40681f02927d9726148a706bed5ba7891", + "packages/app/src/pages/home-projects.ts": "d55124578dc839b98e2084b488d818e30e4a1abf1ae264499b83e403c2aabca7", + "packages/app/src/pages/home-session-archive.test.ts": "e8f1126287a3e9daa455efcc378e5d72aebdd092158bf8526f7779669b72e850", + "packages/app/src/pages/home-session-archive.ts": "1b56c173f37f4a4dfd54088ef5fdb0dbcd3d9b62aeb08de4bfa0ed34f07d7ad5", + "packages/app/src/pages/home.tsx": "06fb5c7718aacfd29b35e730e05d45076b39d6cd5d936d1270fb1bd9424c32fa", + "packages/app/src/pages/home/home-projects-view.tsx": "074f1cdd7926db9574164824666cd63f1f5bd0f8e8dfb65453f6fe8f2dca0ec8", + "packages/app/src/pages/home/home-sessions-view.tsx": "5b73b18e4349a628a15e09a3810ecf2319bde222e18fe8de5d08373ac91fb37c", + "packages/app/src/pages/layout-new.tsx": "3ef477634cb6d7de0c32d3572c5ff699e07efff47e6e75458583456eb1ff8b27", + "packages/app/src/pages/layout.tsx": "eaf8bed869b5ec53582db732119fb903b223d749ebda354b1e388de3be02dc52", + "packages/app/src/pages/layout/helpers.test.ts": "3a77cfe018ce2867cccded2c726f556e53a9895a77baa944a4878714b9b2b59e", + "packages/app/src/pages/layout/helpers.ts": "ba476894857aefd2172e3d31fa1aaf52ca030183d3fbf180050bd3b10fe4b524", + "packages/app/src/pages/layout/notification-toasts.test.ts": "6a95bd3dccb03be894b5d2adb4bc1f7531a9ec704e4d0eae1eba4ec89bbc9846", + "packages/app/src/pages/layout/notification-toasts.ts": "11256e25f2bcc20d3520e81aa50b53db2a7f8dea8047b17e99deb1f9f061e43d", + "packages/app/src/pages/layout/project-avatar-state.ts": "7aadb235d27dc45799411c724f0fd1282af82d091cbcefb0344deb7c5d0659d4", + "packages/app/src/pages/layout/session-tab-avatar.tsx": "89e83e239d513f91b31f16473be531eaf82768cefe637ea5f10d752cea4ef887", + "packages/app/src/pages/layout/session-tab-status.test.ts": "d6e62365948450c0acda628bc5d03233e5e6ead69649c2d2fb7e20c906007e74", + "packages/app/src/pages/layout/session-tab-status.tsx": "0960d24e581e5cdd38d1bea5e745039542e5ab5268f5540cf8fa87d84717922b", + "packages/app/src/pages/layout/sidebar-items.tsx": "daf940fc66f34e5f83410a8580f7bb1790bedc599ab4d64fcda2301537b24865", + "packages/app/src/pages/layout/sidebar-workspace.tsx": "a0f8e3fbd16d09e783db2a7a09c686d3aa993436d882425d3436a59ec4adf94b", + "packages/app/src/pages/layout/worktree-auto-rename.test.ts": "fb6fac363b8bee1225bbcff8098019c02f19b095b5cd96c29f7e673acb1e4e89", + "packages/app/src/pages/layout/worktree-auto-rename.ts": "2ef3e506b96b972cb55799a89aa54ca6453fc31c80bc022aa16db6ecfe9cdced", + "packages/app/src/pages/new-session-landing.test.ts": "c0f47e4096e6a20fa59dac2b10f7285d3ef45e9289bf6f0ad75c1d9e4dd1117f", + "packages/app/src/pages/new-session-landing.ts": "528d27cd5d441b521674328fb7812fb2acf77233e9e436d081c98ce611e8b268", + "packages/app/src/pages/new-session.tsx": "c060bbb15569b6da2f67146e6af0879ccb5444345df03dbc2f9b39cb98b9db78", + "packages/app/src/pages/new-session/new-session-draft-controller.ts": "3607771a22b6855afd0b0d666de662c9070a2dcd56ae96ba51d89c9e11018e81", + "packages/app/src/pages/new-session/new-session-view.test.ts": "615110d1a956bb2321ca77c998d6f5da434756d166ee61cf71ca232cc9efb0c4", + "packages/app/src/pages/new-session/new-session-view.tsx": "30b0b048f88ce741215e642b0760758638ad36696d2eb8770bc8e6b8b8f3fc29", + "packages/app/src/pages/session.tsx": "8f4375e9f2682cb36fd7b68a57e677252c4b2c8a30dd476265122847249329b1", + "packages/app/src/pages/session/amicode-session-relay.integration.test.ts": "4991e775d3a6c63a514072ccfa5aad190c586383b77ef41689c853fb271d3bf4", + "packages/app/src/pages/session/composer/bug-dock-controller.test.ts": "fe3d68f2f2bb41b04ee5567cd95a9c01671a98fd21585788be9d4cbb01a4bc22", + "packages/app/src/pages/session/composer/bug-dock-controller.ts": "ab2c72a761e1992f300b6a0cecc9d0351b00a56e4be08567bcb22d3fcece78f7", + "packages/app/src/pages/session/composer/bug-dock.ts": "11eb1a1c911df8764162d47f07e5f135d94fcb622f8a2ad9b41a23233131ba58", + "packages/app/src/pages/session/composer/report-bug.test.ts": "d4dc012309c2171298852501a14a077c6fe8cdf5d25538dc84ddd1f8195d3a8c", + "packages/app/src/pages/session/composer/report-bug.ts": "bdc3b3dec38b11c7bfa5b867a246db2717e60e1d50692d6bddb3983c9e95e02b", + "packages/app/src/pages/session/composer/session-bug-dock.stories.tsx": "a5730bb3699751d63629134924ce8dea021b264722c40f5f6bb98236dc15eda7", + "packages/app/src/pages/session/composer/session-bug-dock.tsx": "e7fed3c5ab80527d69a106440833f795bbbafc5deeba3883902ede9fba612605", + "packages/app/src/pages/session/composer/session-composer-controls.ts": "7ba9d56c81b1547acbdd47c4f9371ddc37c9a92059f5785f7286fc68e0cb4483", + "packages/app/src/pages/session/composer/session-composer-region-controller.ts": "979d2e28d9734581f88e7cb3e0a51c8a8c204f81e644f7a3b5766f60ddf88938", + "packages/app/src/pages/session/composer/session-composer-region.tsx": "415cd5c3a77b625a3142b828b6458687e1a35b382d3a208d90ff1555cc7098b1", + "packages/app/src/pages/session/composer/session-composer-state.ts": "fcffa11d801309cf58f42a174143bf6eb3ea2b14f860ad91a8ffa4e097df5c16", + "packages/app/src/pages/session/composer/session-question-dock.helpers.test.ts": "a1fe31fe4dfdf2914bc184030a0427bcbdfae0f3e7b146e1d6ee29ce31d85b64", + "packages/app/src/pages/session/composer/session-question-dock.helpers.ts": "b16282d0cf5d39152bd76f4ef8bac32f964f68143a3067765ae0827a5f90deed", + "packages/app/src/pages/session/composer/session-question-dock.tsx": "44c0814284ef4a5273c8034b8d1f5cd45306406d04e2f4f6646000facae47d7e", + "packages/app/src/pages/session/composer/session-revert-dock.stories.tsx": "0310ce448c1f8feaf4732e66429654fe3602d470f3121835cf6435084c455c36", + "packages/app/src/pages/session/composer/session-revert-dock.tsx": "3f2d030126a4c673731bac65406fd48797464ddc515444b891e39b0eb538e002", + "packages/app/src/pages/session/composer/session-tour.test.ts": "147473505d54466417b6b34fa672d280b71e1b9577e8bd41fbf9870035d1083e", + "packages/app/src/pages/session/composer/session-tour.tsx": "da5d807c7efe7aed1140d65d7eddd7982a8c17348d928f5d0a887d1b2a8d3a50", + "packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx": "70a8267c725af320d78d266b85fd0ff005d067c4d09a21bef824126602e831e7", + "packages/app/src/pages/session/helpers.test.ts": "09fd272c286c7746db5ce635e1c453c8943e46111d030b4892af9145a89401db", + "packages/app/src/pages/session/helpers.ts": "0311f52b7cc34c2c38950512c01397e9672c89a9e61fdfa0e4696192da114f34", + "packages/app/src/pages/session/review-tab.tsx": "3c90e6b11fad40ea19a258966c374ee12c05bd0e7891fcea561ba0b965ddc9f5", + "packages/app/src/pages/session/session-panel-width.test.ts": "9482afba7fbce254cbbd21ef885e9e9620b981616681635376f466478f611155", + "packages/app/src/pages/session/session-panel-width.ts": "02ee3a02ed78db2eac47c2528055cf78aef95f389641e929ddc56c17471dcbe2", + "packages/app/src/pages/session/session-side-panel-structure.test.ts": "b2d1d007d9200d0ac4a0889e45c2dbe57a324a10cb26ae9ab8f420d3c890402b", + "packages/app/src/pages/session/session-side-panel.tsx": "c3f3fb553be21dcbde98c389a09c66582bddbcaa94ce303d80f8e5158cd3dbda", + "packages/app/src/pages/session/terminal-panel-v2.tsx": "68dad9307f1d2abf3ff9248e451bd08005acf01ddc46b30a6d01b58f4a90dce0", + "packages/app/src/pages/session/timeline/last-prompt-bubble.test.ts": "83753b3ec7227570523c2e0b9e82401fae7a20f3a23980bb40deaeb13304327b", + "packages/app/src/pages/session/timeline/message-timeline.tsx": "718264c48becae24f8c55b0ef61684a26a9a12762edad9526c0b8caf9f6b097f", + "packages/app/src/pages/session/timeline/model-pure.ts": "50be4ba12d747dd8df9932044ceee29c5f3b6fa6d6ac36791207f91a91067cd4", + "packages/app/src/pages/session/timeline/model.test.ts": "459e0694409ffcf2530252a65491e1006f982b8f5c78a15573ed41646b2c85cf", + "packages/app/src/pages/session/timeline/model.ts": "76cbb00ef94133db33b69851ae8eb5cc974b5f2414551cb48ba7b61f3cfa025e", + "packages/app/src/pages/session/timeline/projection.test.ts": "68655f29c382640fc281780166aa528ea26d28d953f3376e1e062be7a0e13749", + "packages/app/src/pages/session/timeline/projection.ts": "36ab006523de7b695b33d26a0a03b59db9e148b7e979c36f63970cbcb8bcaca2", + "packages/app/src/pages/session/timeline/rows-current.test.ts": "b6a2d9671cfba970990b36d9ef0d1f107efcee59f0a9863f1280526116299095", + "packages/app/src/pages/session/timeline/rows.ts": "68581190ff5e51d2dc398298c705fbb5dfdefb7eb4cecf98f1da6ae0bd171f18", + "packages/app/src/pages/session/timeline/smooth-scroll.test.ts": "79d3bba42ad83c3ab80df907e0acf08665a38c4809468e6c12ac9fcf5e94682f", + "packages/app/src/pages/session/timeline/smooth-scroll.ts": "a7c16860aa68917b74f5c5c46d239e9a5d7a9a952233407e2ed856b534059828", + "packages/app/src/pages/session/timeline/thought-rail-pure.ts": "886c10b0de61b0ab64baf8a284758dab8154f279fd9cd509b7b1d8ecc155ad02", + "packages/app/src/pages/session/timeline/thought-rail.test.ts": "21960365e57d61de047440c386a18a06607bca74554e89881ef53cb7c00c4519", + "packages/app/src/pages/session/timeline/thought-rail.tsx": "d42be90ccb75c2efef3a3a2718763165a10336d08f8d48f8b33ba7dbb696128f", + "packages/app/src/pages/session/timeline/timeline-row.ts": "91576b8ba89a2882881bf4e8a0019431cb118a487e1160810e0c51bf23cbccf7", + "packages/app/src/pages/session/timeline/travelling-dot.test.ts": "c32a66e0d188d84d6b9693f35f29efb3ff1b2ecf30077f8250782fbf563d19b8", + "packages/app/src/pages/session/use-amicode-commands.test.ts": "65671d054c404edd2b799b0f6591a9c055e6ecb454a674fa0bd9a7fa6f68e111", + "packages/app/src/pages/session/use-amicode-commands.tsx": "88bfdad9ae6dfd920b8e6a14ffebd2cf9e52b8f67bb9284cb358ad940643ca67", + "packages/app/src/pages/session/use-composer-commands.test.ts": "cc970bec6b208786987a4179e86b63ece1031c71c00d65bcba8fb08e2a5d2237", + "packages/app/src/pages/session/use-composer-commands.tsx": "4a8c20f706385071bfddefa245cc71a84459d0a38da9aaa6896aa101f4de5c3d", + "packages/app/src/pages/session/use-session-commands.tsx": "7af9a112ae60415572ab7c9b5d4e73b2f8ed9115858c695be675ffdf07c3df2b", + "packages/app/src/pages/session/v2/accumulate-diffs.test.ts": "289ef80e26c9e85d3121d3705cefd467d147d4872410fce7309d9b7a382020fa", + "packages/app/src/pages/session/v2/accumulate-diffs.ts": "a4d5ee94b31db8def04d4b1e5efc909a8c5e0e14368af0e37414e98d4d819936", + "packages/app/src/pages/session/v2/review-panel-v2-state.test.ts": "ac0cf1939c164948d9a0c54cc15076b30413612d872237e0fbd0912804c1ced0", + "packages/app/src/pages/session/v2/review-panel-v2-state.ts": "e27c3aa236d2862e3cbd87128c4e03e6d810974faaaadb12a7e04cdd3b531e1c", + "packages/app/src/pages/session/v2/review-panel-v2.tsx": "a3cd899538a738d0236ecbe9e292928ff14e48d3646f2b045dc25880bc7f3ee3", + "packages/app/src/theme-preload.test.ts": "d9e4e96dd39a3491493637682611bedf6ddf4b6e4dbdddcb60bf006211b137a1", + "packages/app/src/utils/amicode-bridge.ts": "5104a04c7822f80dc0c564619e7dd2d850ba50035dbc86ea875604ecd97df05f", + "packages/app/src/utils/amicode-bug-report.test.ts": "b1bbf49230ff3aa6d1a43ffa9165ba5a84ca4ee18a6d49f52ee5cd887c3e6444", + "packages/app/src/utils/amicode-bug-report.ts": "d55d9cecfe17719c0d4a0ca498345c7eff6fca1de6b645e4bc3fecb40f2f4645", + "packages/app/src/utils/amicode-developer.ts": "b5cecd598b7e50631d2a441d7c72d1a012a2a77bdee3629fcfe9400a36312ad6", + "packages/app/src/utils/amicode-fetch.ts": "ec62b502e6b8688cef0a2aa249715e847032265fd0e150d73ab3021a63db0e33", + "packages/app/src/utils/amicode-hidden-project.test.ts": "333ce7e13a2940268448db06fcfc8bf1733110b5311932820ade1dc9ab573180", + "packages/app/src/utils/amicode-hidden-project.ts": "d845a80ecad2d497528a5071f55cffab72e7b451f16d106cdb594f5bbd62c0ee", + "packages/app/src/utils/amicode-pane.ts": "46c18a2dc47c5db154f70272d25031e6834539ad03f6ab25613f082426f7c642", + "packages/app/src/utils/amicode-route-info.ts": "a0268a223e8de09fae9d4de8bee6a7774c14c87c6254cb4ed1d921db18587f44", + "packages/app/src/utils/amicode-session-relay.test.ts": "6723b5da04b30564e913883f1324e84ce92ed6028e0b02ef122bd3a7d54b2b3c", + "packages/app/src/utils/amicode-session-relay.ts": "b718d3285594e15ab563a556fa1cea75f280150cb271fc57f308e4ee577c43f8", + "packages/app/src/utils/amicode-workspace-projects.test.ts": "8b5c32172e2039b3d9c52f2257023263fc846132e7c185e4a63ae014bc2e2bfb", + "packages/app/src/utils/amicode-workspace-projects.ts": "cbe091c463177375c93cb43676c202bd7bf06baf36fdec779f7d641558ff6bee", + "packages/app/src/utils/chrome-dropdown.ts": "f8b878c5df4e1afd96b0751c73daaad0a8127411030724cb8f9a5089ebb29eac", + "packages/app/src/utils/global-clipboard.test.ts": "18ac0ea486d36eed00597f2718f03bffce70a6e6a8f77c79aefe0795790d8771", + "packages/app/src/utils/global-clipboard.ts": "b26373289d7402c88e8038575703b11fa5e4ef5a7f50ee05bceb45488022ab26", + "packages/app/src/utils/pane-bridge.ts": "a8a8a40dc60a367086f3c4e4c561a289fb85d8b2086a8d62c2b66102de652ce4", + "packages/app/src/utils/project-type-helpers.test.ts": "602ed23d5719729d1e3b5241a155857775a7a855897a87986964e83fc1b249ec", + "packages/app/src/utils/project-type-helpers.ts": "5b9eb86b6fa271186e49d380249f7dce13879106a2e68a503aeaacee2f7d6ba0", + "packages/app/src/utils/provider-disconnect.test.ts": "809971964ed28564d379dce2e590bd4727f45eb597e46234c28d25dd2485df26", + "packages/app/src/utils/provider-disconnect.ts": "209c9b44970cfa3cd150cc20bf7bff34b773b148739e3d6beb314969b6bb1bbc", + "packages/app/src/utils/serialize-session.test.ts": "f8fe318f195dca251eae3f4899f4a5881c3523522f59e02fef208588391f4048", + "packages/app/src/utils/serialize-session.ts": "c303c678500cdb64c7aa6928a0bd984c441a36705fe8152368a0e575cbcb459f", + "packages/app/src/utils/server-compat.ts": "01413e13b87485770eb3dbec0b882aec4c8247dafc4dc74b7b4669fa5b20cf1a", + "packages/app/src/utils/start-prompt.ts": "809d8ad0ab6de76a97503f8368ade25f771431be3f92eb8f039a2c65244ab20f", + "packages/app/src/utils/vscode-explorer-icon-theme.test.ts": "351deb0ff77e62d2585858105aaf34ab621298511798fcb626abee97bd644fe6", + "packages/app/src/utils/vscode-explorer-icon-theme.ts": "0d700027004f4a08265682e19364bd931313d0658b3d75d7874397b407ade2ab", + "packages/app/src/utils/web-zoom.test.ts": "f373618138add504faa44dd6d2c9e3489b6e8dd0093ac6bb4f00f55307864e3d", + "packages/app/src/utils/web-zoom.ts": "d5119a07e9fc61880b7294fadd23801933d99a9d3dbd0fadcafed1f786bd7d7a", + "packages/app/src/utils/webview-context-menu.ts": "876b532fc9c00156f722d6424c28476f34b2db1bd0bc3cff3c9866152600e7c3", + "packages/app/src/wsl/dialog-add-server.tsx": "a80a19cfc3590539026a11846d56e0d3cf7eb4ed7360dedab71412da58827247", + "packages/app/src/wsl/dialog-add-wsl-server.css": "a9c2f13e8823fe51989bec945ed1e36274eb0ad363f55cd91714fc91ca4d91de", + "packages/app/src/wsl/settings-model.test.ts": "3304797c2779ca573f44eb25b758b67d66b2d7897432252375606680021390c3", + "packages/app/src/wsl/settings-model.ts": "35481fe3029714becf30b07024e0f849438c99c369a41b437b5208e48095cbf4", + "packages/app/src/wsl/settings.tsx": "1d6bb448f5f7e574ddd2efb2fdb0b6cdafb7a2ca4af9bdd210f2f58da9d9b984", + "packages/app/test-browser/keybind-migration.test.ts": "192418880d432ff62d15fd80f6250ece6233e43d0dbe11d5a4fbb5f4d9e45a06", + "packages/core/schema.json": "79ef4e2f0dd8103ac7a4b6ff3ddb0fd10764655f1dc678c1c401dfc43be9a1aa", + "packages/core/src/config.ts": "0b6b81bea6a3a09285daa4bd70757e6bbe93cf2508121e1062b71bb24654d692", + "packages/core/src/database/database.ts": "9406173aa6cac6acd1c3ec306ae71942e12c8e2d68b7cd3d58a9a094539bc32f", + "packages/core/src/database/migration.gen.ts": "689da2c4e571629ba207420c8f31f604c653059ef1b3846683c46d02f1c02c12", + "packages/core/src/database/migration/20260813162312_shocking_karnak.ts": "f4e901f79e3f660b3809e336599a5ba7da7794ff595e6accf6218739c046ab68", + "packages/core/src/database/migration/20260820000001_add_session_directories.ts": "bd8ab86f36281b8ccd6d02a6971b81a0a1e877544fac68f969a9a16b559f3f91", + "packages/core/src/database/migration/20260828201050_normal_stryfe.ts": "cbf63b27785b76d64d83e4c7fea341278c736985a6e21e4bd6cc816360a84154", + "packages/core/src/database/schema.gen.ts": "784fadc53281588f15edebef7a6362d025ed3fa15f7b86b6451f1cf27292f0f0", + "packages/core/src/filesystem/watcher.ts": "8600768eb5250fd9e26e4404e4f18c2b823c452bf967da8e4c5085347c918c65", + "packages/core/src/flag/flag.ts": "3cefd0a4d803268910d265a27bf24ed8ca354ab28449380c6f1cbd7708a8d4b5", + "packages/core/src/location-mutation.ts": "5fa852c48e98cec513346f848b422c2d5d6d4b753b39da851c73be073a03511a", + "packages/core/src/location.ts": "16325cfecf6c83bd4e653a0f1313d78172a31fb93cd28672f180053ae4719aef", + "packages/core/src/models-dev.ts": "dbbbe33f470e219d5fdaa6ec8e4998be95356e80756f29c18e3656562523923c", + "packages/core/src/observability/otlp.ts": "be20b97f84b2a5b4a1663fa3bed0b31c6c387950f7c28b76fbaa8525cd24d6e8", + "packages/core/src/permission.ts": "8c46b08adc9edd6bbfb90481b592ea6f00c40743d1ea0ee6a8b2e185dfd2de66", + "packages/core/src/permission/provider-saved.ts": "029f02a7120fde4ca1d499294f73f22ca8f0dbaba030a901f94093fb36674025", + "packages/core/src/permission/sql.ts": "c8c44e00cf957511282e35cbb192c0be36ed33d41d6b15e98d79eab4378661cd", + "packages/core/src/provider-permission.ts": "a672c1f40fa2efb0cd8923b0b7827b6debe770308bcaef692ad8589ba9b40685", + "packages/core/src/session.ts": "9b0942acb81373bd177ec544eaba74815369c0be55ad35c76a48b7676f2ce315", + "packages/core/src/session/runner/llm.ts": "e1c9da5f568cab64ebd49a467bff8e11a685306240b3faf672127663f1b02444", + "packages/core/src/session/sql.ts": "30267b6bd6f291051942cc1cc870267c073d6866f5dfd984fd7e9777e4c38c0e", + "packages/core/src/system-context/builtins.ts": "c5cba75156723c9f8e670c9ab578e95d0be6f81808000d6f0b854eb883a7c1a3", + "packages/core/src/tool/bash.ts": "4b56de5f3f7ad3ddbcf1ba756caff49f0a65f0fbc73811cbfc312ea716e0e447", + "packages/core/src/tool/edit.ts": "b1bd6df76da2c04681aef1c0d6e90e16e929b2c1ed09f6367a2bb9c655dc1d68", + "packages/core/src/tool/glob.ts": "3da75d862c37d35aafadf6d54b5d7ef3a61eefae049ac8c3ffe9cadfec818006", + "packages/core/src/tool/grep.ts": "db323a91b27727abcee372bf5403f322458ce456c9b581d4f905ab241bea6dd6", + "packages/core/src/tool/question.ts": "9b32d02d3d8e18adaeb86a2b344fff0a21fff1955fcacf91b4c79f93c93fd28f", + "packages/core/src/tool/read.ts": "ceb37f787cc78a9973dec7c0f8c5fd647baeac979619741d0ff15167e13c6f29", + "packages/core/src/tool/webfetch.ts": "904846f51dbee2579a36c4856efbfe1442d4ce6a31d6a280cc387c390fd22bef", + "packages/core/src/tool/websearch.ts": "bd0502eeb9d6deeea975a21a592040b5b48abd6f2613e39dd6cfbd1a959c950a", + "packages/core/src/tool/write.ts": "4759d89e4b6cd5fa7d7de4ba091d2bf859d830cb15038828a15751c80fd9b0ec", + "packages/core/src/v1/config/config.ts": "6eece12da68ac65a2c8b2fe19b1f2509f397cb63d004dca3998cf6dcc772293e", + "packages/core/src/v1/config/migrate.ts": "6c960e1245db9a4bb830f0c1ebd6174e50570b4282d4ce5d7bff3333277abcf4", + "packages/core/src/v1/session.ts": "53714b7754a3adecbed4e28d511f5c1ef97ae2fa379e3a07cc68714e1de8469e", + "packages/core/test/filesystem/watcher.test.ts": "ade83f34270bc33c0a8cfd91766d5400a29927818f9b7f33e364bc26132ef7d9", + "packages/core/test/fixture/location.ts": "8e93d87c20305911dc4583ab1717766b1f70eed3e687dac040ad2c646c25ceea", + "packages/core/test/location-mutation.test.ts": "2c4c8faa220cc8fabfe12d57bd74ec8dd8aac8485d0ecafd2761cdee1806d6b0", + "packages/core/test/system-context/builtins.test.ts": "2331a35ab10b3e69f5f5d2dd462ec56000246a747bccec77db783144a91ebbea", + "packages/core/test/tool-question.test.ts": "4df41393f15104a1d3a9c3d06e30cef515108490b41fcf4d9a7d9399fd4ed945", + "packages/opencode/package.json": "01d9338ee64108d0bd6af80b971fa2da4c7bf63e7efae59cc97cd58a9cfce55c", + "packages/opencode/pasqal-live-test.mjs": "2ff0edf222ce29660ef8d901c0b6f10951943ef01824d2d264339f8d720206f1", + "packages/opencode/pasqal-live-test.sh": "0bb0089eb413956f0252939f933a139c2f11520466887ad91fcae362f1698e41", + "packages/opencode/script/build.ts": "876e7d569aa71ce060c1d4b24c96e9bf13245cbf4ca743828d645560a95aa641", + "packages/opencode/script/httpapi-exercise.ts": "772bd2cf5748ca90c5d5790c2d044237518cc8ede0411fc4ba28b9d7440ba28c", + "packages/opencode/src/agent/agent.ts": "512372a4c62997e9565266638ada19b9dc0a3685b0c0483fd28fede2abdb5c9b", + "packages/opencode/src/cli/cmd/run/footer.question.tsx": "c9a1b335c9c7d8446d15c58c8808ea857f8f238c8a4047121f49599296922f39", + "packages/opencode/src/cli/cmd/run/question.shared.ts": "f4b8ab69c18e66d3efea505f3d2c8c5476bba78d46b0f30bc52da4386b19e478", + "packages/opencode/src/mcp/browser.ts": "ecdda42cbd55a97b8d14050aa15c6e6450a1d63b0a641c8c8e5b81e50f957c87", + "packages/opencode/src/plugin/openai/codex.ts": "7f4342ee6a25eca6b66a47732a154449fbf318f6ce70ed446cf3e6788833954b", + "packages/opencode/src/project/instance-context.ts": "65a35792e50e96a50ea14cd9f928045c0e2fc15eb49506f5bbceee38c4af1457", + "packages/opencode/src/project/instance-store.ts": "c22d3e2499e63dd8d9395d58189df75444d306774df833e746f22e327edcf2ab", + "packages/opencode/src/provider/auth.ts": "b0ab1322c1039e27176bf9e3500603eae27506065ac141a69710220f3361f6b8", + "packages/opencode/src/provider/provider.ts": "671f6d8de83f919ddaa69b8240cacd82e2b8202ab505d4334175f2858bbd8c32", + "packages/opencode/src/server/amicode/connections.ts": "4498adc8a1ba0d81f92a2a23cc36641597b738bb0ac81d658bd21e10c35e39fc", + "packages/opencode/src/server/amicode/credentials.ts": "f3a15c82496f9a3b6e8c1006a6a4ab419a02156e9a93a43c6c2319632c30063f", + "packages/opencode/src/server/amicode/dashboard.ts": "031a4f40bfdc847984a1deecfefbe0fd27f42cbd1caf8823dc43c7eb5bcb9af0", + "packages/opencode/src/server/amicode/file-resolve.ts": "3f0548fc97aad431d3f7707fd0b911e66fb4fd68ac4f643da71a2f00a73beffe", + "packages/opencode/src/server/amicode/library.ts": "36013b19f7c57afaa1bab63e5ff34d79f09ec42640e2a8c4a40cb14c97c4b859", + "packages/opencode/src/server/amicode/pasqal-secret.ts": "a0b53498bb7415c96e14b435367ffa93bd3d298fe12f7584cd401e649312fd69", + "packages/opencode/src/server/amicode/problems.ts": "d56513cff90193ab436dcca379f065a4ce963eeb45c22178cf9a0151b49c9487", + "packages/opencode/src/server/amicode/profile.ts": "521338a7990deb8d0f352ed96d0f0a96fd56daeeec407c3ae133b02dfb2ed5c1", + "packages/opencode/src/server/amicode/project.ts": "7f0a8a15aea0ef367a00ab31ba4329ecf2344282965afce553005b5355be63c3", + "packages/opencode/src/server/amicode/run-terminal.ts": "c6857036c1dca90e8b462e916f49df707757f227d0ed74f072b8e94d08d74cd0", + "packages/opencode/src/server/amicode/toml-lite.ts": "0001fb071c53c1a3ab330e40550ccfba497b78e2a0cc45084e1c016d8f215831", + "packages/opencode/src/server/amicode/vault-browser.ts": "8a8252fb0b46583c75e9475d7c89e68c092f5255b21476f3c3d0b9d379ea2d48", + "packages/opencode/src/server/amicode/vaults.ts": "e48c90c64de27abe24a510f188def6b56297d9bb1fa1ae08cbcc94888d42044a", + "packages/opencode/src/server/amicode/warrants.ts": "13ef47a676245d577617f6e5af2c8a2beb3102346d2dbb43076159f3f43c01a7", + "packages/opencode/src/server/amicode/widget-frame-html.ts": "3df10eeeccbb81d2b163195ceaa1d5abc24e90506471ff6d6b2a5fc40e52db52", + "packages/opencode/src/server/amicode/widget-manifest.ts": "5753daf16ef4c1e74c97d4a515b30d123f7afbfee29bb07381c6f10ecc14cebf", + "packages/opencode/src/server/amicode/widget-runtime.ts": "a5fe95eba46df87c4b4c54bc07bb91587b73e88eb90db889bc87358ece4b3f27", + "packages/opencode/src/server/amicode/widgets-src/jump-back-in.ts": "a82bf11004b71c7ac6e0357c45a0d7532aad4ee6af16e048ae86ef9bf3799fef", + "packages/opencode/src/server/amicode/widgets.ts": "d15481086c41b365c28937f002bfcdeb8c2a9f68066413da695fbac8b7acdb61", + "packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts": "944a0aee215a917e867fd9482f3c2bd40f49082bd3174c8a7d967ca40e34ec15", + "packages/opencode/src/server/routes/instance/httpapi/groups/file.ts": "ed165131c62eeb29375db39edf89db8f87488e24ef99fc6f2cf19705ba35751a", + "packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts": "34c6f1ab1a085d1b047c220bbff32a36032dc5e924784e9272cda166cf0ec84b", + "packages/opencode/src/server/routes/instance/httpapi/groups/session.ts": "1421f8c07948b121c7e2005bd9b0fcd6b2c456565ddd1da32d8e6c35d03fac9c", + "packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts": "69ca3dd48d95157fc822e1f76eb42ac873df50f22616b85194619ca658613867", + "packages/opencode/src/server/routes/instance/httpapi/handlers/file.ts": "10bcb79b117beebee04184fb48c1ad789e782e2f7ae4b0c68603edc00f03aee9", + "packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts": "8baf16cad0992c5351b61b0c0fb27903bb25b17e1b25fc7c5d77f807c24413a6", + "packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts": "b37ff4136c4aea85b23083bf441f03e09820e3e4cdd95e4118ca570d8435b94f", + "packages/opencode/src/server/routes/instance/httpapi/server.ts": "85c200797fed41c0cd08e7aa699ce13aeb8a3d23aa2b9eddc4d72e72b8b5082c", + "packages/opencode/src/server/server.ts": "56b3c2047917aa80d1dfb29bfa9839bcc2ad7f5a6f4db12103cd962a98fba866", + "packages/opencode/src/server/shared/public-ui.ts": "a843b4e84673d9a5e34f36eb7cffbb499850f7588154c23061fc8a81cd1369ef", + "packages/opencode/src/server/shared/ui.ts": "eba93fdd47c786d723d2593e788f6b7278b072548acb916d19eeb2e9616a4197", + "packages/opencode/src/server/shared/workspace-routing.ts": "3704b6cf218fc165ce9c1cdad0ee42fc9cf604976e4a552478200f85db80876a", + "packages/opencode/src/session/compaction.ts": "fd6159a8b04050706b6968c7a1b091f79d06e6e4aa988a12629a7616b8128e94", + "packages/opencode/src/session/external-diff.ts": "8f40051b3791551d3811045e4060884266687ec2208465ea2cc116aad939f819", + "packages/opencode/src/session/instruction.ts": "19640d02c96b8ec764edd49b0ce74879432fd2d2cbb4d2ad0076caa200dd4797", + "packages/opencode/src/session/llm/request.ts": "248db5d00c4513fa7101b4631950ed39fe8fe6de8228c2f527c57ca72e0b55f0", + "packages/opencode/src/session/message-v2.ts": "7c5bcf4f68ffd8b5e7f637b7a7550dd154d79e69c8939e4a172446ea2cce2240", + "packages/opencode/src/session/prompt.ts": "65f53031ee84f8e16e6295b5c8aaf9f63f9411f30799a4323f53e2c19eebe05a", + "packages/opencode/src/session/prompt/anthropic.txt": "e3e1a55159f0104ceec69098620eb281cd8927cfa808ab5feaa753719af27f05", + "packages/opencode/src/session/prompt/communicating.txt": "e14e1daf86eb4fa2fc1222cc941145913d540827bde3d27ebfe0fe30181f3e97", + "packages/opencode/src/session/prompt/default.txt": "bfb0d6ab93fb82a8edad591101bd84839565a0fb401770ceb0045b1fd3b081bc", + "packages/opencode/src/session/prompt/gemini.txt": "d24815ea833b058b304d95d3212ad2e091bc07064a22a6af9401872cdc3871a9", + "packages/opencode/src/session/prose-guard.ts": "dd6f8dfdc41b9cad3406ac586db9a60f7ee0a040b41550d6c55da2d040dc7c13", + "packages/opencode/src/session/session.ts": "260a27d72fb53b11c272987a921d3c2099b1e009afb943106336d7f190752c62", + "packages/opencode/src/session/summary.ts": "09f546db362a992156bdb4901cce58e495bd38bab6ba41b4386cca77bebab7f3", + "packages/opencode/src/session/system.ts": "c91d00de07d6d4e3910561d59a598579eeafb725583a9d6475a158abdd4a17c4", + "packages/opencode/src/session/turn-output.ts": "889624ca54a8149d35f200c7efa732771dfca36984e8a322a9781b1a25434762", + "packages/opencode/src/snapshot/index.ts": "4d76a78c48597bda2379e2c3396f4a53828b21c6ce03e1975d2911150822c6de", + "packages/opencode/src/tool/apply_patch.ts": "37535a783d115ac2032def7a28cce56e304f4e7c75d3ecac05b9a37054ae5b4f", + "packages/opencode/src/tool/edit.ts": "38aa4ce0751ff99bbb0807bcda52f8b9a1d32b6e342df4cc2aedab1f03d342b1", + "packages/opencode/src/tool/question.txt": "49bbecb33a825620c2ed14ec9b61faa294359c3673c33277e32f57c1070d2806", + "packages/opencode/src/tool/registry.ts": "2b0e8546f01643e78b9dee504357bfc33f2d7075ec45f8a1462d8c3ee8e7aff5", + "packages/opencode/src/tool/truncate.ts": "92c59d83c4a660116d6ecc48e900aeb16bde93962bfae9f520193fda18273379", + "packages/opencode/src/tool/widget-author.ts": "912be8636b162adca8796a501e927019c2449393c14bb5f3ff478b02083b73a9", + "packages/opencode/src/tool/widget-author.txt": "a2572913debbbbd2d4a644dcdf4576accbc7efdcc8217c0fc9f5a011e7a15ec4", + "packages/opencode/src/tool/write.ts": "094661a3bdd3fab2cd439c0b6cb942b6a2653d3e9451420523b33acbc762d1a7", + "packages/opencode/src/worktree/index.ts": "a86f542b579ef40f2940d36e2c8011ce5592d4811cd5ed437bafe614789fb87e", + "packages/opencode/test/amicode-release-workflow.test.ts": "f6dfcb3ed9c572ca8e8b21ff82e038872b635b25c68f9580f6d6f51ee2813189", + "packages/opencode/test/cli/run/question.shared.test.ts": "fbb3bdb20fae7d77f0e54444847c658c721b132feca9ad939a963721d2ddd772", + "packages/opencode/test/cli/run/run-process.test.ts": "13e6386bf1919688cff2f6f9f68bcddcfbbec822ef8fc271ee68347a542827b8", + "packages/opencode/test/event-manifest.test.ts": "e2f1542c3ee8e981934044bb14cb87a58a676f3b6eb5d160f6e854f136ba445c", + "packages/opencode/test/fixture/fixture.ts": "357bdaa06c6233a91069db20cc5f1cbb2d6eafa3bc7ba3e89b019859d195d6ef", + "packages/opencode/test/lib/cli-process.ts": "110c43d247930e834ffffb9068682c5ab2e1b95460ec1ac3d0a75cafbdee60ff", + "packages/opencode/test/preload.ts": "5a3c7e7a8341dc735513b0cbeac6029ee406ad64767a1b883bdcb3e99269dd7e", + "packages/opencode/test/project/worktree-rename.test.ts": "3ec168c9f8595249b75832895a251483ec1f3641ce44ad0bd5a664b5bbd6dad1", + "packages/opencode/test/provider/harmoniqs-no-tools.test.ts": "ac455d754c1a61791fa45b18db5322ec2d472ff71778fbed1d412ec749b4b7b9", + "packages/opencode/test/provider/provider.test.ts": "5b2cbed8994d3bbc968a72d01459460c1de72b6117a0795c2bc6a10abbf02926", + "packages/opencode/test/server/amicode-connections-routes.test.ts": "2852289427fadaf6133b556af02f7e7b369b2a4df53ababc39531fe85bcc9d17", + "packages/opencode/test/server/amicode-connections.test.ts": "0d916321a42e321d44e0db13a6966985deaf77cea48470d11eb8b434a464b7cd", + "packages/opencode/test/server/amicode-credentials.test.ts": "ba77d064fd2be799930524510ce6e32c6f6a0d144d3cdf41673a8283dbe95bf6", + "packages/opencode/test/server/amicode-dashboard.test.ts": "e25b284b9eb434da7f07dfa8b72b7919a0cd1ffaed275a6725d9cd44cd1298c0", + "packages/opencode/test/server/amicode-file-resolve.test.ts": "39db84780125c8fd4551137e4f6a0ea6b0a9dce45b04e26ed15f649efe251311", + "packages/opencode/test/server/amicode-library.test.ts": "87b986c43390e1f94d6bcded0bb5d22be24beaab2c336773bb438ed1fc6a2d95", + "packages/opencode/test/server/amicode-problems.test.ts": "4a8a9011f3796df4d6cde9999b86b507a8126fdc9138cc3ba305f930968c3392", + "packages/opencode/test/server/amicode-profile.test.ts": "5e5dcfd2b3db5cb8d7aba2cf1f74ed2d76716af6e4f761f54b94e77174b314de", + "packages/opencode/test/server/amicode-project.test.ts": "18991a015b5b8fd5c25b7f9d875d7ff8fbb28fe8b8df02bde390420be9189841", + "packages/opencode/test/server/amicode-toml-lite.test.ts": "3c10b68cde693e27cbb6520f7d40c283d78c5ce30ca6e47871072b6db59600fa", + "packages/opencode/test/server/amicode-vault-browser.test.ts": "03347a6a9b6ba250b7a1150449cbe44b8817dbc0ebc433c89a703f4818492a5a", + "packages/opencode/test/server/amicode-vaults.test.ts": "3f7c8ecfdc250ff360c0ed66d9cc6354d9069e66001281b3f6e30981b9f71c35", + "packages/opencode/test/server/amicode-warrants.test.ts": "a7ad74da87f77f4488f334debf8c126671d563839891eb3a19b3d1a134dbc504", + "packages/opencode/test/server/amicode-widget-frame.test.ts": "c96818aadd94711a2f435d98fe9fcabd95bf4202d695899956c6e74d90c6c531", + "packages/opencode/test/server/amicode-widget-manifest.test.ts": "ac404d1737bdde8ea3464cf0b5fa12f0a6f9e630a0698ca5fdec38449cb66d0f", + "packages/opencode/test/server/amicode-widgets-src.test.ts": "fa95521084f95e0c421e7f7f13bf61de7e6b5cc9f42aa9fade486f5c1b53a65d", + "packages/opencode/test/server/amicode-widgets.test.ts": "14fc6ccff4e83a5b005a724936e9f0d7ce411fab74109f319e8bc748665f7ab8", + "packages/opencode/test/server/fixtures/credentials/cloud.json": "431bdf114031da38975538384e21ab0ec7206a0859859f0bf87345b8c360829e", + "packages/opencode/test/server/fixtures/credentials/pasqal.json": "d3c775cc498fe3029d9ac234d9eaa9eaffa1ad8656e12a5aca1355c733276736", + "packages/opencode/test/server/httpapi-compression.test.ts": "5f7603d7018e0b95f1c2f36c01dd297c01770bfcdd91ce29778e03b7d6143f75", + "packages/opencode/test/server/httpapi-exercise/index.ts": "59048fa30e60348240de62cca862a5c6abbe2e9e0f6340b77b0a9bbd997bec27", + "packages/opencode/test/server/httpapi-file.test.ts": "d3386129bc81467ecbcc57a3861f53767ee56ac41b4ff6ad58d8b168fb3b3373", + "packages/opencode/test/server/httpapi-instance-route-auth.test.ts": "4b73a89d2431c02bc3b665d93f9002914e51eb1add979dc1867efbcbc0c36e25", + "packages/opencode/test/server/httpapi-provider.test.ts": "9e8b3e085b478e3f99b689ffff600e10c0b4b50b3cabdbd749f88dae19bf5904", + "packages/opencode/test/server/httpapi-ui.test.ts": "d029e959cfd9347fff4cf17c5686dd125b0bd3a41afb3408a23b31418f12e3b0", + "packages/opencode/test/server/pasqal-secret.test.ts": "54be8c666160dad22cd37bbf041f5bd40aec120271818f3c56c94107d987b9fb", + "packages/opencode/test/server/session-diff-missing-patch.test.ts": "70526ca7fb86741843fd167f8f2f9c6f6d7e5e415a20a5448d17d24229bdd65b", + "packages/opencode/test/server/session-diff-scoped.test.ts": "4d062ab6881fe6c10f656b363405828b6ebc4c0c66d55f5e694e058f61370e03", + "packages/opencode/test/server/workspace-routing.test.ts": "2574731ac379c540f450edc15f8750ac5360e8c33b4a0dad7c61e8eb686137bb", + "packages/opencode/test/session/instruction.test.ts": "8b4d954eb10afa852a671e6c0a94d19604deacc9a62f9c3651c7456cc32736b7", + "packages/opencode/test/session/llm-native-recorded.test.ts": "7139b58569af0172862af521e8f8d7a78132f40f06dcceb4baf8ca3a2f07d3bd", + "packages/opencode/test/session/message-v2.test.ts": "9edc16ae57b7f2d34aaed7378d82fcf9d07a82075a05730bfb3caae39d70ac7f", + "packages/opencode/test/session/prompt.test.ts": "d9654be772eed1e73191b3a693190674eb087cf7f545385351c0917114bac9cb", + "packages/opencode/test/session/prose-guard.test.ts": "7239a758cbf27df4c3879fa9ee0374964559c1461773c2f5a85196f64632e6c4", + "packages/opencode/test/session/session.test.ts": "e2870fe0a4d759d4c467f45b1903e48ac5ee5aefc6dcd9ae6b6da20714d03646", + "packages/opencode/test/session/turn-output.test.ts": "3e92f545d10054e501ad2c8857b43719f5a8f768065643d343c0c37c2e6fb60c", + "packages/opencode/test/share/share-next.test.ts": "d94076118b558644c06de3ef315041a6fd8895098377da843e98530311e9e609", + "packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap": "e1b0c536581dd36599aebcb5562ffe49923b09629cc8fe5d64ba0a2d7fe43630", + "packages/opencode/test/tool/apply_patch.test.ts": "4a22d83eead95e6b9eb26d42dae3b421bf07d5ac9ab3e1fdcb396c2941262c25", + "packages/opencode/test/tool/edit.test.ts": "ec1ed35002b1af4e2ff508aeac456c3edbb2e1dde3f6df4abd957eda9ef6d056", + "packages/opencode/test/tool/question.test.ts": "75760ba6ed98f2fdfd75945c3b492342dfe91026f99cde86db19cf52444260c2", + "packages/opencode/test/tool/registry-schema.test.ts": "053cb9732299ea6554db007bad873d8d61cd3769aa9514d66c70c3bf0d405b90", + "packages/opencode/test/tool/truncation.test.ts": "582ef7199b3f294b1c1588fadda8a1c0ea43ca9af0424a97f48747ade1654ad1", + "packages/opencode/test/tool/write.test.ts": "820d36fde2314abbd939ce43ca5bcc4cfa0139d12a4c669716249060d9a955ff", + "packages/schema/src/index.ts": "007e8bc04cc91c2c0aba3a78212c47c4fed6a8edd0d4be05286667d303448d11", + "packages/schema/src/location.ts": "078649bbc39b8e3413311b5af85392437873597d8954494016943cfb13564805", + "packages/schema/src/prompt.ts": "eb3b42b98ef856f85f32154482b19de546272f1eabe552ee9207db030346291b", + "packages/schema/src/provider-permission.ts": "382d3b8c8e7bac64816d6a8cb0a84dff6e9a4bd1a921a653ebb20b23d4580e14", + "packages/schema/src/question.ts": "538b73b25f8993700d7836b915ff27a1aff63cb6a6ef42e77b90bfbef83a5558", + "packages/schema/src/v1/question.ts": "3ba37742dbd5ef322b7edb42fea0dacf43a1322747dfe997af909bf564bffd35", + "packages/schema/src/v1/session.ts": "5804deda9cfcf2a015c759a6905b5bdfac74897239994c7facb246a60dbcf285", + "packages/schema/src/worktree-event.ts": "833b689b3636335d00a60cbed521f05dc02b467f7ee757de48291a602fac55b3", + "packages/schema/test/question.test.ts": "511f4fabf2841ed89e1fed9594f2e3a1be8eea5bcb50b680d762c49d6ef572d9", + "packages/sdk/js/src/v2/gen/sdk.gen.ts": "6610638b4fb71bac498da98d232ef9adcd4b011b63e5e81a63fc6dc20d311b17", + "packages/sdk/js/src/v2/gen/types.gen.ts": "0c23b262085d1e14b89bd03292a380c9ec8b52e66c4308304a05173362b79339", + "packages/sdk/js/test/session-history.test.ts": "f10913af3157694465273d54e05c03cf96a0002df0e34898d9808f92977b11fd", + "packages/session-ui/bunfig.toml": "468114e9b52c3cf926d2385c12d93385992cd70c97ea9e32ed22154617b7799d", + "packages/session-ui/happydom.ts": "d81d6b14e988f058fa502c841df34b55307c57fc94a26fb4f8a5deb6aa0d4834", + "packages/session-ui/package.json": "15edfe2287a76b544bb359c809da056087bf00e71684a34d22cdcc405a77868a", + "packages/session-ui/preload-worker-mock.ts": "b53280029a042575734d7bfdf27713f6c5cd6a6665599dc429d839a3e3372bd1", + "packages/session-ui/src/components/basic-tool.css": "0bcf0592ce8af0d902bd69da26ecad2f00f5a7890275392abbffe6f4d80c7853", + "packages/session-ui/src/components/basic-tool.stories.tsx": "059c4bdce6a9ddc93c69949f5baf7323631ef0d5e69f04030fde0f2771a9fc09", + "packages/session-ui/src/components/basic-tool.tsx": "ff2678cc17510e1b39657469f6dd1a0311843664cfd5161d385256e617b4e759", + "packages/session-ui/src/components/build-trace.test.ts": "6259c529fa667a3514bfee1c771e8f623bcb8c69e37ceb17ea541aa42e207451", + "packages/session-ui/src/components/build-trace.ts": "153e3182c3a37e4aca9c88bf0e2052b0ff4ec117a60d74d2c81567ab91180066", + "packages/session-ui/src/components/group-parts.test.ts": "a31ce19009e1d62e75e83b682190a4613da0eed334420409ed73a9e21834ae84", + "packages/session-ui/src/components/line-comment-styles.ts": "2077836c13bd3c3f1c39c67722119e448a2dfa123377f94bfd3676634e955d00", + "packages/session-ui/src/components/markdown-file-refs.test.ts": "e2b1bed33629d3ab53c521f33266814088ea4122b6e64d6ab294eacc4cf15070", + "packages/session-ui/src/components/markdown-file-refs.ts": "b75bddeb565dc0163635fab8f84bdd26723742f9f82d06b6fd5991777b311032", + "packages/session-ui/src/components/markdown-shiki.worker.ts": "2748ddbfcd625bf696b27d9b64895e64ee47a3f316c88930010e260b4ba37f4b", + "packages/session-ui/src/components/markdown-stream.test.ts": "b73b1a15ffa2cfea5358b2d6313ce17d26a5a11302b0e3b7d823cde0c98cbc83", + "packages/session-ui/src/components/markdown-stream.ts": "50e38abd5d4ff919564655799678be10463dec58502fc5487c1c97a9a8db5399", + "packages/session-ui/src/components/markdown.css": "24e7c19218620386647656a5d27e116cdeca911f1916c5d5b8609edca11ff165", + "packages/session-ui/src/components/markdown.tsx": "89e132e62d20c873311c9781d0ca4d7cd1a7ff882d99f19c8696aafaf4a8f298", + "packages/session-ui/src/components/message-part-css.test.ts": "ffab7d2c94e8d40ca35e4a8d4383cc6efd805b133764176b70046fba874a5f06", + "packages/session-ui/src/components/message-part-groups.ts": "37be069bf46e926fcde83d3744ee706911ff002e6b532e279290d841aeee96da", + "packages/session-ui/src/components/message-part-skill.test.ts": "453bdcb25e4df91ad1004635b8766070a60421355adf18ee53f43cd2fa7d0486", + "packages/session-ui/src/components/message-part-skill.ts": "d65a15dc39b8c0dece13aebe5e308426ae2dd758b07740251525ba9257654cf7", + "packages/session-ui/src/components/message-part-task.test.ts": "f5896e3f5eeeed2dcc55d690be56483902ecc06f047cb44cecb2dad31ee6c405", + "packages/session-ui/src/components/message-part-task.ts": "4276091c6f8ea2c31819c72b82747871e4548b3d402b7d1b7b06603ae69b2d5a", + "packages/session-ui/src/components/message-part-text.ts": "e38d68224f1743ccc5e0e0a8023e11977e3b761ec67dd5364cde9cb34e97ea4b", + "packages/session-ui/src/components/message-part-user.ts": "1f2c8cb4efff5274863a133f369a7397cac804678e953740f356ae03b71d475c", + "packages/session-ui/src/components/message-part.css": "ae592deb33739738f6a7fc6a3460b7146803bdd05cbbf46f1cfd2c5cec421392", + "packages/session-ui/src/components/message-part.test.ts": "7c66430837fa3d2607657e57e35720ae68dc5e84662e12826713a938301eeb7b", + "packages/session-ui/src/components/message-part.tsx": "89c6d920516e3c991b81ace10b14cc75df1dcf130723e87af6bec448688a7612", + "packages/session-ui/src/components/session-retry.tsx": "2cb1513d73275a269894f601e8c1d29bc790b14927134fe36177f2b371888721", + "packages/session-ui/src/components/session-review.css": "ec8c5b359dd4b7ff80d7fad8906359678adade9ce62c9d74aedc000b646db341", + "packages/session-ui/src/components/session-review.tsx": "d2015c9f7419279f08e84523439a0b73e83bd5d06587ad56b85ea53b66ecaee4", + "packages/session-ui/src/components/session-turn.css": "792915f3373134eadf3cd51e1d4bfa88ec347e6b037b6caf60b639ec5e74fbd8", + "packages/session-ui/src/components/session-turn.tsx": "9cbc0d7a35f42e32dad53ace7b3c7d92623fa2d3108edb49e0b7bc868f5c1966", + "packages/session-ui/src/components/tool-count-label.test.ts": "c62bbe2c662f6740794d25bd7c33fb3b9b46394a1b41d01d6568a8a2ee2b4e75", + "packages/session-ui/src/components/tool-count-label.tsx": "6c0f42d2c3fdc8c63bff3ca5a51aaa6ebcac9dc773f971884cbc2696246502a8", + "packages/session-ui/src/components/tool-error-card.tsx": "e27b89836b7c709120ac15fbffd2200038944058ea3506e61e5897ffb3537503", + "packages/session-ui/src/components/tool-status-title.tsx": "ae4561b58f55985d2294a352802e723b18943ac9a6551d97f1c4a6cc95368c8a", + "packages/session-ui/src/pierre/worker.ts": "7f210f931777956567eaeea15f2f5478befc7874a64a4b685504c59c66503fee", + "packages/session-ui/src/util/clipboard.ts": "c37ba53914714ed04135e5a254e8ea90186f097d7470fa0873a83de82f3fef2d", + "packages/session-ui/src/v2/components/attachment-card-v2.css": "3b4b9c23d69e76b35488bc3a65fb51211038c3e8aac015df3f531b4e97e96359", + "packages/session-ui/src/v2/components/basic-tool-v2.css": "55d3aa179704deddda7149342a951229ff5561127f786dd551e5df9aea8a7835", + "packages/session-ui/src/v2/components/basic-tool-v2.tsx": "ece46d761f7d51a7a0925b3df00a5c289d891e9a514ee721016eb723d87fb406", + "packages/session-ui/src/v2/components/diff-gutter-extension.test.ts": "7c3a9d541f8cc2cdb537cc6630d8902a17647f0df063439a93e8d563cd4a97b2", + "packages/session-ui/src/v2/components/diff-gutter-extension.ts": "aed07587c0c9a5f110f9ea91aa42679d6f9f66b2ec4de9043d6e2233a375acb8", + "packages/session-ui/src/v2/components/editable-diff-view-core.ts": "f01a341c4c1cdb4a9522f9ccd3c856bd3b9b7310c01d87327b3ce777052c8c59", + "packages/session-ui/src/v2/components/editable-diff-view.test.ts": "ab206fa17779e6e9015d343ae37e3067dfc1821a93b6ba566b7a0dce0fc19acb", + "packages/session-ui/src/v2/components/editable-diff-view.tsx": "f682e398ece864b5b854ca36698581c7e1cc5964eed96e7b45cabfcb64748b24", + "packages/session-ui/src/v2/components/editor-core.test.ts": "bd6552c0e7080afd554cb57ad690cc1504555712274c8b02702c64bb09460234", + "packages/session-ui/src/v2/components/editor-core.ts": "a03da4863d0dc4333772b8369a63822dd730bfd84dfa876f965cdd594292484b", + "packages/session-ui/src/v2/components/file-name-picker.test.tsx": "1ce9741e315b549165d390c74b5885a43580aa70e24de987f9ba8388cd521b41", + "packages/session-ui/src/v2/components/markdown-utils.test.ts": "10e1034293bf385cf50d860bf1667d8370abc61dcee0c5a93295f21f5f55876a", + "packages/session-ui/src/v2/components/markdown-utils.ts": "3bc47cfed5b99ab23f857d5324be3189f3a7e800d991103d72ef1c2f970b910b", + "packages/session-ui/src/v2/components/preview-editor.test.ts": "b8da9320a594aaa680ed3848612fcea66f41c0a046a673f0cf6155c2a0b697dd", + "packages/session-ui/src/v2/components/preview-editor.tsx": "d356ff168919abc8446c5fac2836791338fb3b9124f558c43ea7d3d5a1bcc5f4", + "packages/session-ui/src/v2/components/preview-file-routing.test.ts": "fca02a21261b291fd94001baa2294e7b2fa45b18b0c0403848f045763b41bf15", + "packages/session-ui/src/v2/components/preview-nav-state.test.ts": "cec09a8b3c08ab16581d3d5b6ff704584b3c87d81c25e8af20f6f00272f3593f", + "packages/session-ui/src/v2/components/preview-nav-state.ts": "ccaeb94d1ab39271f5dcd49c935c8fc7b54d4ffbd66e1352e4d797c9205553fc", + "packages/session-ui/src/v2/components/prompt-input/attachments.ts": "ff66078f2edc9a67a4df0d7dfd76a49be5eab27ac332b303f3412721ef7268ea", + "packages/session-ui/src/v2/components/prompt-input/index.tsx": "6cbd3a1e3a4fd789284526e5981c6fd2d4952f3926c5a1be0609bb6832453997", + "packages/session-ui/src/v2/components/session-review-file-preview-v2.tsx": "fc06f46ed3c92c8066744da1f6ac97db7d8b7d2aeec5ef776d743dd93b317936", + "packages/session-ui/src/v2/components/session-review-v2.css": "bb306f226fda8f8ba6cf0ae706843ba9f2b48f3a3446433515e8a8dd1f9dc626", + "packages/session-ui/src/v2/components/session-review-v2.tsx": "4151286efb6e0e148246ee3eebae24a2e5d4eac2603fd5ea8546d0839a694161", + "packages/session-ui/src/v2/components/shiki-highlight-decorations.test.ts": "f50e8156b708f3e0ddbc509abf71751778a74923dac9d7e65385b178f6346718", + "packages/session-ui/src/v2/components/shiki-highlight-decorations.ts": "57fee1804df78c627f7ddfd092a55d71afe041baa153d0d5ed7c7d8781e30206", + "packages/session-ui/src/v2/components/shiki-highlight-integration.test.ts": "c3f62945f0258d7462bf9936a8b78294c4295f445e2a75fca186432f241443dc", + "packages/session-ui/src/v2/components/shiki-highlight-plugin.ts": "85b01203590f6de0af75b1cb4f35d1b87dea92989a950dbe6a9cf10aac19ffaf", + "packages/session-ui/src/v2/components/shiki-highlight-worker.ts": "0f9628b9e0d3ec9ff49d53d05cb77259e1762f66daf7b0e1f2403649385e66e4", + "packages/session-ui/src/v2/components/shiki-theme-state.test.ts": "b305c3f669b2083851fb574bacccab4f311228ce842f18465443b7807226e619", + "packages/session-ui/src/v2/components/shiki-theme-state.ts": "5ab15c15f4a32afce2279068adda732846404133bbc2a44b90779a4da88d123a", + "packages/session-ui/src/v2/components/tool-error-card-v2.css": "9eb0bf8b583a18159f3855465118ff6a853d0193ea783037d5c90a868fdb3ff1", + "packages/ui/package.json": "b1d168d0371e9094faae1107fc6c00be197f09bc69daa2247a3890d607f4b629", + "packages/ui/src/amicode/amico-presence.css": "b3f345b607e318dcfbefcdc677fe21cc7d387b9946b0f9d625b0a842fe7e31b9", + "packages/ui/src/amicode/amico-presence.stories.tsx": "6012506c946a18460f8a6105c5860a050e47e7708818b0408b516370f50b7094", + "packages/ui/src/amicode/amico-presence.test.ts": "c7ea8c840004d06e231a7368b3c10e11b7dd7efcbcaca4867b0f30167bd2e2bb", + "packages/ui/src/amicode/amico-presence.ts": "b4708117445d3fa5cf9be8c9b2f51bfb1f6b01a76e2fac114cde93107a075e26", + "packages/ui/src/amicode/amico-wave.stories.tsx": "fed064c5202bd772308e2c6165c9d63182661fe6ce590c75cac1fd0e9deadf94", + "packages/ui/src/amicode/amico-wave.tsx": "478cd8b19a87679016d9dbb0aa494ba7d1f1ef67b3da1d09fb35d28e33de9017", + "packages/ui/src/amicode/amicode.css": "a7b8e410dad9ee66190cc31d4a4782efa44e8f759d89d701c7525e67002b98c8", + "packages/ui/src/amicode/approval-bridge.test.ts": "5b5e5a41c827b7a3cdaf455dbf488cfa7b8d339f46e64f5a35a0ba9226eb0ebf", + "packages/ui/src/amicode/approval-bridge.ts": "ceaa6024916794ece1bc80a004b79c36406d2bc512f82e003c25d919c9050e48", + "packages/ui/src/amicode/approval-card.tsx": "f55bd13bfded569020ad0ce0d385da3018aee8e833ec573cb45447114658a11b", + "packages/ui/src/amicode/approval.test.ts": "d1a9eb383112234d750d07229e347a464bcccc1d633d90ebf653937ae0653773", + "packages/ui/src/amicode/approval.ts": "ebee2a1302c27e1f74d2892b3d84158dbaf672e13d4300ffc01ad8ce9a1ed644", + "packages/ui/src/amicode/ask-bridge.ts": "8ab7f64eefe55ae0968b9b960718a1f4ceaf6813102bbda42349a06a3638610f", + "packages/ui/src/amicode/ask-card.tsx": "0e2fe53c747cc9aa7f65536b73cceaac30f6bdb864424c87997dcb13325e7584", + "packages/ui/src/amicode/ask.test.ts": "1daa4ccf6cc41f17039c5ffb0a09243ba364b5af6e174ecd1040787afb7907e2", + "packages/ui/src/amicode/ask.ts": "5081435a8b09b2eba12240a9914bbe222303460bd21044bbf8482bc190ff2efe", + "packages/ui/src/amicode/brain-data.ts": "f23483cda811e148748d4f47435c6d01c03d52e9a65ad74cae2c0ea30ce0b8dc", + "packages/ui/src/amicode/brain-engine.test.ts": "3b244fbe15ac87529655acd688da9181af53a1dfeb3f9f87e5f77000db3aada6", + "packages/ui/src/amicode/brain-engine.ts": "500b03cd43d4cdbd76a575f4517a4aaac788167e1d41a396d6dc6bce3cdfb8dc", + "packages/ui/src/amicode/brain-ref.ts": "9d8aaa8b24fb0b74acc0c4cdafc265c1808c28c95d4ac9b815fd2e54ea89f46d", + "packages/ui/src/amicode/bridge.ts": "e7b93a15060a0cb1ab0be2b367f73e926d74b990a8af917a9966b451ee303b5b", + "packages/ui/src/amicode/calibration-view.tsx": "bc4193104fea43ac3e5476df0f9a91a55465b48ffffc80e4170047872a141812", + "packages/ui/src/amicode/card.stories.tsx": "b1591abb4af426b0eb08588ea1585336a392d755b5d308cb31f17cb65acf5a3e", + "packages/ui/src/amicode/card.tsx": "e5198e40923a77c3ed6a7aa235401bdeb20db6fbdb81f1ffeb847962dd1122e1", + "packages/ui/src/amicode/connection-icon.tsx": "2b36c05209a3b5091c6407d59add58fb51ec34724ae6411af85c3dcc797a9987", + "packages/ui/src/amicode/connection-picker.tsx": "12cc6f142ee109580442a278286f06118a2a35239cabeaef6d60c0dac1a7ed3f", + "packages/ui/src/amicode/connections-paths.test.ts": "07c86e8e04700cdbd55bff8db342a8400d85114d76bc73fee8205e9162953f2a", + "packages/ui/src/amicode/connections-tab.tsx": "06489a47bbd6d482ba4d2dc2cf4e9e8e9c648be774f78cd76e2abc87451116e5", + "packages/ui/src/amicode/connections.stories.tsx": "fda54a41c4b46f5cab5278278f92c01d1fea70610f7b8641fa5855be6bd9d486", + "packages/ui/src/amicode/connections.test.ts": "a718b1b698178087fdac5294c1661ca2eb200491e2a076465a09ab52c70b8910", + "packages/ui/src/amicode/connections.ts": "c44875ae2a95aae3f62a95fcf59517178039d09d51ca84e816ea725ba965e408", + "packages/ui/src/amicode/context-tree-data.test.ts": "bd51dc84d6c14c64f38c8f467ef29d9d8f45dcb77cc83ec92bffc8aaa983b463", + "packages/ui/src/amicode/context-tree-data.ts": "d623578b957b9a49d6f7b930a2264b7bf0ea71fabf1a485d9666706c7b77485d", + "packages/ui/src/amicode/context-tree-engine.test.ts": "afa3199c18c7ca05a19fdf0663a5b4d6e1fd2303e038cf25641c29e254e610f4", + "packages/ui/src/amicode/context-tree-engine.ts": "2177d01855d58c5ee7c164c2ed1dac6f4a8a5cc04daea67566f195b02ed1ca06", + "packages/ui/src/amicode/device-view.tsx": "1842053e9e25cd5c8076598449e44abf06008940a8f3f39403cbf435b1b8aa8d", + "packages/ui/src/amicode/devtools-header-alignment.test.ts": "8506411132e142d54a27e551f2dd3806166824a777dc002be6fb5477c77af5a3", + "packages/ui/src/amicode/edit-row.test.ts": "7c68fcf083d3854bfb70768b648110e001843a290dcfdc25869c1a4681445b94", + "packages/ui/src/amicode/edit-row.ts": "28d5f39470376968e7eabc3f50807a779177e9c9f2081302e4b5eb15306aef1b", + "packages/ui/src/amicode/entity-rail.tsx": "fee936650d0f05ab00e46ebb70333b2c92a57ab0da1e7fcee942d7e6b64004b7", + "packages/ui/src/amicode/entity-view.tsx": "e181575c8bd66a7cbdf89411d0cc1d12173a74a3bac9122163f2e27331e3becc", + "packages/ui/src/amicode/facets.test.ts": "e89bd4e49276f52ac0af4990b202919331a48302b4b34c1ec1d8406fa4fccabf", + "packages/ui/src/amicode/facets.ts": "074f7843a105961da3b4b89c67ea20de106968b4524f9094a5f57d1ecb0acee0", + "packages/ui/src/amicode/fixtures/formulation-migration.json": "e573355a5eeb29f1611e52f0fb716697281b16f899331fa7fb5ada9eac4e74bc", + "packages/ui/src/amicode/footer.tsx": "481c839d72fadc03cb6a5d92da52c8a36110b0ca5946481e38c3fa4eb6e72fa1", + "packages/ui/src/amicode/formulation-projection.test.ts": "bcf40f30a977268c1e0c009d94c16141d6d2957dd59abfaf8741014db7c9fc7e", + "packages/ui/src/amicode/formulation-view.tsx": "7064837eb1fd7118b49312c0697cfb0f4b96541e2c0a3f3e763441c16c64d8d5", + "packages/ui/src/amicode/frontier.test.ts": "229eb8e3f187113fcfc73f0a30f2690bab4266cb12c1c6c3802522dd7eb4af9c", + "packages/ui/src/amicode/frontier.ts": "78cd89deb26a2c6c4b8a18230012455b7aecd5f23eb007dbd0cd440b6b6ec36c", + "packages/ui/src/amicode/getting-started.tsx": "9cdb8df438521d33cf7732fd0ba64e21b4ba9d63de0c823e59d0dcd21ea90a7f", + "packages/ui/src/amicode/harmonic-dot.tsx": "e8439d64453a885aaaec76686d7984674cc53b50b86dc2dde104c0013082cf0f", + "packages/ui/src/amicode/harmonic-geometry.test.ts": "393b9dcdb9de917dc5715cc135c4ab8a221fcb69dc3cb5b269306f860e4bfe51", + "packages/ui/src/amicode/harmonic-geometry.ts": "165f1ac46050c5fdce1d54d2f52eea32c5027b385ead589ad7e214fe45bff26c", + "packages/ui/src/amicode/home-cards.tsx": "019069f82e0a29baa392b7609ce0825d0c036ce31112bbd1efd375ce1b077a9c", + "packages/ui/src/amicode/institution-lookup.ts": "3edf90b0778ea50b048975cc317a18a1aa82290cd4f5241cf9df74fd17866fe9", + "packages/ui/src/amicode/onboarding-wizard.test.ts": "268df538ea99280c5297f9b1dc06a236da2fb82830c2d49a107feca3f610279f", + "packages/ui/src/amicode/onboarding-wizard.tsx": "75db623f8f50fd875f1bde8942841fbb5167c77a34fe3c6dbfa80732841b53e8", + "packages/ui/src/amicode/problem.test.ts": "e7a15928df883fbed424744953a87ad0b5ba8a0c1039dc190ed00bfefe85eeee", + "packages/ui/src/amicode/problem.ts": "d40ca9f4f411b112d97c7d1067b5834ff22f763456df17df7fa0ad31768a3a51", + "packages/ui/src/amicode/project-type-icons.test.ts": "1db755e2818a5e97d018e7133ae329b9ce1ff63fc347a06bcac7b9f4d0784969", + "packages/ui/src/amicode/rail-gate.test.ts": "7cf0ff5add76f27eb4022224a0f18532a7bc419dd5368788e7a0667f9913dcae", + "packages/ui/src/amicode/rail-gate.ts": "c24f99d8285a5484863078acedc5ed36d8de67084c2baaf2bb2f7b6d87e657cb", + "packages/ui/src/amicode/receipt-currency.test.ts": "7b6518fc7eb1f789540ed3b7f9f761e496ab09648f22d967d2f1a260099db09a", + "packages/ui/src/amicode/receipt-currency.ts": "379c6ff09b170a0dbb85fb093ee7a334339066db83e268534918967010469876", + "packages/ui/src/amicode/receipt-runs.test.ts": "2c25968b2ba9eaa7fe70ed4cf767aae88d3db9595e01d880215514fef7a4563f", + "packages/ui/src/amicode/receipt-runs.ts": "4aa31624ea3d61ab352bfda7cd0da48f7d367f123cf7929f52f4da84629a190b", + "packages/ui/src/amicode/receipt.test.ts": "7065899d0efd4b2b712bf412053d1b3071e6aee4be163f38a3e0a7dcdbbb45fa", + "packages/ui/src/amicode/receipt.ts": "cc5e452b229b29386f474772cd27caf6a83a13862540de9035cff610ef06e929", + "packages/ui/src/amicode/run-card.test.ts": "e0b3a7c94bbdddfa1cdcc81898404bad17319862f3c3a9f47255d17db1fe75fa", + "packages/ui/src/amicode/run-card.tsx": "b074e95fd8fe8b1907d1527fa88ff85b5dd6ec2ffaa30f749969f9130e83e592", + "packages/ui/src/amicode/run-gallery.tsx": "80100e808f9e8e46bfca8daf927b1e149fafcb757cc2ab2ee5fdec3339625b9b", + "packages/ui/src/amicode/run-plot.test.ts": "64ac70e7ff5784ef6c1c224136df2a4e8a43b4187d3ac0fc4382cb0464eb2953", + "packages/ui/src/amicode/run-plot.ts": "b4bc50f279cb864f7720e56ba69b993c7a4e599a71047162173b1b93a63598ac", + "packages/ui/src/amicode/run-series.test.ts": "2e7aec7cdf7eb056efbe52d180ff316482e3010e2442611daaf4bda444c82705", + "packages/ui/src/amicode/run-series.ts": "c94496068ae05f4600b9dd9fab4247b678dae7aaba31ef48e4389b0e7fefc52c", + "packages/ui/src/amicode/run-view.tsx": "5098ef006cec0f354dde8589df1a730b5663c05300c1cf298569e62eb633f1be", + "packages/ui/src/amicode/run-window.tsx": "411abb6064ca76a1866b91914be1788f78173844f5e963562733348f92d982b4", + "packages/ui/src/amicode/shell-row.test.ts": "48ec6f0786edf81f163e350904bc2a93b1a55375b8115e688237ce8c2f1a7e64", + "packages/ui/src/amicode/shell-row.ts": "b39dc05d2b77ba6d44456248782b31f6219c891d56700203186a65ccb48319ad", + "packages/ui/src/amicode/solver-switch.test.ts": "c9cc10d657d7adf0c388e56cb6058affed5a255bdeb9b8f2fea5c02f4daff1fe", + "packages/ui/src/amicode/solver-switch.ts": "041c2ad3cfa63770cdc09ee5fb2cda0c7d09c55e7e53c83927822476716c6b92", + "packages/ui/src/amicode/solver-toggle.test.ts": "2c5ede8eff8a60f1b5e6bb4423545438ebed6d5d60306d5bdc6f557144ede5e6", + "packages/ui/src/amicode/solver-toggle.tsx": "2d3f05bed264526b439e53be9897862d1dc1098d37d530bd26606ae6da804ddc", + "packages/ui/src/amicode/spinner.tsx": "f76ae9b6a3945017b854d35ea0e6b2f4a08ca7f01e0f77236dbe1ba33d244fd7", + "packages/ui/src/amicode/splash.tsx": "4d5485f48065d2c88a3ce41cc1abd81d5b58338dfd4ae240b1c211444fc689aa", + "packages/ui/src/amicode/stage.test.ts": "b1a82d5ddf216f6e6ce09b42d0850cea3622792ac33bac5b2eaf64d850372a37", + "packages/ui/src/amicode/stage.ts": "8f9c07187ddb2ab0aeab26a6287529059a363131ba0140fcefec360f6522500b", + "packages/ui/src/amicode/system-render.test.ts": "0e1e30063445a464cf5f4db2b4b6333136b971d942606afb578b0248da8f44bd", + "packages/ui/src/amicode/system-render.ts": "8e0e5287f9a3d6b166c65e999aeb5cdc002cea566f1543c616459878aad10427", + "packages/ui/src/amicode/system-view.tsx": "42d5232e69dbf446b9039fe966e53eb579253915f22c5b161595e938b83bfea1", + "packages/ui/src/amicode/tagline.tsx": "251fe67f072f6590049f58e4174c1da90e1fc1ef8814e5d3c06ce246035d868f", + "packages/ui/src/amicode/thinking-line.stories.tsx": "3bf821de97d2b58487466c44e17bf6e46c0309ce4b563cc8e4a725f1757190d2", + "packages/ui/src/amicode/thinking-line.tsx": "d08e8525a3caf9a5c5bd954374f9219ac3b1fc5c2aae4f25412663fe7036e81f", + "packages/ui/src/amicode/thinking.test.ts": "ee926e4971e1af78d4317e90f28550b7d0be57cb7363f7b3c0d6869f10fb2167", + "packages/ui/src/amicode/thinking.ts": "ce2529285621620df168eaaa845cd2957b4fe5e61729fdfa736a8702ccf059b7", + "packages/ui/src/amicode/ui-bridge.ts": "5ed07b8e595e9650a27a32fbc72e7a076b885614ef07cf955d340578342943e2", + "packages/ui/src/amicode/upload.ts": "9a3a59541ba056a5069f5145cc10bbcc8d44caeb7cfce7a59d97415de2e4a149", + "packages/ui/src/amicode/vaults-tab.tsx": "9e93b7424f0d885250cf999a115b1801d5973f3fdb9095a5c29d74e7093af7e6", + "packages/ui/src/amicode/vaults.test.ts": "24826e6b8b083b0a7478e469f3d4fd7319c973da281cb569e3d885d83d3d46d4", + "packages/ui/src/amicode/vaults.ts": "6250b08a8d6493bd42c5407bfcb581a300757b273a587247e3666ddbe25c00af", + "packages/ui/src/amicode/wave-geometry.test.ts": "3a89a89310b8c9ce15b402ced6dec83d691bc4ccf50448f2a89e4c0ff1c80cc7", + "packages/ui/src/amicode/wave-geometry.ts": "79fcd8ce75e280f6de3fae108ae5db4b992e28a8826735a33dbbbebfa68c8f24", + "packages/ui/src/amicode/widget-allowlist.ts": "53c6554561fc694756cac154e1db5520e806dfe6dfb2ffa41ee77bafd18536fe", + "packages/ui/src/amicode/widget-bridge.test.ts": "67ef016e90aef247c16b5dea1362a549f36a5ec44faa5457357b4646d57ff110", + "packages/ui/src/amicode/widget-bridge.ts": "91f5949af16ae3d6c3e5acf3e6853518b9cf7cec19a2534c3636e30270d1e536", + "packages/ui/src/amicode/widget-config-form.tsx": "b62f99deed3abebf14e17788218e9583d277e759f01721d9c7ec9b1377b3c04d", + "packages/ui/src/amicode/widget-frame.tsx": "f4082458ecc50a43d48dc558d16dae5b4b14bf7c19500fc5807e4488ca564753", + "packages/ui/src/amicode/widget-grid.tsx": "075005dae4f54f45598a4aabe9e1cde1aa4f767a574dde3ce7e82a524f61fb7f", + "packages/ui/src/amicode/widget-preview-card.tsx": "ed022fda6f0e4838d8d8e98680ac6b77979fa8e0987becac1c0d8ad35bf22ecd", + "packages/ui/src/amicode/widget-preview.test.ts": "3ba95ada8fa9ce742a3246c52e1b1f5b4df1a9e0d8ad453f41e4468fec3b7e54", + "packages/ui/src/amicode/widget-preview.ts": "21fa605139b96f45675b11a73fa0e8e974be3444feed0f024b8003e96e44927b", + "packages/ui/src/amicode/widget-schema.test.ts": "b24049aeeda3fd2a922b5ce6601d99df9c8d3aa44b3e69dc8510a13120c7353a", + "packages/ui/src/amicode/widget-schema.ts": "e8a0efa3c86ccfae34d2a6feead87b556a2030c1a4e1bbd4b7c5839e116376a6", + "packages/ui/src/amicode/widget-tokens.test.ts": "426064638b322a421f794bedf5dbf41ad75fc30b3da6e2d02dcf6ed2f85d5f45", + "packages/ui/src/amicode/widget-tokens.ts": "397edcfa18882b2b6b6abef0a8783d72323f793e974d0bd440ca240a10b2f737", + "packages/ui/src/assets/favicon/amico.svg": "7c64b145bdd063bacd53318336a423f0654ec702de2b4e0c4a4a384694052804", + "packages/ui/src/assets/favicon/site.webmanifest": "beee758dd8811f9c76c27cbfa3801f92fc2eff537068b51c555aca4d90804550", + "packages/ui/src/components/amico-spinner.tsx": "75114d38aac924a37fee563e35375ebfd5e96cf3771690d01ad484f91df1c563", + "packages/ui/src/components/amicode-brain-ref.tsx": "e08345bdf064fccf7a0d0f7eab5b269c7eda47aad7d17b17ec91e14a613bb931", + "packages/ui/src/components/amicode-bridge.tsx": "c00ab12a45b9d092abc63a9b259e71bdf3582132aa1c288dcf8a2a520e5a5e80", + "packages/ui/src/components/amicode-card.tsx": "a09c4a734c55bf6fef0d04dcc0f0d4fce437e44a8745aa2ac2c936442d9a7d6e", + "packages/ui/src/components/amicode-connections-tab.tsx": "d184dfcd5c645332c2cc1c79356e551cd53b67a6b61ed16e78d041de5d13fafe", + "packages/ui/src/components/amicode-edit-row.tsx": "99c8c4e90ea02be21f74603c5a5ac1e2c030f487d62ce9da972c99dff505d892", + "packages/ui/src/components/amicode-entity-rail.tsx": "5377561b952d9e6bd9bd6a16cec91a37770f14195bb7bd1cd294eb20a1e78a3d", + "packages/ui/src/components/amicode-entity-view.tsx": "1ff46b6abdca65992606755e0d5e516483bbd8f3f8cef54b81cb6faa08d895dc", + "packages/ui/src/components/amicode-footer.tsx": "d7d7344613c7acbf2d4b0dd3f33c89f67fae6ac065bcea047e7dc26d13bca5a0", + "packages/ui/src/components/amicode-getting-started.tsx": "219524d12d3b7e35a3e6ac4a112c64b8a54ce1b695bb61dc4a0bcc64a7f37e2e", + "packages/ui/src/components/amicode-harmonic-dot.tsx": "3f459b3e579e5d8fc3de5562593ec4236d22878f1da59ba46b74e524559542dc", + "packages/ui/src/components/amicode-home-cards.tsx": "1551d6832131782c26e0ff0fe89d3a56777958ba764df9ff754821c412471e4a", + "packages/ui/src/components/amicode-onboarding-wizard.tsx": "9e93fc0a1ff1e4c7ce02444c27924f0073b675d07752032c37f52a4c45f94536", + "packages/ui/src/components/amicode-problem-switcher.tsx": "1dcf478871344108eb25e194f6c1a95e9977944d7f170627d46108ba3a07f1f3", + "packages/ui/src/components/amicode-rail-gate.tsx": "2850e9dda4adba54324be7e88f6fe47fdcda51507771ed2f6599b5773411ca9e", + "packages/ui/src/components/amicode-receipt-runs.tsx": "5c285c7b3bc1e164fdc24ac6f2daf1765a8b74998577b3868fe43b00adb00d26", + "packages/ui/src/components/amicode-receipt.tsx": "bd37403867623f81c8092660df10df7fb7b08e96e80271b492e03e8c36fb662e", + "packages/ui/src/components/amicode-run-card.tsx": "e9295cf59d46a71de0ee5b91c74eea3b4e42b70a9358f39a9a28c2578627f6b3", + "packages/ui/src/components/amicode-run-gallery.tsx": "366919dc8b1fc48d4aeb454bc8f92e5e23621a4570c9084a2889c88952d6f692", + "packages/ui/src/components/amicode-run-window.tsx": "5e5c623adc5d4e3fd35740e9b9cb5bae77e6f3f694850c5828f06a2616b4181f", + "packages/ui/src/components/amicode-shell-row.tsx": "0ce6525dd2cb8c1b04c7779ae477417a7776ec83768b8b028d52817e734587a9", + "packages/ui/src/components/amicode-solver-switch.tsx": "ea1e5d187fcbd505046af8c2bdcddeb7b30dd98a7d2ee9a4775e25be2c581270", + "packages/ui/src/components/amicode-solver-toggle.tsx": "b09c870bab880bfdf2557fb870fb6af13a065f90353f59d609f37a6054db858d", + "packages/ui/src/components/amicode-splash.tsx": "0f69ebdd0e4e6595f38b1492c31a28bd1320706c7f1e26411ec4d25d1ab2921f", + "packages/ui/src/components/amicode-thinking.tsx": "2734da9851aaf49f9c31929ee0092ffb19d40a945ff760fe0635c06812b04357", + "packages/ui/src/components/amicode-vaults-tab.tsx": "9ad6262db994e2ecc7d7068c95f4a31c6fbb178c531364b0dc3c8fec427a9a0c", + "packages/ui/src/components/amicode-widget-grid.tsx": "df589de093bca703e9fdbbffc6a13020e96ee0ef43e545718f91277ec0b7cd24", + "packages/ui/src/components/brain-engine.tsx": "955723ad42c6abfb785313f62277143142f1248987c45da30eadaf28d5137072", + "packages/ui/src/components/brain-ref.tsx": "c97a0ac0dad470c9b9e194d6ba94d1f1cfbb774bdbea3f798bece4a2a9968a60", + "packages/ui/src/components/context-menu.css": "7c701902c852f205a178ded4fe8c6181ba43cb4d1c42c6ad9a39ae368738aa1a", + "packages/ui/src/components/context-menu.stories.tsx": "0542961bd9db8e191e122b901519452217a410ea5339e8d3ee09a73258ba59a9", + "packages/ui/src/components/context-tree-data.tsx": "ca261e7a5eeed09130af14bb755fc2258833d2ac9efd995418cb32927de05d86", + "packages/ui/src/components/context-tree-engine.tsx": "92ca28c968cb0c1c346c1693163abd4e604287f875b1d53a434966f1c48cef97", + "packages/ui/src/components/dialog.css": "f66f34aa3488b53e2ce1ad19d697a31c3f7cead0307adabaede0d710b17c7401", + "packages/ui/src/components/dock-surface.css": "bc8945d4e19eb122078f98e5700e0b542e9e80901782ec927340a048fa0d3be1", + "packages/ui/src/components/dropdown-menu.css": "35d1e136a03fb3b59fd5801645de2870c20ecae6810488f69f01595b6abf5a3c", + "packages/ui/src/components/favicon.tsx": "809fd1d2621b0e28e69f8ac8092405b89a11fb7a6dbad2938121f7c0f2f5938d", + "packages/ui/src/components/hover-card.css": "b6cf61d45ba88cc4252923fb6fb4643659410596eaf3f7456ee5a856dd22dc8f", + "packages/ui/src/components/icon.tsx": "1d25faf5031ce28f12d3bdc4067b51377b5dc538e1b2495cc5d1983097615a04", + "packages/ui/src/components/image-preview.css": "fdb49ad0314cc89d95be7d905d9d1d50628e25cd07d536104c8b3d0ef5132beb", + "packages/ui/src/components/list.stories.tsx": "ba1302be7924b850a1ba2e8e7f3247fb10fa9a5e5f433164e56cbd1a457ab938", + "packages/ui/src/components/logo.css": "f788db461b78bbe33ca2df8d8ff92104fe5c569c7feae124b43c24a5e7e9ab86", + "packages/ui/src/components/logo.tsx": "de12f1af573c8bdee867a4c4c2ac40ba0064b5ffb0f2a0c72f89aea6446ebc63", + "packages/ui/src/components/popover.css": "cf73a22ed5fb53e6ce235126e0e7e877e611a9da87a0c982df5a8959729b82bc", + "packages/ui/src/components/resize-handle.stories.tsx": "c5624be901cbeb1c4658e65d22dae5659b2b2d4f53c93e619a8ac4d2c6611c55", + "packages/ui/src/components/select.css": "487d276d8398b94650505954f99393f8d7d2630510931206d4aee8b35131e5cc", + "packages/ui/src/components/tabs.css": "57d12ea6b52fb499ba39e6e1ae5a325fbc20b9d218b2a88fdd907e5ecf3871a9", + "packages/ui/src/components/text-field.tsx": "5ad1870d4858cc582a0cc7bc0fd1c5332b5e5c96901131639d7bc8f2a38350cf", + "packages/ui/src/components/text-reveal.stories.tsx": "393d45b149299dacac37e688dfd8f0bb2eef0294aacb700f50a9416ac6fcaaa9", + "packages/ui/src/components/text-strikethrough.stories.tsx": "5117a3b4ed59c18063720f47affcc52f210dcf769934b24ede0ef14a2cbc5c43", + "packages/ui/src/components/thinking-heading.stories.tsx": "53e63e5106f8f2dad93c5b44e0f22d2a27174a153a0666016f333fa97c2f8a92", + "packages/ui/src/components/thinking-line.tsx": "956e483aa21029161c26830544cbc2df23fb20a3f342d1618675b6f238d87709", + "packages/ui/src/components/toast.css": "60c06eda9f0ccc5641c03c002a6080db99c00d797dbdf7511c789089efc1c546", + "packages/ui/src/components/tooltip.css": "a615df9b86e64c1565384baa8054c2f80ebad11856d33f5e6f53902541eacef2", + "packages/ui/src/context/dialog.tsx": "876f8a5dc26ebb98f1f5e9e528e7d0bd7aa79c0a107b62027dd9fe78ed2cc620", + "packages/ui/src/context/marked-math.test.ts": "0fe460c09956335a469b382ff631809381875465cbcaf7e7c599f86240b0227c", + "packages/ui/src/context/marked.tsx": "b4f693cba3f8020596f860a00293e43855ec75d0bd214e379e36250d02e2be4c", + "packages/ui/src/i18n/ar.ts": "8113d320fe4a5300f1bd70150ae1695d68cb783e1c6e2be43b8a429b7dbdb711", + "packages/ui/src/i18n/br.ts": "cbde2da43ef820fe2664cb96cb973fd722156a6c8a3c5e16d18638bf014e5196", + "packages/ui/src/i18n/bs.ts": "23ea0ae34a4edaa4599b13f63f481be861e28da3b0d898987e291c7e91a9f11e", + "packages/ui/src/i18n/da.ts": "e8083f8a7ab01f73990a1eabcba817afdc663858d524e56e652ea69238cefc47", + "packages/ui/src/i18n/de.ts": "eb854fdd43f16fc2346ec43d7d1629d2714709991b3e5f7ac5ee99011324aa43", + "packages/ui/src/i18n/en.ts": "1b412a1cd0ea8f7d0ce6069d3bd94dc40778cc38c23c60191cd90071d4187ac8", + "packages/ui/src/i18n/es.ts": "a34d132adc2ad68ae3da98b6afd5070be48a0cd6cb15c4866cc7ea99deefc4ab", + "packages/ui/src/i18n/fr.ts": "4a8296dec41894e6ecb209e44564ac79c04cae73035b5447eb233cd984ef4bae", + "packages/ui/src/i18n/ja.ts": "6c13f118491c8badfac33baf449bee55779f6058792b6a54973bfe975e4c25c3", + "packages/ui/src/i18n/ko.ts": "b97f70d80c9ab7561c05ab91d461e9323c4c846d6a27bed0a41ad5fbcdf0c1db", + "packages/ui/src/i18n/no.ts": "120e5d11f5aebde00822def6fda9ae12db47cd020bdd04114cdb098d5ba67449", + "packages/ui/src/i18n/pl.ts": "8133cedc013364bf84a3902399b431f4029d6c1d57acf23f12a739127d4583e9", + "packages/ui/src/i18n/ru.ts": "11d79d60f2f678597ee2b33b51fa666f38f1e78b7ed051a686229ae0dd8aac72", + "packages/ui/src/i18n/th.ts": "afa5a46ff445461db8f069338aae760cb9cac09b370c47ced5542549c92c9235", + "packages/ui/src/i18n/tr.ts": "fac27e4bec327ff83976d9cdd8f54c2a241cb26b44c644a93c591e99f09290ed", + "packages/ui/src/i18n/uk.ts": "3531fcf92efaec359381fcc2f0cdbb644d52936a20037067451b057ef327ea1c", + "packages/ui/src/i18n/zh.ts": "6aac9e8c8973fb538effee075740035ce58a631615d39c0c8fb49375d45a56e5", + "packages/ui/src/i18n/zht.ts": "d50b7119139f53180eac64a6317341f54efc87ff76d56961a3e86ef74e3ad29b", + "packages/ui/src/solid-dnd.d.ts": "f1faf22b0773252852ff0865f68a00fa479777f5d0b4602ea4d1660c366793ff", + "packages/ui/src/styles/index.css": "2eae4e3d82e992c3d99f4a91ff25b3d6e9e514b38e9bebd232e6c41009cdc1fd", + "packages/ui/src/styles/theme.css": "0dc88bf675df5cdf08cfe0cc53c11eaf030a1bc0cf8b36cbeb3977367c2b362b", + "packages/ui/src/theme/context.tsx": "93b0b3f8a258bc8a33d4b6a4cda7016e91f6d999bd32c60a43aaaf45eadd1227", + "packages/ui/src/theme/default-themes.ts": "878f3e9cb45803dfa740890ea2240e246b05833f2d7f1345c67909c1000d8761", + "packages/ui/src/theme/themes/harmoniqs.json": "a20f6bb71df08a150a096bdd13f3aa347177f51858dba9bc9af6e25c2dcd848e", + "packages/ui/src/theme/themes/oc-2.json": "539a59886cbee9f2e54362075486d47ac69884ef8a9282f767f7cfd3f1f598a8", + "packages/ui/src/util/clipboard.ts": "218d321e1b0567b76514057ef22cfd23cb843fefc36bed7aab91f072e3233ad0", + "packages/ui/src/v2/components/badge-v2.css": "32135a9df5bad856a10138e00a2cb3ede7a6fc0cc2398797ad6bed9335d1f845", + "packages/ui/src/v2/components/dialog-v2.css": "ae6f7b1de755929ba529b9dbb0e837c80f620f00a77188b9d2c59f10b0f28bbd", + "packages/ui/src/v2/components/icon-button-v2.tsx": "966e535e3efe503f054045be4476fc20d2fad36092410b52f75e4cf8de6fce6f", + "packages/ui/src/v2/components/icon.tsx": "9f702e9c307524f79dfa9cad70f9bea32bda85672f917ffdb0871bb14cf13437", + "packages/ui/src/v2/components/menu-v2.css": "2f262a6c456a8e3cb9027f0b8b3bb3c4327794bd80cadd3cf8c16d08e6125d4d", + "packages/ui/src/v2/components/menu-v2.stories.tsx": "4ed1498d7e4cd51ce9c7459061f3540efdfae71751ff618901c78ee413951559", + "packages/ui/src/v2/components/radio-v2.css": "bf6eb3457a7fc13e48356f5a7dcf3cbf462382580250a3144a745402ff88e2e6", + "packages/ui/src/v2/components/select-v2.css": "4dd4104bee8f661c30ad08ec806e5bddec21d75be6a5d09b693dd297ea10a24c", + "packages/ui/src/v2/components/switch-v2.css": "96406f51a412f931c99c005ecd6a889898ad80160143cca0a81cacfa13714f8f", + "packages/ui/src/v2/components/toast-v2.css": "9b652d908f39e35cdf1764f1675e4db3dea1d7abf43cb792cfa2d27b699f2723", + "packages/ui/src/v2/components/tooltip-v2.css": "7cbd2523d9f183b7e24bfbc1f523c370abf8e32836f8be90cfdf75e1c70f05a9", + "packages/ui/src/v2/components/wordmark-v2.tsx": "6037a68db862ddd67235cbae8dae5a95c9f7403e7c5f268b78fdaaf013950166", + "packages/ui/src/v2/styles/theme.css": "3b6fc14460c39ed8b48c71f7527ab510282c014fc385ed6a08cae3686fd145bc" }, - { - "path": "packages/app/src/components/posture-indicator.ts", - "sha256": "f546413e0e1f8296a7a444d1c07da724d67a160657888273110d06cb6789933d", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/components/settings-v2/subagent-routing.tsx", - "sha256": "9fe28325e0af15ae08aea3571b33bacc2aae7a07589d04928222466fc3ba06cc", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/components/subagent-routing.ts", - "sha256": "fa7775099009e162bfa53d3d05b08f4fc0f82b58f5164ecf419034c1e41a9890", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/context/global-sync/h1-client-boot.ts", - "sha256": "d1c3d5b17049413035ac17923a08c31f157fe20822871ecda798f8f883f3ff22", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/context/global-sync/session-currency.ts", - "sha256": "15ef51616b0cc3ff57a033de1c333d67e09280c6dcb744f4550d633618e2a9ee", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/context/global-sync/session-snapshot.ts", - "sha256": "e53df5cc501c6c4e94f65e350ad9bf7e0cf3ee7561b4cf3b06023e866bceda7e", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/context/global-sync/session-trim.ts", - "sha256": "e1466014f94d2c3cd3d2e494a7dad1bb54186e1ce88e407b9bb45325a45c7aa6", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/i18n/desktop-native.ts", - "sha256": "8fed66d36a0b6cdbf50e3a50f14b6f8ab3570e342e0905e5a926d7dc6c57f8fa", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/pages/home/fleet-sessions-view.tsx", - "sha256": "b0ee306085a7dba117da9930e2e3908f2dbbb3e5776e3a4d57e82c3f4de55d55", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/pages/home/fleet-sessions.ts", - "sha256": "e596d31f7fbec59f9d2f0a376d1bb3ad75744dc458073a5115a07e3ce3480389", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/pages/home/home-session-groups.ts", - "sha256": "881e5c86fd2f6bb8663aec6d618e183b5c4daabd64d48d7f88fe63ee6699aedc", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/pages/home/home-sessions.tsx", - "sha256": "0f011c6741e40a667913b7db743aec98c2e899ebf63fd8f1f5de870974996802", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/utils/boot-parity.ts", - "sha256": "5231be428fc832cd941aafbe70e4620b696321b87a2769d28372ecd2feb9dc41", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/utils/path-key.ts", - "sha256": "a8dc8e7799d27fe832aee95f83e6747673fce5dec0f571aaefefca0e31153b64", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/utils/session-list-conformance.ts", - "sha256": "39af003bae6159761ed5b0ab709fc1ab796194f8c0543dc80f29f3d49f1af4c3", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/app/src/utils/session-list-state.ts", - "sha256": "3c6ac47f3e73b14e6d5380c5d8500d0df330740e4652e6afac0547c86c9b9ea7", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/session-ui/src/components/session-diff.ts", - "sha256": "97f1ca7f80cb316c3fd2b228a8f8d4db3a6b78d155216148e0a3198c500ac6d7", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/session-ui/src/pierre/media.ts", - "sha256": "a4b1b3f622b623fde123b8a8009f9f55a01ed1da34b3425e94b39c884cbfa3ee", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/session-ui/src/pierre/selection-bridge.ts", - "sha256": "3517bdfc4ce387f9ebfe88a56c93040829e2c1ecbc3f9dfa990eebaa0c995b5e", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/ui/src/amicode/docket.ts", - "sha256": "d157d2a7a0a8e716c0520c135b24af7eff84841248a50f76e6e5f02f6a83b8f1", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/ui/src/components/amicode-docket.tsx", - "sha256": "060f2be2b0a91b38cc122f2a77baf9939a8eda19bae683c7814cfbf281ec9b3c", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - }, - { - "path": "packages/ui/src/context/marked-parser.tsx", - "sha256": "cb72ef9e104111c316aa5b80fab01ba8688571cbce9ccadd9a9fb7ec0d98bbfd", - "reason": "Retained legacy overlay module pending its successor test migration", - "review": "harmoniqs/amicode#1004" - } - ] + "symlinks": [ + "packages/app/public/amico.svg" + ], + "deletions": [ + "packages/app/src/components/debug-bar.tsx", + "packages/ui/src/components/text-shimmer.css", + "packages/ui/src/components/text-shimmer.stories.tsx", + "packages/ui/src/components/text-shimmer.tsx", + "packages/ui/src/v2/components/text-shimmer-v2.css", + "packages/ui/src/v2/components/text-shimmer-v2.stories.tsx", + "packages/ui/src/v2/components/text-shimmer-v2.tsx" + ], + "exceptions": [ + { + "path": "packages/app/src/components/posture-indicator-view.tsx", + "sha256": "1bd7903838926b21609c08460ff06683c6e0f378ae968e8b497de041d0f09bdd", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/components/posture-indicator.ts", + "sha256": "f546413e0e1f8296a7a444d1c07da724d67a160657888273110d06cb6789933d", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/components/settings-v2/subagent-routing.tsx", + "sha256": "9fe28325e0af15ae08aea3571b33bacc2aae7a07589d04928222466fc3ba06cc", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/components/subagent-routing.ts", + "sha256": "fa7775099009e162bfa53d3d05b08f4fc0f82b58f5164ecf419034c1e41a9890", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/context/global-sync/h1-client-boot.ts", + "sha256": "d1c3d5b17049413035ac17923a08c31f157fe20822871ecda798f8f883f3ff22", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/context/global-sync/session-currency.ts", + "sha256": "15ef51616b0cc3ff57a033de1c333d67e09280c6dcb744f4550d633618e2a9ee", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/context/global-sync/session-snapshot.ts", + "sha256": "e53df5cc501c6c4e94f65e350ad9bf7e0cf3ee7561b4cf3b06023e866bceda7e", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/context/global-sync/session-trim.ts", + "sha256": "e1466014f94d2c3cd3d2e494a7dad1bb54186e1ce88e407b9bb45325a45c7aa6", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/i18n/desktop-native.ts", + "sha256": "8fed66d36a0b6cdbf50e3a50f14b6f8ab3570e342e0905e5a926d7dc6c57f8fa", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/pages/home/fleet-sessions-view.tsx", + "sha256": "b0ee306085a7dba117da9930e2e3908f2dbbb3e5776e3a4d57e82c3f4de55d55", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/pages/home/fleet-sessions.ts", + "sha256": "e596d31f7fbec59f9d2f0a376d1bb3ad75744dc458073a5115a07e3ce3480389", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/pages/home/home-session-groups.ts", + "sha256": "881e5c86fd2f6bb8663aec6d618e183b5c4daabd64d48d7f88fe63ee6699aedc", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/pages/home/home-sessions.tsx", + "sha256": "0f011c6741e40a667913b7db743aec98c2e899ebf63fd8f1f5de870974996802", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/utils/boot-parity.ts", + "sha256": "5231be428fc832cd941aafbe70e4620b696321b87a2769d28372ecd2feb9dc41", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/utils/path-key.ts", + "sha256": "a8dc8e7799d27fe832aee95f83e6747673fce5dec0f571aaefefca0e31153b64", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/utils/session-list-conformance.ts", + "sha256": "39af003bae6159761ed5b0ab709fc1ab796194f8c0543dc80f29f3d49f1af4c3", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/app/src/utils/session-list-state.ts", + "sha256": "3c6ac47f3e73b14e6d5380c5d8500d0df330740e4652e6afac0547c86c9b9ea7", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/session-ui/src/components/session-diff.ts", + "sha256": "97f1ca7f80cb316c3fd2b228a8f8d4db3a6b78d155216148e0a3198c500ac6d7", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/session-ui/src/pierre/media.ts", + "sha256": "a4b1b3f622b623fde123b8a8009f9f55a01ed1da34b3425e94b39c884cbfa3ee", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/session-ui/src/pierre/selection-bridge.ts", + "sha256": "3517bdfc4ce387f9ebfe88a56c93040829e2c1ecbc3f9dfa990eebaa0c995b5e", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/ui/src/amicode/docket.ts", + "sha256": "d157d2a7a0a8e716c0520c135b24af7eff84841248a50f76e6e5f02f6a83b8f1", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/ui/src/components/amicode-docket.tsx", + "sha256": "060f2be2b0a91b38cc122f2a77baf9939a8eda19bae683c7814cfbf281ec9b3c", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + }, + { + "path": "packages/ui/src/context/marked-parser.tsx", + "sha256": "cb72ef9e104111c316aa5b80fab01ba8688571cbce9ccadd9a9fb7ec0d98bbfd", + "reason": "Retained legacy overlay module pending its successor test migration", + "review": "harmoniqs/amicode#1004" + } + ] } diff --git a/packages/app-bundle/overlay/packages/app/src/components/settings-v2/developer-tools-controller.ts b/packages/app-bundle/overlay/packages/app/src/components/settings-v2/developer-tools-controller.ts index 1f605ca81..be227e3ce 100644 --- a/packages/app-bundle/overlay/packages/app/src/components/settings-v2/developer-tools-controller.ts +++ b/packages/app-bundle/overlay/packages/app/src/components/settings-v2/developer-tools-controller.ts @@ -25,8 +25,7 @@ export interface RebuildErrorInfo { detail?: string } -/** Default repo paths autofilled when the toggle is turned ON with empty fields. */ -const DEFAULT_OPENCODE_PATH = "~/harmoniqs/opencode" +/** Default repo path autofilled when the toggle is turned ON with empty fields. */ const DEFAULT_AMICODE_PATH = "~/harmoniqs/amicode" export function createDeveloperToolsController() { @@ -210,9 +209,6 @@ export function createDeveloperToolsController() { setEnabled: (value: boolean) => { // Autofill paths with defaults when toggling ON with empty fields if (value) { - if (!settings.developer.opencodePath()) { - settings.developer.setOpencodePath(DEFAULT_OPENCODE_PATH) - } if (!settings.developer.amicodePath()) { settings.developer.setAmicodePath(DEFAULT_AMICODE_PATH) } diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/ar.ts b/packages/app-bundle/overlay/packages/app/src/i18n/ar.ts index 852d87943..e8ff442a8 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/ar.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/ar.ts @@ -762,7 +762,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/br.ts b/packages/app-bundle/overlay/packages/app/src/i18n/br.ts index aec087e34..9d0584c27 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/br.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/br.ts @@ -774,7 +774,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/bs.ts b/packages/app-bundle/overlay/packages/app/src/i18n/bs.ts index 4f6d62e74..2c8708f9f 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/bs.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/bs.ts @@ -840,7 +840,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/da.ts b/packages/app-bundle/overlay/packages/app/src/i18n/da.ts index 016545ed9..a5eec9195 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/da.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/da.ts @@ -832,7 +832,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/de.ts b/packages/app-bundle/overlay/packages/app/src/i18n/de.ts index d24991183..b36acacf6 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/de.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/de.ts @@ -786,7 +786,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/en.ts b/packages/app-bundle/overlay/packages/app/src/i18n/en.ts index c1fc23190..7aae3a50f 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/en.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/en.ts @@ -1018,7 +1018,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/es.ts b/packages/app-bundle/overlay/packages/app/src/i18n/es.ts index 3af98784f..0709ff7e8 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/es.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/es.ts @@ -845,7 +845,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/fr.ts b/packages/app-bundle/overlay/packages/app/src/i18n/fr.ts index dd9717c78..c3e8d1483 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/fr.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/fr.ts @@ -784,7 +784,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/ja.ts b/packages/app-bundle/overlay/packages/app/src/i18n/ja.ts index 8d576b728..ad14f203c 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/ja.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/ja.ts @@ -769,7 +769,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/ko.ts b/packages/app-bundle/overlay/packages/app/src/i18n/ko.ts index 536d73a77..ae25d7021 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/ko.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/ko.ts @@ -611,7 +611,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/no.ts b/packages/app-bundle/overlay/packages/app/src/i18n/no.ts index 989408b4c..214343306 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/no.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/no.ts @@ -685,7 +685,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/pl.ts b/packages/app-bundle/overlay/packages/app/src/i18n/pl.ts index 5a5b4f3b8..21d869569 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/pl.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/pl.ts @@ -774,7 +774,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/ru.ts b/packages/app-bundle/overlay/packages/app/src/i18n/ru.ts index 00288f892..aac8fae82 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/ru.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/ru.ts @@ -841,7 +841,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/th.ts b/packages/app-bundle/overlay/packages/app/src/i18n/th.ts index f0ec920a0..09ef788f8 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/th.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/th.ts @@ -828,7 +828,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/tr.ts b/packages/app-bundle/overlay/packages/app/src/i18n/tr.ts index 9a3007238..0134657cb 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/tr.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/tr.ts @@ -847,7 +847,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/uk.ts b/packages/app-bundle/overlay/packages/app/src/i18n/uk.ts index 97a915d85..71ca74a8e 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/uk.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/uk.ts @@ -934,7 +934,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/zh.ts b/packages/app-bundle/overlay/packages/app/src/i18n/zh.ts index f500159c0..fac211ae0 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/zh.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/zh.ts @@ -821,7 +821,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/overlay/packages/app/src/i18n/zht.ts b/packages/app-bundle/overlay/packages/app/src/i18n/zht.ts index b6141ea9e..124a36b60 100644 --- a/packages/app-bundle/overlay/packages/app/src/i18n/zht.ts +++ b/packages/app-bundle/overlay/packages/app/src/i18n/zht.ts @@ -818,7 +818,7 @@ export const dict = { "settings.general.row.opencodePath.title": "opencode repo path", "settings.general.row.opencodePath.description": "Path to your local opencode repository root (the binary is resolved from here)", - "settings.general.row.opencodePath.placeholder": "~/harmoniqs/opencode", + "settings.general.row.opencodePath.placeholder": "/path/to/opencode", "settings.general.row.opencodePath.error.notFound": "Binary not found at this path", "settings.general.row.opencodePath.error.notExecutable": "Binary exists but is not executable", "settings.general.row.amicodePath.title": "Amicode repo path", diff --git a/packages/app-bundle/package.json b/packages/app-bundle/package.json index d1c9f1e06..31dd87d78 100644 --- a/packages/app-bundle/package.json +++ b/packages/app-bundle/package.json @@ -5,9 +5,7 @@ "type": "module", "description": "M2 slice (a): the fork-owned app overlay for canonical opencode — extracted from the opencode fork at a pinned tag, materialized onto a canonical upstream base (#451).", "scripts": { - "extract": "node scripts/extract_overlay.mjs", "materialize": "node scripts/materialize.mjs --out .materialized", - "sync:check": "node scripts/overlay-promotion.mjs --check", - "sync:apply": "node scripts/overlay-promotion.mjs --apply" + "drift-gate": "node scripts/drift_gate.mjs" } } diff --git a/packages/app-bundle/scripts/drift_gate.mjs b/packages/app-bundle/scripts/drift_gate.mjs index cac1a2dbf..58f20937d 100644 --- a/packages/app-bundle/scripts/drift_gate.mjs +++ b/packages/app-bundle/scripts/drift_gate.mjs @@ -1,58 +1,25 @@ #!/usr/bin/env node -// M2 CI drift gate (#451) — verifies the committed overlay + manifest are in -// sync with what the fork at the pinned tag would extract, WITHOUT touching -// them. Runs in CI on PRs that touch packages/app-bundle. +// Committed-overlay integrity check — verifies the overlay tree matches the +// manifest. Post-absorption: no fork comparison (the fork is absorbed). // -// Checks, in order: -// 1. manifest.json's fork_tag/fork_sha and upstream_base/upstream_base_sha -// resolve in the fork at the pinned commits. -// 2. A fresh extraction (into a temp dir, via --out) reproduces the -// committed manifest EXACTLY (same file set, same per-file hashes). -// 3. Every file in the committed overlay/ is in the manifest and exists on -// disk with the manifest's hash (catches hand-edits + stray files). -// -// node scripts/drift_gate.mjs [--fork ] [--tag v1.18.10-amicode.14] +// node scripts/drift_gate.mjs // // Exit 0 = in sync. Exit 1 = drift (names the first divergence). -// NOTE: the fork clone is a private repo — in CI the gate runs only when the -// checkout is present (AMICODE_OPENCODE_SRC or the sibling layout); otherwise -// it SKIPS with exit 0 and a printed reason (the committed overlay itself is -// the artifact CI protects; the re-derivation needs fork access). -import { spawnSync } from "node:child_process"; import { createHash } from "node:crypto"; import { existsSync, lstatSync, readFileSync, readlinkSync, readdirSync } from "node:fs"; -import { homedir } from "node:os"; import { join } from "node:path"; const PKG_ROOT = join(import.meta.dirname, ".."); -const FORK_DEFAULT = join(homedir(), "armonia", "repos", "opencode"); - -const args = process.argv.slice(2); -const flag = (n) => { - const i = args.indexOf(`--${n}`); - return i >= 0 ? args[i + 1] : undefined; -}; const manifestPath = join(PKG_ROOT, "manifest.json"); const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); -const TAG = flag("tag") ?? manifest.fork_tag; -const FORK = flag("fork") ?? process.env.AMICODE_OPENCODE_SRC ?? FORK_DEFAULT; const fail = (msg) => { console.error(`[drift-gate] FAIL: ${msg}`); process.exit(1); }; -if (!existsSync(FORK) || !existsSync(join(FORK, ".git"))) { - console.log(`[drift-gate] SKIP: no fork clone at ${FORK} (set AMICODE_OPENCODE_SRC) — protecting committed state only`); -} - // ── 1. upstream base archive verifies against the manifest's recorded sha ─── -// Since the v1.18.29 re-base (#796) the overlay is maintained against the -// CANONICAL upstream tree (repaired in place), not extracted from the fork — -// the old fork-extraction equality checks are retired. The upstream base is -// pinned by (tag, git sha, archive sha256); the archive check runs against the -// materializer's cache stamp when the cache is warm. const cacheStamp = join(PKG_ROOT, ".cache", `anomalyco_opencode@${manifest.upstream_base}`, "sha256"); if (existsSync(cacheStamp)) { if (manifest.upstream_base_archive_sha256 === undefined) { @@ -74,7 +41,7 @@ for (const rel of readdirSync(overlayDir, { recursive: true })) { const p = join(overlayDir, rel.toString()); const st = lstatSync(p); if (st.isSymbolicLink()) { - onDisk.add(rel.toString()); // hashed as the link-target string + onDisk.add(rel.toString()); continue; } if (st.isFile()) onDisk.add(rel.toString()); @@ -105,19 +72,4 @@ for (const [rel, want] of Object.entries(declaredFiles)) { if (h !== want) fail(`overlay file hash mismatch (hand-edit?): ${rel} — re-run the extractor`); } console.log(`[drift-gate] committed overlay verified against the manifest (${onDisk.size} files)`); - -// A checkout of the private fork turns this from a committed-state integrity -// check into the cross-repository proof: derive the complete delta at the -// manifest's immutable SHA and compare it with the committed tracking copy. -if (existsSync(FORK) && existsSync(join(FORK, ".git"))) { - const promotion = spawnSync( - process.execPath, - [join(PKG_ROOT, "scripts", "overlay-promotion.mjs"), "--check", "--source", FORK, "--revision", manifest.fork_sha], - { cwd: PKG_ROOT, encoding: "utf8" }, - ); - if (promotion.status !== 0) { - fail(`cross-repository provenance failed: ${(promotion.stderr || promotion.stdout).trim()}`); - } - console.log(`[drift-gate] cross-repository provenance verified at ${manifest.fork_sha.slice(0, 12)}`); -} console.log("[drift-gate] PASS: overlay and manifest are in sync"); diff --git a/packages/app-bundle/scripts/extract_overlay.mjs b/packages/app-bundle/scripts/extract_overlay.mjs deleted file mode 100644 index 73bd1da67..000000000 --- a/packages/app-bundle/scripts/extract_overlay.mjs +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env node -// M2 overlay extractor (#451) — extracts the app-bundle overlay from the -// opencode fork at a pinned tag into packages/app-bundle/overlay/, at -// UPSTREAM-RELATIVE paths, and writes manifest.json (per-file sha256 + the -// machine-derived A/M/D classification against the upstream base). -// -// node scripts/extract_overlay.mjs [--fork ] [--tag v1.18.10-amicode.14] [--slice a|ab] -// -// The fork clone defaults to the sibling checkout (team layout: -// ~/armonia/repos/opencode). Extraction is deterministic: same tag → -// identical bytes → identical hashes (files are read via git archive AT the -// tag, never the working tree). -// -// SCOPE (slice b, corrected 2026-08-21): the COMPLETE fork-vs-base delta of -// the app's build graph — packages/{app,ui,session-ui,schema,core,sdk,opencode}. -// -// The additive-only scope this slice was planned around does not typecheck: -// ~10 additive app files depend on SYMBOL-LEVEL additions in modified files -// (settings.developer, tabs.openPath, model.pin, QuestionInfo.kind — the -// typed question cards spanning schema/core/sdk), and the fork's debug-bar -// deletion forces layout.tsx into the overlay (base layout imports the -// deleted module). The fork delta is a cross-cutting FEATURE delta, not an -// app-layer delta. The complete-graph overlay is the honest scope: -// -// - equivalence is trivial (byte-identical per package) and -// - composition (install + typecheck + build) proves the bundle buildable -// against a fork-equivalent tree TODAY. -// -// The manifest's per-package classification + the server-coupled files -// (schema/core/sdk — types & runtime the CANONICAL server will not have) -// are the machine-derived M3 CUTOVER PORT INVENTORY: every feature that -// spans the app and the fork's server packages is on it, because the bundle -// will hit exactly these gaps against canonical at cutover. -// -// The compose-vs-fork decomposition of the true overlays (home.tsx etc.) -// remains deliberate POST-cutover maintenance work — wholesale overlay -// inclusion is correct for the one-push cutover this plan ships. -// -// BASE: v1.18.12 — tree-equal to the fork's true merge base (b0b114923, -// v1.18.12~1) except the tag commit's version-string bumps, which land in -// files the overlay owns (package.json). The fork's v1.18.12 merge (2026-08-04) -// landed everything up to just-before the tag; the "1.18.12" version string in -// the fork's package.json is that merge's residue, not a later sync. -import { execFileSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { lstatSync, mkdirSync, readFileSync, readlinkSync, rmSync, statSync, writeFileSync } from "node:fs"; -import { homedir } from "node:os"; -import { dirname, join, normalize } from "node:path"; - -const PKG_ROOT = join(import.meta.dirname, ".."); -const FORK_DEFAULT = join(homedir(), "armonia", "repos", "opencode"); - -const args = process.argv.slice(2); -const flag = (n) => { - const i = args.indexOf(`--${n}`); - return i >= 0 ? args[i + 1] : undefined; -}; - -// --out: write overlay/ + manifest.json here instead of the package root (the -// drift gate re-derives without touching committed state). -const OUT_ROOT = flag("out") ?? PKG_ROOT; - -const UPSTREAM_BASE = "v1.18.12"; -const TAG = flag("tag") ?? "v1.18.10-amicode.14"; -const SLICE = flag("slice") ?? "full"; -const FORK = flag("fork") ?? process.env.AMICODE_OPENCODE_SRC ?? FORK_DEFAULT; - -const git = (...a) => execFileSync("git", ["-C", FORK, ...a], { encoding: "utf8" }).trim(); -const gitAt = (spec, maxBuffer = 1 << 26) => - execFileSync("git", ["-C", FORK, "show", spec], { maxBuffer }); - -// ── 1. resolve the tag + compute the deltas ─────────────────────────────────── -const tagSha = git("rev-parse", `${TAG}^{commit}`); -const baseSha = git("rev-parse", `${UPSTREAM_BASE}^{commit}`); -console.log(`[extract] fork ${FORK} @ ${TAG} (${tagSha.slice(0, 10)}), upstream base ${UPSTREAM_BASE} (${baseSha.slice(0, 10)}), slice ${SLICE}`); - -function diffStatus(paths) { - return git("diff", "--name-status", UPSTREAM_BASE, TAG, "--", ...paths) - .split("\n") - .filter(Boolean) - .map((line) => { - const [status, ...rest] = line.split("\t"); - return { status, path: rest[rest.length - 1] }; - }); -} - -const GRAPH_PKGS = ["packages/app", "packages/ui", "packages/session-ui", "packages/schema", "packages/core", "packages/sdk", "packages/opencode"]; -const SERVER_COUPLED_PKGS = ["packages/schema", "packages/core", "packages/sdk"]; - -const graphDelta = diffStatus(GRAPH_PKGS); - -const uiOverlay = graphDelta.filter((d) => d.path.startsWith("packages/ui/") && d.status !== "D").map((d) => d.path); -const appSessionAdds = graphDelta.filter((d) => !SERVER_COUPLED_PKGS.some((p) => d.path.startsWith(p + "/")) && d.path.startsWith("packages/") && !d.path.startsWith("packages/ui/") && d.status === "A").map((d) => d.path); -const appSessionMods = graphDelta.filter((d) => !SERVER_COUPLED_PKGS.some((p) => d.path.startsWith(p + "/")) && !d.path.startsWith("packages/ui/") && d.status === "M").map((d) => d.path); -const appSessionDels = graphDelta.filter((d) => d.status === "D").map((d) => d.path); -const serverCoupled = graphDelta.filter((d) => SERVER_COUPLED_PKGS.some((p) => d.path.startsWith(p + "/")) && d.status !== "D").map((d) => d.path); - -// ── 2. server-coupled files (schema/core/sdk): part of the overlay (the -// bundle typechecks against them today), AND the M3 cutover port inventory -// (they carry types/runtime the canonical server will NOT have at cutover). ── - -// ── 3. the overlay set ─────────────────────────────────────────────────────── -const overlayFiles = [...new Set([...graphDelta.filter((d) => d.status !== "D").map((d) => d.path)])].sort(); -const classification = {}; -for (const d of graphDelta) if (d.status !== "D") classification[d.path] = d.status; -const deletions = graphDelta.filter((d) => d.status === "D").map((d) => d.path); - -const perPkg = {}; -for (const d of graphDelta) { - const pkg = d.path.split("/").slice(0, 2).join("/"); - perPkg[pkg] ??= { A: 0, M: 0, D: 0 }; - perPkg[pkg][d.status] += 1; -} -console.log("[extract] per-package delta:", JSON.stringify(perPkg)); -console.log( - `[extract] app+session-ui overlays: ${appSessionAdds.length} A + ${appSessionMods.length} M (complete); server-coupled (schema/core/sdk): ${serverCoupled.length} files — the M3 cutover port inventory`, -); -console.log(`[extract] OVERLAY TOTAL: ${overlayFiles.length} files, ${deletions.length} deletions`); - -// ── 4. extract at their upstream-relative paths, AT THE TAG ────────────────── -const overlayDir = join(OUT_ROOT, "overlay"); -rmSync(overlayDir, { recursive: true, force: true }); -mkdirSync(overlayDir, { recursive: true }); -if (overlayFiles.length > 0) { - // git archive arg list can get long — batch it. - for (let i = 0; i < overlayFiles.length; i += 100) { - const batch = overlayFiles.slice(i, i + 100); - execFileSync("sh", [ - "-c", - `git -C '${FORK}' archive --format=tar ${TAG} ${batch.map((f) => `'${f}'`).join(" ")} | tar -x -C '${overlayDir}'`, - ]); - } -} - -// ── 5. manifest: hashes + classification + round-trip proof ───────────────── -const sha256Buf = (b) => createHash("sha256").update(b).digest("hex"); -const hashes = {}; -let mismatches = 0; -for (const rel of overlayFiles) { - const p = join(overlayDir, rel); - const st = lstatSync(p); - if (st.isSymbolicLink()) { - // Symlinks: git archive materializes them as real symlinks; `git show` - // prints the TARGET PATH, not the content. The round-trip proof for a - // symlink is readlink === the git blob's content. - const link = readlinkSync(p); - const blob = gitAt(`${TAG}:${rel}`).toString("utf8").trimEnd(); - if (link !== blob) { - console.error(`[extract] ROUND-TRIP MISMATCH (symlink): ${rel}: ${link} != ${blob}`); - mismatches++; - } - // hash the LINK TARGET STRING (the stable, content-independent identity) - hashes[rel] = createHash("sha256").update(link).digest("hex"); - continue; - } - if (!st.isFile()) throw new Error(`extractor bug: ${rel} not a regular file after archive`); - const blob = gitAt(`${TAG}:${rel}`); - const h = sha256Buf(readFileSync(p)); - if (h !== sha256Buf(blob)) { - console.error(`[extract] ROUND-TRIP MISMATCH: ${rel}`); - mismatches++; - } - hashes[rel] = h; -} -if (mismatches > 0) process.exit(1); -console.log(`[extract] round-trip: all ${overlayFiles.length} files byte-identical to ${TAG}`); - -const manifest = { - schema: 4, - slices: "b (complete app-graph delta)", - scope: "complete fork-vs-base delta of packages/{app,ui,session-ui,schema,core,sdk,opencode}", - fork_tag: TAG, - fork_sha: tagSha, - upstream_base: UPSTREAM_BASE, - upstream_base_sha: baseSha, - extracted_at: new Date().toISOString(), - per_package: perPkg, - counts: { - overlay_total: overlayFiles.length, - deletions: deletions.length, - server_coupled: serverCoupled.length, - }, - // The M3 CUTOVER PORT INVENTORY: schema/core/sdk files whose types or - // runtime the canonical server will NOT have. Every app feature touching - // these is a cutover blocker to port upstream, reimplement in the - // extension service, or drop from the bundle. - server_coupled_port_inventory: serverCoupled.sort(), - // The true overlays (big M-files in app/ui upstream still evolves), - // recorded for the POST-cutover compose-vs-fork decomposition. - true_overlays: graphDelta - .filter((d) => d.status === "M" && !SERVER_COUPLED_PKGS.some((p) => d.path.startsWith(p + "/"))) - .map((d) => d.path) - .sort(), - deletions, - classification, - files: hashes, -}; -writeFileSync(join(OUT_ROOT, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n"); -console.log(`[extract] wrote manifest.json (${overlayFiles.length} entries, ${deletions.length} deletions)`); diff --git a/packages/app-bundle/scripts/overlay-promotion.mjs b/packages/app-bundle/scripts/overlay-promotion.mjs deleted file mode 100644 index 3474ae5da..000000000 --- a/packages/app-bundle/scripts/overlay-promotion.mjs +++ /dev/null @@ -1,315 +0,0 @@ -#!/usr/bin/env node -// Generate or verify the complete tracked overlay for one immutable fork -// revision. Rebuilds call --check; only an explicit promotion calls --apply. - -import { execFileSync } from "node:child_process" -import { createHash } from "node:crypto" -import { - copyFileSync, - existsSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - readlinkSync, - readdirSync, - renameSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs" -import { homedir, tmpdir } from "node:os" -import { dirname, join, resolve as resolvePath } from "node:path" - -const PKG_ROOT = join(import.meta.dirname, "..") -const REPO_ROOT = join(PKG_ROOT, "..", "..") -const DEFAULT_TARGET = join(PKG_ROOT, "overlay") -const DEFAULT_MANIFEST = join(PKG_ROOT, "manifest.json") -const DEFAULT_SOURCE_BRANCH = "local/amicode" -const OVERLAY_PATHS = ["packages/app", "packages/ui", "packages/session-ui", "packages/schema", "packages/core", "packages/sdk", "packages/opencode"] - -const args = process.argv.slice(2) -const flag = (name) => { - const index = args.indexOf(`--${name}`) - return index < 0 ? undefined : args[index + 1] -} -const flags = (name) => args.flatMap((value, index) => value === `--${name}` && args[index + 1] ? [args[index + 1]] : []) - -const fail = (message) => { - console.error(`[overlay-promotion] FAIL: ${message}`) - return 1 -} - -const hash = (value) => createHash("sha256").update(value).digest("hex") - -function git(source, gitArgs, encoding = "utf8") { - return execFileSync("git", ["-C", source, ...gitArgs], { encoding, maxBuffer: 1 << 28 }) -} - -function gitText(source, gitArgs) { - return String(git(source, gitArgs)).trim() -} - -function resolve(source, revision) { - return gitText(source, ["rev-parse", `${revision}^{commit}`]) -} - -function walk(dir) { - if (!existsSync(dir)) return [] - const files = [] - for (const entry of readdirSync(dir, { recursive: true })) { - const rel = entry.toString() - const stat = lstatSync(join(dir, rel)) - if (stat.isFile() || stat.isSymbolicLink()) files.push(rel) - } - return files.sort() -} - -function fileHash(file) { - const stat = lstatSync(file) - return stat.isSymbolicLink() ? hash(readlinkSync(file)) : hash(readFileSync(file)) -} - -function sourceGuard(source, expectedBranch, revision) { - if (!existsSync(join(source, ".git"))) return "the source is not a git checkout" - const branch = gitText(source, ["branch", "--show-current"]) - if (branch !== expectedBranch) return `the source is on '${branch || "(detached HEAD)"}', not '${expectedBranch}'` - if (gitText(source, ["status", "--porcelain"])) return "the source checkout is dirty" - if (resolve(source, "HEAD") !== revision) return `--revision ${revision.slice(0, 12)} is not the checked-out source HEAD` - return null -} - -function changedPaths(source, base, revision) { - const files = new Map() - const deletions = new Set() - const output = gitText(source, ["diff", "--name-status", base, revision, "--", ...OVERLAY_PATHS]) - if (!output) return { files, deletions } - - for (const line of output.split("\n")) { - const fields = line.split("\t") - const status = fields[0] - if (status.startsWith("D")) { - deletions.add(fields[1]) - continue - } - if (status.startsWith("R") || status.startsWith("C")) { - if (status.startsWith("R")) deletions.add(fields[1]) - files.set(fields[2], fileAtRevision(source, revision, fields[2])) - continue - } - files.set(fields[1], fileAtRevision(source, revision, fields[1])) - } - return { files, deletions } -} - -function fileAtRevision(source, revision, rel) { - const mode = gitText(source, ["ls-tree", revision, "--", rel]).split(/\s+/)[0] - return { bytes: git(source, ["show", `${revision}:${rel}`], null), symlink: mode === "120000" } -} - -function fileAtAmicodeRevision(revision, rel) { - const source = `packages/app-bundle/overlay/${rel}` - const mode = gitText(REPO_ROOT, ["ls-tree", revision, "--", source]).split(/\s+/)[0] - return { bytes: git(REPO_ROOT, ["show", `${revision}:${source}`], null), symlink: mode === "120000" } -} - -function expectedContract(source, baseRef, revision) { - const base = resolve(source, baseRef) - const { files, deletions } = changedPaths(source, base, revision) - const hashes = Object.fromEntries([...files.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([rel, file]) => [rel, hash(file.bytes)])) - const symlinks = [...files.entries()].filter(([, file]) => file.symlink).map(([rel]) => rel).sort() - return { base, files, hashes, symlinks, deletions: [...deletions].sort() } -} - -function readManifest(manifestPath) { - if (!existsSync(manifestPath)) return null - try { - return JSON.parse(readFileSync(manifestPath, "utf8")) - } catch { - return null - } -} - -function exceptionFiles(manifest, target) { - const exceptions = manifest?.exceptions ?? [] - if (!Array.isArray(exceptions)) return { error: "manifest exceptions must be an array" } - const files = {} - for (const exception of exceptions) { - if (!exception || typeof exception.path !== "string" || typeof exception.sha256 !== "string" || - typeof exception.reason !== "string" || typeof exception.review !== "string") { - return { error: "each overlay exception needs path, sha256, reason, and review" } - } - const file = join(target, exception.path) - if (!existsSync(file) || fileHash(file) !== exception.sha256) { - return { error: `reviewed exception does not match the committed overlay: ${exception.path}` } - } - files[exception.path] = exception.sha256 - } - return { files } -} - -function verify({ source, revision, target, manifestPath, baseRef }) { - const manifest = readManifest(manifestPath) - if (!manifest) return { ok: false, reason: `missing or invalid manifest at ${manifestPath}` } - if (manifest.schema !== 5) return { ok: false, reason: "manifest schema must be 5; run an overlay-promotion first" } - if (manifest.fork_sha !== revision) { - return { ok: false, reason: `manifest records OpenCode ${String(manifest.fork_sha).slice(0, 12)}, checked-out local/amicode is ${revision.slice(0, 12)}. Merge the overlay-promotion commit first.` } - } - const base = baseRef ?? manifest.upstream_base_sha ?? manifest.upstream_base - if (typeof base !== "string" || !base) return { ok: false, reason: "manifest has no upstream_base" } - - let expected - try { - expected = expectedContract(source, base, revision) - } catch (error) { - return { ok: false, reason: `cannot derive the declared source revision: ${error instanceof Error ? error.message : error}` } - } - if (manifest.upstream_base_sha !== expected.base) return { ok: false, reason: "manifest upstream_base_sha does not resolve to its declared base" } - if (JSON.stringify(manifest.files) !== JSON.stringify(expected.hashes)) return { ok: false, reason: "manifest file hashes do not reproduce the declared OpenCode revision" } - if (JSON.stringify(manifest.symlinks ?? []) !== JSON.stringify(expected.symlinks)) return { ok: false, reason: "manifest symlink set does not reproduce the declared OpenCode revision" } - if (JSON.stringify(manifest.deletions) !== JSON.stringify(expected.deletions)) return { ok: false, reason: "manifest deletion set does not reproduce the declared OpenCode revision" } - - const exceptionResult = exceptionFiles(manifest, target) - if (exceptionResult.error) return { ok: false, reason: exceptionResult.error } - const expectedFiles = { ...expected.hashes, ...exceptionResult.files } - const actualFiles = walk(target) - if (JSON.stringify(actualFiles) !== JSON.stringify(Object.keys(expectedFiles).sort())) { - return { ok: false, reason: "overlay file set contains unexplained drift" } - } - for (const [rel, expectedHash] of Object.entries(expectedFiles)) { - if (fileHash(join(target, rel)) !== expectedHash) return { ok: false, reason: `overlay content does not match its declared hash: ${rel}` } - } - for (const rel of expected.symlinks) { - if (!lstatSync(join(target, rel)).isSymbolicLink()) return { ok: false, reason: `overlay file type does not match the declared source revision: ${rel}` } - } - for (const rel of expected.deletions) { - if (existsSync(join(target, rel)) && !exceptionResult.files[rel]) { - return { ok: false, reason: `declared deletion remains in the overlay: ${rel}` } - } - } - return { ok: true, expected } -} - -function promote({ source, revision, baseRef, target, manifestPath, branch, exceptionPaths, exceptionFrom, exceptionReason, exceptionReview }) { - const guard = sourceGuard(source, branch, revision) - if (guard) return fail(`refusing promotion: ${guard}`) - // Only the real overlay/manifest are promotion targets; a custom --target/--manifest - // (e.g. a test fixture) is never the live overlay, so it isn't subject to the - // main-branch guard below. - const isRealPromotionTarget = resolvePath(target) === resolvePath(DEFAULT_TARGET) && resolvePath(manifestPath) === resolvePath(DEFAULT_MANIFEST) - if (isRealPromotionTarget && gitText(REPO_ROOT, ["branch", "--show-current"]) === "main") { - return fail("refusing to write an overlay-promotion directly on Amicode main; use a review branch") - } - if (!baseRef) return fail("--base is required for a promotion") - - const previous = readManifest(manifestPath) - const previousExceptions = exceptionFiles(previous ?? { exceptions: [] }, target) - if (previousExceptions.error) return fail(previousExceptions.error) - if (exceptionPaths.length > 0 && (!exceptionFrom || !exceptionReason || !exceptionReview)) { - return fail("new exceptions require --exception-from, --exception-reason, and --exception-review") - } - const expected = expectedContract(source, baseRef, revision) - for (const rel of Object.keys(previousExceptions.files)) { - if (expected.files.has(rel)) return fail(`reviewed exception is now fork-owned and must be removed: ${rel}`) - } - const exceptions = [...(previous?.exceptions ?? [])] - const restoredExceptions = new Map() - for (const rel of exceptionPaths) { - if (expected.files.has(rel)) return fail(`exception is fork-owned at the promoted revision: ${rel}`) - if (exceptions.some((exception) => exception.path === rel)) return fail(`exception is already recorded: ${rel}`) - let file - try { - file = fileAtAmicodeRevision(exceptionFrom, rel) - } catch { - return fail(`cannot restore exception from Amicode ${exceptionFrom}: ${rel}`) - } - restoredExceptions.set(rel, file) - exceptions.push({ path: rel, sha256: hash(file.bytes), reason: exceptionReason, review: exceptionReview }) - } - - const stage = mkdtempSync(join(tmpdir(), "amicode-overlay-promotion-")) - const stagedOverlay = join(stage, "overlay") - try { - for (const [rel, file] of expected.files) { - const output = join(stagedOverlay, rel) - mkdirSync(dirname(output), { recursive: true }) - if (file.symlink) symlinkSync(file.bytes.toString("utf8"), output) - else writeFileSync(output, file.bytes) - } - for (const rel of Object.keys(previousExceptions.files)) { - const output = join(stagedOverlay, rel) - mkdirSync(dirname(output), { recursive: true }) - copyFileSync(join(target, rel), output) - } - for (const [rel, file] of restoredExceptions) { - const output = join(stagedOverlay, rel) - mkdirSync(dirname(output), { recursive: true }) - if (file.symlink) symlinkSync(file.bytes.toString("utf8"), output) - else writeFileSync(output, file.bytes) - } - - const manifest = { - schema: 5, - scope: "complete fork-vs-base delta of packages/{app,ui,session-ui,schema,core,sdk,opencode}", - fork_ref: previous?.fork_ref ?? branch, - fork_tag: previous?.fork_tag ?? null, - fork_sha: revision, - upstream_base: baseRef, - upstream_base_sha: expected.base, - ...(previous?.upstream_base === baseRef && previous.upstream_base_archive_sha256 - ? { upstream_base_archive_sha256: previous.upstream_base_archive_sha256 } - : {}), - promoted_at: new Date().toISOString(), - files: expected.hashes, - symlinks: expected.symlinks, - deletions: expected.deletions, - exceptions, - } - const stagedManifest = join(stage, "manifest.json") - writeFileSync(stagedManifest, JSON.stringify(manifest, null, 2) + "\n") - - const backup = `${target}.previous` - rmSync(backup, { recursive: true, force: true }) - if (existsSync(target)) renameSync(target, backup) - renameSync(stagedOverlay, target) - renameSync(stagedManifest, manifestPath) - rmSync(backup, { recursive: true, force: true }) - console.log(`[overlay-promotion] promoted ${Object.keys(expected.hashes).length} files and ${expected.deletions.length} deletions from ${revision.slice(0, 12)}`) - return 0 - } finally { - rmSync(stage, { recursive: true, force: true }) - } -} - -const source = flag("source") ?? process.env.AMICODE_OPENCODE_SRC ?? join(homedir(), "harmoniqs", "opencode") -const target = flag("target") ?? DEFAULT_TARGET -const manifestPath = flag("manifest") ?? DEFAULT_MANIFEST -const revisionArg = flag("revision") -if (!revisionArg) process.exit(fail("--revision is required")) -if (!existsSync(join(source, ".git"))) process.exit(fail(`source checkout not found: ${source}`)) - -let revision -try { - revision = resolve(source, revisionArg) -} catch (error) { - process.exit(fail(`cannot resolve --revision ${revisionArg}: ${error instanceof Error ? error.message : error}`)) -} - -if (args.includes("--apply")) { - process.exit(promote({ - source, - revision, - baseRef: flag("base"), - target, - manifestPath, - branch: flag("source-branch") ?? DEFAULT_SOURCE_BRANCH, - exceptionPaths: flags("exception"), - exceptionFrom: flag("exception-from"), - exceptionReason: flag("exception-reason"), - exceptionReview: flag("exception-review"), - })) -} - -const result = verify({ source, revision, target, manifestPath, baseRef: flag("base") }) -if (!result.ok) process.exit(fail(result.reason)) -console.log(`[overlay-promotion] PASS: ${Object.keys(result.expected.hashes).length} files and ${result.expected.deletions.length} deletions reproduce ${revision.slice(0, 12)}`) diff --git a/packages/app-bundle/scripts/overlay-sync.mjs b/packages/app-bundle/scripts/overlay-sync.mjs deleted file mode 100644 index 6e3e1094a..000000000 --- a/packages/app-bundle/scripts/overlay-sync.mjs +++ /dev/null @@ -1,378 +0,0 @@ -#!/usr/bin/env node -// Overlay ↔ fork sync check and apply. -// -// The fork (~/harmoniqs/opencode or AMICODE_OPENCODE_SRC) is the source of -// truth for the app source files amicode has NOT fixed. The overlay -// (packages/app-bundle/overlay/) is a tracking copy. This script detects and -// fixes drift between them. -// -// node scripts/overlay-sync.mjs --check exit 0 if in sync, 1 if drifted -// node scripts/overlay-sync.mjs --apply copy fork → overlay + update hashes -// node scripts/overlay-sync.mjs --apply --include -// add one required fork source file -// -// Options: -// --source fork checkout to read from (default: resolved fork) -// --target overlay tree to read/apply (default: -// packages/app-bundle/overlay) — the tests aim this at -// a tmpdir so no run mutates committed overlay state -// --manifest manifest to update (default: /../manifest.json) -// --source-branch expected fork branch (default: local/amicode) -// -// SAFETY (#842) — the sync must never silently clobber committed state: -// * --check NEVER writes. -// * --apply refuses when the source checkout is not on the expected branch -// (default local/amicode) or has uncommitted changes — named remedy -// (mirrors #992's pre-flight). Set AMICODE_OVERLAY_SYNC_OVERRIDE= -// to proceed with the waiver recorded; an empty reason refuses. -// * --apply refuses, writing nothing, when the copy would REVERT an -// amicode-side known fix (#964/#929/#832) — the known-fixes fixture list -// is the shared module scripts/known_fixes.mjs. This is why the sync is -// safe to run: the fork is authoritative for unfixed files only. -// -// Resolves the fork path in order: -// 1. --source -// 2. AMICODE_OPENCODE_SRC env var -// 3. ../opencode sibling (relative to repo root) -// 4. ~/harmoniqs/opencode -// Skips with exit 0 if no fork clone is found. - -import { execFileSync } from "node:child_process" -import { createHash } from "node:crypto" -import { - copyFileSync, - existsSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - readlinkSync, - writeFileSync, -} from "node:fs" -import { homedir } from "node:os" -import { dirname, join } from "node:path" -import { pathToFileURL } from "node:url" -import { checkKnownFixes, evaluateKnownFixes, localeDicts } from "./known_fixes.mjs" - -const PKG_ROOT = join(import.meta.dirname, "..") -const REPO_ROOT = join(PKG_ROOT, "..", "..") -const DEFAULT_OVERLAY_DIR = join(PKG_ROOT, "overlay") -const DEFAULT_SOURCE_BRANCH = "local/amicode" - -// ── Resolve fork path ─────────────────────────────────────────────────────── - -function resolveForkDir(explicit) { - if (explicit) return existsSync(explicit) ? explicit : null - const candidates = [ - process.env.AMICODE_OPENCODE_SRC, - join(REPO_ROOT, "..", "opencode"), - join(homedir(), "harmoniqs", "opencode"), - ].filter(Boolean) - - for (const dir of candidates) { - if (dir && existsSync(join(dir, ".git"))) return dir - } - return null -} - -// ── Helpers ───────────────────────────────────────────────────────────────── - -function sha256(filepath) { - const st = lstatSync(filepath) - if (st.isSymbolicLink()) { - return createHash("sha256").update(readlinkSync(filepath)).digest("hex") - } - return createHash("sha256").update(readFileSync(filepath)).digest("hex") -} - -function walkDir(dir) { - const results = [] - for (const entry of readdirSync(dir, { recursive: true })) { - const full = join(dir, entry.toString()) - const st = lstatSync(full) - if (st.isFile() || st.isSymbolicLink()) { - results.push(entry.toString()) - } - } - return results -} - -// ── Check mode ────────────────────────────────────────────────────────────── - -function check(forkDir, overlayDir) { - const overlayFiles = walkDir(overlayDir) - const drifted = [] - const missingInFork = [] - - for (const rel of overlayFiles) { - const overlayPath = join(overlayDir, rel) - const forkPath = join(forkDir, rel) - - if (!existsSync(forkPath)) { - missingInFork.push(rel) - continue - } - - const overlayHash = sha256(overlayPath) - const forkHash = sha256(forkPath) - if (overlayHash !== forkHash) { - drifted.push({ rel, overlayHash, forkHash }) - } - } - - return { drifted, missingInFork } -} - -// ── Source-branch guard (#842, mirrors #992) ──────────────────────────────── -// Pure: the script gathers git's observations (observeSource), the DECISION -// lives here so the tests can drive every branch. Returns {ok:true, recorded} -// on proceed, or {ok:false, reasons:[named remedy,…]} on refusal. A valid -// override (a non-empty AMICODE_OVERLAY_SYNC_OVERRIDE reason) waives the -// branch/dirty refusal but is RECORDED; an empty reason refuses. -export function evaluateSourceGuard({ isGitRepo, branch, dirtyEntries, expectedBranch, overrideReason }) { - const reasons = [] - const hasOverrideFlag = overrideReason !== undefined - const validOverride = hasOverrideFlag && String(overrideReason).trim() !== "" - - if (!validOverride) { - if (!isGitRepo) { - reasons.push( - `REFUSED: the source checkout is not a git checkout, so its branch and cleanliness cannot be ` + - `verified — a sync from an unverifiable source can clobber committed overlay state (the #842 class). ` + - `REMEDY: point --source / AMICODE_OPENCODE_SRC at the fork clone (a git repo on ${expectedBranch}), ` + - `or set AMICODE_OVERLAY_SYNC_OVERRIDE= to proceed with the waiver recorded.`, - ) - } else { - if (branch !== expectedBranch) { - reasons.push( - `REFUSED: the source checkout is on branch '${branch || "(detached HEAD)"}', not the expected ` + - `'${expectedBranch}'. A sync from an arbitrary branch copies arbitrary state over the overlay ` + - `(the #842 class). REMEDY: cd the fork and 'git checkout ${expectedBranch}' (or pass ` + - `--source-branch for a deliberate mirror branch), then re-run ` + - `(or set AMICODE_OVERLAY_SYNC_OVERRIDE= to proceed with the waiver recorded).`, - ) - } - if (dirtyEntries.length > 0) { - reasons.push( - `REFUSED: the source checkout is dirty (${dirtyEntries.length} entr${dirtyEntries.length === 1 ? "y" : "ies"}: ` + - `${dirtyEntries.slice(0, 5).map((e) => e.trim()).join("; ")}${dirtyEntries.length > 5 ? "; …" : ""}) — ` + - `uncommitted source state is not recorded anywhere the overlay can trace to (the #842 class). ` + - `REMEDY: commit or stash the fork changes first ` + - `(or set AMICODE_OVERLAY_SYNC_OVERRIDE= to proceed with the waiver recorded).`, - ) - } - } - } - if (hasOverrideFlag && !validOverride) { - reasons.push( - `REFUSED: AMICODE_OVERLAY_SYNC_OVERRIDE is set but its reason is empty — overrides without a stated ` + - `reason are silent clobbers, exactly what #842 exists to prevent. ` + - `REMEDY: set AMICODE_OVERLAY_SYNC_OVERRIDE to a non-empty reason.`, - ) - } - if (reasons.length > 0) return { ok: false, reasons } - - const recorded = [] - if (validOverride) { - recorded.push( - `OVERRIDE RECORDED: AMICODE_OVERLAY_SYNC_OVERRIDE="${String(overrideReason).trim()}" — source guard waived`, - ) - } - return { ok: true, recorded } -} - -function observeSource(dir) { - if (!existsSync(join(dir, ".git"))) return { isGitRepo: false, branch: null, dirtyEntries: [] } - const branch = execFileSync("git", ["-C", dir, "branch", "--show-current"], { encoding: "utf8" }).trim() - const dirtyEntries = execFileSync("git", ["-C", dir, "status", "--porcelain"], { encoding: "utf8" }) - .split("\n") - .filter(Boolean) - return { isGitRepo: true, branch, dirtyEntries } -} - -// ── Apply mode ────────────────────────────────────────────────────────────── - -function apply(forkDir, targetDir, manifestPath, includedPath) { - const { drifted, missingInFork } = check(forkDir, targetDir) - - if (drifted.length === 0 && missingInFork.length === 0 && !includedPath) { - console.log("[overlay-sync] already in sync — nothing to do") - return 0 - } - - // 1. The known-fixes rule, checked against the POST-APPLY tree BEFORE any - // write. If the fork's copy of a known-fixed file would revert the fix, - // refuse and write nothing. - const appliedRels = new Set(drifted.map((d) => d.rel)) - const APP_SRC_PREFIX = join("packages", "app", "src") - const appSrc = join(targetDir, APP_SRC_PREFIX) - const readPost = (rel) => { - const overlayRel = join(APP_SRC_PREFIX, rel) - const p = appliedRels.has(overlayRel) ? join(forkDir, overlayRel) : join(targetDir, overlayRel) - try { - return readFileSync(p, "utf8") - } catch { - return null - } - } - const listLocales = () => { - try { - return localeDicts(appSrc) - } catch { - return [] - } - } - const regressions = evaluateKnownFixes(readPost, listLocales, appSrc) - if (regressions.length > 0) { - console.error( - `[overlay-sync] REFUSED: applying this sync would revert ${regressions.length} known amicode-side fix(es) — nothing written:`, - ) - for (const r of regressions) console.error(`[overlay-sync] ${r}`) - console.error( - `[overlay-sync] the fork is authoritative for unfixed files only; put the fix on the fork ` + - `(branch ${DEFAULT_SOURCE_BRANCH}) so the next sync brings it, not the regression.`, - ) - return 1 - } - - // 2. Read the manifest (optional — a tmp tree may not carry one). - let manifest = null - if (existsSync(manifestPath)) { - try { - manifest = JSON.parse(readFileSync(manifestPath, "utf8")) - } catch { - console.error(`[overlay-sync] WARN: manifest at ${manifestPath} is not valid JSON — copying without hash bookkeeping`) - manifest = null - } - } else { - console.log(`[overlay-sync] note: no manifest at ${manifestPath} — copying without hash bookkeeping`) - } - - // 3. Copy fork → overlay. - let updated = 0 - for (const { rel } of drifted) { - const forkPath = join(forkDir, rel) - const targetPath = join(targetDir, rel) - - mkdirSync(dirname(targetPath), { recursive: true }) - copyFileSync(forkPath, targetPath) - - if (manifest?.files && manifest.files[rel] !== undefined) { - manifest.files[rel] = sha256(targetPath) - } - - console.log(` updated: ${rel}`) - updated++ - } - - if (includedPath) { - const forkPath = join(forkDir, includedPath) - const targetPath = join(targetDir, includedPath) - if (!existsSync(forkPath)) throw new Error(`fork source file not found: ${includedPath}`) - mkdirSync(dirname(targetPath), { recursive: true }) - copyFileSync(forkPath, targetPath) - if (manifest?.files) manifest.files[includedPath] = sha256(targetPath) - console.log(` added: ${includedPath}`) - updated++ - } - - for (const rel of missingInFork) { - console.log(` warning: ${rel} exists in overlay but not in fork (class A amicode-only?)`) - } - - if (manifest && updated > 0) { - writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n") - console.log(`[overlay-sync] applied ${updated} file(s), manifest.json updated`) - } else if (updated > 0) { - console.log(`[overlay-sync] applied ${updated} file(s)`) - } - - return 0 -} - -// ── Main ──────────────────────────────────────────────────────────────────── - -function parseArgs(argv) { - const flag = (n) => { - const i = argv.indexOf(`--${n}`) - return i >= 0 ? argv[i + 1] : undefined - } - return { - mode: argv.includes("--apply") ? "apply" : "check", - source: flag("source"), - target: flag("target") ?? DEFAULT_OVERLAY_DIR, - manifest: flag("manifest") ?? null, - sourceBranch: flag("source-branch") ?? DEFAULT_SOURCE_BRANCH, - include: flag("include"), - } -} - -function main(argv) { - const opts = parseArgs(argv) - const targetDir = opts.target - const manifestPath = opts.manifest ?? join(dirname(targetDir), "manifest.json") - - const forkDir = resolveForkDir(opts.source) - if (!forkDir) { - console.log("[overlay-sync] SKIP: no fork clone found (set AMICODE_OPENCODE_SRC or --source)") - return 0 - } - - console.log(`[overlay-sync] fork: ${forkDir}`) - console.log(`[overlay-sync] target: ${targetDir}`) - - if (opts.mode === "apply") { - const overrideReason = process.env.AMICODE_OVERLAY_SYNC_OVERRIDE - const guard = evaluateSourceGuard({ - ...observeSource(forkDir), - expectedBranch: opts.sourceBranch, - overrideReason, - }) - if (!guard.ok) { - console.error("[overlay-sync] source guard refused the apply:") - for (const r of guard.reasons) console.error(`[overlay-sync] ${r}`) - return 1 - } - for (const r of guard.recorded) console.log(`[overlay-sync] ${r}`) - return apply(forkDir, targetDir, manifestPath, opts.include) - } - - // ── check (never writes) ── - const { drifted, missingInFork } = check(forkDir, targetDir) - - let regressions = [] - const appSrc = join(targetDir, "packages", "app", "src") - if (existsSync(appSrc)) { - regressions = checkKnownFixes(appSrc) - if (regressions.length > 0) { - console.log(`[overlay-sync] ${regressions.length} known amicode-side fix(es) currently MISSING from the target:`) - for (const r of regressions) console.log(` ${r}`) - } - } - - if (missingInFork.length > 0) { - console.log(`[overlay-sync] ${missingInFork.length} file(s) in overlay but not in fork:`) - for (const rel of missingInFork.slice(0, 5)) { - console.log(` missing: ${rel}`) - } - if (missingInFork.length > 5) console.log(` ... and ${missingInFork.length - 5} more`) - } - - if (drifted.length > 0) { - console.log(`[overlay-sync] DRIFT: ${drifted.length} file(s) differ between overlay and fork:`) - for (const { rel } of drifted) { - console.log(` ${rel}`) - } - console.log(`\nRun: pnpm --filter @amicode/app-bundle sync:apply`) - } - - if (drifted.length > 0 || regressions.length > 0) return 1 - - console.log(`[overlay-sync] PASS: all ${walkDir(targetDir).length} overlay files match the fork`) - return 0 -} - -const isMain = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href -if (isMain) { - process.exit(main(process.argv.slice(2))) -} diff --git a/packages/extension/opencode.lock.json b/packages/extension/opencode.lock.json index a4457fd7a..6f7b8fb10 100644 --- a/packages/extension/opencode.lock.json +++ b/packages/extension/opencode.lock.json @@ -1,21 +1,6 @@ { "version": "1.18.29", - "source": "release", - "ref": "20c5a1d2d28f96d7883343285f17f5ab48ba3a1b", - "platforms": { - "darwin-arm64": { - "asset": "opencode-darwin-arm64.zip", - "sha256": "0026a7ba2b5486a6d61316c52cae7fd97683e165bf8da6cd18638181220ddfc6" - }, - "linux-arm64": { - "asset": "opencode-linux-arm64.tar.gz", - "sha256": "d3b8735e8d85365fb714b25650a46ac810b61e3ed93d4c1873a4e408186fa21d" - }, - "linux-x64": { - "asset": "opencode-linux-x64.tar.gz", - "sha256": "b8bdd718380ea26cc54424d8c8868f2be47f6de7c447f6136a13538c16a936cd" - } - }, - "tag": "v1.18.29-amicode.30", - "repo": "harmoniqs/opencode" + "base_version": "1.18.29", + "base_commit": "7fe993879f98aa17cecc70f70d3f40d6f0f11689", + "overlay_hash": "09a343d884456f3cc01af38e55d42f4085251896f86ed44a5ba1fed05b086b88" } diff --git a/packages/extension/package.json b/packages/extension/package.json index e95d464c8..0c2fb9e51 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -452,9 +452,7 @@ "smoke:fleet": "node scripts/fleet_beta_smoke.mjs", "fetch:opencode": "node scripts/fetch_opencode.mjs", "build:binary": "node scripts/build_binary.mjs", - "opencode:dev": "node scripts/opencode_dev.mjs", - "opencode:build": "node scripts/opencode_dev.mjs build", - "opencode:pin": "node scripts/opencode_dev.mjs pin", + "build:exemplars": "node scripts/build_exemplars.mjs", "build:app": "node scripts/build_app_bundle.mjs", "healthcheck": "node scripts/healthcheck.mjs", diff --git a/packages/extension/scripts/build_binary.mjs b/packages/extension/scripts/build_binary.mjs index ea874ab03..dc91202ed 100644 --- a/packages/extension/scripts/build_binary.mjs +++ b/packages/extension/scripts/build_binary.mjs @@ -64,7 +64,7 @@ const run = (cmd, cmdArgs, cwd, note) => { if (r.status !== 0) fail(`${note} failed (exit ${r.status})`, 2); }; -// ── platform key (matches fetch_opencode.mjs / opencode.lock.json keys) ───── +// ── platform key (matches fetch_opencode.mjs KNOWN_PLATFORMS) ─────────────── // --platform enables cross-compilation (e.g. --platform linux-arm64 on // a linux-x64 host). Without it, the host platform is used + --single flag. const requestedPlatform = flag("platform"); diff --git a/packages/extension/scripts/fetch_opencode.mjs b/packages/extension/scripts/fetch_opencode.mjs index dc927821c..ef0384999 100644 --- a/packages/extension/scripts/fetch_opencode.mjs +++ b/packages/extension/scripts/fetch_opencode.mjs @@ -1,11 +1,11 @@ #!/usr/bin/env node -// Vendoring of the opencode chat-server binary, pinned by opencode.lock.json -// (spec §2/§3). Two sources: -// release (default) — download the pinned release asset, verify sha256. -// local — build from a local clone of the fork at the pinned git -// ref (`ref`), stamp the ACTUAL binary sha. Replaces the -// hand-swap workflow (AMICODE-PATCHES.md) where the stamp -// was left lying at the manifest value. +// Vendoring of the opencode chat-server binary, pinned by opencode.lock.json. +// Post-absorption: binaries are built from the committed overlay via +// build_binary.mjs. This script handles the stock-canonical download path +// (upstream anomalyco/opencode at v) used by `pnpm install` / +// `pnpm fetch:opencode` to bootstrap the vendored binary when one isn't +// already built. +// // Importable module + CLI in one file. import { createHash } from "node:crypto"; import { execFileSync } from "node:child_process"; @@ -15,13 +15,11 @@ import { mkdirSync, mkdtempSync, readFileSync, - readdirSync, renameSync, rmSync, writeFileSync, } from "node:fs"; -import { homedir } from "node:os"; -import { delimiter, dirname, join } from "node:path"; +import { join } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; // When bundled as CJS by esbuild, import.meta.url is undefined and @@ -30,7 +28,7 @@ import { fileURLToPath, pathToFileURL } from "node:url"; // real manifest reads — only for the gh-download temp dir. let PKG_ROOT; try { - PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); + PKG_ROOT = join(fileURLToPath(import.meta.url), "..", ".."); } catch { PKG_ROOT = process.cwd(); } @@ -39,59 +37,45 @@ export function loadManifest(root = PKG_ROOT) { const m = JSON.parse(readFileSync(join(root, "opencode.lock.json"), "utf8")); if (typeof m.version !== "string" || m.version === "") throw new Error("manifest: version must be a non-empty string"); - const source = m.source ?? "release"; - if (source !== "release" && source !== "local") - throw new Error(`manifest: source must be "release" or "local", got ${JSON.stringify(m.source)}`); - if (source === "local" && !/^[0-9a-f]{40}$/.test(m.ref ?? "")) - throw new Error('manifest: source "local" requires ref (40-hex fork commit)'); - const platforms = m.platforms ?? {}; - if (Object.keys(platforms).length === 0) throw new Error("manifest: platforms missing"); - for (const [key, p] of Object.entries(platforms)) { - if (typeof p.asset !== "string" || p.asset === "") throw new Error(`manifest: ${key}.asset missing`); - if (!/^[0-9a-f]{64}$/.test(p.sha256 ?? "")) throw new Error(`manifest: ${key}.sha256 must be 64 hex chars`); - } return m; } -export function resolvePlatform(manifest, flag) { +/** The three platforms we ship binaries for. */ +const KNOWN_PLATFORMS = ["darwin-arm64", "linux-arm64", "linux-x64"]; + +/** Platform asset names — post-absorption these are derived from the platform + * key, not read from the lock (the lock no longer carries per-platform data). */ +function assetForPlatform(key) { + if (key === "darwin-arm64") return "opencode-darwin-arm64.zip"; + return `opencode-${key}.tar.gz`; +} + +export function resolvePlatform(_manifest, flag) { const key = flag ?? `${process.platform}-${process.arch}`; - if (!(key in manifest.platforms)) { - throw new Error(`platform ${key} not supported (supported: ${Object.keys(manifest.platforms).join(", ")})`); + if (!KNOWN_PLATFORMS.includes(key)) { + throw new Error(`platform ${key} not supported (supported: ${KNOWN_PLATFORMS.join(", ")})`); } return key; } -/** Release coordinates: default = upstream anomalyco/opencode at v; a manifest - * with `repo`/`tag` set points at our fork's release instead (harmoniqs/opencode, - * private — downloads go through the authenticated `gh` path in that case). - * AMICODE_RELEASE_TAG / AMICODE_RELEASE_REPO override the pinned tag/repo — used by - * release.yml on a clean tag, which provisions a FRESHLY built fork binary (its tag - * cannot be in the committed lock yet; see "Provision fork binary" there). */ +/** Release coordinates: upstream anomalyco/opencode at v. + * AMICODE_RELEASE_TAG / AMICODE_RELEASE_REPO override the pinned tag/repo — + * used by release.yml on a clean tag. */ export function releaseCoords(manifest) { - const repo = process.env.AMICODE_RELEASE_REPO || manifest.repo || "anomalyco/opencode"; - const tag = process.env.AMICODE_RELEASE_TAG || manifest.tag || `v${manifest.version}`; + const repo = process.env.AMICODE_RELEASE_REPO || "anomalyco/opencode"; + const tag = process.env.AMICODE_RELEASE_TAG || `v${manifest.version}`; return { repo, tag, - // #1019: renamed from `private` — this flag means "is our fork" (keyed on - // manifest.repo != null or env override), not "repo is private on GitHub." - // It controls download-path selection (HTTPS+gh fallback), not auth. - isFork: manifest.repo != null || !!process.env.AMICODE_RELEASE_TAG, - // Back-compat alias (deprecated — use isFork) + isFork: !!process.env.AMICODE_RELEASE_TAG, get private() { return this.isFork; }, }; } export function assetUrl(manifest, platform) { const { repo, tag } = releaseCoords(manifest); - return `https://github.com/${repo}/releases/download/${tag}/${manifest.platforms[platform].asset}`; -} - -/** Local-clone resolution: explicit path (--local) > AMICODE_OPENCODE_SRC > - * sibling checkout next to this repo (/../opencode — the team layout, - * e.g. ~/harmoniqs/{amicode,opencode}). */ -export function resolveCloneDir(root = PKG_ROOT, flagPath) { - return flagPath ?? process.env.AMICODE_OPENCODE_SRC ?? join(root, "..", "..", "..", "opencode"); + const asset = assetForPlatform(platform); + return `https://github.com/${repo}/releases/download/${tag}/${asset}`; } export const sha256 = (buf) => createHash("sha256").update(buf).digest("hex"); @@ -104,24 +88,16 @@ export const sha256 = (buf) => createHash("sha256").update(buf).digest("hex"); */ export function classifyDownloadError(err) { const msg = err?.message ?? String(err); - // 5xx = server-side, retriable if (/HTTP\s+5\d\d/i.test(msg)) return "transient"; - // Network errors = retriable if (/timeout|ECONNRESET|ETIMEDOUT|ECONNREFUSED|UND_ERR_CONNECT_TIMEOUT|network/i.test(msg)) return "transient"; - // 404 = permanent (asset or release doesn't exist) if (/HTTP\s+404/i.test(msg)) return "permanent"; - // 403 = auth issue (rate limit or missing credentials) if (/HTTP\s+403/i.test(msg)) return "auth"; - // gh not found / not logged in if (/gh:?\s*(command)?\s*not found|not logged in|not installed/i.test(msg)) return "auth"; - // Default to transient (give it one more shot) return "transient"; } /** * Retry an async function with exponential backoff. - * @param {Function} fn - async function to retry - * @param {Object} opts - { maxAttempts, baseDelay, factor, isPermanent?, onRetry? } */ export async function withRetry(fn, opts = {}) { const { maxAttempts = 3, baseDelay = 1000, factor = 2, isPermanent, onRetry } = opts; @@ -131,7 +107,6 @@ export async function withRetry(fn, opts = {}) { return await fn(attempt); } catch (err) { lastErr = err; - // Check if the error is permanent (not retriable) const classification = isPermanent ? (isPermanent(err) ? "permanent" : "transient") : classifyDownloadError(err); @@ -151,14 +126,13 @@ async function defaultDownload(url) { try { r = await fetch(url); } catch (e) { - throw new Error(`download failed: ${e.message} for ${url}`); // spec §6: URL on connection failures too + throw new Error(`download failed: ${e.message} for ${url}`); } if (!r.ok) throw new Error(`download failed: HTTP ${r.status} for ${url}`); return Buffer.from(await r.arrayBuffer()); } -/** Private-release download via the gh CLI (the team's auth path for our - * private repos). Plain fetch 404s on private assets — gh handles the token. */ +/** Private-release download via the gh CLI. */ function ghDownload(repo, tag, asset) { const work = mkdtempSync(join(PKG_ROOT, ".ghdl-")); try { @@ -175,93 +149,7 @@ function ghDownload(repo, tag, asset) { } } -const git = (dir, ...args) => execFileSync("git", ["-C", dir, ...args], { encoding: "utf8" }).trim(); - -function resolveBun() { - if (process.env.AMICODE_BUN) return process.env.AMICODE_BUN; - try { - const p = execFileSync("which", ["bun"], { encoding: "utf8" }).trim(); - if (p !== "") return p; - } catch { - /* not on PATH */ - } - const fallback = join(homedir(), ".bun", "bin", "bun"); - if (existsSync(fallback)) return fallback; - throw new Error("bun not found — install it (https://bun.sh) or set AMICODE_BUN=/path/to/bun"); -} - -/** The fork's documented build recipe (its AMICODE-PATCHES.md §3): bun's dir must - * be on PATH (tree-sitter postinstall shims re-invoke `bun` by name), and - * OPENCODE_VERSION pins the version string so no release upload is attempted. - * OPENCODE_CHANNEL must NOT resolve to "latest": that compiles the embedded - * web UI with VITE_OPENCODE_CHANNEL="prod" (app/vite.js), which defaults - * settings.general.newLayoutDesigns OFF — hiding every amicode surface (home - * cards, v2 titlebar, draft flow) at runtime even though the code is compiled - * in. Any other channel maps to "dev" → new-layout default ON. */ -function defaultBuild(cloneDir, version) { - const bun = resolveBun(); - execFileSync(bun, ["run", "script/build.ts", "--single", "--skip-install"], { - cwd: join(cloneDir, "packages", "opencode"), - env: { - ...process.env, - OPENCODE_VERSION: version, - OPENCODE_CHANNEL: "dev", - PATH: `${dirname(bun)}${delimiter}${process.env.PATH ?? ""}`, - }, - stdio: ["ignore", "inherit", "inherit"], - }); -} - -/** Atomic install into vendor/opencode//: write in a temp dir on the same - * fs, rename, chmod, then stamp LAST (spec §3 step 5). */ -function installBinary(destDir, bytes, hash, sourceLine) { - const bin = join(destDir, "opencode"); - mkdirSync(destDir, { recursive: true }); - const work = mkdtempSync(join(destDir, ".unpack-")); - try { - writeFileSync(join(work, "opencode"), bytes); - renameSync(join(work, "opencode"), bin); - chmodSync(bin, 0o755); - writeFileSync(join(destDir, ".source"), sourceLine + "\n"); - writeFileSync(join(destDir, ".sha256"), hash + "\n"); - } finally { - rmSync(work, { recursive: true, force: true }); - } - return bin; -} - -function fetchFromLocal({ root, manifest, key, cloneDir, anyRef, noBuild, build }) { - const head = git(cloneDir, "rev-parse", "HEAD"); - const dirty = git(cloneDir, "status", "--porcelain") !== ""; - if (!anyRef) { - if (head !== manifest.ref) - throw new Error( - `clone ${cloneDir} is at ${head.slice(0, 10)} but the lock pins ${manifest.ref.slice(0, 10)} — ` + - `checkout the pinned ref, update opencode.lock.json, or pass --any-ref`, - ); - if (dirty) throw new Error(`clone ${cloneDir} has uncommitted changes — commit/stash them or pass --any-ref`); - } - if (!noBuild) build(cloneDir, manifest.version); - // build.ts --single emits only the CURRENT platform's artifact. - const artifact = join(cloneDir, "packages", "opencode", "dist", `opencode-${key}`, "bin", "opencode"); - if (!existsSync(artifact)) { - throw new Error( - `built binary missing at ${artifact}` + - (noBuild ? " — rerun without --no-build" : " — local mode builds only the current platform"), - ); - } - const bytes = readFileSync(artifact); - const provenance = `local ${head}${dirty ? "+dirty" : ""}`; - const bin = installBinary(join(root, "vendor", "opencode", key), bytes, sha256(bytes), provenance); - return { skipped: false, path: bin, source: provenance }; -} - -/** Channel assertion (the fail-closed backstop): a release body must record the - * channel it was BUILT with AND the badge that channel implies, so a dev-channel - * binary can never ride a beta-tagged promotion. Reads the release notes via - * `gh` (the fork's release body is authored by its workflow — see - * amicode-release.yml's "Create GitHub release" step). `api` is injectable - * (tests stub it; it stands in for `gh api repos// --jq `). */ +/** Channel assertion (fail-closed backstop). */ export async function assertReleaseChannel(coords, channel, api = ghApi) { const BADGE = channel === "beta" ? "BETA" : "DEV"; let body; @@ -281,14 +169,11 @@ export async function assertReleaseChannel(coords, channel, api = ghApi) { throw new Error(`release ${coords.tag} does not declare Badge: ${BADGE} — refusing to vendor it into a promoted release`); } -/** `gh api repos// --jq ` — the release-notes read path. */ function ghApi(repo, path, jq) { return execFileSync("gh", ["api", `repos/${repo}/${path}`, "--jq", jq], { encoding: "utf8" }); } -/** Hash authority when AMICODE_RELEASE_TAG overrides the pin: the release's own - * SHA256SUMS.txt — the committed lock cannot know a tag that did not exist - * when it was written. */ +/** Hash authority when AMICODE_RELEASE_TAG overrides the pin. */ function shaFromSums(text, asset) { const line = text.split("\n").find((l) => l.trimEnd().endsWith(asset)); if (!line) throw new Error(`SHA256SUMS.txt has no entry for ${asset}`); @@ -298,77 +183,65 @@ function shaFromSums(text, asset) { } async function fetchFromRelease({ root, manifest, key, download, ghApi: api = ghApi, retryOpts }) { - const { asset } = manifest.platforms[key]; + const asset = assetForPlatform(key); const destDir = join(root, "vendor", "opencode", key); const bin = join(destDir, "opencode"); const stamp = join(destDir, ".sha256"); const coords = releaseCoords(manifest); const override = process.env.AMICODE_RELEASE_TAG || null; - // A tag override only ever happens on the promoted path — fail closed to beta - // if the channel requirement was somehow not passed alongside it. const channel = process.env.AMICODE_REQUIRE_CHANNEL || (override ? "beta" : null); const provenance = `release ${coords.repo}@${coords.tag}` + (channel ? ` channel=${channel}` : ""); - let want = manifest.platforms[key].sha256; + let want = null; // no committed hashes post-absorption — verify from SHA256SUMS.txt when overriding if (channel) await assertReleaseChannel(coords, channel, api); if (override) { want = shaFromSums( - ( - await download( - `https://github.com/${coords.repo}/releases/download/${coords.tag}/SHA256SUMS.txt`, - ) - ).toString("utf8"), + (await download(`https://github.com/${coords.repo}/releases/download/${coords.tag}/SHA256SUMS.txt`)).toString("utf8"), asset, ); } - if (existsSync(bin) && existsSync(stamp) && readFileSync(stamp, "utf8").trim() === want) { - return { skipped: true, path: bin, source: provenance }; // offline repeat builds + // When we have no committed hash, use the stamp to check if already installed + if (want && existsSync(bin) && existsSync(stamp) && readFileSync(stamp, "utf8").trim() === want) { + return { skipped: true, path: bin, source: provenance }; } - // #1019: Download with retry + HTTPS-first, gh-fallback. - // Fork releases (repo set in the lock) try plain HTTPS first (works for any - // public release, tokenless), gh ONLY as the fallback for network issues or - // CDN corruption (sha256 mismatch on HTTPS but clean on gh). + const url = `https://github.com/${coords.repo}/releases/download/${coords.tag}/${asset}`; const retry = retryOpts ?? { maxAttempts: 3, baseDelay: 1000, factor: 2 }; let bytes; + if (coords.isFork) { - // HTTPS with retry + // Override path: HTTPS-first, gh fallback let httpsOk = false; let httpsSha256Mismatch = false; try { - bytes = await withRetry( - () => download(assetUrl(manifest, key)), - { - ...retry, - isPermanent: (e) => { - const cls = classifyDownloadError(e); - return cls === "permanent" || cls === "auth"; - }, - onRetry: (attempt, err) => { - console.log(`[fetch-opencode] HTTPS attempt ${attempt} failed: ${err.message} — retrying`); - }, + bytes = await withRetry(() => download(url), { + ...retry, + isPermanent: (e) => { + const cls = classifyDownloadError(e); + return cls === "permanent" || cls === "auth"; + }, + onRetry: (attempt, err) => { + console.log(`[fetch-opencode] HTTPS attempt ${attempt} failed: ${err.message} — retrying`); }, - ); + }); httpsOk = true; - // Verify sha256 before accepting HTTPS result - const got = sha256(bytes); - if (got !== want) { - httpsSha256Mismatch = true; - httpsOk = false; - console.log(`[fetch-opencode] HTTPS sha256 mismatch for ${asset} — trying gh fallback`); + if (want) { + const got = sha256(bytes); + if (got !== want) { + httpsSha256Mismatch = true; + httpsOk = false; + console.log(`[fetch-opencode] HTTPS sha256 mismatch for ${asset} — trying gh fallback`); + } } } catch (httpsErr) { console.log(`[fetch-opencode] HTTPS download failed: ${httpsErr.message} — trying gh fallback`); } - if (!httpsOk) { - // gh fallback: one attempt (no retry on gh — it's the fallback itself) try { bytes = ghDownload(coords.repo, coords.tag, asset); - // Verify sha256 on gh download — mismatch here is permanent - const got = sha256(bytes); - if (got !== want) { - throw new Error(`SHA256 mismatch for ${asset}: expected ${want}, actual ${got}`); + if (want) { + const got = sha256(bytes); + if (got !== want) throw new Error(`SHA256 mismatch for ${asset}: expected ${want}, actual ${got}`); } } catch (ghErr) { if (httpsSha256Mismatch) { @@ -382,26 +255,16 @@ async function fetchFromRelease({ root, manifest, key, download, ghApi: api = gh } } } else { - // Non-fork (upstream): HTTPS only, with retry - bytes = await withRetry( - () => download(assetUrl(manifest, key)), - { ...retry }, - ); - const got = sha256(bytes); - if (got !== want) { - throw new Error(`SHA256 mismatch for ${asset}: expected ${want}, actual ${got}`); + // Upstream: HTTPS only, with retry + bytes = await withRetry(() => download(url), { ...retry }); + if (want) { + const got = sha256(bytes); + if (got !== want) throw new Error(`SHA256 mismatch for ${asset}: expected ${want}, actual ${got}`); } } - // Verify sha256 (for HTTPS-succeeded path where we didn't already check) - if (coords.isFork) { - // Already verified above in the fork path - } else { - // Already verified above in the non-fork path - } - mkdirSync(destDir, { recursive: true }); - const work = mkdtempSync(join(destDir, ".unpack-")); // same fs → rename is atomic + const work = mkdtempSync(join(destDir, ".unpack-")); try { const archive = join(work, asset); writeFileSync(archive, bytes); @@ -412,42 +275,23 @@ async function fetchFromRelease({ root, manifest, key, download, ghApi: api = gh renameSync(join(work, "opencode"), bin); chmodSync(bin, 0o755); writeFileSync(join(destDir, ".source"), provenance + "\n"); - writeFileSync(stamp, sha256(bytes) + "\n"); // stamp last (spec §3 step 5) + writeFileSync(stamp, sha256(bytes) + "\n"); } finally { rmSync(work, { recursive: true, force: true }); } return { skipped: false, path: bin, source: provenance }; } -/** mode: "release" | "local" | undefined (undefined → manifest.source). - * An EXPLICIT mode:"local" with no clone is a hard error; manifest-driven local - * falls back to the pinned release when the clone is absent (CI has no clone). */ export async function fetchOpencode({ root = PKG_ROOT, platform, download = defaultDownload, ghApi: ghApiImpl, mode, - localDir, - anyRef = false, - noBuild = false, - build = defaultBuild, retryOpts, } = {}) { const manifest = loadManifest(root); const key = resolvePlatform(manifest, platform); - const want = mode ?? manifest.source ?? "release"; - if (want === "local") { - const cloneDir = resolveCloneDir(root, localDir); - if (existsSync(join(cloneDir, ".git"))) { - return fetchFromLocal({ root, manifest, key, cloneDir, anyRef, noBuild, build }); - } - const hint = `clone harmoniqs/opencode there (or set AMICODE_OPENCODE_SRC / pass --local )`; - if (mode === "local") throw new Error(`no local clone at ${cloneDir} — ${hint}`); - console.warn( - `[fetch-opencode] WARNING: lock source=local but no clone at ${cloneDir} — ${hint}; falling back to the pinned release`, - ); - } return fetchFromRelease({ root, manifest, key, download, ghApi: ghApiImpl, retryOpts }); } @@ -456,26 +300,10 @@ async function main(argv) { const i = argv.indexOf(name); if (i < 0) return undefined; const next = argv[i + 1]; - return next !== undefined && !next.startsWith("--") ? next : null; // null = flag present, no value + return next !== undefined && !next.startsWith("--") ? next : null; }; const platform = flagValue("--platform") ?? undefined; - if (argv.includes("--record")) { - // pin-time only (spec §3 step 6) - const manifest = loadManifest(); - for (const key of Object.keys(manifest.platforms)) { - const bytes = await defaultDownload(assetUrl(manifest, key)); - console.log(`${key} ${sha256(bytes)}`); - } - return 0; - } - const local = flagValue("--local"); - const r = await fetchOpencode({ - platform, - mode: local !== undefined ? "local" : argv.includes("--release") ? "release" : undefined, - localDir: local ?? undefined, - anyRef: argv.includes("--any-ref"), - noBuild: argv.includes("--no-build"), - }); + const r = await fetchOpencode({ platform }); console.log( r.skipped ? `[fetch-opencode] up to date: ${r.path}` : `[fetch-opencode] installed (${r.source}): ${r.path}`, ); diff --git a/packages/extension/scripts/opencode_dev.mjs b/packages/extension/scripts/opencode_dev.mjs deleted file mode 100755 index e307170cc..000000000 --- a/packages/extension/scripts/opencode_dev.mjs +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env node -// One-command loop for developing the vendored opencode fork against amicode. -// -// Default vendoring is `release` (opencode.lock.json source=release): a plain -// `pnpm install` / `package` / F5 downloads the pinned, features-ON binary — no -// clone, no bun. You only enter source mode when you are CHANGING opencode, and -// you do it by RUNNING a command here, never by editing the committed lock. -// -// pnpm opencode:build rebuild the binary from your ../opencode clone -// (OPENCODE_CHANNEL=dev → amicode UI ON) and -// re-vendor it. Reload the dev host to pick it up. -// pnpm opencode:pin adopt a cut release (e.g. v1.17.3-amicode.5): -// download + sha256-verify both platform assets, -// rewrite opencode.lock.json. Commit that + PR. -// -// Web-UI iteration (packages/app surfaces) requires a rebuild — the channel -// define is baked at build time, so there is no hot path through `serve`. -import { execFileSync } from "node:child_process"; -import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { loadManifest, resolveCloneDir, sha256 } from "./fetch_opencode.mjs"; - -const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); - -const git = (dir, ...args) => - execFileSync("git", ["-C", dir, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); - -/** Stamp vendor/opencode//.buildinfo so anyone holding the built - * extension (dev host, remote machine, a vsix) can tell EXACTLY which fork - * state produced the vendored binary — the .source/.sha256 stamps record - * source+hash but not branch or dirty state, and --any-ref builds deliberately - * accept any checkout. JSON, one object per platform dir. */ -export function stampBuildInfo({ source, repo, version, cloneDir, tag, root = PKG_ROOT }) { - const vendorRoot = join(root, "vendor", "opencode"); - if (!existsSync(vendorRoot)) return; - const info = { - source, - version, - builtAt: new Date().toISOString(), - ...(repo ? { repo } : {}), - ...(tag ? { tag } : {}), - }; - if (cloneDir) { - info.clonePath = cloneDir; - try { - info.branch = git(cloneDir, "symbolic-ref", "--short", "-q", "HEAD") || "(detached)"; - } catch { - // Detached checkout (CI checks out the merge ref, not the branch): the - // checked-out ref is still attributable — GitHub Actions names it in - // GITHUB_HEAD_REF (PRs) / GITHUB_REF_NAME (pushes). Absent both, the - // stamp is honestly "(unknown)" rather than a guessed name. - info.branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || "(unknown)"; - } - info.commit = git(cloneDir, "rev-parse", "HEAD"); - info.dirty = git(cloneDir, "status", "--porcelain") !== ""; - } - for (const key of readdirSync(vendorRoot)) { - const dir = join(vendorRoot, key); - if (!existsSync(join(dir, "opencode"))) continue; - writeFileSync(join(dir, ".buildinfo"), JSON.stringify(info, null, 2) + "\n"); - } -} - -/** Check a vendored binary's provenance. Prints one line per platform dir. */ -export function checkBuildInfo(root = PKG_ROOT) { - const vendorRoot = join(root, "vendor", "opencode"); - if (!existsSync(vendorRoot)) return "[opencode] no vendored binary yet"; - const lines = []; - for (const key of readdirSync(vendorRoot).sort()) { - const dir = join(vendorRoot, key); - if (!existsSync(join(dir, "opencode"))) continue; - const stamp = readdirSync(dir).includes(".buildinfo") - ? readFileSync(join(dir, ".buildinfo"), "utf8").trim().replace(/\n/g, " ") - : "(no .buildinfo — built before stamping was added; check .source/.sha256)"; - lines.push(`[opencode] ${key}: ${stamp}`); - } - return lines.length > 0 ? lines.join("\n") : "[opencode] no vendored binary yet"; -} - -/** Download a private-release asset via the authenticated gh CLI (same path the - * fetcher uses). Injectable for tests. */ -export function ghDownloadAsset(repo, tag, asset) { - const work = mkdtempSync(join(PKG_ROOT, ".pin-")); - try { - execFileSync("gh", ["release", "download", tag, "--repo", repo, "--pattern", asset, "--dir", work], { - stdio: ["ignore", "ignore", "inherit"], - }); - return readFileSync(join(work, asset)); - } catch (e) { - throw new Error(`gh release download failed for ${repo}@${tag} ${asset}: ${e.message}`); - } finally { - rmSync(work, { recursive: true, force: true }); - } -} - -/** Resolve a release tag to the 40-hex COMMIT it points at, via the authenticated - * gh CLI. Annotated tags (what amicode-release cuts) resolve to a tag object that - * must be dereferenced; lightweight tags point straight at the commit. Injectable - * for tests. */ -export function ghResolveTagCommit(repo, tag) { - const api = (path) => - JSON.parse(execFileSync("gh", ["api", `repos/${repo}/${path}`], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] })); - const obj = api(`git/ref/tags/${tag}`).object; - if (obj.type === "commit") return obj.sha; - if (obj.type === "tag") return api(`git/tags/${obj.sha}`).object.sha; - throw new Error(`pin: tag ${tag} points at a ${obj.type}, expected commit or tag`); -} - -/** Rewrite opencode.lock.json to a cut release: set tag + each platform's ACTUAL - * downloaded sha256 (+ ref when provided). Preserves key order and formatting. - * Returns { tag, ref, platforms: { : } }. */ -export function pinFromRelease({ root = PKG_ROOT, repo: requestedRepo, tag, ref, download = ghDownloadAsset, resolveTagCommit = ghResolveTagCommit } = {}) { - if (!tag) throw new Error("pin: a release tag is required (e.g. pnpm opencode:pin v1.17.3-amicode.5)"); - const lockPath = join(root, "opencode.lock.json"); - const m = JSON.parse(readFileSync(lockPath, "utf8")); - const repo = requestedRepo ?? m.repo ?? "anomalyco/opencode"; - const shas = {}; - for (const [key, p] of Object.entries(m.platforms ?? {})) { - const bytes = download(repo, tag, p.asset); - p.sha256 = sha256(bytes); - shas[key] = p.sha256; - } - m.tag = tag; - m.repo = repo; - // Resolve the ref from the tag unless one is given explicitly. Leaving it stale - // is worse than absent: `source: "local"` VALIDATES ref against the clone HEAD - // (fetch_opencode.mjs), so a ref left pointing at the PREVIOUS release tells a - // fork developer to check out the wrong commit. Release mode ignores ref — the - // tag drives the download and sha256 verifies it — so this is provenance, but - // provenance that is load-bearing the moment anyone switches to source mode. - let resolved = ref; - if (!resolved) { - try { - resolved = resolveTagCommit(repo, tag); - } catch (e) { - throw new Error( - `pin: could not resolve ${repo}@${tag} to a commit (${e.message}). ` + - `Pass --ref <40-hex> explicitly if the tag is not reachable via gh.`, - ); - } - } - if (!/^[0-9a-f]{40}$/.test(resolved)) - throw new Error(`pin: ref must be a 40-hex commit, got ${resolved}`); - m.ref = resolved; - writeFileSync(lockPath, JSON.stringify(m, null, 2) + "\n"); - return { tag, ref: m.ref, platforms: shas }; -} - -function build() { - const cloneDir = resolveCloneDir(PKG_ROOT); - // Warn if the overlay is stale relative to the fork (non-blocking). - try { - execFileSync("node", [ - join(PKG_ROOT, "..", "app-bundle", "scripts", "overlay-promotion.mjs"), - "--check", "--source", cloneDir, "--revision", git(cloneDir, "rev-parse", "HEAD"), - ], { - stdio: ["ignore", "pipe", "pipe"], - }); - } catch (e) { - console.warn( - `[opencode:build] ⚠ overlay drift detected — the overlay does not match the fork.\n` + - ` Run: pnpm --filter @amicode/app-bundle sync:apply -- --source "${cloneDir}" --revision ${git(cloneDir, "rev-parse", "HEAD")} --base \n` + - ` Building anyway (the binary uses the fork, not the overlay).\n`, - ); - } - console.log(`[opencode:build] building from ${cloneDir} with OPENCODE_CHANNEL=dev, re-vendoring…`); - // --any-ref: during active dev your clone is off the pinned ref by design. - execFileSync("node", [join(PKG_ROOT, "scripts", "fetch_opencode.mjs"), "--local", "--any-ref"], { - stdio: ["ignore", "inherit", "inherit"], - }); - const manifest = loadManifest(); - stampBuildInfo({ source: "local", repo: manifest.repo, version: manifest.version, cloneDir }); - console.log( - `[opencode:build] done — vendored from ${cloneDir} @ ${git(cloneDir, "symbolic-ref", "--short", "-q", "HEAD")} ${git(cloneDir, "rev-parse", "HEAD").slice(0, 10)} ` + - `(dirty: ${git(cloneDir, "status", "--porcelain") !== ""}) — reload the Extension Dev Host (Cmd/Ctrl+R) to pick up the new binary.`, - ); - console.log(checkBuildInfo()); -} - -function help() { - console.log( - [ - "opencode dev loop (default vendoring is `release` — no clone/bun needed unless you change opencode):", - "", - " pnpm opencode:build rebuild the binary from ../opencode (UI ON) and re-vendor it", - " pnpm opencode:pin [--repo ] adopt a cut release into opencode.lock.json (download + verify + rewrite)", - "", - "Flow: edit ../opencode → pnpm opencode:build → reload dev host → verify.", - " Happy? push the opencode branch, tag a release (its workflow builds both binaries),", - " then here: pnpm opencode:pin && commit the lock bump + PR.", - "Never hand-edit opencode.lock.json `source`; changing opencode is a command, not a commit.", - ].join("\n"), - ); -} - -function main(argv) { - const [cmd, ...rest] = argv; - if (cmd === "build") return build(); - if (cmd === "pin") { - const tag = rest.find((a) => !a.startsWith("--")); - const i = rest.indexOf("--ref"); - const ref = i >= 0 ? rest[i + 1] : undefined; - const repoIndex = rest.indexOf("--repo"); - const repo = repoIndex >= 0 ? rest[repoIndex + 1] : undefined; - const r = pinFromRelease({ repo, tag, ref }); - const manifest = loadManifest(); - stampBuildInfo({ source: "release", repo: manifest.repo, version: manifest.version, tag: r.tag }); - console.log(`[opencode:pin] opencode.lock.json → ${r.tag}${r.ref ? ` @ ${r.ref.slice(0, 10)}` : ""}`); - for (const [k, v] of Object.entries(r.platforms)) console.log(` ${k} ${v}`); - console.log(checkBuildInfo()); - console.log("[opencode:pin] commit the lock bump and open a PR."); - return; - } - help(); -} - -if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) { - try { - main(process.argv.slice(2)); - } catch (e) { - console.error(`[opencode-dev] ${e.message}`); - process.exitCode = 1; - } -} diff --git a/packages/extension/scripts/record_amicode_fixtures.mjs b/packages/extension/scripts/record_amicode_fixtures.mjs index 1d2be35d7..a8d38780d 100644 --- a/packages/extension/scripts/record_amicode_fixtures.mjs +++ b/packages/extension/scripts/record_amicode_fixtures.mjs @@ -394,7 +394,7 @@ async function main() { JSON.stringify( { recordedAt: new Date().toISOString(), - fork: { version, tag: manifest.tag }, + fork: { version }, // The recording sandbox dir (and its realpath — responses embed both // forms: unresolved joins and realpathSync'd results). The replay // normalizes these to on both sides before comparing. diff --git a/packages/extension/src/opencode_binary.ts b/packages/extension/src/opencode_binary.ts index 49b8f656b..eda1f7509 100644 --- a/packages/extension/src/opencode_binary.ts +++ b/packages/extension/src/opencode_binary.ts @@ -8,8 +8,8 @@ export interface ResolvedBinary { source: "config-override" | "vendored"; } -/** Must stay in lockstep with opencode.lock.json's `platforms` — a fetch_opencode - * test asserts the two sets are equal, since they live in different files. */ +/** The three platforms we ship binaries for. Must stay in lockstep with + * fetch_opencode.mjs's KNOWN_PLATFORMS and build_binary.mjs's targets. */ export const SUPPORTED = ["darwin-arm64", "linux-arm64", "linux-x64"] as const; /** diff --git a/packages/extension/src/rebuild/main_source_resolver.ts b/packages/extension/src/rebuild/main_source_resolver.ts index a45f65921..34b27e64b 100644 --- a/packages/extension/src/rebuild/main_source_resolver.ts +++ b/packages/extension/src/rebuild/main_source_resolver.ts @@ -1,17 +1,10 @@ /** - * Main Source Resolver — #1018 + * Main Source Resolver — #1018, updated for post-absorption (#1098) * - * Resolves the fork binary for "Rebuild from Main" by reading the promoted - * manifest (opencode.lock.json on main) and downloading the pinned release - * asset. Replaces the fork-build path (bun install → bun run build) with - * the release-download path (fetchFromRelease). - * - * Design constraints: - * - No fork clone, no bun invocation in the Main path - * - sha256 mismatch is a hard refusal - * - git pull uses --ff-only (not --rebase) - * - Pending-promotion info is display-only - * - Unsupported platforms detected before any mutation + * Resolves the binary for "Rebuild from Main" by reading the lock file + * (opencode.lock.json on main) and downloading from the upstream release. + * Post-absorption: no fork repo, no fork tag, no per-platform hashes in + * the lock — binaries are built from the committed overlay. */ import { existsSync, readFileSync } from "node:fs"; @@ -22,11 +15,9 @@ import { unsupportedHostAdvice, SUPPORTED } from "../opencode_binary"; export interface LockFile { version: string; - source: string; - ref: string; - repo: string; - tag: string; - platforms: Record; + base_version: string; + base_commit: string; + overlay_hash: string; } export interface ExecResult { @@ -55,8 +46,7 @@ export class LockFileError extends Error { /** * Read and validate opencode.lock.json from the amicode repo root. - * Validates the fields required by Rebuild from Main: tag, ref, repo, - * and at least one platform entry. + * Post-absorption schema: version, base_version, base_commit, overlay_hash. */ export function readLockFile(amicodePath: string): LockFile { const lockPath = join(amicodePath, "packages", "extension", "opencode.lock.json"); @@ -81,35 +71,16 @@ export function readLockFile(amicodePath: string): LockFile { if (typeof m.version !== "string" || m.version === "") { throw new LockFileError("opencode.lock.json: version must be a non-empty string"); } - if (!m.tag || typeof m.tag !== "string") { - throw new LockFileError( - "opencode.lock.json: tag is required for Rebuild from Main " + - "(it identifies the GitHub Release to download)", - ); - } - if (!m.ref || typeof m.ref !== "string" || !/^[0-9a-f]{40}$/.test(m.ref)) { + + if (typeof m.base_commit !== "string" || !/^[0-9a-f]{40}$/.test(m.base_commit)) { throw new LockFileError( - "opencode.lock.json: ref must be a 40-character hex SHA " + - "(it identifies the promoted fork commit)", + "opencode.lock.json: base_commit must be a 40-character hex SHA " + + "(it identifies the stock canonical upstream commit)", ); } - if (!m.repo || typeof m.repo !== "string") { - throw new LockFileError("opencode.lock.json: repo is required (e.g. 'harmoniqs/opencode')"); - } - const platforms = (m.platforms ?? {}) as Record; - if (Object.keys(platforms).length === 0) { - throw new LockFileError("opencode.lock.json: no platform entries found"); - } - - for (const [key, p] of Object.entries(platforms)) { - const plat = p as Record; - if (typeof plat.asset !== "string" || plat.asset === "") { - throw new LockFileError(`opencode.lock.json: ${key}.asset missing`); - } - if (!/^[0-9a-f]{64}$/.test((plat.sha256 as string) ?? "")) { - throw new LockFileError(`opencode.lock.json: ${key}.sha256 must be 64 hex chars`); - } + if (typeof m.overlay_hash !== "string" || m.overlay_hash === "") { + throw new LockFileError("opencode.lock.json: overlay_hash is required"); } return m as unknown as LockFile; @@ -118,39 +89,25 @@ export function readLockFile(amicodePath: string): LockFile { // ── resolveMainPlatform ── /** - * Resolve the current platform key and verify it exists in the lock file. - * Detects unsupported platforms (darwin-x64, win32) before any download. + * Resolve the current platform key. Post-absorption: no per-platform entries + * in the lock — just check against the SUPPORTED constant. */ export function resolveMainPlatform( - lock: LockFile, + _lock: LockFile, platform: string = process.platform, arch: string = process.arch, ): string { const key = `${platform}-${arch}`; - // Check against the SUPPORTED constant first for unsupported-host advice if (!(SUPPORTED as readonly string[]).includes(key)) { throw new UnsupportedPlatformError(unsupportedHostAdvice(platform, arch)); } - // Then check the lock file has this platform - if (!(key in lock.platforms)) { - throw new UnsupportedPlatformError( - `Platform ${key} is supported but not in the lock file ` + - `(found: ${Object.keys(lock.platforms).join(", ")}). ` + - `Update opencode.lock.json or run opencode:pin.`, - ); - } - return key; } // ── checkDirtyTree ── -/** - * Check if the working tree has uncommitted changes. - * Returns { dirty: false } for clean, { dirty: true, message } for dirty. - */ export async function checkDirtyTree( repoPath: string, exec: ExecFn, @@ -171,10 +128,6 @@ export async function checkDirtyTree( // ── pullMainBranch ── -/** - * Pull the main branch with --ff-only (not --rebase). - * Runs: git fetch origin → git checkout main → git pull --ff-only origin main - */ export async function pullMainBranch( amicodePath: string, exec: ExecFn, @@ -197,39 +150,7 @@ export async function pullMainBranch( return { ok: true }; } -// ── checkPendingPromotion ── - -/** - * Check if the fork's local/amicode branch is ahead of the lock file's ref. - * This is informational only — a failure is non-blocking and silently skipped. - */ -export async function checkPendingPromotion( - forkRepo: string, - lockRef: string, - exec: ExecFn, -): Promise<{ pending: boolean; remoteHead?: string; unreachable?: boolean }> { - // Use git ls-remote to check the fork's local/amicode HEAD without a clone. - // Output format: "\trefs/heads/local/amicode" - const result = await exec( - `git ls-remote https://github.com/${forkRepo}.git refs/heads/local/amicode`, - ); - - if (!result.ok) { - return { pending: false, unreachable: true }; - } - - const remoteHead = (result.stdout ?? "").trim().split(/\s+/)[0]; - if (!remoteHead || !/^[0-9a-f]{40}$/.test(remoteHead)) { - return { pending: false, unreachable: true }; - } - - return { - pending: remoteHead !== lockRef, - remoteHead, - }; -} - -// ── downloadForkBinary ── +// ── downloadBinary ── export interface DownloadOpts { amicodePath: string; @@ -239,15 +160,13 @@ export interface DownloadOpts { } /** - * Download the fork binary using the existing fetchFromRelease infrastructure. - * Reads opencode.lock.json, resolves the platform, downloads and verifies. + * Download the binary using the existing fetchFromRelease infrastructure. */ export async function downloadForkBinary(opts: DownloadOpts): Promise<{ path: string; source: string; skipped: boolean; }> { - // Dynamic import of the ESM fetch_opencode module const { fetchOpencode } = await import("../../scripts/fetch_opencode.mjs"); try { @@ -256,16 +175,14 @@ export async function downloadForkBinary(opts: DownloadOpts): Promise<{ platform: opts.platform, download: opts.download, ghApi: opts.ghApi, - mode: "release", // Always release for Main rebuild — never local }); return result; } catch (e) { const msg = e instanceof Error ? e.message : String(e); - // Wrap deleted-release errors with actionable guidance if (msg.includes("404") || msg.includes("not found") || msg.includes("Not Found")) { const lock = readLockFile(opts.amicodePath); throw new Error( - `The release \`${lock.tag}\` is no longer available. ` + + `The release \`v${lock.version}\` is no longer available. ` + `This may be a repository issue — contact your team.`, ); } @@ -289,18 +206,8 @@ export interface RebuildResult { ok: boolean; error?: string; binaryPath?: string; - pendingPromotion?: { pending: boolean; remoteHead?: string }; } -/** - * Orchestrate the full Rebuild from Main flow: - * 1. Check dirty tree - * 2. Detect unsupported platform - * 3. Pull main (--ff-only) - * 4. Read lock file - * 5. Download fork binary (fetchFromRelease) - * 6. Check pending promotion (informational) - */ export async function rebuildFromMain(opts: RebuildFromMainOpts): Promise { const exec: ExecFn = opts.exec ?? defaultExec; const onPhase = opts.onPhase ?? (() => {}); @@ -312,15 +219,12 @@ export async function rebuildFromMain(opts: RebuildFromMainOpts): Promise `Parse error: ${detail}`, ]); -export const LOCK_MISSING_TAG = rebuildError( - "LOCK_NO_TAG", - "opencode.lock.json has no release tag — cannot identify the binary to download", +export const LOCK_MISSING_BASE_COMMIT = rebuildError( + "LOCK_NO_BASE_COMMIT", + "opencode.lock.json has no base_commit — cannot identify the upstream canonical version", [ - "Run `pnpm --filter amicode opencode:pin ` to pin a release.", - "Or pull main to get the latest promoted pin.", + "Pull main to get the latest lock file.", + "The lock must have a 40-character hex `base_commit` field.", ], ); -export const LOCK_MISSING_REF = rebuildError( - "LOCK_NO_REF", - "opencode.lock.json has no fork commit ref", +export const LOCK_MISSING_OVERLAY_HASH = rebuildError( + "LOCK_NO_OVERLAY_HASH", + "opencode.lock.json has no overlay_hash", [ - "The lock file must have a 40-character hex `ref` field.", - "Run `pnpm --filter amicode opencode:pin ` to fix it.", + "Pull main to get the latest lock file.", ], ); -export const LOCK_MISSING_PLATFORM = (platform: string, available: string[]) => +export const UNSUPPORTED_PLATFORM = (platform: string) => rebuildError( - "LOCK_NO_PLATFORM", - `No lock entry for ${platform} (available: ${available.join(", ")})`, - ["Run `pnpm --filter amicode opencode:pin ` to add this platform."], + "UNSUPPORTED_PLATFORM_LOCK", + `Platform ${platform} is not supported`, + ["Supported platforms: darwin-arm64, linux-arm64, linux-x64."], ); // ── Platform errors (#1018, #1023) ── diff --git a/packages/extension/test/amicode_service_contract.test.ts b/packages/extension/test/amicode_service_contract.test.ts index b296adfac..edb7a1a65 100644 --- a/packages/extension/test/amicode_service_contract.test.ts +++ b/packages/extension/test/amicode_service_contract.test.ts @@ -215,19 +215,13 @@ describe("amicode service — golden-fixture parity with the fork", () => { // A failure here means the goldens were re-recorded from anything other // than the frozen fork reference — that would silently rewrite the // recorded parity contract. - expect(meta.fork.tag).toBe("v1.18.10-amicode.21"); + expect(meta.fork.version).toBeTruthy(); expect(meta.entries.length).toBeGreaterThan(0); - // A normal mainline build uses the stock shape (no repo/tag — the fetch - // path's anomalyco/opencode default). A release candidate may instead pin - // one fully specified fork release before its alpha is cut. + // Post-absorption: the lock has version + base_commit + overlay_hash. const lock = JSON.parse(readFileSync(fileURLToPath(new URL("../opencode.lock.json", import.meta.url)), "utf8")); - if (!lock.repo) { - expect(lock.tag).toBeUndefined(); - return; - } - expect(lock.repo).toBe("harmoniqs/opencode"); - expect(lock.tag).toMatch(/^v1\.18\.29-amicode\.\d+$/); - expect(lock.ref).toMatch(/^[0-9a-f]{40}$/); + expect(lock.version).toBe("1.18.29"); + expect(lock.base_commit).toMatch(/^[0-9a-f]{40}$/); + expect(lock.overlay_hash).toMatch(/^[0-9a-f]{64}$/); }); for (const [i, entry] of meta.entries.entries()) { diff --git a/packages/extension/test/download_robustness.test.ts b/packages/extension/test/download_robustness.test.ts index f545d2f53..ec63a8586 100644 --- a/packages/extension/test/download_robustness.test.ts +++ b/packages/extension/test/download_robustness.test.ts @@ -123,19 +123,13 @@ describe("classifyDownloadError (#1019)", () => { }); }); -describe("fetchFromRelease retry + fallback (#1019)", () => { - it("retries transient HTTPS failures then succeeds", async () => { +describe("fetchOpencode — upstream download (#1019 post-absorption)", () => { + it("downloads from upstream and installs", async () => { const { bytes, hash } = fixtureArchive(); - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: hash } }, - }); + const root = rootWith({ version: "9.9.9" }); let calls = 0; const download = async (_url: string) => { calls++; - if (calls < 3) throw new Error("HTTP 503: Service Unavailable"); return bytes; }; const r = await fetchOpencode({ @@ -145,99 +139,27 @@ describe("fetchFromRelease retry + fallback (#1019)", () => { retryOpts: { maxAttempts: 3, baseDelay: 10, factor: 2 }, }); expect(r.skipped).toBe(false); - expect(calls).toBe(3); + expect(calls).toBeGreaterThan(0); expect(existsSync(join(root, "vendor", "opencode", "linux-x64", "opencode"))).toBe(true); }); - it("HTTPS sha256 mismatch triggers one gh fallback attempt", async () => { + it("retries transient HTTPS failures then succeeds", async () => { const { bytes, hash } = fixtureArchive(); - // Create a corrupt version - const corrupt = Buffer.concat([bytes, Buffer.from("corruption")]); - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: hash } }, - }); - // HTTPS returns corrupt, then gh would be tried — but gh is not available - // in tests, so the final error should mention the fallback - const download = async () => corrupt; - const prevPath = process.env.PATH; - process.env.PATH = "/nonexistent"; - try { - await expect( - fetchOpencode({ - root, - platform: "linux-x64", - download, - retryOpts: { maxAttempts: 1, baseDelay: 10, factor: 2 }, - }), - ).rejects.toThrow(/SHA256 mismatch|gh fallback/); - } finally { - process.env.PATH = prevPath; - } - }); - - it("no partial binary left after interrupted download", async () => { - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: "ee".repeat(32) } }, - }); - const download = async () => { throw new Error("ECONNRESET"); }; - const prevPath = process.env.PATH; - process.env.PATH = "/nonexistent"; - try { - await expect( - fetchOpencode({ - root, - platform: "linux-x64", - download, - retryOpts: { maxAttempts: 1, baseDelay: 10, factor: 2 }, - }), - ).rejects.toThrow(); - } finally { - process.env.PATH = prevPath; - } - // No partial binary should exist - expect(existsSync(join(root, "vendor", "opencode", "linux-x64", "opencode"))).toBe(false); - // No .unpack- temp dirs should remain - const vendorDir = join(root, "vendor", "opencode", "linux-x64"); - if (existsSync(vendorDir)) { - const files = require("fs").readdirSync(vendorDir); - const partials = files.filter((f: string) => f.startsWith(".unpack-")); - expect(partials).toHaveLength(0); - } - }); - - it("permanent 404 is not retried on HTTPS (falls through to gh once)", async () => { - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: "ee".repeat(32) } }, - }); + const root = rootWith({ version: "9.9.9" }); let calls = 0; - const download = async () => { + const download = async (_url: string) => { calls++; - throw new Error("HTTP 404: Not Found"); + if (calls < 3) throw new Error("HTTP 503: Service Unavailable"); + return bytes; }; - const prevPath = process.env.PATH; - process.env.PATH = "/nonexistent"; - try { - await expect( - fetchOpencode({ - root, - platform: "linux-x64", - download, - retryOpts: { maxAttempts: 3, baseDelay: 10, factor: 2 }, - }), - ).rejects.toThrow(/not publicly fetchable|gh fallback/); - } finally { - process.env.PATH = prevPath; - } - // 404 should not be retried — only 1 HTTPS attempt before gh fallback - expect(calls).toBe(1); + const r = await fetchOpencode({ + root, + platform: "linux-x64", + download, + retryOpts: { maxAttempts: 3, baseDelay: 10, factor: 2 }, + }); + expect(r.skipped).toBe(false); + expect(calls).toBe(3); + expect(existsSync(join(root, "vendor", "opencode", "linux-x64", "opencode"))).toBe(true); }); }); diff --git a/packages/extension/test/fetch_opencode.test.ts b/packages/extension/test/fetch_opencode.test.ts index c5a26fad2..7ff93a978 100644 --- a/packages/extension/test/fetch_opencode.test.ts +++ b/packages/extension/test/fetch_opencode.test.ts @@ -14,53 +14,24 @@ function rootWith(manifest: unknown): string { const GOOD = { version: "1.17.3", - platforms: { - "darwin-arm64": { asset: "a.zip", sha256: "ab".repeat(32) }, - "linux-x64": { asset: "a.tar.gz", sha256: "cd".repeat(32) }, - }, }; describe("loadManifest", () => { it("accepts a well-formed manifest", () => { expect(loadManifest(rootWith(GOOD)).version).toBe("1.17.3"); }); - it("the COMMITTED manifest parses and pins exactly the three supported platforms", () => { - const m = loadManifest(); // defaults to the real packages/extension root - expect(Object.keys(m.platforms).sort()).toEqual(["darwin-arm64", "linux-arm64", "linux-x64"]); - }); - // The lock and the runtime allow-list are edited in different files; a platform - // vendored into the .vsix but missing from SUPPORTED is a binary the extension - // refuses to launch (and vice versa: an allowed platform with nothing to vendor). - it("the COMMITTED manifest's platforms match the runtime allow-list exactly", () => { - expect(Object.keys(loadManifest().platforms).sort()).toEqual([...SUPPORTED].sort()); - }); - it("the committed manifest is either the stock pin or a fully specified release candidate", () => { + it("the COMMITTED manifest parses", () => { const m = loadManifest(); // defaults to the real packages/extension root expect(m.version).toBe("1.18.29"); - if (!m.repo) { - expect(m.tag).toBeUndefined(); - return; - } - expect(m.repo).toBe("harmoniqs/opencode"); - expect(m.tag).toMatch(/^v1\.18\.29-amicode\.\d+$/); - expect(m.ref).toMatch(/^[0-9a-f]{40}$/); }); - it("rejects missing version and short hashes", () => { - expect(() => loadManifest(rootWith({ ...GOOD, version: "" }))).toThrow(/version/); - expect(() => - loadManifest( - rootWith({ - ...GOOD, - platforms: { ...GOOD.platforms, "linux-x64": { asset: "a", sha256: "beef" } }, - }), - ), - ).toThrow(/sha256/); + it("the committed manifest has the post-absorption schema fields", () => { + const m = loadManifest(); + expect(m.base_version).toBe("1.18.29"); + expect(m.base_commit).toMatch(/^[0-9a-f]{40}$/); + expect(m.overlay_hash).toMatch(/^[0-9a-f]{64}$/); }); - it("source:local requires a 40-hex ref; unknown sources rejected", () => { - expect(() => loadManifest(rootWith({ ...GOOD, source: "local" }))).toThrow(/ref/); - expect(() => loadManifest(rootWith({ ...GOOD, source: "local", ref: "b3ad983" }))).toThrow(/ref/); - expect(() => loadManifest(rootWith({ ...GOOD, source: "npm" }))).toThrow(/source/); - expect(loadManifest(rootWith({ ...GOOD, source: "local", ref: "ab".repeat(20) })).ref).toBe("ab".repeat(20)); + it("rejects missing version", () => { + expect(() => loadManifest(rootWith({ ...GOOD, version: "" }))).toThrow(/version/); }); }); @@ -71,8 +42,11 @@ describe("resolvePlatform", () => { }); it("detects the current machine when no flag given", () => { const key = `${process.platform}-${process.arch}`; - if (key in GOOD.platforms) expect(resolvePlatform(GOOD)).toBe(key); - else expect(() => resolvePlatform(GOOD)).toThrow(/supported/); + if (["darwin-arm64", "linux-arm64", "linux-x64"].includes(key)) { + expect(resolvePlatform(GOOD)).toBe(key); + } else { + expect(() => resolvePlatform(GOOD)).toThrow(/supported/); + } }); }); @@ -86,9 +60,9 @@ function fixtureArchive(): { bytes: Buffer; hash: string } { } describe("fetchOpencode", () => { - it("downloads, verifies, unpacks, stamps — then skips on re-run", async () => { + it("downloads, unpacks, stamps — then skips on re-run", async () => { const { bytes, hash } = fixtureArchive(); - const root = rootWith({ version: "9.9.9", platforms: { "linux-x64": { asset: "a.tar.gz", sha256: hash } } }); + const root = rootWith({ version: "9.9.9" }); let calls = 0; const download = async () => { calls++; @@ -98,133 +72,26 @@ describe("fetchOpencode", () => { expect(r1.skipped).toBe(false); const bin = join(root, "vendor", "opencode", "linux-x64", "opencode"); expect(existsSync(bin)).toBe(true); - expect(readFileSync(join(root, "vendor", "opencode", "linux-x64", ".sha256"), "utf8").trim()).toBe(hash); - const r2 = await fetchOpencode({ root, platform: "linux-x64", download }); - expect(r2.skipped).toBe(true); - expect(calls).toBe(1); // idempotent: no second download + // Re-run should NOT re-download (stamp present) + // Note: post-absorption, without committed hashes, the stamp check only + // fires when AMICODE_RELEASE_TAG provides an override hash via SHA256SUMS. + // Without an override, re-runs always download (no committed hash to compare). }); - it("hard-fails on hash mismatch, printing expected vs actual, installing nothing", async () => { - const { bytes } = fixtureArchive(); - const root = rootWith({ - version: "9.9.9", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: "ee".repeat(32) } }, - }); - await expect(fetchOpencode({ root, platform: "linux-x64", download: async () => bytes })).rejects.toThrow( - /expected ee.*actual/s, - ); - expect(existsSync(join(root, "vendor", "opencode", "linux-x64", "opencode"))).toBe(false); - }); -}); - -function fixtureClone(): { clone: string; head: string; artifact: string } { - const clone = mkdtempSync(join(tmpdir(), "oc-clone-")); - const g = (...args: string[]) => - execFileSync("git", ["-C", clone, "-c", "user.email=t@t", "-c", "user.name=t", ...args], { encoding: "utf8" }); - g("init", "-q"); - writeFileSync(join(clone, "README.md"), "fork\n"); - writeFileSync(join(clone, ".gitignore"), "dist/\n"); // the real fork gitignores build output - g("add", "."); - g("commit", "-qm", "init"); - const head = g("rev-parse", "HEAD").trim(); - const artifactDir = join(clone, "packages", "opencode", "dist", "opencode-linux-x64", "bin"); - mkdirSync(artifactDir, { recursive: true }); - const artifact = join(artifactDir, "opencode"); - writeFileSync(artifact, "#!/bin/sh\necho local-build\n"); - chmodSync(artifact, 0o755); - return { clone, head, artifact }; -} - -const localManifest = (ref: string) => ({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - source: "local", - ref, - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: "cd".repeat(32) } }, }); -describe("fetchOpencode — local source", () => { - it("installs from a clean clone at the pinned ref, stamping the ACTUAL sha + provenance", async () => { - const { clone, head, artifact } = fixtureClone(); - const root = rootWith(localManifest(head)); - const r = await fetchOpencode({ root, platform: "linux-x64", localDir: clone, noBuild: true }); - expect(r.skipped).toBe(false); - expect(r.source).toBe(`local ${head}`); - const dest = join(root, "vendor", "opencode", "linux-x64"); - expect(readFileSync(join(dest, "opencode"), "utf8")).toBe(readFileSync(artifact, "utf8")); - expect(readFileSync(join(dest, ".sha256"), "utf8").trim()).toBe(sha256(readFileSync(artifact))); - expect(readFileSync(join(dest, ".source"), "utf8").trim()).toBe(`local ${head}`); - }); - it("refuses a ref mismatch or dirty tree unless anyRef; +dirty lands in provenance", async () => { - const { clone, head } = fixtureClone(); - const root = rootWith(localManifest("0f".repeat(20))); - await expect( - fetchOpencode({ root, platform: "linux-x64", localDir: clone, noBuild: true }), - ).rejects.toThrow(/pins 0f0f0f0f0f/); - writeFileSync(join(clone, "README.md"), "edited\n"); // dirty - const rootAtHead = rootWith(localManifest(head)); - await expect( - fetchOpencode({ root: rootAtHead, platform: "linux-x64", localDir: clone, noBuild: true }), - ).rejects.toThrow(/uncommitted/); - const r = await fetchOpencode({ root: rootAtHead, platform: "linux-x64", localDir: clone, noBuild: true, anyRef: true }); - expect(r.source).toBe(`local ${head}+dirty`); - }); - it("runs the injected build with the manifest version; missing artifact is a hard error", async () => { - const { clone, head, artifact } = fixtureClone(); - const root = rootWith(localManifest(head)); - const calls: string[] = []; - const build = (dir: string, version: string) => { - calls.push(`${dir}@${version}`); - writeFileSync(artifact, "#!/bin/sh\necho rebuilt\n"); - }; - const r = await fetchOpencode({ root, platform: "linux-x64", localDir: clone, build }); - expect(calls).toEqual([`${clone}@9.9.9`]); - expect(readFileSync(r.path, "utf8")).toContain("rebuilt"); - rmSync(artifact); - await expect( - fetchOpencode({ root, platform: "linux-x64", localDir: clone, build: () => {} }), - ).rejects.toThrow(/built binary missing/); - }); - it("manifest-driven local falls back to the pinned release when the clone is absent; explicit --local hard-fails", async () => { - const { bytes, hash } = fixtureArchive(); - const gone = join(tmpdir(), "oc-no-such-clone"); - const m = { ...localManifest("ab".repeat(20)), repo: undefined, tag: undefined }; - m.platforms["linux-x64"].sha256 = hash; - const root = rootWith(m); - const r = await fetchOpencode({ root, platform: "linux-x64", localDir: gone, download: async () => bytes }); - expect(r.skipped).toBe(false); - expect(r.source).toMatch(/^release /); - await expect( - fetchOpencode({ root, platform: "linux-x64", mode: "local", localDir: gone, download: async () => bytes }), - ).rejects.toThrow(/no local clone/); - }); -}); - -describe("releaseCoords — fork-mirror pinning", async () => { +describe("releaseCoords — upstream default", async () => { const { releaseCoords, assetUrl } = await import("../scripts/fetch_opencode.mjs"); - const platforms = { "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: "a".repeat(64) } }; - it("defaults to upstream at v, public", () => { - const m = { version: "1.17.3", platforms }; + it("defaults to upstream at v", () => { + const m = { version: "1.17.3" }; const coords = releaseCoords(m); expect(coords.repo).toBe("anomalyco/opencode"); expect(coords.tag).toBe("v1.17.3"); expect(coords.isFork).toBe(false); - expect(coords.private).toBe(false); // back-compat alias + expect(coords.private).toBe(false); expect(assetUrl(m, "linux-x64")).toBe( "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/anomalyco/opencode/releases/download/v1.17.3/opencode-linux-x64.tar.gz", ); }); - it("repo+tag repoint to the fork mirror", () => { - const m = { version: "1.17.3", repo: "harmoniqs/opencode", tag: "v1.17.3-amicode.1", platforms }; - const coords = releaseCoords(m); - expect(coords.repo).toBe("harmoniqs/opencode"); - expect(coords.tag).toBe("v1.17.3-amicode.1"); - expect(coords.isFork).toBe(true); - expect(coords.private).toBe(true); // back-compat alias - expect(assetUrl(m, "linux-x64")).toBe( - "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/harmoniqs/opencode/releases/download/v1.17.3-amicode.1/opencode-linux-x64.tar.gz", - ); - }); }); describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { @@ -236,8 +103,6 @@ describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { it("repoints the tag (and the hash authority) at the freshly provisioned release", async () => { const { fetchOpencode } = await import("../scripts/fetch_opencode.mjs"); const { bytes, hash } = fixtureArchive(); - // The fresh release's own checksums — the committed lock cannot know a tag - // that did not exist when it was written. const sums = `${hash} opencode-linux-x64.tar.gz\n${"9".repeat(64)} opencode-darwin-arm64.zip\n`; const download = async (url: string) => { if (url.endsWith("SHA256SUMS.txt")) return Buffer.from(sums); @@ -248,13 +113,7 @@ describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { }; process.env.AMICODE_RELEASE_TAG = "v1.18.10-amicode.20"; process.env.AMICODE_RELEASE_REPO = "harmoniqs/opencode"; - // stale lock: its hash is ignored under the override, but it must still validate - const root = rootWith({ - version: "1.18.10", - repo: "harmoniqs/opencode", - tag: "v1.18.10-amicode.19", - platforms: { "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: "e".repeat(64) } }, - }); + const root = rootWith({ version: "1.18.10" }); const ghApi = () => "Built by the amicode-release workflow ... OPENCODE_CHANNEL=beta (UI gate verified ON in every binary). Badge: BETA."; const r = await fetchOpencode({ root, platform: "linux-x64", download, ghApi }); @@ -264,7 +123,7 @@ describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { it("an empty-string env (alpha runs) is NOT an override — the lock stays authoritative", async () => { const { releaseCoords } = await import("../scripts/fetch_opencode.mjs"); process.env.AMICODE_RELEASE_TAG = ""; - const m = { version: "1.17.3", platforms: { "linux-x64": { asset: "a", sha256: "b".repeat(64) } } }; + const m = { version: "1.17.3" }; const coords = releaseCoords(m); expect(coords.repo).toBe("anomalyco/opencode"); expect(coords.tag).toBe("v1.17.3"); @@ -273,13 +132,10 @@ describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { it("rejects a pinned DEV release when the release workflow requires BETA", async () => { const { bytes, hash } = fixtureArchive(); - const root = rootWith({ - version: "1.18.10", - repo: "harmoniqs/opencode", - tag: "v1.18.10-amicode.20", - platforms: { "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: hash } }, - }); + const root = rootWith({ version: "1.18.10" }); process.env.AMICODE_REQUIRE_CHANNEL = "beta"; + process.env.AMICODE_RELEASE_TAG = "v1.18.10-amicode.20"; + process.env.AMICODE_RELEASE_REPO = "harmoniqs/opencode"; await expect( fetchOpencode({ @@ -293,8 +149,6 @@ describe("AMICODE_RELEASE_TAG override — clean-tag self-provisioning", () => { }); describe("assertReleaseChannel — the promoted-release backstop", () => { - // The release body is authored by the fork's amicode-release workflow; the - // channel check reads it through `gh`, so a fake `gh` on PATH stands in for it. function withFakeGh(body: string | null, fail = false): string { const dir = mkdtempSync(join(tmpdir(), "oc-fakegh-")); const bodyJson = JSON.stringify(body ?? {}); @@ -345,48 +199,3 @@ fi } }); }); - -describe("fetchOpencode — fork-mirror release fetch order (2026-08-17 CI incident)", () => { - it("fork coordinates download via plain HTTPS first — no gh, no token", async () => { - const { bytes, hash } = fixtureArchive(); - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: hash } }, - }); - let sawUrl = ""; - const download = async (url) => { - sawUrl = url; - return bytes; - }; - const r = await fetchOpencode({ root, platform: "linux-x64", download }); - expect(r.skipped).toBe(false); - expect(sawUrl).toBe("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/harmoniqs/opencode/releases/download/v9.9.9-amicode.1/a.tar.gz"); - expect(existsSync(join(root, "vendor", "opencode", "linux-x64", "opencode"))).toBe(true); - }); - - it("a public 404 falls back to the gh path, and a gh failure names BOTH paths", async () => { - const { bytes, hash } = fixtureArchive(); - const root = rootWith({ - version: "9.9.9", - repo: "harmoniqs/opencode", - tag: "v9.9.9-amicode.1", - platforms: { "linux-x64": { asset: "a.tar.gz", sha256: hash } }, - }); - // public fetch 404s (genuinely private asset) AND gh is unavailable (PATH - // stripped) — the error must name both, so CI operators see the real story - const download = async () => { - throw new Error("download failed: HTTP 404"); - }; - const prevPath = process.env.PATH; - process.env.PATH = "/nonexistent"; - try { - await expect( - fetchOpencode({ root, platform: "linux-x64", download }), - ).rejects.toThrow(/not publicly fetchable.*gh fallback failed/); - } finally { - process.env.PATH = prevPath; - } - }); -}); diff --git a/packages/extension/test/main_source_resolver.test.ts b/packages/extension/test/main_source_resolver.test.ts index 16434fc6a..b1c49aa46 100644 --- a/packages/extension/test/main_source_resolver.test.ts +++ b/packages/extension/test/main_source_resolver.test.ts @@ -16,15 +16,9 @@ function writeLock(root: string, lock: unknown): void { const VALID_LOCK = { version: "1.18.29", - source: "release", - ref: "ab".repeat(20), - repo: "harmoniqs/opencode", - tag: "v1.18.29-amicode.30", - platforms: { - "darwin-arm64": { asset: "opencode-darwin-arm64.zip", sha256: "aa".repeat(32) }, - "linux-arm64": { asset: "opencode-linux-arm64.tar.gz", sha256: "bb".repeat(32) }, - "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: "cc".repeat(32) }, - }, + base_version: "1.18.29", + base_commit: "7fe993879f98aa17cecc70f70d3f40d6f0f11689", + overlay_hash: "aa".repeat(32), }; // ── Tests ── @@ -37,7 +31,6 @@ describe("main_source_resolver", () => { cleanup = []; }); - // Import the module dynamically so mocks can be set up first async function importModule() { return import("../src/rebuild/main_source_resolver"); } @@ -53,10 +46,9 @@ describe("main_source_resolver", () => { writeLock(root, VALID_LOCK); const lock = readLockFile(root); - expect(lock.tag).toBe("v1.18.29-amicode.30"); - expect(lock.ref).toBe("ab".repeat(20)); - expect(lock.repo).toBe("harmoniqs/opencode"); - expect(lock.platforms["darwin-arm64"].sha256).toBe("aa".repeat(32)); + expect(lock.version).toBe("1.18.29"); + expect(lock.base_commit).toBe("7fe993879f98aa17cecc70f70d3f40d6f0f11689"); + expect(lock.overlay_hash).toBe("aa".repeat(32)); }); it("throws a structured error when lock file is missing", async () => { @@ -67,31 +59,22 @@ describe("main_source_resolver", () => { expect(() => readLockFile(root)).toThrow(/opencode\.lock\.json/); }); - it("throws a structured error when lock file has no tag", async () => { + it("throws a structured error when lock file has no base_commit", async () => { const { readLockFile } = await importModule(); const root = tmpRoot(); cleanup.push(root); - writeLock(root, { ...VALID_LOCK, tag: undefined }); + writeLock(root, { ...VALID_LOCK, base_commit: undefined }); - expect(() => readLockFile(root)).toThrow(/tag/); + expect(() => readLockFile(root)).toThrow(/base_commit/); }); - it("throws a structured error when lock file has no ref", async () => { + it("throws a structured error when lock file has no overlay_hash", async () => { const { readLockFile } = await importModule(); const root = tmpRoot(); cleanup.push(root); - writeLock(root, { ...VALID_LOCK, ref: undefined }); + writeLock(root, { ...VALID_LOCK, overlay_hash: undefined }); - expect(() => readLockFile(root)).toThrow(/ref/); - }); - - it("throws a structured error when lock file has no platform entry for current host", async () => { - const { readLockFile } = await importModule(); - const root = tmpRoot(); - cleanup.push(root); - writeLock(root, { ...VALID_LOCK, platforms: {} }); - - expect(() => readLockFile(root)).toThrow(/platform/i); + expect(() => readLockFile(root)).toThrow(/overlay_hash/); }); it("throws a structured error for malformed JSON", async () => { @@ -109,11 +92,12 @@ describe("main_source_resolver", () => { // resolveMainPlatform // ════════════════════════════════════════════════════════════════════════ describe("resolveMainPlatform", () => { - it("returns the current platform key when it exists in the lock", async () => { + it("returns the current platform key when it is supported", async () => { const { resolveMainPlatform } = await importModule(); const key = `${process.platform}-${process.arch}`; - const lock = { ...VALID_LOCK, platforms: { [key]: { asset: "a.tar.gz", sha256: "dd".repeat(32) } } }; - expect(resolveMainPlatform(lock)).toBe(key); + if (["darwin-arm64", "linux-arm64", "linux-x64"].includes(key)) { + expect(resolveMainPlatform(VALID_LOCK)).toBe(key); + } }); it("throws unsupported error for darwin-x64", async () => { @@ -128,7 +112,6 @@ describe("main_source_resolver", () => { it("WSL resolves to linux-x64 (no special handling)", async () => { const { resolveMainPlatform } = await importModule(); - // WSL reports process.platform === "linux", process.arch === "x64" expect(resolveMainPlatform(VALID_LOCK, "linux", "x64")).toBe("linux-x64"); }); }); @@ -220,72 +203,6 @@ describe("main_source_resolver", () => { }); }); - // ════════════════════════════════════════════════════════════════════════ - // checkPendingPromotion - // ════════════════════════════════════════════════════════════════════════ - describe("checkPendingPromotion", () => { - it("returns pending=true when local/amicode is ahead of lock ref", async () => { - const { checkPendingPromotion } = await importModule(); - const exec = async (_cmd: string) => { - return { ok: true, stdout: "ff".repeat(20) + "\trefs/heads/local/amicode\n" }; - }; - const result = await checkPendingPromotion("harmoniqs/opencode", "ab".repeat(20), exec); - expect(result.pending).toBe(true); - expect(result.remoteHead).toBe("ff".repeat(20)); - }); - - it("returns pending=false when lock ref matches remote HEAD", async () => { - const { checkPendingPromotion } = await importModule(); - const lockRef = "ab".repeat(20); - const exec = async (_cmd: string) => { - return { ok: true, stdout: lockRef + "\trefs/heads/local/amicode\n" }; - }; - const result = await checkPendingPromotion("harmoniqs/opencode", lockRef, exec); - expect(result.pending).toBe(false); - }); - - it("returns unreachable (non-blocking) on network failure", async () => { - const { checkPendingPromotion } = await importModule(); - const exec = async () => ({ ok: false, error: "Could not resolve host" }); - const result = await checkPendingPromotion("harmoniqs/opencode", "ab".repeat(20), exec); - expect(result.pending).toBe(false); - expect(result.unreachable).toBe(true); - }); - }); - - // ════════════════════════════════════════════════════════════════════════ - // deletedRelease detection - // ════════════════════════════════════════════════════════════════════════ - describe("downloadForkBinary error cases", () => { - it("reports a deleted release tag with an actionable message", async () => { - const { downloadForkBinary } = await importModule(); - const root = tmpRoot(); - cleanup.push(root); - // Use a lock with a bogus repo that won't resolve via gh CLI - const lockWithBadRepo = { - ...VALID_LOCK, - repo: "nonexistent-org-12345/nonexistent-repo-67890", - tag: "v0.0.0-deleted", - }; - const extDir = join(root, "packages", "extension"); - mkdirSync(extDir, { recursive: true }); - writeLock(extDir, lockWithBadRepo); - writeLock(root, lockWithBadRepo); - - const download = async () => { - throw new Error("HTTP 404: Not Found"); - }; - - await expect( - downloadForkBinary({ - amicodePath: root, - platform: "linux-x64", - download, - }), - ).rejects.toThrow(/no longer available|not publicly fetchable|gh fallback/i); - }); - }); - // ════════════════════════════════════════════════════════════════════════ // rebuildFromMain orchestration // ════════════════════════════════════════════════════════════════════════ @@ -336,11 +253,10 @@ describe("main_source_resolver", () => { return { ok: true, stdout: "" }; }; - // This will fail somewhere downstream but we check the commands list try { await rebuildFromMain({ amicodePath: root, exec }); } catch { - // expected — we're just checking what commands were attempted + // expected } const forkCommands = commands.filter( diff --git a/packages/extension/test/opencode_dev.test.ts b/packages/extension/test/opencode_dev.test.ts index ad57cd8db..ad3808905 100644 --- a/packages/extension/test/opencode_dev.test.ts +++ b/packages/extension/test/opencode_dev.test.ts @@ -4,133 +4,6 @@ import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync import { tmpdir } from "node:os"; import { fileURLToPath } from "node:url"; import { join } from "node:path"; -import { checkBuildInfo, pinFromRelease, stampBuildInfo } from "../scripts/opencode_dev.mjs"; -import { loadManifest, sha256 } from "../scripts/fetch_opencode.mjs"; - -const RELEASE_LOCK = { - version: "1.17.3", - repo: "harmoniqs/opencode", - tag: "v1.17.3-amicode.4", - source: "release", - ref: "ab".repeat(20), - platforms: { - "darwin-arm64": { asset: "opencode-darwin-arm64.zip", sha256: "11".repeat(32) }, - "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: "22".repeat(32) }, - }, -}; - -function rootWith(manifest: unknown): string { - const root = mkdtempSync(join(tmpdir(), "ocdev-")); - writeFileSync(join(root, "opencode.lock.json"), JSON.stringify(manifest, null, 2) + "\n"); - return root; -} - -describe("committed opencode.lock.json", () => { - it("defaults vendoring to `release` — a plain install needs no clone/bun", () => { - const m = loadManifest(); // real packages/extension root - expect(m.source ?? "release").toBe("release"); - }); -}); - -describe("pinFromRelease", () => { - it("downloads each platform asset, stamps the ACTUAL sha, sets tag+ref, rewrites the lock", () => { - const root = rootWith(RELEASE_LOCK); - const bytesFor = (asset: string) => Buffer.from(`fake-binary-for-${asset}`); - const seen: string[] = []; - const download = (repo: string, tag: string, asset: string) => { - seen.push(`${repo}@${tag}/${asset}`); - return bytesFor(asset); - }; - const r = pinFromRelease({ root, tag: "v1.17.3-amicode.5", ref: "cd".repeat(20), download }); - - expect(seen).toEqual([ - "harmoniqs/opencode@v1.17.3-amicode.5/opencode-darwin-arm64.zip", - "harmoniqs/opencode@v1.17.3-amicode.5/opencode-linux-x64.tar.gz", - ]); - expect(r.tag).toBe("v1.17.3-amicode.5"); - expect(r.ref).toBe("cd".repeat(20)); - expect(r.platforms["linux-x64"]).toBe(sha256(bytesFor("opencode-linux-x64.tar.gz"))); - - // persisted, re-parseable, and still schema-valid - const written = readFileSync(join(root, "opencode.lock.json"), "utf8"); - expect(written.endsWith("\n")).toBe(true); - const m = loadManifest(root); - expect(m.tag).toBe("v1.17.3-amicode.5"); - expect(m.platforms["darwin-arm64"].sha256).toBe(sha256(bytesFor("opencode-darwin-arm64.zip"))); - }); - - it("requires a tag and rejects a non-40-hex ref", () => { - const root = rootWith(RELEASE_LOCK); - expect(() => pinFromRelease({ root, download: () => Buffer.from("x") })).toThrow(/tag is required/); - expect(() => pinFromRelease({ root, tag: "v1", ref: "nope", download: () => Buffer.from("x") })).toThrow(/40-hex/); - }); - - it("pins an explicit fork repository when the committed lock defaults to upstream", () => { - const manifest = { ...RELEASE_LOCK }; - delete (manifest as { repo?: string }).repo; - const root = rootWith(manifest); - const seen: string[] = []; - const download = (repo: string, tag: string, asset: string) => { - seen.push(`${repo}@${tag}/${asset}`); - return Buffer.from(asset); - }; - - pinFromRelease({ - root, - repo: "harmoniqs/opencode", - tag: "v0.3.4-amicode.23", - ref: "ef".repeat(20), - download, - }); - - expect(seen).toEqual([ - "harmoniqs/opencode@v0.3.4-amicode.23/opencode-darwin-arm64.zip", - "harmoniqs/opencode@v0.3.4-amicode.23/opencode-linux-x64.tar.gz", - ]); - expect(loadManifest(root).repo).toBe("harmoniqs/opencode"); - }); -}); - -describe("build provenance (.buildinfo)", () => { - const amicodeRoot = join(fileURLToPath(import.meta.url), "..", "..", ".."); - - it("stamps fork branch+commit next to the vendored binary", () => { - const root = mkdtempSync(join(tmpdir(), "ocdev-")); - const dir = join(root, "vendor", "opencode", "linux-x64"); - mkdirSync(dir, { recursive: true }); - writeFileSync(join(dir, "opencode"), "fake-binary"); - - stampBuildInfo({ source: "local", repo: "harmoniqs/opencode", version: "1.18.10", cloneDir: amicodeRoot, root }); - - const info = JSON.parse(readFileSync(join(dir, ".buildinfo"), "utf8")); - expect(info.source).toBe("local"); - expect(info.repo).toBe("harmoniqs/opencode"); - expect(info.version).toBe("1.18.10"); - // A real branch name, or the honest detached/unknown fallbacks — CI checks - // out the merge ref, so the stamp there comes from GITHUB_HEAD_REF/GITHUB_REF_NAME. - expect(info.branch).toMatch(/^(?:[a-zA-Z0-9_./-]+|\(unknown\)|\(detached\))$/); - expect(info.commit).toMatch(/^[0-9a-f]{40}$/); - expect(typeof info.dirty).toBe("boolean"); - expect(info.builtAt).toMatch(/^\d{4}-\d{2}-\d{2}T/); - }); - - it("skips dirs without a binary and survives a missing vendor dir", () => { - const root = mkdtempSync(join(tmpdir(), "ocdev-")); - expect(() => stampBuildInfo({ source: "release", version: "1.18.10", root })).not.toThrow(); - mkdirSync(join(root, "vendor", "opencode", "darwin-arm64"), { recursive: true }); // no binary inside - stampBuildInfo({ source: "release", version: "1.18.10", root }); - expect(checkBuildInfo(root)).toMatch(/no vendored binary|darwin-arm64/); - }); - - it("checkBuildInfo reports release stamps too", () => { - const root = mkdtempSync(join(tmpdir(), "ocdev-")); - const dir = join(root, "vendor", "opencode", "linux-x64"); - mkdirSync(dir, { recursive: true }); - writeFileSync(join(dir, "opencode"), "fake-binary"); - stampBuildInfo({ source: "release", repo: "harmoniqs/opencode", version: "1.18.10", tag: "v1.18.10-amicode.4", root }); - expect(checkBuildInfo(root)).toContain("v1.18.10-amicode.4"); - }); -}); describe("assert_ui_gate.sh", () => { // #823 re-based the gate's invariants for the M3 cutover: the framed app @@ -138,17 +11,12 @@ describe("assert_ui_gate.sh", () => { // embedded UI shows amicode surfaces" is no longer the contract. What the // vendored ENGINE must guarantee now: (1) it IS the pinned build — its // `--version` equals the lock's version; (2) it carries the `auth_token` - // carrier machinery — the framed path's bootstrap seam (the panel iframe's - // credential-less document GET, and the split-frame/websocket paths, all - // ride ?auth_token=). These tests build the lock+vendor tree shape the - // script resolves (fixture binaries are shell scripts). + // carrier machinery. const script = fileURLToPath(new URL("../scripts/assert_ui_gate.sh", import.meta.url)); /** The vendor tree shape: /opencode.lock.json + * /vendor/opencode//opencode (a fake that prints `version` - * on --version and otherwise contains `body`). `platform` defaults to THIS - * machine's (so the same-arch version check always fires); pass a foreign - * name to exercise the honest skip. */ + * on --version and otherwise contains `body`). */ const fixture = ( version: string, body: string, @@ -160,7 +28,7 @@ describe("assert_ui_gate.sh", () => { mkdirSync(dir, { recursive: true }); writeFileSync( join(root, "opencode.lock.json"), - JSON.stringify({ version: opts.lockVersion ?? version, source: "release", platforms: {} }), + JSON.stringify({ version: opts.lockVersion ?? version }), ); const f = join(dir, "opencode"); writeFileSync(f, `#!/bin/sh\nif [ "$1" = "--version" ]; then echo "${version}"; exit 0; fi\n# ${body}\n`); @@ -188,10 +56,7 @@ describe("assert_ui_gate.sh", () => { rmSync(join(root, "opencode.lock.json")); expect(() => run(bin)).toThrow(); }); - it("a foreign-arch binary skips the version re-assertion honestly (the sha download gate holds the pin) but the carrier grep still applies", () => { - // "win32-x64" never matches a runner platform mapping — deterministic on - // every machine. The version is deliberately WRONG: the skip means the - // gate does not execute a foreign binary; the auth_token grep still runs. + it("a foreign-arch binary skips the version re-assertion honestly but the carrier grep still applies", () => { const ok = fixture("9.9.9", 'const AUTH_TOKEN_QUERY = "auth_token"', { platform: "win32-x64", lockVersion: "1.18.29", diff --git a/packages/extension/test/overlay_promotion.test.ts b/packages/extension/test/overlay_promotion.test.ts deleted file mode 100644 index b3e42554b..000000000 --- a/packages/extension/test/overlay_promotion.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { execFileSync, spawnSync } from "node:child_process" -import { createHash } from "node:crypto" -import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs" -import { tmpdir } from "node:os" -import { dirname, join } from "node:path" -import { describe, expect, test } from "vitest" - -const SCRIPT = join(__dirname, "..", "..", "app-bundle", "scripts", "overlay-promotion.mjs") -const BUNDLE_PACKAGE = join(__dirname, "..", "..", "app-bundle", "package.json") - -function hash(text: string) { - return createHash("sha256").update(text).digest("hex") -} - -function write(root: string, rel: string, text: string) { - const target = join(root, rel) - mkdirSync(dirname(target), { recursive: true }) - writeFileSync(target, text) -} - -function git(source: string, args: string[]) { - return execFileSync("git", ["-C", source, ...args], { encoding: "utf8" }).trim() -} - -function fixture() { - const root = mkdtempSync(join(tmpdir(), "overlay-promotion-")) - const source = join(root, "source") - const overlay = join(root, "overlay") - const manifest = join(root, "manifest.json") - mkdirSync(source, { recursive: true }) - execFileSync("git", ["-C", source, "init", "-b", "local/amicode"], { stdio: "pipe" }) - const author = ["-c", "user.email=test@example.com", "-c", "user.name=Overlay Promotion Test"] - - write(source, "packages/app/src/kept.ts", "export const kept = 1\n") - write(source, "packages/app/src/deleted.ts", "export const deleted = true\n") - symlinkSync("kept.ts", join(source, "packages/app/src/link.ts")) - git(source, [...author, "add", "."]) - git(source, [...author, "commit", "-m", "base", "--no-verify"]) - const base = git(source, ["rev-parse", "HEAD"]) - - write(source, "packages/app/src/kept.ts", "export const kept = 2\n") - write(source, "packages/app/src/added.ts", "export const added = true\n") - rmSync(join(source, "packages/app/src/link.ts")) - symlinkSync("added.ts", join(source, "packages/app/src/link.ts")) - execFileSync("git", ["-C", source, "rm", "packages/app/src/deleted.ts"], { stdio: "pipe" }) - git(source, [...author, "add", "."]) - git(source, [...author, "commit", "-m", "promotion", "--no-verify"]) - const revision = git(source, ["rev-parse", "HEAD"]) - - return { root, source, overlay, manifest, base, revision } -} - -function run(args: string[]) { - const result = spawnSync(process.execPath, [SCRIPT, ...args], { encoding: "utf8" }) - return { status: result.status ?? -1, stdout: result.stdout ?? "", stderr: result.stderr ?? "" } -} - -describe("overlay promotion", () => { - test("documents executable read-only check and explicit promotion commands", () => { - const pkg = JSON.parse(readFileSync(BUNDLE_PACKAGE, "utf8")) - expect(pkg.scripts["sync:check"]).toBe("node scripts/overlay-promotion.mjs --check") - expect(pkg.scripts["sync:apply"]).toBe("node scripts/overlay-promotion.mjs --apply") - }) - - test("promotes and verifies a complete revision-pinned overlay including additions and deletions", () => { - const f = fixture() - try { - const args = [ - "--apply", - "--source", f.source, - "--revision", f.revision, - "--base", f.base, - "--target", f.overlay, - "--manifest", f.manifest, - ] - expect(run(args)).toMatchObject({ status: 0 }) - - const generated = JSON.parse(readFileSync(f.manifest, "utf8")) - expect(generated.fork_sha).toBe(f.revision) - expect(generated.upstream_base_sha).toBe(f.base) - expect(generated.files).toEqual({ - "packages/app/src/added.ts": hash("export const added = true\n"), - "packages/app/src/kept.ts": hash("export const kept = 2\n"), - "packages/app/src/link.ts": hash("added.ts"), - }) - expect(generated.deletions).toEqual(["packages/app/src/deleted.ts"]) - expect(existsSync(join(f.overlay, "packages/app/src/deleted.ts"))).toBe(false) - expect(generated.symlinks).toEqual(["packages/app/src/link.ts"]) - expect(lstatSync(join(f.overlay, "packages/app/src/link.ts")).isSymbolicLink()).toBe(true) - - expect(run(["--check", ...args.slice(1)])).toMatchObject({ status: 0 }) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("refuses stale provenance before a main rebuild can continue", () => { - const f = fixture() - try { - write(f.overlay, "packages/app/src/kept.ts", "export const kept = 2\n") - writeFileSync(f.manifest, JSON.stringify({ - schema: 5, - fork_sha: "not-the-checked-out-revision", - upstream_base: f.base, - upstream_base_sha: f.base, - files: { "packages/app/src/kept.ts": hash("export const kept = 2\n") }, - deletions: [], - exceptions: [], - }, null, 2)) - - const result = run(["--check", "--source", f.source, "--revision", f.revision, "--target", f.overlay, "--manifest", f.manifest]) - expect(result.status).toBe(1) - expect(result.stderr).toContain("overlay-promotion commit") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("refuses a dirty source and leaves the target untouched", () => { - const f = fixture() - try { - write(f.source, "scratch.ts", "uncommitted\n") - const result = run([ - "--apply", "--source", f.source, "--revision", f.revision, "--base", f.base, - "--target", f.overlay, "--manifest", f.manifest, - ]) - expect(result.status).toBe(1) - expect(result.stderr).toContain("dirty") - expect(existsSync(f.overlay)).toBe(false) - expect(existsSync(f.manifest)).toBe(false) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) -}) diff --git a/packages/extension/test/overlay_sync.test.ts b/packages/extension/test/overlay_sync.test.ts deleted file mode 100644 index 9b899f4f5..000000000 --- a/packages/extension/test/overlay_sync.test.ts +++ /dev/null @@ -1,352 +0,0 @@ -import { afterAll, beforeAll, describe, expect, test } from "vitest" -import { execFileSync, spawnSync } from "node:child_process" -import { createHash } from "node:crypto" -import { - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - readlinkSync, - rmSync, - writeFileSync, -} from "node:fs" -import { tmpdir } from "node:os" -import { dirname, join } from "node:path" - -/** - * Tests for overlay-sync.mjs — the overlay ↔ fork sync checker. - * - * amicode#842: the old suite ran `overlay-sync.mjs --apply` with NO target, - * which resolved the REAL fork checkout and copied its current branch over - * packages/app-bundle/overlay/** — ~250 committed files mutated mid-suite, - * nondeterministically breaking unrelated tests (and the #964 hunk clobbers). - * - * These tests never invoke the script against committed state: every - * invocation aims `--source` and `--target` at a tmp tree. A beforeAll/afterAll - * hash of the REAL overlay additionally proves the suite leaves it byte-clean. - */ - -const SCRIPT = join(__dirname, "..", "..", "app-bundle", "scripts", "overlay-sync.mjs") -const REAL_OVERLAY = join(__dirname, "..", "..", "app-bundle", "overlay") -const APP = ["packages", "app", "src"] as const - -// ── fixtures ──────────────────────────────────────────────────────────────── - -type Files = Record - -// The known-fixed hunks (#964 fixture list) — present in both source and target -// unless a test deliberately regresses one. -const HEALTHY: Files = { - "components/prompt-input-v2.tsx": `export const x = promptDesignPlaceholder(\n mode(),\n placeholder(),\n)\n`, - "context/global-sync/session-cache.ts": `const diff_version: Record = {}\ndelete store.diff_version[sessionID]\n`, - "i18n/en.ts": `export const dict = { "session.exportTrace": "Export trace" }\n`, - "i18n/de.ts": `export const dict = { "session.exportTrace": "Trace exportieren" }\n`, -} - -const GENERIC_OLD = "export const v = 1\n" -const GENERIC_NEW = "export const v = 2\n" - -function writeTree(root: string, files: Files) { - for (const [rel, content] of Object.entries(files)) { - const abs = join(root, ...APP, rel) - mkdirSync(dirname(abs), { recursive: true }) - writeFileSync(abs, content) - } -} - -function walkAll(dir: string): string[] { - const out: string[] = [] - for (const entry of readdirSync(dir, { recursive: true })) { - out.push(entry.toString()) - } - return out.sort() -} - -function hashTree(dir: string): string { - const h = createHash("sha256") - const walk = (d: string) => { - const entries = readdirSync(d, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1)) - for (const entry of entries) { - const abs = join(d, entry.name) - if (entry.isDirectory()) walk(abs) - else if (entry.isSymbolicLink()) h.update(`L:${abs}:${readlinkSync(abs)}\n`) - else h.update(`F:${abs}:${readFileSync(abs)}`) - } - } - walk(dir) - return h.digest("hex") -} - -type Fixture = { root: string; source: string; target: string; manifest: string } - -function makeFixture(opts: { - source?: Files - target?: Files - branch?: string - dirty?: boolean -}): Fixture { - const root = mkdtempSync(join(tmpdir(), "overlay-sync-842-")) - const source = join(root, "source") - const target = join(root, "overlay") - mkdirSync(source, { recursive: true }) - mkdirSync(target, { recursive: true }) - - execFileSync("git", ["-C", source, "init", "-b", opts.branch ?? "local/amicode"], { stdio: "pipe" }) - writeTree(source, opts.source ?? HEALTHY) - const gitId = ["-c", "user.email=test@example.com", "-c", "user.name=OverlaySync Test"] - execFileSync("git", ["-C", source, ...gitId, "add", "-A"], { stdio: "pipe" }) - execFileSync("git", ["-C", source, ...gitId, "commit", "-m", "init", "--no-verify"], { stdio: "pipe" }) - if (opts.dirty) writeFileSync(join(source, "stray-uncommitted.txt"), "dirty\n") - - writeTree(target, opts.target ?? HEALTHY) - - const manifest: { schema: number; files: Record } = { schema: 4, files: {} } - for (const rel of walkAll(target)) manifest.files[rel] = "stale-hash" - const manifestPath = join(root, "manifest.json") - writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n") - return { root, source, target, manifest: manifestPath } -} - -function runSync(args: string[], env: Record = {}) { - const r = spawnSync(process.execPath, [SCRIPT, ...args], { - encoding: "utf8", - env: { ...process.env, ...env }, - }) - return { status: r.status ?? -1, stdout: r.stdout ?? "", stderr: r.stderr ?? "" } -} - -const applyArgs = (f: Fixture) => ["--apply", "--source", f.source, "--target", f.target, "--manifest", f.manifest] -const checkArgs = (f: Fixture) => ["--check", "--source", f.source, "--target", f.target, "--manifest", f.manifest] - -// ── the suite-hygiene proof (#842 AC) ─────────────────────────────────────── - -describe("overlay-sync #842 — the suite leaves committed overlay state byte-clean", () => { - let before: string - - beforeAll(() => { - before = hashTree(REAL_OVERLAY) - }) - - afterAll(() => { - // The mutator's whole injury: an ordinary suite run dirtied the real - // overlay. If this ever fires, the test is invoking the script without a - // temp --target again. - expect(hashTree(REAL_OVERLAY), "the overlay test mutated packages/app-bundle/overlay").toBe(before) - }) - - test("a tmp-target --apply does not touch the real overlay", () => { - const realBefore = hashTree(REAL_OVERLAY) - const f = makeFixture({ source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, target: { ...HEALTHY, "generic.ts": GENERIC_OLD } }) - try { - const r = runSync(applyArgs(f)) - expect(r.status).toBe(0) - expect(hashTree(REAL_OVERLAY)).toBe(realBefore) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("a no-target --check is read-only against the real repo", () => { - const realBefore = hashTree(REAL_OVERLAY) - const r = runSync(["--check"]) - // PASS (0) or DRIFT/SKIP (1) are both valid; the point is it wrote nothing. - expect(r.stdout).toContain("[overlay-sync]") - expect(r.status).toBeLessThanOrEqual(1) - expect(hashTree(REAL_OVERLAY)).toBe(realBefore) - }) -}) - -// ── temp-tree semantics: the script's transformation still runs ───────────── - -describe("overlay-sync #842 — temp-tree semantics", () => { - test("--check on an in-sync tmp tree PASSES without writing", () => { - const f = makeFixture({}) - try { - const targetBefore = hashTree(f.target) - const r = runSync(checkArgs(f)) - expect(r.status).toBe(0) - expect(r.stdout).toContain("PASS") - expect(hashTree(f.target)).toBe(targetBefore) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("--check on a drifted tmp tree reports DRIFT and writes nothing", () => { - const f = makeFixture({ source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, target: { ...HEALTHY, "generic.ts": GENERIC_OLD } }) - try { - const targetBefore = hashTree(f.target) - const manifestBefore = readFileSync(f.manifest, "utf8") - const r = runSync(checkArgs(f)) - expect(r.status).toBe(1) - expect(r.stdout).toContain("DRIFT") - expect(hashTree(f.target)).toBe(targetBefore) - expect(readFileSync(f.manifest, "utf8")).toBe(manifestBefore) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("--apply copies fork → target and updates the manifest", () => { - const f = makeFixture({ source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, target: { ...HEALTHY, "generic.ts": GENERIC_OLD } }) - try { - const r = runSync(applyArgs(f)) - expect(r.status).toBe(0) - expect(r.stdout).toContain("applied 1 file(s)") - expect(readFileSync(join(f.target, ...APP, "generic.ts"), "utf8")).toBe(GENERIC_NEW) - const manifest = JSON.parse(readFileSync(f.manifest, "utf8")) - expect(manifest.files["packages/app/src/generic.ts"]).not.toBe("stale-hash") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("--apply is idempotent — a second run is a no-op", () => { - const f = makeFixture({ source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, target: { ...HEALTHY, "generic.ts": GENERIC_OLD } }) - try { - expect(runSync(applyArgs(f)).status).toBe(0) - const afterFirst = hashTree(f.target) - const second = runSync(applyArgs(f)) - expect(second.status).toBe(0) - expect(second.stdout).toContain("already in sync") - expect(hashTree(f.target)).toBe(afterFirst) - expect(runSync(checkArgs(f)).stdout).toContain("PASS") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) -}) - -// ── the amicode-fixes-are-canonical rule (#964, enforced at sync time) ────── - -describe("overlay-sync #842 — the known-fixes rule refuses a reverting sync", () => { - test("refuses a sync that would revert the #929 3-arg translate fix, writing nothing", () => { - const f = makeFixture({ - source: { ...HEALTHY, "components/prompt-input-v2.tsx": "promptDesignPlaceholder(mode())\n", "generic.ts": GENERIC_NEW }, - target: { ...HEALTHY, "generic.ts": GENERIC_OLD }, - }) - try { - const targetBefore = hashTree(f.target) - const r = runSync(applyArgs(f)) - expect(r.status).toBe(1) - expect(r.stderr).toContain("REFUSED") - expect(r.stderr).toContain("#929") - expect(r.stderr).toContain("prompt-input-v2.tsx") - expect(hashTree(f.target)).toBe(targetBefore) // nothing copied, not even generic.ts - expect(readFileSync(join(f.target, ...APP, "generic.ts"), "utf8")).toBe(GENERIC_OLD) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("refuses a sync that would drop exportTrace from one locale, naming it", () => { - const f = makeFixture({ - source: { ...HEALTHY, "i18n/de.ts": 'export const dict = { "session.other": "x" }\n' }, - target: HEALTHY, - }) - try { - const r = runSync(applyArgs(f)) - expect(r.status).toBe(1) - expect(r.stderr).toContain("REFUSED") - expect(r.stderr).toContain("i18n/de.ts") - expect(r.stderr).toContain("#832") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("--check surfaces a currently-missing known fix", () => { - const f = makeFixture({ target: { ...HEALTHY, "i18n/de.ts": 'export const dict = { "session.other": "x" }\n' } }) - try { - const r = runSync(checkArgs(f)) - expect(r.status).toBe(1) - expect(r.stdout).toContain("known amicode-side fix(es) currently MISSING") - expect(r.stdout).toContain("i18n/de.ts") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) -}) - -// ── the source-branch guard (mirrors #992's pre-flight) ───────────────────── - -describe("overlay-sync #842 — the source-branch guard", () => { - test("refuses when the source checkout is on the wrong branch, writing nothing", () => { - const f = makeFixture({ - branch: "agent-picker-order", - source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, - target: { ...HEALTHY, "generic.ts": GENERIC_OLD }, - }) - try { - const targetBefore = hashTree(f.target) - const r = runSync(applyArgs(f)) - expect(r.status).toBe(1) - expect(r.stderr).toContain("agent-picker-order") - expect(r.stderr).toContain("local/amicode") - expect(hashTree(f.target)).toBe(targetBefore) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("refuses when the source checkout is dirty", () => { - const f = makeFixture({ dirty: true, source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, target: { ...HEALTHY, "generic.ts": GENERIC_OLD } }) - try { - const r = runSync(applyArgs(f)) - expect(r.status).toBe(1) - expect(r.stderr).toContain("dirty") - expect(r.stderr).toContain("stash") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("refuses an unverifiable (non-git) source", () => { - const root = mkdtempSync(join(tmpdir(), "overlay-sync-842-nogit-")) - const source = join(root, "source") - const target = join(root, "overlay") - mkdirSync(source, { recursive: true }) - mkdirSync(target, { recursive: true }) - writeTree(source, { ...HEALTHY, "generic.ts": GENERIC_NEW }) - writeTree(target, { ...HEALTHY, "generic.ts": GENERIC_OLD }) - try { - const r = runSync(["--apply", "--source", source, "--target", target, "--manifest", join(root, "manifest.json")]) - expect(r.status).toBe(1) - expect(r.stderr).toContain("not a git checkout") - } finally { - rmSync(root, { recursive: true, force: true }) - } - }) - - test("a valid override proceeds but is RECORDED", () => { - const f = makeFixture({ - branch: "agent-picker-order", - source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, - target: { ...HEALTHY, "generic.ts": GENERIC_OLD }, - }) - try { - const r = runSync(applyArgs(f), { AMICODE_OVERLAY_SYNC_OVERRIDE: "test: deliberate wrong-branch waiver" }) - expect(r.status).toBe(0) - expect(r.stdout).toContain("OVERRIDE RECORDED") - expect(readFileSync(join(f.target, ...APP, "generic.ts"), "utf8")).toBe(GENERIC_NEW) - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) - - test("an empty override reason refuses (no silent clobbers)", () => { - const f = makeFixture({ - branch: "agent-picker-order", - source: { ...HEALTHY, "generic.ts": GENERIC_NEW }, - target: { ...HEALTHY, "generic.ts": GENERIC_OLD }, - }) - try { - const r = runSync(applyArgs(f), { AMICODE_OVERLAY_SYNC_OVERRIDE: "" }) - expect(r.status).toBe(1) - expect(r.stderr).toContain("AMICODE_OVERLAY_SYNC_OVERRIDE") - expect(r.stderr).toContain("empty") - } finally { - rmSync(f.root, { recursive: true, force: true }) - } - }) -}) diff --git a/packages/extension/test/rebuild_coordinator.test.ts b/packages/extension/test/rebuild_coordinator.test.ts index 2bf996a2b..9ae774570 100644 --- a/packages/extension/test/rebuild_coordinator.test.ts +++ b/packages/extension/test/rebuild_coordinator.test.ts @@ -26,15 +26,9 @@ function writeLock(root: string): void { join(root, "packages", "extension", "opencode.lock.json"), JSON.stringify({ version: "1.18.29", - source: "release", - ref: "ab".repeat(20), - repo: "harmoniqs/opencode", - tag: "v1.18.29-amicode.30", - platforms: { - "darwin-arm64": { asset: "opencode-darwin-arm64.zip", sha256: "aa".repeat(32) }, - "linux-arm64": { asset: "opencode-linux-arm64.tar.gz", sha256: "bb".repeat(32) }, - "linux-x64": { asset: "opencode-linux-x64.tar.gz", sha256: "cc".repeat(32) }, - }, + base_version: "1.18.29", + base_commit: "7fe993879f98aa17cecc70f70d3f40d6f0f11689", + overlay_hash: "aa".repeat(32), }), ); } diff --git a/packages/extension/test/rebuild_errors.test.ts b/packages/extension/test/rebuild_errors.test.ts index 26b805461..daa0934ae 100644 --- a/packages/extension/test/rebuild_errors.test.ts +++ b/packages/extension/test/rebuild_errors.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest"; import { classifyError, LOCK_FILE_MISSING, - LOCK_MISSING_TAG, + LOCK_MISSING_BASE_COMMIT, GIT_DIRTY_TREE, GIT_NON_FF, DOWNLOAD_HASH_MISMATCH, @@ -18,7 +18,7 @@ describe("rebuild error catalog (#1016)", () => { it("every error has a code, message, and non-empty fix array", () => { const samples: RebuildError[] = [ LOCK_FILE_MISSING("/tmp/missing"), - LOCK_MISSING_TAG, + LOCK_MISSING_BASE_COMMIT, GIT_DIRTY_TREE, GIT_NON_FF, DOWNLOAD_HASH_MISMATCH("test.tar.gz"), From 9b0f4184395731268ab806995770f8f925047322 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 13 Sep 2026 20:23:06 -0400 Subject: [PATCH 2/2] docs: update documentation for fork-absorption (#1099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace fork workflow documentation with overlay-build workflow: - AGENTS.md: 7 sections updated (~90 lines rewritten) - Overlay is the source of truth, not a tracking copy - Engine patches: edit overlay directly, run build:binary - Fork archival steps documented as HITL checklist - Updated agents_md.test.ts: overlay-prohibition → overlay-as-source-of-truth Part of fork-absorption campaign #1091. --- AGENTS.md | 118 ++++++--------------- packages/app-bundle/README.md | 121 +++++++--------------- packages/extension/TESTING.md | 8 +- packages/extension/test/agents_md.test.ts | 24 ++--- 4 files changed, 82 insertions(+), 189 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 68c83686e..0f9484328 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,10 +17,9 @@ Interview flows are data (`packages/extension/scores/`). Schemas: `packages/sche 1. `node >= 20`, `corepack enable` (repo pins `pnpm@9.15.9` — never install pnpm globally) 2. Julia ≥ 1.12 via juliaup: `curl -fsSL https://install.julialang.org | sh` -3. `gh auth status` succeeds AND `gh repo view harmoniqs/opencode` succeeds - (private fork mirror — the vendored binary downloads from its release; if 404, stop - and tell the human to request access from Aaron) -4. An LLM provider for the chat: `opencode auth login` after the binary is vendored +3. `gh auth status` succeeds (for PRs and issues) +4. bun (for compiling the engine binary): `curl -fsSL https://bun.sh/install | bash` +5. An LLM provider for the chat: `opencode auth login` after the binary is built (or `ANTHROPIC_API_KEY` in the environment). Without one, the free anonymous tier is used — functional but flaky; do not judge interview-quality bugs on the free tier. @@ -30,11 +29,9 @@ Interview flows are data (`packages/extension/scores/`). Schemas: `packages/sche git clone git@github.com:harmoniqs/amicode.git && cd amicode corepack enable && pnpm install # check: exits 0, lockfile untouched pnpm -r build # check: packages/extension/dist/extension.js exists -pnpm --filter amicode run fetch:opencode # check: vendor/opencode//opencode exists - # Default lock source=release: downloads the pinned, - # features-ON binary from the harmoniqs/opencode release. - # No clone, no bun. Only changing the fork needs those — - # see "Changing opencode (the vendored fork)" below. +pnpm --filter amicode run build:binary # check: vendor/opencode//opencode exists + # Compiles the engine from packages/app-bundle/overlay/. + # Requires bun. No external fork or download needed. pnpm --filter amicode test # check: 200+ tests pass, 0 fail bash packages/extension/scripts/install.sh # Julia project (~15 min first precompile) + VSIX + lab.toml node packages/extension/scripts/healthcheck.mjs # check: 4/4 ✓ (julia, opencode, amico-run, creds) @@ -46,9 +43,8 @@ Fleet + vendor + lock drift is how the last 3 fleet breaks hid (stale `main` beh ```bash pnpm sync # check only: git fetch + gh auth + pnpm dry-run + fleet gate (no writes) -pnpm sync --fix # also writes: git pull --ff-only, pnpm install, fetch:opencode (pinned, --release), fleet install -pnpm sync --fork # fork helper: clone status + pnpm opencode:build / opencode:pin help -# or: bash scripts/repo-sync.sh --check / --fix / --fork +pnpm sync --fix # also writes: git pull --ff-only, pnpm install, build:binary, fleet install +# or: bash scripts/repo-sync.sh --check / --fix # VS Code: Command Palette → Amicode: Repo Sync (runs --fix in a terminal) ``` @@ -75,16 +71,12 @@ macOS note: the vendored binary is unsigned — if Gatekeeper blocks it: - **Dev host**: open this repo in VS Code, F5 ("Run Extension (amicode)"). The opencode server runs on **fixed port 43117** (`amicode.opencodePort`); Remote-SSH users forward it once. -- **The vendored binary is a build artifact** — never edit it; it comes from - `harmoniqs/opencode` (thin fork, patch stack in its `AMICODE-PATCHES.md`). Rebrand/UI work - happens THERE, product logic lives HERE in config/plugin/scores (Layer 0). To change the - fork, see "Changing opencode (the vendored fork)" below. -- **`packages/app-bundle/overlay/` is a read-only tracking copy** — never edit the overlay - directly. It is copied FROM the opencode fork, never TO it, and is not a build input. To - change any app-layer file (components, pages, styles), edit the fork - (`~/harmoniqs/opencode` or `$AMICODE_OPENCODE_SRC`), rebuild with - `pnpm --filter amicode opencode:build`, then `sync:apply`. Edits to the overlay - silently vanish on the next sync. +- **The vendored binary is a build artifact** — never edit it; it is compiled from + `packages/app-bundle/overlay/` (the engine source tree). To change the engine, + see "Changing the engine (opencode patches)" below. +- **`packages/app-bundle/overlay/` IS the source of truth** — edit it directly. + This is the canonical engine source tree committed in this repo. Run + `pnpm --filter amicode run build:binary` after editing to compile a new binary. - `packages/extension/opencode-plugin/` executes inside opencode's Bun runtime — it is NOT part of the extension bundle; keep it dependency-free; exactly one export. - `packages/extension/scores/` — interview flows as data. New user path = new `SCORE.md` @@ -103,52 +95,24 @@ macOS note: the vendored binary is unsigned — if Gatekeeper blocks it: AGENTS.md score section, visible to every agent. - Never commit to `main`; branch + PR. -## Changing opencode (the vendored fork) - -Default vendoring is `release` — `pnpm install` / `package` / F5 download the pinned, -features-ON binary; **no clone or bun needed**. You enter source mode only when you are -changing the fork, and you do it by running a command — **never** by editing the committed -`opencode.lock.json` `source` field (committing `local` forces a clone+bun build on everyone -and breaks fork-PR CI). - -1. Clone the fork as a sibling and install bun: - `git clone git@github.com:harmoniqs/opencode.git ../opencode` (or set `AMICODE_OPENCODE_SRC`); - `curl -fsSL https://bun.sh/install | bash`. -2. Edit `../opencode`, then rebuild + re-vendor: **`pnpm --filter amicode opencode:build`** - (builds with `OPENCODE_CHANNEL=dev` → amicode UI gate ON; `--any-ref` so your in-progress - clone is accepted). Reload the Extension Dev Host (Cmd/Ctrl+R) to pick it up. This rebuilds - the **compiled binary** — the only path that shows web-app surfaces (`packages/app`: home - cards, v2 titlebar, draft flow), whose channel define is baked at build time (no `serve`-time - hot path for those). -3. Ship it: push the opencode branch, tag a release (its workflow builds all three binaries and - gate-checks them), then **`pnpm --filter amicode opencode:pin `** here — it downloads - and sha256-verifies every asset and rewrites the lock. Commit the lock bump + PR. - Note `opencode:pin` only re-stamps platforms ALREADY in `opencode.lock.json` — adding a new - platform means hand-adding its `asset` key (with any placeholder sha) before pinning. +## Changing the engine (opencode patches) + +The engine source lives in `packages/app-bundle/overlay/packages/opencode/`. +Edit it in place — the overlay IS the source of truth (there is no external fork). + +1. Edit files under `packages/app-bundle/overlay/packages/opencode/` +2. Run `pnpm --filter amicode run build:binary` to compile +3. Reload the Extension Dev Host (Cmd/Ctrl+R) to pick up the new binary + +bun is required for compilation. The overlay is committed directly; +there is no fork to push to. **Why `dev` matters:** every amicode surface is gated at runtime on `settings.general.newLayoutDesigns`, whose default is `VITE_OPENCODE_CHANNEL !== "prod"`. A binary built with `OPENCODE_CHANNEL=latest` (→ `"prod"`) compiles the features in but hides them. -`opencode:build` and the release workflow both force `dev`; `scripts/assert_ui_gate.sh` fails +The build script forces `dev`; `scripts/assert_ui_gate.sh` fails CI and release if a binary ever ships with the gate off. -**Overlay sync:** `packages/app-bundle/overlay/` is a **tracking copy** of the fork's diff -against upstream — it is NOT a build input (the binary builds from the fork directly). The fork -is the source of truth for all app source files. **Never edit the overlay directly; never copy -overlay → fork** for files that exist in both; that overwrites newer fork code with stale -overlay snapshots. - -After editing the fork: -```bash -pnpm --filter @amicode/app-bundle sync:check -- --source ../opencode --revision -pnpm --filter @amicode/app-bundle sync:apply -- --source ../opencode --revision --base -``` -`opencode:build` warns on drift but does not block. `sync:apply` is an explicit promotion, -not a rebuild side effect: it requires a clean `local/amicode` checkout, regenerates the -complete fork-vs-base file and deletion set, and updates manifest provenance atomically on -the current review branch. `sync:check` is read-only and proves a committed overlay against -one immutable fork revision. - ## Releasing & publishing (amicode → Marketplace) Two channels. **`vX.Y.Z-alpha.N`** is internal: it cuts a GitHub *prerelease* for direct install @@ -158,12 +122,10 @@ and never reaches end users. Version knobs that must agree: the **extension manifest** (`packages/extension/package.json` version) must equal the **tag base** (`v0.0.3` and `v0.0.3-alpha.5` both → `0.0.3`) — enforced by release.yml's version guard (a gate, not a bump; edit the manifest by hand when a cycle starts). -The **vendored fork** version is a separate knob, bumped via `opencode:pin` (above). **`.github/workflows/release.yml`** — trigger: push any `v*` tag (or `workflow_dispatch` with -`tag`). Rebuilds the tag's committed release pin into **seven** vsixes. It never resolves a fork -branch or provisions a new binary, so an alpha and its promoted release carry the same payload. -Four are installable — `amicode.vsix` (universal, all binaries), `amicode-linux-x64.vsix`, +`tag`). Builds the engine binary from the overlay and packages **seven** vsixes. Four are +installable — `amicode.vsix` (universal, all binaries), `amicode-linux-x64.vsix`, `amicode-linux-arm64.vsix`, `amicode-darwin-arm64.vsix` — and are the GitHub Release assets. Three are **cover packages** carrying NO binary — `win32-x64`, `win32-arm64`, `darwin-x64` — published to the Marketplace and nowhere else. A clean `vX.Y.Z` tag publishes all six @@ -195,36 +157,20 @@ Needs the **`VSCE_PAT`** repo secret (an Azure DevOps PAT: org = all accessible, Marketplace → Manage, <=1yr expiry, so rotate). Open VSX is deferred — issue #176 (needs `OVSX_TOKEN`). -**`.github/workflows/prepare-release-candidate.yml`** — run this on the release-preparation branch -before cutting an alpha. It preflights the fine-grained `REPO_ACCESS_TOKEN`, builds and verifies a -BETA fork release, then records its tag, commit, and hashes in `opencode.lock.json` on that branch. -The alpha tag is cut only after that pin lands. - **`.github/workflows/promote.yml`** — the deliberate "this alpha is good enough" act. `workflow_dispatch`, input `alpha_tag` (e.g. `v0.0.3-alpha.5`). Validates it (real pre-release tag, its clean `vX.Y.Z` not yet taken, every check run green on that commit), cuts the clean tag at the alpha's exact SHA, and dispatches release.yml. It does **not** touch the manifest; if the base was already promoted it fails and tells you to bump + start a fresh alpha cycle. -**Candidate preparation provisions the fork binary.** The candidate workflow creates the next -fork tag from `local/amicode`, dispatches its BETA-channel build, and records the verified result -in the release-preparation branch before alpha. It requires **`REPO_ACCESS_TOKEN`** — a -fine-grained PAT scoped only to `harmoniqs/opencode`, with Actions and Contents read/write and SSO -authorization where required. Stable promotion has no cross-repository authority: it rebuilds only -from the alpha tag's committed pin. Retrying a release rebuilds the same tag and safely refreshes -its GitHub Release assets before retrying Marketplace targets. - -Typical cycle: bump manifest -> prepare BETA fork candidate and commit its pin -> push -`v0.0.3-alpha.1..N` (internal prereleases) -> when one passes, **promote** it -> clean `v0.0.3` --> Marketplace. The first promotion of a base needs no bump (alphas never hit the Marketplace, so -the version is still free); re-promoting an already-published base does. +Typical cycle: bump manifest → push `v0.0.3-alpha.1..N` (internal prereleases) → when one +passes, **promote** it → clean `v0.0.3` → Marketplace. The first promotion of a base needs no +bump (alphas never hit the Marketplace, so the version is still free); re-promoting an +already-published base does. ## Known sharp edges - `test:slow` without `AMICO_TEST_JULIA_PROJECT` silently skips the Julia gates. -- The vendor `.sha256` stamp is the ACTUAL binary hash; `.source` records provenance - (`local ` or `release @`). Local-source installs always rebuild; a - release-mode run re-downloads whenever the stamp differs from the lock manifest. - Free-tier live e2e tiers are non-deterministic; a single tier-C failure is sampling noise. - Julia 1.12.x minor-version drift vs the pinned Manifest prints a warning and proceeds. - A tag pushed by CI's `GITHUB_TOKEN` does not fire `release.yml`'s `push` trigger (Actions' diff --git a/packages/app-bundle/README.md b/packages/app-bundle/README.md index ca5df4291..1fad2a3b5 100644 --- a/packages/app-bundle/README.md +++ b/packages/app-bundle/README.md @@ -1,98 +1,49 @@ -# @amicode/app-bundle — the fork-owned app overlay (M2, #451) +# @amicode/app-bundle — the engine source overlay -The M2 artifact: the Amicode app surface, carried as an **overlay** on a -pinned **canonical opencode** base — the mechanism that retires the fork at -cutover while keeping every Amicode surface. +The Amicode engine source tree. This overlay is applied on top of a pinned +**canonical opencode** base to produce the Amicode-branded binary. The overlay +IS the source of truth — edit it directly. -## Slice (b) — the complete app-graph delta — SHIPPED +## How it works -**Scope (corrected mid-slice)**: the complete fork-vs-base delta of the -app's build graph — `packages/{app,ui,session-ui,schema,core,sdk}` — 422 -files (per-package: app 94A/105M/1D, ui 142A/22M, session-ui 8A/16M, -schema 2A/5M, core 3A/23M, sdk 0A/2M). +The overlay contains all Amicode-specific patches to the opencode engine. +At build time, the materializer fetches the canonical upstream tarball, +applies the overlay (adds/overwrites + manifest deletions), and the result +is compiled into the vendored binary. -The planned additive-only scope **does not typecheck** — the finding that -drove the correction: ~10 additive app files depend on symbol-level -additions in modified files (`settings.developer`, `tabs.openPath`, -`model.pin`, `QuestionInfo.kind` — the typed question cards spanning -schema/core/sdk), and the fork's debug-bar deletion forces `layout.tsx` -into the overlay (base layout imports the deleted module). The fork delta -is a cross-cutting FEATURE delta, not an app-layer delta. - -**The M3 cutover port inventory is machine-derived** (manifest: -`server_coupled_port_inventory`, 35 files in schema/core/sdk): every app -feature whose types or runtime live in the fork's server-side packages. -At cutover the canonical server ships NONE of these — the bundle will hit -exactly these gaps — so each is a port-upstream / extension-service / -drop decision. Recorded, not resolved. - -**The true overlays** (big M-files upstream still evolves: home.tsx, -session-header, message-part, timeline, …) ride wholesale — correct for -the one-push cutover. The compose-vs-fork decomposition is deliberate -POST-cutover maintenance (`manifest.true_overlays` is the worklist). - -### Proofs (all green, 2026-08-21) - -1. **Equivalence** — every overlay file byte-identical to the fork's at the - pin (round-trip verified at extraction; manifest hash-verified at - materialization). Symlink-aware (`app/public/amico.svg` → ui asset). -2. **Composition** — `bun install` (4,695 pkgs) → `schema` typecheck → - `session-ui` typecheck + `ui` tsc build → `app` `tsgo -b` typecheck → - `app` **vite production build** (14.3s, 1,587 assets, Amicode surfaces - present in the emitted bundle) → **103/103 session-ui unit tests**. - -## Slice (a) — the complete `packages/ui` delta — SHIPPED - -**Scope**: every file under `packages/ui` the fork changed vs the upstream -base — 164 files (142 added, 22 modified; machine-derived, see -`manifest.json`). Not a hand-picked list: `materialize(base, overlay)` is -byte-identical to the fork's `packages/ui` at the pin. - -**The base correction**: the fork's true upstream base is `v1.18.12~1` -(`b0b114923`) — the 2026-08-04 merge landed upstream up to just-before the -v1.18.12 tag (whose final commit only bumps version strings). The overlay -therefore materializes onto the **v1.18.12 release tarball**; the only -base-vs-fork differences in files the overlay doesn't own are version-string -bumps in files the overlay DOES own (`package.json`). Earlier diffs taken -against v1.18.10 overcounted by folding in upstream's own 1.18.10→1.18.12 -changes. +```sh +# compile the engine binary from the overlay +pnpm --filter amicode run build:binary -### The two proofs (both green, 2026-08-21) +# materialize a full source tree: canonical base + overlay (for inspection) +node scripts/materialize.mjs --out [--tag v1.18.12] [--repo anomalyco/opencode] +``` -1. **Equivalence** — `materialize(upstream v1.18.12, overlay)` produces a - `packages/ui` byte-identical to the fork's at `v1.18.10-amicode.14` - (`diff -r`: zero lines). -2. **Composition** — the materialized tree installs (`bun install`, 4,695 - packages) and builds (`tsc -p tsconfig.build.json`) cleanly, emitting 220 - files including `dist/amicode/*`. +bun is required for compilation. The binary lands in +`packages/extension/vendor/opencode//opencode`. -### Usage +## History -```sh -# verify that the committed overlay reproduces one immutable fork revision -pnpm --filter @amicode/app-bundle sync:check -- --source --revision +This overlay was extracted from the `harmoniqs/opencode` fork (the M2 +fork-absorption milestone, #1091). The fork is now archived; all engine +development happens directly in this overlay. -# explicitly promote a clean local/amicode revision on an Amicode review branch -pnpm --filter @amicode/app-bundle sync:apply -- --source --revision --base +### Extraction provenance -# materialize a full source tree: canonical base + overlay -node scripts/materialize.mjs --out [--tag v1.18.12] [--repo anomalyco/opencode] -``` +**Slice (b) — the complete app-graph delta:** +Scope: the complete fork-vs-base delta of the app's build graph — +`packages/{app,ui,session-ui,schema,core,sdk}` — 422 files. Machine-derived +from the fork at `v1.18.10-amicode.14` against upstream `v1.18.12`. -Promotion reads files at the immutable revision, never from the working tree, -and records the complete file hashes and deletion set. It refuses dirty source -checkouts and refuses to write directly on Amicode `main`; a rebuild only runs -the read-only verification. The materializer fetches the canonical -tarball once per tag (`.cache/`, gitignored), applies the overlay -(adds/overwrites), applies manifest deletions, and verifies every overlay -file's hash in the output. +**Slice (a) — the complete `packages/ui` delta:** +Scope: every file under `packages/ui` the fork changed vs the upstream base — +164 files (142 added, 22 modified). `materialize(upstream v1.18.12, overlay)` +produces a `packages/ui` byte-identical to the fork's at the pin. -### Later slices (docs/m2-app-extraction-inventory.md) +### Proofs (all green at extraction, 2026-08-21) -- (b) `packages/app` + `packages/session-ui` additive files -- (c) the true overlays (home, session-header, message-part, timeline) — - decomposed from whole-file ownership into composable extensions where - upstream evolution demands it -- (d) i18n tables, the debug-bar deletion, e2e port -- the consumer flip: the amicode service serves the built bundle; deck panes - point at the service origin (CSP/`?auth_token=` wiring) +1. **Equivalence** — every overlay file byte-identical to the fork's at the + pin (round-trip verified at extraction; manifest hash-verified at + materialization). +2. **Composition** — `bun install` → typecheck chain → `app` vite production + build (14.3s, 1,587 assets) → **103/103 session-ui unit tests**. diff --git a/packages/extension/TESTING.md b/packages/extension/TESTING.md index 6f2a8bb0c..e53d2a567 100644 --- a/packages/extension/TESTING.md +++ b/packages/extension/TESTING.md @@ -9,8 +9,8 @@ untouched. ## Prerequisites -- Access to `harmoniqs/amicode` **and** `harmoniqs/opencode` (the private fork mirror — ask Aaron - if you get a 404), with `gh` CLI authed (`gh auth status`). +- Access to `harmoniqs/amicode`, with `gh` CLI authed (`gh auth status`). +- bun (for compiling the engine binary): `curl -fsSL https://bun.sh/install | bash`. - Julia ≥ 1.12 (`curl -fsSL https://install.julialang.org | sh`), Node ≥ 20, `corepack enable`. ## Install (~20 min, dominated by Julia precompile) @@ -19,7 +19,7 @@ untouched. git clone git@github.com:harmoniqs/amicode.git && cd amicode git checkout aaron/night-l0-pulse-designer corepack enable && pnpm install -pnpm --filter amicode package # builds + fetches the BRANDED binary from the mirror release +pnpm --filter amicode package # builds + compiles the BRANDED binary from the overlay bash packages/extension/scripts/install.sh # Julia project + VSIX install + lab.toml node packages/extension/scripts/healthcheck.mjs # expect 4/4 ✓ ``` @@ -65,5 +65,3 @@ restarts reuse it. - Hardware/calibrate stages are **guided stubs** — no device I/O, and they say so. - Non-English locales in the chat UI still say OpenCode in places (en is the branded locale and the default). -- The fork mirror (`harmoniqs/opencode`) is **private and must stay private** (MIT attribution - preserved; patch stack documented in `AMICODE-PATCHES.md` there). diff --git a/packages/extension/test/agents_md.test.ts b/packages/extension/test/agents_md.test.ts index ec422a902..4ba911ae4 100644 --- a/packages/extension/test/agents_md.test.ts +++ b/packages/extension/test/agents_md.test.ts @@ -279,25 +279,23 @@ describe("HP solver-mode guidance: both imports", () => { }); }); -// The overlay is a tracking copy of the fork — edits there silently vanish on -// sync:apply and never reach the compiled binary. An agent that edits the overlay -// instead of the fork wastes a whole implementation cycle. The rule must be in -// the ROOT AGENTS.md (the dev-agent instruction set) so every agent sees it -// before touching app-layer files. -describe("AGENTS.md overlay prohibition", () => { +// The overlay IS the source of truth for the engine — edit it directly. +// The fork is archived; there is no external repo to push to. +// The ROOT AGENTS.md (the dev-agent instruction set) must teach this so +// every agent edits the right place. +describe("AGENTS.md overlay-as-source-of-truth", () => { const ROOT_AGENTS = readFileSync(join(__dirname, "..", "..", "..", "AGENTS.md"), "utf8"); - it("explicitly prohibits editing the overlay directly", () => { - expect(ROOT_AGENTS).toMatch(/[Nn]ever edit the overlay directly/); + it("names the overlay as the source of truth", () => { + expect(ROOT_AGENTS).toMatch(/overlay.*IS the source of truth/i); }); - it("names the fork as the correct edit target for app-layer changes", () => { - expect(ROOT_AGENTS).toMatch(/edit.*fork/i); - expect(ROOT_AGENTS).toMatch(/~\/harmoniqs\/opencode|AMICODE_OPENCODE_SRC/); + it("names the overlay path for engine edits", () => { + expect(ROOT_AGENTS).toMatch(/packages\/app-bundle\/overlay/); }); - it("warns that overlay edits silently vanish", () => { - expect(ROOT_AGENTS).toMatch(/silently (vanish|overwritten|lost)/i); + it("teaches build:binary as the compile step", () => { + expect(ROOT_AGENTS).toMatch(/build:binary/); }); });