@rexvane/piweb 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/assets/showcase.png +0 -0
- package/bin/pi.js +50 -0
- package/bin/piweb.js +12 -0
- package/next.config.ts +21 -0
- package/package.json +88 -0
- package/postcss.config.mjs +7 -0
- package/public/file-icons/3d.svg +1 -0
- package/public/file-icons/LICENSE +8 -0
- package/public/file-icons/adobe-illustrator.svg +1 -0
- package/public/file-icons/adobe-photoshop.svg +1 -0
- package/public/file-icons/agent.svg +1 -0
- package/public/file-icons/asciidoc.svg +1 -0
- package/public/file-icons/assembly.svg +1 -0
- package/public/file-icons/astro.svg +1 -0
- package/public/file-icons/audio.svg +1 -0
- package/public/file-icons/authors.svg +1 -0
- package/public/file-icons/babel.svg +1 -0
- package/public/file-icons/bibliography.svg +1 -0
- package/public/file-icons/bicep.svg +1 -0
- package/public/file-icons/blender.svg +1 -0
- package/public/file-icons/bun.svg +1 -0
- package/public/file-icons/c.svg +1 -0
- package/public/file-icons/certificate.svg +1 -0
- package/public/file-icons/changelog.svg +1 -0
- package/public/file-icons/clojure.svg +1 -0
- package/public/file-icons/cmake.svg +1 -0
- package/public/file-icons/codeowners.svg +1 -0
- package/public/file-icons/commitlint.svg +1 -0
- package/public/file-icons/conduct.svg +1 -0
- package/public/file-icons/console.svg +1 -0
- package/public/file-icons/contributing.svg +1 -0
- package/public/file-icons/cpp.svg +1 -0
- package/public/file-icons/csharp.svg +1 -0
- package/public/file-icons/css.svg +1 -0
- package/public/file-icons/cursor.svg +1 -0
- package/public/file-icons/dart.svg +1 -0
- package/public/file-icons/database.svg +1 -0
- package/public/file-icons/deno.svg +1 -0
- package/public/file-icons/diff.svg +1 -0
- package/public/file-icons/docker.svg +1 -0
- package/public/file-icons/document.svg +1 -0
- package/public/file-icons/editorconfig.svg +1 -0
- package/public/file-icons/ejs.svg +1 -0
- package/public/file-icons/elixir.svg +1 -0
- package/public/file-icons/elm.svg +1 -0
- package/public/file-icons/email.svg +1 -0
- package/public/file-icons/erlang.svg +1 -0
- package/public/file-icons/eslint.svg +1 -0
- package/public/file-icons/favicon.svg +1 -0
- package/public/file-icons/file.svg +1 -0
- package/public/file-icons/folder-admin-open.svg +1 -0
- package/public/file-icons/folder-admin.svg +1 -0
- package/public/file-icons/folder-android-open.svg +1 -0
- package/public/file-icons/folder-android.svg +1 -0
- package/public/file-icons/folder-api-open.svg +1 -0
- package/public/file-icons/folder-api.svg +1 -0
- package/public/file-icons/folder-app-open.svg +1 -0
- package/public/file-icons/folder-app.svg +1 -0
- package/public/file-icons/folder-archive-open.svg +1 -0
- package/public/file-icons/folder-archive.svg +1 -0
- package/public/file-icons/folder-atom-open.svg +1 -0
- package/public/file-icons/folder-atom.svg +1 -0
- package/public/file-icons/folder-audio-open.svg +1 -0
- package/public/file-icons/folder-audio.svg +1 -0
- package/public/file-icons/folder-aws-open.svg +1 -0
- package/public/file-icons/folder-aws.svg +1 -0
- package/public/file-icons/folder-backup-open.svg +1 -0
- package/public/file-icons/folder-backup.svg +1 -0
- package/public/file-icons/folder-benchmark-open.svg +1 -0
- package/public/file-icons/folder-benchmark.svg +1 -0
- package/public/file-icons/folder-cart-open.svg +1 -0
- package/public/file-icons/folder-cart.svg +1 -0
- package/public/file-icons/folder-ci-open.svg +1 -0
- package/public/file-icons/folder-ci.svg +1 -0
- package/public/file-icons/folder-circleci-open.svg +1 -0
- package/public/file-icons/folder-circleci.svg +1 -0
- package/public/file-icons/folder-class-open.svg +1 -0
- package/public/file-icons/folder-class.svg +1 -0
- package/public/file-icons/folder-client-open.svg +1 -0
- package/public/file-icons/folder-client.svg +1 -0
- package/public/file-icons/folder-command-open.svg +1 -0
- package/public/file-icons/folder-command.svg +1 -0
- package/public/file-icons/folder-components-open.svg +1 -0
- package/public/file-icons/folder-components.svg +1 -0
- package/public/file-icons/folder-config-open.svg +1 -0
- package/public/file-icons/folder-config.svg +1 -0
- package/public/file-icons/folder-console-open.svg +1 -0
- package/public/file-icons/folder-console.svg +1 -0
- package/public/file-icons/folder-content-open.svg +1 -0
- package/public/file-icons/folder-content.svg +1 -0
- package/public/file-icons/folder-context-open.svg +1 -0
- package/public/file-icons/folder-context.svg +1 -0
- package/public/file-icons/folder-contract-open.svg +1 -0
- package/public/file-icons/folder-contract.svg +1 -0
- package/public/file-icons/folder-controller-open.svg +1 -0
- package/public/file-icons/folder-controller.svg +1 -0
- package/public/file-icons/folder-core-open.svg +1 -0
- package/public/file-icons/folder-core.svg +1 -0
- package/public/file-icons/folder-coverage-open.svg +1 -0
- package/public/file-icons/folder-coverage.svg +1 -0
- package/public/file-icons/folder-css-open.svg +1 -0
- package/public/file-icons/folder-css.svg +1 -0
- package/public/file-icons/folder-database-open.svg +1 -0
- package/public/file-icons/folder-database.svg +1 -0
- package/public/file-icons/folder-debug-open.svg +1 -0
- package/public/file-icons/folder-debug.svg +1 -0
- package/public/file-icons/folder-deprecated-open.svg +1 -0
- package/public/file-icons/folder-deprecated.svg +1 -0
- package/public/file-icons/folder-desktop-open.svg +1 -0
- package/public/file-icons/folder-desktop.svg +1 -0
- package/public/file-icons/folder-dist-open.svg +1 -0
- package/public/file-icons/folder-dist.svg +1 -0
- package/public/file-icons/folder-docker-open.svg +1 -0
- package/public/file-icons/folder-docker.svg +1 -0
- package/public/file-icons/folder-docs-open.svg +1 -0
- package/public/file-icons/folder-docs.svg +1 -0
- package/public/file-icons/folder-element-open.svg +1 -0
- package/public/file-icons/folder-element.svg +1 -0
- package/public/file-icons/folder-environment-open.svg +1 -0
- package/public/file-icons/folder-environment.svg +1 -0
- package/public/file-icons/folder-event-open.svg +1 -0
- package/public/file-icons/folder-event.svg +1 -0
- package/public/file-icons/folder-examples-open.svg +1 -0
- package/public/file-icons/folder-examples.svg +1 -0
- package/public/file-icons/folder-features-open.svg +1 -0
- package/public/file-icons/folder-features.svg +1 -0
- package/public/file-icons/folder-font-open.svg +1 -0
- package/public/file-icons/folder-font.svg +1 -0
- package/public/file-icons/folder-functions-open.svg +1 -0
- package/public/file-icons/folder-functions.svg +1 -0
- package/public/file-icons/folder-generator-open.svg +1 -0
- package/public/file-icons/folder-generator.svg +1 -0
- package/public/file-icons/folder-git-open.svg +1 -0
- package/public/file-icons/folder-git.svg +1 -0
- package/public/file-icons/folder-github-open.svg +1 -0
- package/public/file-icons/folder-github.svg +1 -0
- package/public/file-icons/folder-gitlab-open.svg +1 -0
- package/public/file-icons/folder-gitlab.svg +1 -0
- package/public/file-icons/folder-graphql-open.svg +1 -0
- package/public/file-icons/folder-graphql.svg +1 -0
- package/public/file-icons/folder-helper-open.svg +1 -0
- package/public/file-icons/folder-helper.svg +1 -0
- package/public/file-icons/folder-hook-open.svg +1 -0
- package/public/file-icons/folder-hook.svg +1 -0
- package/public/file-icons/folder-husky-open.svg +1 -0
- package/public/file-icons/folder-husky.svg +1 -0
- package/public/file-icons/folder-i18n-open.svg +1 -0
- package/public/file-icons/folder-i18n.svg +1 -0
- package/public/file-icons/folder-images-open.svg +1 -0
- package/public/file-icons/folder-images.svg +1 -0
- package/public/file-icons/folder-include-open.svg +1 -0
- package/public/file-icons/folder-include.svg +1 -0
- package/public/file-icons/folder-intellij-open.svg +1 -0
- package/public/file-icons/folder-intellij.svg +1 -0
- package/public/file-icons/folder-interface-open.svg +1 -0
- package/public/file-icons/folder-interface.svg +1 -0
- package/public/file-icons/folder-ios-open.svg +1 -0
- package/public/file-icons/folder-ios.svg +1 -0
- package/public/file-icons/folder-java-open.svg +1 -0
- package/public/file-icons/folder-java.svg +1 -0
- package/public/file-icons/folder-job-open.svg +1 -0
- package/public/file-icons/folder-job.svg +1 -0
- package/public/file-icons/folder-jupyter-open.svg +1 -0
- package/public/file-icons/folder-jupyter.svg +1 -0
- package/public/file-icons/folder-keys-open.svg +1 -0
- package/public/file-icons/folder-keys.svg +1 -0
- package/public/file-icons/folder-kubernetes-open.svg +1 -0
- package/public/file-icons/folder-kubernetes.svg +1 -0
- package/public/file-icons/folder-layout-open.svg +1 -0
- package/public/file-icons/folder-layout.svg +1 -0
- package/public/file-icons/folder-less-open.svg +1 -0
- package/public/file-icons/folder-less.svg +1 -0
- package/public/file-icons/folder-lib-open.svg +1 -0
- package/public/file-icons/folder-lib.svg +1 -0
- package/public/file-icons/folder-log-open.svg +1 -0
- package/public/file-icons/folder-log.svg +1 -0
- package/public/file-icons/folder-messages-open.svg +1 -0
- package/public/file-icons/folder-messages.svg +1 -0
- package/public/file-icons/folder-meta-open.svg +1 -0
- package/public/file-icons/folder-meta.svg +1 -0
- package/public/file-icons/folder-middleware-open.svg +1 -0
- package/public/file-icons/folder-middleware.svg +1 -0
- package/public/file-icons/folder-migrations-open.svg +1 -0
- package/public/file-icons/folder-migrations.svg +1 -0
- package/public/file-icons/folder-mobile-open.svg +1 -0
- package/public/file-icons/folder-mobile.svg +1 -0
- package/public/file-icons/folder-mock-open.svg +1 -0
- package/public/file-icons/folder-mock.svg +1 -0
- package/public/file-icons/folder-molecule-open.svg +1 -0
- package/public/file-icons/folder-molecule.svg +1 -0
- package/public/file-icons/folder-next-open.svg +1 -0
- package/public/file-icons/folder-next.svg +1 -0
- package/public/file-icons/folder-node-open.svg +1 -0
- package/public/file-icons/folder-node.svg +1 -0
- package/public/file-icons/folder-nuxt-open.svg +1 -0
- package/public/file-icons/folder-nuxt.svg +1 -0
- package/public/file-icons/folder-open.svg +1 -0
- package/public/file-icons/folder-organism-open.svg +1 -0
- package/public/file-icons/folder-organism.svg +1 -0
- package/public/file-icons/folder-packages-open.svg +1 -0
- package/public/file-icons/folder-packages.svg +1 -0
- package/public/file-icons/folder-plugin-open.svg +1 -0
- package/public/file-icons/folder-plugin.svg +1 -0
- package/public/file-icons/folder-prisma-open.svg +1 -0
- package/public/file-icons/folder-prisma.svg +1 -0
- package/public/file-icons/folder-prompts-open.svg +1 -0
- package/public/file-icons/folder-prompts.svg +1 -0
- package/public/file-icons/folder-proto-open.svg +1 -0
- package/public/file-icons/folder-proto.svg +1 -0
- package/public/file-icons/folder-public-open.svg +1 -0
- package/public/file-icons/folder-public.svg +1 -0
- package/public/file-icons/folder-python-open.svg +1 -0
- package/public/file-icons/folder-python.svg +1 -0
- package/public/file-icons/folder-queue-open.svg +1 -0
- package/public/file-icons/folder-queue.svg +1 -0
- package/public/file-icons/folder-resource-open.svg +1 -0
- package/public/file-icons/folder-resource.svg +1 -0
- package/public/file-icons/folder-review-open.svg +1 -0
- package/public/file-icons/folder-review.svg +1 -0
- package/public/file-icons/folder-robot-open.svg +1 -0
- package/public/file-icons/folder-robot.svg +1 -0
- package/public/file-icons/folder-routes-open.svg +1 -0
- package/public/file-icons/folder-routes.svg +1 -0
- package/public/file-icons/folder-rust-open.svg +1 -0
- package/public/file-icons/folder-rust.svg +1 -0
- package/public/file-icons/folder-sass-open.svg +1 -0
- package/public/file-icons/folder-sass.svg +1 -0
- package/public/file-icons/folder-scripts-open.svg +1 -0
- package/public/file-icons/folder-scripts.svg +1 -0
- package/public/file-icons/folder-secure-open.svg +1 -0
- package/public/file-icons/folder-secure.svg +1 -0
- package/public/file-icons/folder-seeders-open.svg +1 -0
- package/public/file-icons/folder-seeders.svg +1 -0
- package/public/file-icons/folder-server-open.svg +1 -0
- package/public/file-icons/folder-server.svg +1 -0
- package/public/file-icons/folder-shared-open.svg +1 -0
- package/public/file-icons/folder-shared.svg +1 -0
- package/public/file-icons/folder-skills-open.svg +1 -0
- package/public/file-icons/folder-skills.svg +1 -0
- package/public/file-icons/folder-src-open.svg +1 -0
- package/public/file-icons/folder-src.svg +1 -0
- package/public/file-icons/folder-store-open.svg +1 -0
- package/public/file-icons/folder-store.svg +1 -0
- package/public/file-icons/folder-storybook-open.svg +1 -0
- package/public/file-icons/folder-storybook.svg +1 -0
- package/public/file-icons/folder-supabase-open.svg +1 -0
- package/public/file-icons/folder-supabase.svg +1 -0
- package/public/file-icons/folder-svelte-open.svg +1 -0
- package/public/file-icons/folder-svelte.svg +1 -0
- package/public/file-icons/folder-target-open.svg +1 -0
- package/public/file-icons/folder-target.svg +1 -0
- package/public/file-icons/folder-tasks-open.svg +1 -0
- package/public/file-icons/folder-tasks.svg +1 -0
- package/public/file-icons/folder-temp-open.svg +1 -0
- package/public/file-icons/folder-temp.svg +1 -0
- package/public/file-icons/folder-template-open.svg +1 -0
- package/public/file-icons/folder-template.svg +1 -0
- package/public/file-icons/folder-terraform-open.svg +1 -0
- package/public/file-icons/folder-terraform.svg +1 -0
- package/public/file-icons/folder-test-open.svg +1 -0
- package/public/file-icons/folder-test.svg +1 -0
- package/public/file-icons/folder-theme-open.svg +1 -0
- package/public/file-icons/folder-theme.svg +1 -0
- package/public/file-icons/folder-tools-open.svg +1 -0
- package/public/file-icons/folder-tools.svg +1 -0
- package/public/file-icons/folder-turborepo-open.svg +1 -0
- package/public/file-icons/folder-turborepo.svg +1 -0
- package/public/file-icons/folder-typescript-open.svg +1 -0
- package/public/file-icons/folder-typescript.svg +1 -0
- package/public/file-icons/folder-ui-open.svg +1 -0
- package/public/file-icons/folder-ui.svg +1 -0
- package/public/file-icons/folder-utils-open.svg +1 -0
- package/public/file-icons/folder-utils.svg +1 -0
- package/public/file-icons/folder-video-open.svg +1 -0
- package/public/file-icons/folder-video.svg +1 -0
- package/public/file-icons/folder-views-open.svg +1 -0
- package/public/file-icons/folder-views.svg +1 -0
- package/public/file-icons/folder-vscode-open.svg +1 -0
- package/public/file-icons/folder-vscode.svg +1 -0
- package/public/file-icons/folder.svg +1 -0
- package/public/file-icons/font.svg +1 -0
- package/public/file-icons/fsharp.svg +1 -0
- package/public/file-icons/gemfile.svg +1 -0
- package/public/file-icons/git.svg +1 -0
- package/public/file-icons/go-mod.svg +1 -0
- package/public/file-icons/go.svg +1 -0
- package/public/file-icons/gradle.svg +1 -0
- package/public/file-icons/graphql.svg +1 -0
- package/public/file-icons/groovy.svg +1 -0
- package/public/file-icons/h.svg +1 -0
- package/public/file-icons/handlebars.svg +1 -0
- package/public/file-icons/haskell.svg +1 -0
- package/public/file-icons/hcl.svg +1 -0
- package/public/file-icons/heroku.svg +1 -0
- package/public/file-icons/hpp.svg +1 -0
- package/public/file-icons/html.svg +1 -0
- package/public/file-icons/husky.svg +1 -0
- package/public/file-icons/i18n.svg +1 -0
- package/public/file-icons/image.svg +1 -0
- package/public/file-icons/java.svg +1 -0
- package/public/file-icons/javascript.svg +1 -0
- package/public/file-icons/jenkins.svg +1 -0
- package/public/file-icons/jest.svg +1 -0
- package/public/file-icons/jsconfig.svg +1 -0
- package/public/file-icons/json.svg +1 -0
- package/public/file-icons/julia.svg +1 -0
- package/public/file-icons/jupyter.svg +1 -0
- package/public/file-icons/just.svg +1 -0
- package/public/file-icons/key.svg +1 -0
- package/public/file-icons/kotlin.svg +1 -0
- package/public/file-icons/lerna.svg +1 -0
- package/public/file-icons/less.svg +1 -0
- package/public/file-icons/license.svg +1 -0
- package/public/file-icons/lintstaged.svg +1 -0
- package/public/file-icons/liquid.svg +1 -0
- package/public/file-icons/lock.svg +1 -0
- package/public/file-icons/log.svg +1 -0
- package/public/file-icons/lua.svg +1 -0
- package/public/file-icons/makefile.svg +1 -0
- package/public/file-icons/markdown.svg +1 -0
- package/public/file-icons/maven.svg +1 -0
- package/public/file-icons/mdx.svg +1 -0
- package/public/file-icons/netlify.svg +1 -0
- package/public/file-icons/next.svg +1 -0
- package/public/file-icons/nim.svg +1 -0
- package/public/file-icons/nix.svg +1 -0
- package/public/file-icons/nodejs.svg +1 -0
- package/public/file-icons/nodemon.svg +1 -0
- package/public/file-icons/npm.svg +1 -0
- package/public/file-icons/nx.svg +1 -0
- package/public/file-icons/objective-c.svg +1 -0
- package/public/file-icons/objective-cpp.svg +1 -0
- package/public/file-icons/ocaml.svg +1 -0
- package/public/file-icons/pdf.svg +1 -0
- package/public/file-icons/php.svg +1 -0
- package/public/file-icons/pm2-ecosystem.svg +1 -0
- package/public/file-icons/pnpm.svg +1 -0
- package/public/file-icons/poetry.svg +1 -0
- package/public/file-icons/postcss.svg +1 -0
- package/public/file-icons/powerpoint.svg +1 -0
- package/public/file-icons/powershell.svg +1 -0
- package/public/file-icons/prettier.svg +1 -0
- package/public/file-icons/prisma.svg +1 -0
- package/public/file-icons/prolog.svg +1 -0
- package/public/file-icons/proto.svg +1 -0
- package/public/file-icons/pug.svg +1 -0
- package/public/file-icons/python-misc.svg +1 -0
- package/public/file-icons/python.svg +1 -0
- package/public/file-icons/r.svg +1 -0
- package/public/file-icons/razor.svg +1 -0
- package/public/file-icons/react.svg +1 -0
- package/public/file-icons/react_ts.svg +1 -0
- package/public/file-icons/readme.svg +1 -0
- package/public/file-icons/renovate.svg +1 -0
- package/public/file-icons/robots.svg +1 -0
- package/public/file-icons/rollup.svg +1 -0
- package/public/file-icons/ruby.svg +1 -0
- package/public/file-icons/rust.svg +1 -0
- package/public/file-icons/sass.svg +1 -0
- package/public/file-icons/scala.svg +1 -0
- package/public/file-icons/semantic-release.svg +1 -0
- package/public/file-icons/settings.svg +1 -0
- package/public/file-icons/shader.svg +1 -0
- package/public/file-icons/sml.svg +1 -0
- package/public/file-icons/solidity.svg +1 -0
- package/public/file-icons/stylus.svg +1 -0
- package/public/file-icons/svelte.svg +1 -0
- package/public/file-icons/svg.svg +1 -0
- package/public/file-icons/swift.svg +1 -0
- package/public/file-icons/table.svg +1 -0
- package/public/file-icons/tailwindcss.svg +1 -0
- package/public/file-icons/taskfile.svg +1 -0
- package/public/file-icons/terraform.svg +1 -0
- package/public/file-icons/test-js.svg +1 -0
- package/public/file-icons/test-jsx.svg +1 -0
- package/public/file-icons/test-ts.svg +1 -0
- package/public/file-icons/tex.svg +1 -0
- package/public/file-icons/toml.svg +1 -0
- package/public/file-icons/travis.svg +1 -0
- package/public/file-icons/tsconfig.svg +1 -0
- package/public/file-icons/tune.svg +1 -0
- package/public/file-icons/turborepo.svg +1 -0
- package/public/file-icons/typescript-def.svg +1 -0
- package/public/file-icons/typescript.svg +1 -0
- package/public/file-icons/unity.svg +1 -0
- package/public/file-icons/uv.svg +1 -0
- package/public/file-icons/vala.svg +1 -0
- package/public/file-icons/vercel.svg +1 -0
- package/public/file-icons/video.svg +1 -0
- package/public/file-icons/vim.svg +1 -0
- package/public/file-icons/vite.svg +1 -0
- package/public/file-icons/vitest.svg +1 -0
- package/public/file-icons/vlang.svg +1 -0
- package/public/file-icons/vue.svg +1 -0
- package/public/file-icons/webassembly.svg +1 -0
- package/public/file-icons/webpack.svg +1 -0
- package/public/file-icons/word.svg +1 -0
- package/public/file-icons/xml.svg +1 -0
- package/public/file-icons/yaml.svg +1 -0
- package/public/file-icons/yarn.svg +1 -0
- package/public/file-icons/zig.svg +1 -0
- package/public/file-icons/zip.svg +1 -0
- package/public/provider-icons/antgroup-color.svg +1 -0
- package/public/provider-icons/anthropic.svg +1 -0
- package/public/provider-icons/azure-color.svg +1 -0
- package/public/provider-icons/baseten.svg +1 -0
- package/public/provider-icons/bedrock-color.svg +1 -0
- package/public/provider-icons/cerebras-color.svg +1 -0
- package/public/provider-icons/cloudflare-color.svg +1 -0
- package/public/provider-icons/deepseek-color.svg +1 -0
- package/public/provider-icons/fireworks-color.svg +1 -0
- package/public/provider-icons/githubcopilot.svg +1 -0
- package/public/provider-icons/google-color.svg +1 -0
- package/public/provider-icons/googlecloud-color.svg +1 -0
- package/public/provider-icons/groq.svg +1 -0
- package/public/provider-icons/huggingface-color.svg +1 -0
- package/public/provider-icons/kimi-color.svg +1 -0
- package/public/provider-icons/minimax-color.svg +1 -0
- package/public/provider-icons/mistral-color.svg +1 -0
- package/public/provider-icons/moonshot.svg +1 -0
- package/public/provider-icons/nvidia-color.svg +1 -0
- package/public/provider-icons/openai.svg +1 -0
- package/public/provider-icons/opencode.svg +1 -0
- package/public/provider-icons/openrouter-color.svg +1 -0
- package/public/provider-icons/qwen-color.svg +1 -0
- package/public/provider-icons/together-color.svg +1 -0
- package/public/provider-icons/vercel.svg +1 -0
- package/public/provider-icons/xai.svg +1 -0
- package/public/provider-icons/xiaomimimo.svg +1 -0
- package/public/provider-icons/zai.svg +1 -0
- package/scripts/build-output.mjs +131 -0
- package/scripts/dev.mjs +18 -0
- package/scripts/entrypoint.mjs +8 -0
- package/scripts/install-build.mjs +134 -0
- package/scripts/launcher.mjs +249 -0
- package/scripts/pick-folder.ps1 +110 -0
- package/scripts/postinstall.mjs +12 -0
- package/scripts/process-runner.mjs +60 -0
- package/scripts/release.mjs +172 -0
- package/scripts/sync-file-icons.mjs +118 -0
- package/scripts/sync-provider-icons.mjs +41 -0
- package/src/app/api/agent/[id]/events/route.ts +81 -0
- package/src/app/api/agent/[id]/route.ts +24 -0
- package/src/app/api/agent/[id]/tree/route.ts +49 -0
- package/src/app/api/agent/new/route.ts +19 -0
- package/src/app/api/config/route.ts +22 -0
- package/src/app/api/files/route.ts +63 -0
- package/src/app/api/git/route.ts +32 -0
- package/src/app/api/growth/route.ts +50 -0
- package/src/app/api/health/route.ts +7 -0
- package/src/app/api/models/route.ts +129 -0
- package/src/app/api/pi-settings/route.ts +22 -0
- package/src/app/api/plugins/route.ts +79 -0
- package/src/app/api/security/route.ts +41 -0
- package/src/app/api/sessions/[id]/export/route.ts +25 -0
- package/src/app/api/sessions/[id]/route.ts +37 -0
- package/src/app/api/sessions/route.ts +23 -0
- package/src/app/api/skills/route.ts +39 -0
- package/src/app/api/update/route.ts +33 -0
- package/src/app/api/version/route.ts +8 -0
- package/src/app/api/web-auth/route.ts +80 -0
- package/src/app/api/workspaces/route.ts +78 -0
- package/src/app/globals.css +2039 -0
- package/src/app/icon.svg +21 -0
- package/src/app/layout.tsx +29 -0
- package/src/app/login/page.tsx +111 -0
- package/src/app/page.tsx +10 -0
- package/src/components/AppShell.tsx +1171 -0
- package/src/components/ChatInput.tsx +729 -0
- package/src/components/ChatWindow.tsx +1320 -0
- package/src/components/ContextMeter.tsx +131 -0
- package/src/components/DiffView.tsx +139 -0
- package/src/components/ExtensionUI.tsx +181 -0
- package/src/components/FileViewer.tsx +555 -0
- package/src/components/FullDiff.tsx +220 -0
- package/src/components/GitPanel.tsx +357 -0
- package/src/components/GrowthTree.tsx +317 -0
- package/src/components/ModelSelector.tsx +286 -0
- package/src/components/OutlineRail.tsx +166 -0
- package/src/components/PiMark.tsx +79 -0
- package/src/components/ProjectPanel.tsx +309 -0
- package/src/components/ProviderBrand.tsx +28 -0
- package/src/components/ProviderSetupModal.module.css +560 -0
- package/src/components/ProviderSetupModal.tsx +559 -0
- package/src/components/SessionSidebar.tsx +1066 -0
- package/src/components/SettingsPanel.tsx +2216 -0
- package/src/components/TrajectoryAnalyzer.module.css +225 -0
- package/src/components/TrajectoryView.tsx +289 -0
- package/src/components/icons.tsx +443 -0
- package/src/hooks/useFileViewer.ts +58 -0
- package/src/hooks/useGrowth.ts +635 -0
- package/src/hooks/usePiWeb.ts +900 -0
- package/src/i18n.tsx +1043 -0
- package/src/lib/agent-manager.ts +1348 -0
- package/src/lib/app-root.ts +4 -0
- package/src/lib/auth.ts +51 -0
- package/src/lib/command-validation.ts +116 -0
- package/src/lib/enter-behavior.ts +40 -0
- package/src/lib/extension-ui.ts +134 -0
- package/src/lib/file-icons.json +557 -0
- package/src/lib/file-icons.ts +39 -0
- package/src/lib/files-service.ts +280 -0
- package/src/lib/git-service.ts +255 -0
- package/src/lib/growth-rounds.ts +84 -0
- package/src/lib/growth-service.ts +586 -0
- package/src/lib/growth-tracker.ts +328 -0
- package/src/lib/growth-tree.ts +245 -0
- package/src/lib/growth-turns.ts +23 -0
- package/src/lib/highlight.ts +59 -0
- package/src/lib/model-draft.ts +103 -0
- package/src/lib/models-service.ts +852 -0
- package/src/lib/path-security.ts +101 -0
- package/src/lib/pi-settings.ts +115 -0
- package/src/lib/pi.ts +367 -0
- package/src/lib/plugins-service.ts +312 -0
- package/src/lib/process-format.ts +261 -0
- package/src/lib/provider-display.ts +57 -0
- package/src/lib/security-service.ts +52 -0
- package/src/lib/semver.ts +39 -0
- package/src/lib/session-reader.ts +204 -0
- package/src/lib/settings-write-lock.ts +45 -0
- package/src/lib/skills-service.ts +97 -0
- package/src/lib/text-sanitize.ts +20 -0
- package/src/lib/theme.ts +137 -0
- package/src/lib/trajectory.ts +294 -0
- package/src/lib/types.ts +300 -0
- package/src/lib/update-service.ts +129 -0
- package/src/lib/version.ts +6 -0
- package/src/lib/web-auth-shared.ts +35 -0
- package/src/lib/web-auth.ts +53 -0
- package/src/lib/workspace-store.ts +261 -0
- package/src/proxy.ts +53 -0
- package/tsconfig.json +49 -0
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const BASIC_PREFIX = "Basic ";
|
|
2
|
+
|
|
3
|
+
/** 恒定时间字符串比较(长度不同也走完全程,不早退) */
|
|
4
|
+
export function equalText(left: string, right: string): boolean {
|
|
5
|
+
const max = Math.max(left.length, right.length);
|
|
6
|
+
let mismatch = left.length ^ right.length;
|
|
7
|
+
for (let i = 0; i < max; i += 1) {
|
|
8
|
+
mismatch |= (left.charCodeAt(i) || 0) ^ (right.charCodeAt(i) || 0);
|
|
9
|
+
}
|
|
10
|
+
return mismatch === 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function validBasicAuthorization(header: string | null, password: string): boolean {
|
|
14
|
+
if (!header?.startsWith(BASIC_PREFIX)) return false;
|
|
15
|
+
try {
|
|
16
|
+
const decoded = Buffer.from(header.slice(BASIC_PREFIX.length), "base64").toString("utf8");
|
|
17
|
+
const separator = decoded.indexOf(":");
|
|
18
|
+
if (separator < 0) return false;
|
|
19
|
+
return equalText(decoded.slice(0, separator), "pi") && equalText(decoded.slice(separator + 1), password);
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isSafeOrigin(request: Request): boolean {
|
|
26
|
+
const origin = request.headers.get("origin");
|
|
27
|
+
if (!origin) return true;
|
|
28
|
+
try {
|
|
29
|
+
const originUrl = new URL(origin);
|
|
30
|
+
const expectedHost = request.headers.get("host") || new URL(request.url).host;
|
|
31
|
+
return originUrl.host.toLowerCase() === expectedHost.toLowerCase();
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isSafeHost(request: Request, passwordConfigured: boolean): boolean {
|
|
38
|
+
if (passwordConfigured) return true;
|
|
39
|
+
try {
|
|
40
|
+
const host = request.headers.get("host") || new URL(request.url).host;
|
|
41
|
+
const parsed = new URL(`http://${host}`);
|
|
42
|
+
return !parsed.username && !parsed.password && parsed.host.toLowerCase() === host.toLowerCase() && isLoopbackHostname(parsed.hostname);
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isLoopbackHostname(hostname: string): boolean {
|
|
49
|
+
const host = hostname.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
50
|
+
return host === "localhost" || host === "::1" || host === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/.test(host);
|
|
51
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { AgentCommand, ImageAttachment, ToolPreset } from "./types";
|
|
2
|
+
|
|
3
|
+
const COMMANDS = new Set<AgentCommand["cmd"]>([
|
|
4
|
+
"prepare",
|
|
5
|
+
"prompt",
|
|
6
|
+
"steer",
|
|
7
|
+
"followUp",
|
|
8
|
+
"abort",
|
|
9
|
+
"compact",
|
|
10
|
+
"setModel",
|
|
11
|
+
"setThinkingLevel",
|
|
12
|
+
"setToolPreset",
|
|
13
|
+
"setActiveTools",
|
|
14
|
+
"rename",
|
|
15
|
+
"fork",
|
|
16
|
+
"cycleModel",
|
|
17
|
+
"navigate",
|
|
18
|
+
"clearQueue",
|
|
19
|
+
"extensionUiResponse",
|
|
20
|
+
"reload",
|
|
21
|
+
]);
|
|
22
|
+
const TOOL_PRESETS = new Set<ToolPreset>(["readonly", "standard", "full"]);
|
|
23
|
+
const STREAMING_BEHAVIORS = new Set(["steer", "followUp"]);
|
|
24
|
+
const IMAGE_TYPES = new Set(["image/jpeg", "image/png", "image/webp", "image/gif"]);
|
|
25
|
+
const MAX_TEXT = 1_000_000;
|
|
26
|
+
const MAX_IMAGES = 20;
|
|
27
|
+
const MAX_IMAGE_BASE64 = 28_000_000; // dsh: 单图 20MB
|
|
28
|
+
const MAX_IMAGES_BASE64 = 268_000_000; // dsh: 单条消息图片总量 200MB
|
|
29
|
+
|
|
30
|
+
export type CommandParseResult = { ok: true; command: AgentCommand } | { ok: false; error: string };
|
|
31
|
+
|
|
32
|
+
function optionalText(value: unknown, field: string): string | undefined {
|
|
33
|
+
if (value === undefined) return undefined;
|
|
34
|
+
if (typeof value !== "string") throw new Error(`${field} must be a string`);
|
|
35
|
+
if (value.length > MAX_TEXT) throw new Error(`${field} is too long`);
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseImages(value: unknown): ImageAttachment[] | undefined {
|
|
40
|
+
if (value === undefined) return undefined;
|
|
41
|
+
if (!Array.isArray(value) || value.length > MAX_IMAGES) throw new Error(`images must contain at most ${MAX_IMAGES} items`);
|
|
42
|
+
let total = 0;
|
|
43
|
+
return value.map((raw) => {
|
|
44
|
+
if (!raw || typeof raw !== "object") throw new Error("invalid image");
|
|
45
|
+
const image = raw as Record<string, unknown>;
|
|
46
|
+
if (image.type !== "image" || typeof image.data !== "string" || typeof image.mimeType !== "string") {
|
|
47
|
+
throw new Error("invalid image");
|
|
48
|
+
}
|
|
49
|
+
if (!IMAGE_TYPES.has(image.mimeType)) throw new Error(`unsupported image type ${image.mimeType}`);
|
|
50
|
+
if (image.data.length === 0 || image.data.length > MAX_IMAGE_BASE64 || !/^[A-Za-z0-9+/]*={0,2}$/.test(image.data)) {
|
|
51
|
+
throw new Error("invalid or oversized image data");
|
|
52
|
+
}
|
|
53
|
+
total += image.data.length;
|
|
54
|
+
if (total > MAX_IMAGES_BASE64) throw new Error("image attachments are too large");
|
|
55
|
+
return { type: "image", data: image.data, mimeType: image.mimeType };
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function parseAgentCommand(value: unknown): CommandParseResult {
|
|
60
|
+
try {
|
|
61
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("command must be an object");
|
|
62
|
+
const raw = value as Record<string, unknown>;
|
|
63
|
+
if (typeof raw.cmd !== "string" || !COMMANDS.has(raw.cmd as AgentCommand["cmd"])) throw new Error("unknown command");
|
|
64
|
+
|
|
65
|
+
const command: AgentCommand = {
|
|
66
|
+
cmd: raw.cmd as AgentCommand["cmd"],
|
|
67
|
+
text: optionalText(raw.text, "text"),
|
|
68
|
+
instructions: optionalText(raw.instructions, "instructions"),
|
|
69
|
+
provider: optionalText(raw.provider, "provider"),
|
|
70
|
+
modelId: optionalText(raw.modelId, "modelId"),
|
|
71
|
+
level: optionalText(raw.level, "level"),
|
|
72
|
+
entryId: optionalText(raw.entryId, "entryId"),
|
|
73
|
+
images: parseImages(raw.images),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (raw.preset !== undefined) {
|
|
77
|
+
if (typeof raw.preset !== "string" || !TOOL_PRESETS.has(raw.preset as ToolPreset)) throw new Error("invalid tool preset");
|
|
78
|
+
command.preset = raw.preset as ToolPreset;
|
|
79
|
+
}
|
|
80
|
+
if (raw.behavior !== undefined) {
|
|
81
|
+
if (typeof raw.behavior !== "string" || !STREAMING_BEHAVIORS.has(raw.behavior)) throw new Error("invalid streaming behavior");
|
|
82
|
+
command.behavior = raw.behavior as "steer" | "followUp";
|
|
83
|
+
}
|
|
84
|
+
if (raw.direction !== undefined) {
|
|
85
|
+
if (raw.direction !== "forward" && raw.direction !== "backward") throw new Error("invalid cycle direction");
|
|
86
|
+
command.direction = raw.direction;
|
|
87
|
+
}
|
|
88
|
+
if (raw.names !== undefined) {
|
|
89
|
+
// setActiveTools 的目标工具名列表:数量与长度上限防滥用(未知名字由 agent-manager 求交集丢弃)
|
|
90
|
+
if (!Array.isArray(raw.names) || raw.names.length === 0 || raw.names.length > 64 || raw.names.some((n) => typeof n !== "string" || !n || n.length > 100)) {
|
|
91
|
+
throw new Error("names must be a non-empty array of tool names");
|
|
92
|
+
}
|
|
93
|
+
command.names = raw.names as string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (raw.requestId !== undefined) command.requestId = optionalText(raw.requestId, "requestId");
|
|
97
|
+
if (raw.value !== undefined) command.value = optionalText(raw.value, "value");
|
|
98
|
+
if (raw.confirmed !== undefined) {
|
|
99
|
+
if (typeof raw.confirmed !== "boolean") throw new Error("confirmed must be a boolean");
|
|
100
|
+
command.confirmed = raw.confirmed;
|
|
101
|
+
}
|
|
102
|
+
if (raw.cancelled !== undefined) {
|
|
103
|
+
if (typeof raw.cancelled !== "boolean") throw new Error("cancelled must be a boolean");
|
|
104
|
+
command.cancelled = raw.cancelled;
|
|
105
|
+
}
|
|
106
|
+
if (command.cmd === "extensionUiResponse" && !command.requestId) throw new Error("requestId is required");
|
|
107
|
+
if (command.cmd === "setModel" && (!command.provider || !command.modelId)) throw new Error("provider and modelId are required");
|
|
108
|
+
if (command.cmd === "setThinkingLevel" && !command.level) throw new Error("level is required");
|
|
109
|
+
if (command.cmd === "setToolPreset" && !command.preset) throw new Error("preset is required");
|
|
110
|
+
if (command.cmd === "setActiveTools" && !command.names) throw new Error("names are required");
|
|
111
|
+
if (command.cmd === "navigate" && !command.entryId) throw new Error("entryId is required");
|
|
112
|
+
return { ok: true, command };
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return { ok: false, error: error instanceof Error ? error.message : "invalid command" };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 繁忙时 Enter 的发送方式:steer(插话,当前工具跑完就送达)/ queue(排队,本轮结束后发送)。
|
|
3
|
+
* 存 localStorage;用 useSyncExternalStore 让输入卡和设置面板同步(改设置立刻反映到提示文案)。
|
|
4
|
+
*/
|
|
5
|
+
import { useSyncExternalStore } from "react";
|
|
6
|
+
|
|
7
|
+
export type EnterBehavior = "steer" | "queue";
|
|
8
|
+
|
|
9
|
+
const KEY = "piweb.enterBehavior";
|
|
10
|
+
/** 默认插话:与 pi 终端的 Enter 一致,也是 Claude Code 排队消息「尽快送达」的行为 */
|
|
11
|
+
export const DEFAULT_ENTER_BEHAVIOR: EnterBehavior = "steer";
|
|
12
|
+
const listeners = new Set<() => void>();
|
|
13
|
+
|
|
14
|
+
export function getEnterBehavior(): EnterBehavior {
|
|
15
|
+
if (typeof window === "undefined") return DEFAULT_ENTER_BEHAVIOR;
|
|
16
|
+
const v = localStorage.getItem(KEY);
|
|
17
|
+
return v === "queue" || v === "steer" ? v : DEFAULT_ENTER_BEHAVIOR;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function setEnterBehavior(v: EnterBehavior): void {
|
|
21
|
+
localStorage.setItem(KEY, v);
|
|
22
|
+
for (const l of listeners) l();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function otherBehavior(v: EnterBehavior): EnterBehavior {
|
|
26
|
+
return v === "steer" ? "queue" : "steer";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function subscribe(l: () => void): () => void {
|
|
30
|
+
listeners.add(l);
|
|
31
|
+
window.addEventListener("storage", l);
|
|
32
|
+
return () => {
|
|
33
|
+
listeners.delete(l);
|
|
34
|
+
window.removeEventListener("storage", l);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useEnterBehavior(): EnterBehavior {
|
|
39
|
+
return useSyncExternalStore(subscribe, getEnterBehavior, () => DEFAULT_ENTER_BEHAVIOR);
|
|
40
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extension-ui:把 pi 扩展的界面请求(select / confirm / input / notify / setStatus)
|
|
3
|
+
* 桥接到浏览器——与 pi 自己的 RPC 模式(extension_ui_request / extension_ui_response)同一套语义。
|
|
4
|
+
* 没有页面在看时(无订阅者)select/input 返回 undefined、confirm 返回 false,与 pi 的 noOp 行为一致。
|
|
5
|
+
*/
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import type { WebEvent } from "./types";
|
|
8
|
+
|
|
9
|
+
type UiMethod = Extract<WebEvent, { type: "extension_ui" }>["method"];
|
|
10
|
+
type UiEvent = Extract<WebEvent, { type: "extension_ui" }>;
|
|
11
|
+
|
|
12
|
+
interface PendingUi {
|
|
13
|
+
request: UiEvent;
|
|
14
|
+
resolve: (response: { value?: string; confirmed?: boolean; cancelled?: boolean }) => void;
|
|
15
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
16
|
+
removeAbortListener?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ExtensionUiBridge {
|
|
20
|
+
/** 供 AgentSession.bindExtensions 的 uiContext(只实现 Web 能承接的部分,其余 no-op) */
|
|
21
|
+
uiContext: Record<string, unknown>;
|
|
22
|
+
/** 浏览器应答 */
|
|
23
|
+
respond(requestId: string, response: { value?: string; confirmed?: boolean; cancelled?: boolean }): boolean;
|
|
24
|
+
/** 当前仍待应答的请求,不含已答/取消/过期请求。 */
|
|
25
|
+
getPendingRequests(): UiEvent[];
|
|
26
|
+
/** 会话销毁:把挂起的对话框全部按取消结束 */
|
|
27
|
+
dispose(): void;
|
|
28
|
+
/** 扩展通过 setStatus 设的状态文本(页脚展示) */
|
|
29
|
+
statuses: Map<string, string>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
33
|
+
|
|
34
|
+
export function createExtensionUiBridge(opts: {
|
|
35
|
+
publish: (evt: WebEvent) => void;
|
|
36
|
+
hasViewers: () => boolean;
|
|
37
|
+
}): ExtensionUiBridge {
|
|
38
|
+
const pending = new Map<string, PendingUi>();
|
|
39
|
+
const statuses = new Map<string, string>();
|
|
40
|
+
let disposed = false;
|
|
41
|
+
|
|
42
|
+
const ask = <T,>(
|
|
43
|
+
request: Omit<UiEvent, "type" | "id" | "ts">,
|
|
44
|
+
dialogOpts: { signal?: AbortSignal; timeout?: number } | undefined,
|
|
45
|
+
fallback: T,
|
|
46
|
+
parse: (r: { value?: string; confirmed?: boolean; cancelled?: boolean }) => T,
|
|
47
|
+
): Promise<T> => {
|
|
48
|
+
// 没有浏览器在看:不能永远挂着扩展,按 pi 的 noOp 语义立即返回默认值
|
|
49
|
+
if (disposed || !opts.hasViewers() || dialogOpts?.signal?.aborted) return Promise.resolve(fallback);
|
|
50
|
+
const id = randomUUID();
|
|
51
|
+
return new Promise<T>((resolve) => {
|
|
52
|
+
const finish = (r: { value?: string; confirmed?: boolean; cancelled?: boolean } | null) => {
|
|
53
|
+
const entry = pending.get(id);
|
|
54
|
+
if (!entry) return;
|
|
55
|
+
pending.delete(id);
|
|
56
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
57
|
+
entry.removeAbortListener?.();
|
|
58
|
+
opts.publish({ type: "extension_ui_resolved", id, ts: Date.now() });
|
|
59
|
+
resolve(r ? parse(r) : fallback);
|
|
60
|
+
};
|
|
61
|
+
const event: UiEvent = { type: "extension_ui", id, ...request, timeout: dialogOpts?.timeout, ts: Date.now() };
|
|
62
|
+
const entry: PendingUi = { request: event, resolve: (r) => finish(r) };
|
|
63
|
+
const timeout = dialogOpts?.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
64
|
+
entry.timer = setTimeout(() => finish(null), timeout);
|
|
65
|
+
entry.timer.unref?.();
|
|
66
|
+
const onAbort = () => finish(null);
|
|
67
|
+
dialogOpts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
68
|
+
entry.removeAbortListener = () => dialogOpts?.signal?.removeEventListener("abort", onAbort);
|
|
69
|
+
pending.set(id, entry);
|
|
70
|
+
opts.publish(event);
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const uiContext: Record<string, unknown> = {
|
|
75
|
+
select: (title: string, options: string[], o?: { signal?: AbortSignal; timeout?: number }) =>
|
|
76
|
+
ask<string | undefined>({ method: "select", title, options }, o, undefined, (r) => (r.cancelled ? undefined : r.value)),
|
|
77
|
+
confirm: (title: string, message: string, o?: { signal?: AbortSignal; timeout?: number }) =>
|
|
78
|
+
ask<boolean>({ method: "confirm", title, message }, o, false, (r) => (r.cancelled ? false : r.confirmed === true)),
|
|
79
|
+
input: (title: string, placeholder?: string, o?: { signal?: AbortSignal; timeout?: number }) =>
|
|
80
|
+
ask<string | undefined>({ method: "input", title, placeholder }, o, undefined, (r) => (r.cancelled ? undefined : r.value)),
|
|
81
|
+
notify: (message: string, type?: "info" | "warning" | "error") => {
|
|
82
|
+
opts.publish({ type: "extension_ui", id: randomUUID(), method: "notify", message, notifyType: type ?? "info", ts: Date.now() });
|
|
83
|
+
},
|
|
84
|
+
setStatus: (key: string, text: string | undefined) => {
|
|
85
|
+
if (text === undefined) statuses.delete(key);
|
|
86
|
+
else statuses.set(key, text);
|
|
87
|
+
opts.publish({ type: "extension_ui", id: randomUUID(), method: "setStatus", statusKey: key, statusText: text, ts: Date.now() });
|
|
88
|
+
},
|
|
89
|
+
setWorkingMessage: (message?: string) => {
|
|
90
|
+
opts.publish({ type: "extension_ui", id: randomUUID(), method: "setWorkingMessage", message, ts: Date.now() });
|
|
91
|
+
},
|
|
92
|
+
// 终端专属能力:Web 无对应物,按 pi 的 noOp 处理
|
|
93
|
+
onTerminalInput: () => () => {},
|
|
94
|
+
setWorkingVisible: () => {},
|
|
95
|
+
setWorkingIndicator: () => {},
|
|
96
|
+
setHiddenThinkingLabel: () => {},
|
|
97
|
+
setWidget: () => {},
|
|
98
|
+
setFooter: () => {},
|
|
99
|
+
setHeader: () => {},
|
|
100
|
+
setTitle: () => {},
|
|
101
|
+
custom: async () => undefined,
|
|
102
|
+
pasteToEditor: () => {},
|
|
103
|
+
setEditorText: () => {},
|
|
104
|
+
getEditorText: () => "",
|
|
105
|
+
editor: async () => undefined,
|
|
106
|
+
addAutocompleteProvider: () => {},
|
|
107
|
+
setEditorComponent: () => {},
|
|
108
|
+
getEditorComponent: () => undefined,
|
|
109
|
+
getAllThemes: () => [],
|
|
110
|
+
getTheme: () => undefined,
|
|
111
|
+
setTheme: () => {},
|
|
112
|
+
getToolsExpanded: () => false,
|
|
113
|
+
setToolsExpanded: () => {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
uiContext,
|
|
118
|
+
statuses,
|
|
119
|
+
getPendingRequests: () => [...pending.values()].map(({ request }) => ({ ...request, options: request.options ? [...request.options] : undefined })),
|
|
120
|
+
respond(requestId, response) {
|
|
121
|
+
const entry = pending.get(requestId);
|
|
122
|
+
if (!entry) return false;
|
|
123
|
+
entry.resolve(response);
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
126
|
+
dispose() {
|
|
127
|
+
disposed = true;
|
|
128
|
+
for (const entry of pending.values()) entry.resolve({ cancelled: true });
|
|
129
|
+
pending.clear();
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type { UiMethod };
|