mirror of
https://github.com/penpot/penpot.git
synced 2026-05-30 04:08:08 +00:00
Merge remote-tracking branch 'origin/main' into staging
This commit is contained in:
commit
f6c76711f4
1
.gitignore
vendored
1
.gitignore
vendored
@ -89,3 +89,4 @@
|
||||
/.idea
|
||||
/.claude
|
||||
/.playwright-mcp
|
||||
/tools/__pycache__
|
||||
|
||||
@ -134,7 +134,11 @@
|
||||
- Fix incorrect error message when applying tokens while editing text [#9620](https://github.com/penpot/penpot/issues/9620) (PR: [#9708](https://github.com/penpot/penpot/pull/9708))
|
||||
|
||||
|
||||
## 2.15.4 (Unreleased)
|
||||
## 2.15.4
|
||||
|
||||
### :sparkles: New features & Enhancements
|
||||
|
||||
- Add rate limiting and concurrency safety for file snapshot operations [#9723](https://github.com/penpot/penpot/issues/9723) (PR: [#9722](https://github.com/penpot/penpot/pull/9722))
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
@ -143,6 +147,7 @@
|
||||
- Fix API doc endpoint returning HTML as text/plain [#9680](https://github.com/penpot/penpot/issues/9680) (PR: [#9681](https://github.com/penpot/penpot/pull/9681))
|
||||
- Fix unexpected error when opening the export dialog [#9721](https://github.com/penpot/penpot/issues/9721) (PR: [#9704](https://github.com/penpot/penpot/pull/9704))
|
||||
|
||||
|
||||
## 2.15.3
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
{:permits 40}
|
||||
|
||||
:root/by-profile
|
||||
{:permits 10}
|
||||
{:permits 10 :queue 30 :timeout 30000}
|
||||
|
||||
:file-thumbnail-ops/global
|
||||
{:permits 20}
|
||||
@ -27,4 +27,16 @@
|
||||
{:permits 2}
|
||||
|
||||
:submit-audit-events/by-profile
|
||||
{:permits 1 :queue 3}}
|
||||
{:permits 1 :queue 3}
|
||||
|
||||
:restore-file-snapshot/global
|
||||
{:permits 3}
|
||||
|
||||
:restore-file-snapshot/by-profile
|
||||
{:permits 1 :queue 2 :timeout 60000}
|
||||
|
||||
:create-file-snapshot/global
|
||||
{:permits 3}
|
||||
|
||||
:create-file-snapshot/by-profile
|
||||
{:permits 1 :queue 2 :timeout 60000}}
|
||||
|
||||
@ -27,7 +27,9 @@
|
||||
[next.jdbc.transaction])
|
||||
(:import
|
||||
com.zaxxer.hikari.HikariConfig
|
||||
com.zaxxer.hikari.HikariConfigMXBean
|
||||
com.zaxxer.hikari.HikariDataSource
|
||||
com.zaxxer.hikari.HikariPoolMXBean
|
||||
com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory
|
||||
io.whitfin.siphash.SipHasher
|
||||
io.whitfin.siphash.SipHasherContainer
|
||||
@ -67,9 +69,8 @@
|
||||
|
||||
(def defaults
|
||||
{::name :main
|
||||
::min-size 0
|
||||
::max-size 60
|
||||
::connection-timeout 10000
|
||||
::connection-timeout 30000
|
||||
::validation-timeout 10000
|
||||
::idle-timeout 120000 ; 2min
|
||||
::max-lifetime 1800000 ; 30m
|
||||
@ -82,7 +83,7 @@
|
||||
(defmethod ig/init-key ::pool
|
||||
[_ cfg]
|
||||
(let [{:keys [::uri ::read-only] :as cfg}
|
||||
(merge defaults cfg)]
|
||||
(merge defaults (d/without-nils cfg))]
|
||||
(when uri
|
||||
(l/info :hint "initialize connection pool"
|
||||
:name (d/name (::name cfg))
|
||||
@ -90,7 +91,8 @@
|
||||
:read-only read-only
|
||||
:credentials (and (contains? cfg ::username)
|
||||
(contains? cfg ::password))
|
||||
:min-size (::min-size cfg)
|
||||
:min-size (or (::min-size cfg)
|
||||
(::max-size cfg))
|
||||
:max-size (::max-size cfg))
|
||||
(create-pool cfg))))
|
||||
|
||||
@ -111,7 +113,9 @@
|
||||
[{:keys [::uri] :as cfg}]
|
||||
|
||||
;; (app.common.pprint/pprint cfg)
|
||||
(let [config (HikariConfig.)]
|
||||
(let [config (HikariConfig.)
|
||||
max-size (::max-size cfg)
|
||||
min-size (or (::min-size cfg) max-size)]
|
||||
(doto config
|
||||
(.setJdbcUrl (str "jdbc:" uri))
|
||||
(.setPoolName (d/name (::name cfg)))
|
||||
@ -121,8 +125,8 @@
|
||||
(.setValidationTimeout (::validation-timeout cfg))
|
||||
(.setIdleTimeout (::idle-timeout cfg))
|
||||
(.setMaxLifetime (::max-lifetime cfg))
|
||||
(.setMinimumIdle (::min-size cfg))
|
||||
(.setMaximumPoolSize (::max-size cfg))
|
||||
(.setMinimumIdle min-size)
|
||||
(.setMaximumPoolSize max-size)
|
||||
(.setConnectionInitSql initsql)
|
||||
(.setInitializationFailTimeout -1))
|
||||
|
||||
@ -180,6 +184,20 @@
|
||||
:code :invalid-connection
|
||||
:hint "invalid connection provided")))
|
||||
|
||||
(defn pool-stats
|
||||
"Given a HikariDataSource instance, returns a map with current pool
|
||||
statistics: active/idle connections, threads awaiting connection,
|
||||
total connections, maximum pool size, and minimum idle connections."
|
||||
[^HikariDataSource pool]
|
||||
(let [^HikariPoolMXBean pool-mxbean (.getHikariPoolMXBean pool)
|
||||
^HikariConfigMXBean cfg-mxbean (.getHikariConfigMXBean pool)]
|
||||
{:active-connections (.getActiveConnections pool-mxbean)
|
||||
:idle-connections (.getIdleConnections pool-mxbean)
|
||||
:threads-awaiting-connection (.getThreadsAwaitingConnection pool-mxbean)
|
||||
:total-connections (.getTotalConnections pool-mxbean)
|
||||
:maximum-pool-size (.getMaximumPoolSize cfg-mxbean)
|
||||
:minimum-idle (.getMinimumIdle cfg-mxbean)}))
|
||||
|
||||
(defn create-pool
|
||||
[cfg]
|
||||
(let [dsc (create-datasource-config cfg)]
|
||||
|
||||
@ -66,11 +66,6 @@
|
||||
LEFT JOIN file_data AS fd ON (fd.file_id = f.id AND fd.id = f.id)
|
||||
WHERE f.id = ?")
|
||||
|
||||
(defn- get-minimal-file
|
||||
[cfg id & {:as opts}]
|
||||
(-> (db/get-with-sql cfg [sql:get-minimal-file id] opts)
|
||||
(d/update-when :metadata fdata/decode-metadata)))
|
||||
|
||||
(def ^:private sql:get-snapshot-without-data
|
||||
(str "WITH snapshots AS (" sql:snapshots ")"
|
||||
"SELECT c.id,
|
||||
@ -112,7 +107,7 @@
|
||||
THEN (c.deleted_at IS NULL OR c.deleted_at >= ?::timestamptz)
|
||||
END"))
|
||||
|
||||
(defn get-snapshot-data
|
||||
(defn get-snapshot
|
||||
"Get a fully decoded snapshot for read-only preview or restoration.
|
||||
Returns the snapshot map with decoded :data field."
|
||||
[cfg file-id snapshot-id]
|
||||
@ -320,79 +315,87 @@
|
||||
|
||||
(defn restore!
|
||||
[{:keys [::db/conn] :as cfg} file-id snapshot-id]
|
||||
(let [file (get-minimal-file conn file-id {::db/for-update true})
|
||||
vern (rand-int Integer/MAX_VALUE)
|
||||
(let [lock-sql (str sql:get-minimal-file " FOR UPDATE OF f SKIP LOCKED")
|
||||
row (db/exec-one! conn [lock-sql file-id])]
|
||||
|
||||
storage
|
||||
(sto/resolve cfg {::db/reuse-conn true})
|
||||
(when-not row
|
||||
(ex/raise :type :conflict
|
||||
:code :file-locked
|
||||
:hint "the file is currently locked by another operation, retry later"))
|
||||
|
||||
snapshot
|
||||
(get-snapshot-data cfg file-id snapshot-id)]
|
||||
(let [file (d/update-when row :metadata fdata/decode-metadata)
|
||||
vern (rand-int Integer/MAX_VALUE)
|
||||
|
||||
(when-not snapshot
|
||||
(ex/raise :type :not-found
|
||||
:code :snapshot-not-found
|
||||
:hint "unable to find snapshot with the provided label"
|
||||
:snapshot-id snapshot-id
|
||||
:file-id file-id))
|
||||
storage
|
||||
(sto/resolve cfg {::db/reuse-conn true})
|
||||
|
||||
(when-not (:data snapshot)
|
||||
(ex/raise :type :internal
|
||||
:code :snapshot-without-data
|
||||
:hint "snapshot has no data"
|
||||
:label (:label snapshot)
|
||||
:file-id file-id))
|
||||
snapshot
|
||||
(get-snapshot cfg file-id snapshot-id)]
|
||||
|
||||
(let [;; If the snapshot has applied migrations stored, we reuse
|
||||
;; them, if not, we take a safest set of migrations as
|
||||
;; starting point. This is because, at the time of
|
||||
;; implementing snapshots, migrations were not taken into
|
||||
;; account so we need to make this backward compatible in
|
||||
;; some way.
|
||||
migrations
|
||||
(or (:migrations snapshot)
|
||||
(fmg/generate-migrations-from-version 67))
|
||||
(when-not snapshot
|
||||
(ex/raise :type :not-found
|
||||
:code :snapshot-not-found
|
||||
:hint "unable to find snapshot with the provided label"
|
||||
:snapshot-id snapshot-id
|
||||
:file-id file-id))
|
||||
|
||||
file
|
||||
(-> file
|
||||
(update :revn inc)
|
||||
(assoc :migrations migrations)
|
||||
(assoc :data (:data snapshot))
|
||||
(assoc :vern vern)
|
||||
(assoc :version (:version snapshot))
|
||||
(assoc :has-media-trimmed false)
|
||||
(assoc :modified-at (:modified-at snapshot))
|
||||
(assoc :features (:features snapshot)))]
|
||||
(when-not (:data snapshot)
|
||||
(ex/raise :type :internal
|
||||
:code :snapshot-without-data
|
||||
:hint "snapshot has no data"
|
||||
:label (:label snapshot)
|
||||
:file-id file-id))
|
||||
|
||||
(l/dbg :hint "restoring snapshot"
|
||||
:file-id (str file-id)
|
||||
:label (:label snapshot)
|
||||
:snapshot-id (str (:id snapshot)))
|
||||
(let [;; If the snapshot has applied migrations stored, we reuse
|
||||
;; them, if not, we take a safest set of migrations as
|
||||
;; starting point. This is because, at the time of
|
||||
;; implementing snapshots, migrations were not taken into
|
||||
;; account so we need to make this backward compatible in
|
||||
;; some way.
|
||||
migrations
|
||||
(or (:migrations snapshot)
|
||||
(fmg/generate-migrations-from-version 67))
|
||||
|
||||
;; In the same way, on reseting the file data, we need to restore
|
||||
;; the applied migrations on the moment of taking the snapshot
|
||||
(bfc/update-file! cfg file ::bfc/reset-migrations? true)
|
||||
file
|
||||
(-> file
|
||||
(update :revn inc)
|
||||
(assoc :migrations migrations)
|
||||
(assoc :data (:data snapshot))
|
||||
(assoc :vern vern)
|
||||
(assoc :version (:version snapshot))
|
||||
(assoc :has-media-trimmed false)
|
||||
(assoc :modified-at (:modified-at snapshot))
|
||||
(assoc :features (:features snapshot)))]
|
||||
|
||||
;; FIXME: this should be separated functions, we should not have
|
||||
;; inline sql here.
|
||||
(l/dbg :hint "restoring snapshot"
|
||||
:file-id (str file-id)
|
||||
:label (:label snapshot)
|
||||
:snapshot-id (str (:id snapshot)))
|
||||
|
||||
;; clean object thumbnails
|
||||
(let [sql (str "update file_tagged_object_thumbnail "
|
||||
" set deleted_at = now() "
|
||||
" where file_id=? returning media_id")
|
||||
res (db/exec! conn [sql file-id])]
|
||||
(doseq [media-id (into #{} (keep :media-id) res)]
|
||||
(sto/touch-object! storage media-id)))
|
||||
;; In the same way, on reseting the file data, we need to restore
|
||||
;; the applied migrations on the moment of taking the snapshot
|
||||
(bfc/update-file! cfg file ::bfc/reset-migrations? true)
|
||||
|
||||
;; clean file thumbnails
|
||||
(let [sql (str "update file_thumbnail "
|
||||
" set deleted_at = now() "
|
||||
" where file_id=? returning media_id")
|
||||
res (db/exec! conn [sql file-id])]
|
||||
(doseq [media-id (into #{} (keep :media-id) res)]
|
||||
(sto/touch-object! storage media-id)))
|
||||
;; FIXME: this should be separated functions, we should not have
|
||||
;; inline sql here.
|
||||
|
||||
vern)))
|
||||
;; clean object thumbnails
|
||||
(let [sql (str "update file_tagged_object_thumbnail "
|
||||
" set deleted_at = now() "
|
||||
" where file_id=? returning media_id")
|
||||
res (db/exec! conn [sql file-id])]
|
||||
(doseq [media-id (into #{} (keep :media-id) res)]
|
||||
(sto/touch-object! storage media-id)))
|
||||
|
||||
;; clean file thumbnails
|
||||
(let [sql (str "update file_thumbnail "
|
||||
" set deleted_at = now() "
|
||||
" where file_id=? returning media_id")
|
||||
res (db/exec! conn [sql file-id])]
|
||||
(doseq [media-id (into #{} (keep :media-id) res)]
|
||||
(sto/touch-object! storage media-id)))
|
||||
|
||||
vern))))
|
||||
|
||||
(defn delete!
|
||||
[cfg & {:keys [id file-id deleted-at]}]
|
||||
|
||||
@ -154,8 +154,8 @@
|
||||
::db/username (cf/get :database-username)
|
||||
::db/password (cf/get :database-password)
|
||||
::db/read-only (cf/get :database-readonly false)
|
||||
::db/min-size (cf/get :database-min-pool-size 0)
|
||||
::db/max-size (cf/get :database-max-pool-size 60)
|
||||
::db/min-size (cf/get :database-min-pool-size)
|
||||
::db/max-size (cf/get :database-max-pool-size)
|
||||
::mtx/metrics (ig/ref ::mtx/metrics)}
|
||||
|
||||
;; Default netty IO pool (shared between several services)
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
[app.main :as-alias main]
|
||||
[app.msgbus :as mbus]
|
||||
[app.rpc :as-alias rpc]
|
||||
[app.rpc.climit :as-alias climit]
|
||||
[app.rpc.commands.files :as files]
|
||||
[app.rpc.commands.teams :as teams]
|
||||
[app.rpc.doc :as-alias doc]
|
||||
@ -54,7 +55,7 @@
|
||||
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id file-id id] :as params}]
|
||||
(let [perms (bfc/get-file-permissions conn profile-id file-id)]
|
||||
(files/check-read-permissions! perms)
|
||||
(let [snapshot (fsnap/get-snapshot-data cfg file-id id)]
|
||||
(let [snapshot (fsnap/get-snapshot cfg file-id id)]
|
||||
(when-not snapshot
|
||||
(ex/raise :type :not-found
|
||||
:code :snapshot-not-found
|
||||
@ -81,9 +82,10 @@
|
||||
(sv/defmethod ::create-file-snapshot
|
||||
{::doc/added "1.20"
|
||||
::sm/params schema:create-file-snapshot
|
||||
::db/transaction true}
|
||||
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id file-id label]}]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
::climit/id [[:create-file-snapshot/by-profile ::rpc/profile-id]
|
||||
[:create-file-snapshot/global]]}
|
||||
[cfg {:keys [::rpc/profile-id file-id label]}]
|
||||
(files/check-edition-permissions! cfg profile-id file-id)
|
||||
(let [file (bfc/get-file cfg file-id :realize? true)
|
||||
project (db/get-by-id cfg :project (:project-id file))]
|
||||
|
||||
@ -95,10 +97,10 @@
|
||||
(quotes/check! {::quotes/id ::quotes/snapshots-per-file}
|
||||
{::quotes/id ::quotes/snapshots-per-team}))
|
||||
|
||||
(fsnap/create! cfg file
|
||||
{:label label
|
||||
:profile-id profile-id
|
||||
:created-by "user"})))
|
||||
(db/tx-run! cfg fsnap/create! file
|
||||
{:label label
|
||||
:profile-id profile-id
|
||||
:created-by "user"})))
|
||||
|
||||
(def ^:private schema:restore-file-snapshot
|
||||
[:map {:title "restore-file-snapshot"}
|
||||
@ -108,29 +110,43 @@
|
||||
(sv/defmethod ::restore-file-snapshot
|
||||
{::doc/added "1.20"
|
||||
::sm/params schema:restore-file-snapshot
|
||||
::db/transaction true}
|
||||
[{:keys [::db/conn ::mbus/msgbus] :as cfg} {:keys [::rpc/profile-id ::rpc/session-id file-id id] :as params}]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
::climit/id [[:restore-file-snapshot/by-profile ::rpc/profile-id]
|
||||
[:restore-file-snapshot/global]]}
|
||||
[{:keys [::db/pool ::mbus/msgbus] :as cfg} {:keys [::rpc/profile-id ::rpc/session-id file-id id] :as params}]
|
||||
|
||||
;; Check permissions and read current file state (short-lived, outside restore transaction)
|
||||
(files/check-edition-permissions! pool profile-id file-id)
|
||||
(let [file (bfc/get-file cfg file-id)
|
||||
team (teams/get-team conn
|
||||
team (teams/get-team pool
|
||||
:profile-id profile-id
|
||||
:file-id file-id)
|
||||
delay (ldel/get-deletion-delay team)]
|
||||
delay (ldel/get-deletion-delay team)
|
||||
file-revn (:revn file)]
|
||||
|
||||
;; Create backup snapshot of the current state (committed immediately
|
||||
;; independently of the restore outcome)
|
||||
(fsnap/create! cfg file
|
||||
{:profile-id profile-id
|
||||
:deleted-at (ct/in-future delay)
|
||||
:created-by "system"})
|
||||
|
||||
(let [vern (fsnap/restore! cfg file-id id)]
|
||||
;; Send to the clients a notification to reload the file
|
||||
(mbus/pub! msgbus
|
||||
:topic (:id file)
|
||||
:message {:type :file-restored
|
||||
:session-id session-id
|
||||
:file-id (:id file)
|
||||
:vern vern})
|
||||
nil)))
|
||||
;; Restore snapshot inside its own transaction; the revn check
|
||||
;; ensures no data is lost if the file was edited concurrently
|
||||
(db/tx-run! cfg
|
||||
(fn [{:keys [::db/conn] :as cfg}]
|
||||
(let [current (bfc/get-minimal-file conn file-id {::db/for-update true})]
|
||||
(when (not= (:revn current) file-revn)
|
||||
(ex/raise :type :conflict
|
||||
:code :file-modified
|
||||
:hint "the file was modified during the restore process, please retry")))
|
||||
(let [vern (fsnap/restore! cfg file-id id)]
|
||||
(mbus/pub! msgbus
|
||||
:topic (:id file)
|
||||
:message {:type :file-restored
|
||||
:session-id session-id
|
||||
:file-id (:id file)
|
||||
:vern vern})
|
||||
nil)))))
|
||||
|
||||
(def ^:private schema:update-file-snapshot
|
||||
[:map {:title "update-file-snapshot"}
|
||||
|
||||
43
backend/test/backend_tests/db_test.clj
Normal file
43
backend/test/backend_tests/db_test.clj
Normal file
@ -0,0 +1,43 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns backend-tests.db-test
|
||||
(:require
|
||||
[app.db :as db]
|
||||
[backend-tests.helpers :as th]
|
||||
[clojure.test :as t])
|
||||
(:import
|
||||
com.zaxxer.hikari.HikariConfig
|
||||
com.zaxxer.hikari.HikariDataSource
|
||||
java.sql.Connection))
|
||||
|
||||
(t/use-fixtures :once th/state-init)
|
||||
|
||||
(t/deftest pool-stats-returns-expected-keys
|
||||
(let [stats (db/pool-stats th/*pool*)]
|
||||
(t/testing "all expected keys are present"
|
||||
(t/is (contains? stats :active-connections))
|
||||
(t/is (contains? stats :idle-connections))
|
||||
(t/is (contains? stats :threads-awaiting-connection))
|
||||
(t/is (contains? stats :total-connections))
|
||||
(t/is (contains? stats :maximum-pool-size))
|
||||
(t/is (contains? stats :minimum-idle)))
|
||||
|
||||
(t/testing "values are non-negative integers"
|
||||
(t/is (>= (:active-connections stats) 0))
|
||||
(t/is (>= (:idle-connections stats) 0))
|
||||
(t/is (>= (:threads-awaiting-connection stats) 0))
|
||||
(t/is (>= (:total-connections stats) 0))
|
||||
(t/is (>= (:maximum-pool-size stats) 0))
|
||||
(t/is (>= (:minimum-idle stats) 0)))
|
||||
|
||||
(t/testing "total connections equals active + idle"
|
||||
(t/is (= (:total-connections stats)
|
||||
(+ (:active-connections stats)
|
||||
(:idle-connections stats)))))
|
||||
|
||||
(t/testing "maximum pool size is reasonable"
|
||||
(t/is (pos? (:maximum-pool-size stats))))))
|
||||
@ -89,6 +89,7 @@ services:
|
||||
depends_on:
|
||||
- penpot-backend
|
||||
- penpot-exporter
|
||||
- penpot-mcp
|
||||
|
||||
networks:
|
||||
- penpot
|
||||
@ -106,7 +107,8 @@ services:
|
||||
|
||||
environment:
|
||||
<< : [*penpot-flags, *penpot-http-body-size, *penpot-public-uri]
|
||||
|
||||
# Set to "true" on hosts where IPv6 is disabled at kernel boot level.
|
||||
# PENPOT_DISABLE_IPV6_LISTEN: "true"
|
||||
penpot-backend:
|
||||
image: "penpotapp/backend:${PENPOT_VERSION:-2.15}"
|
||||
restart: always
|
||||
|
||||
@ -46,7 +46,11 @@ export PENPOT_NITRATE_URI=${PENPOT_NITRATE_URI:-http://penpot-nitrate:3000}
|
||||
export PENPOT_MCP_URI=${PENPOT_MCP_URI:-http://penpot-mcp:4401}
|
||||
export PENPOT_MCP_URI_WS=${PENPOT_MCP_URI_WS:-http://penpot-mcp:4402}
|
||||
export PENPOT_HTTP_SERVER_MAX_BODY_SIZE=${PENPOT_HTTP_SERVER_MAX_BODY_SIZE:-367001600} # Default to 350MiB
|
||||
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_NITRATE_URI,\$PENPOT_MCP_URI,\$PENPOT_MCP_URI_WS,\$PENPOT_HTTP_SERVER_MAX_BODY_SIZE" \
|
||||
export PENPOT_IPV6_LISTEN_DIRECTIVE=${PENPOT_IPV6_LISTEN_DIRECTIVE:-"listen [::]:8080 default_server;"}
|
||||
if [ "${PENPOT_DISABLE_IPV6_LISTEN}" = "true" ]; then
|
||||
export PENPOT_IPV6_LISTEN_DIRECTIVE=""
|
||||
fi
|
||||
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_NITRATE_URI,\$PENPOT_MCP_URI,\$PENPOT_MCP_URI_WS,\$PENPOT_HTTP_SERVER_MAX_BODY_SIZE,\$PENPOT_IPV6_LISTEN_DIRECTIVE" \
|
||||
< /tmp/nginx.conf.template > /etc/nginx/nginx.conf
|
||||
|
||||
PENPOT_DEFAULT_INTERNAL_RESOLVER="$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf)"
|
||||
|
||||
@ -73,7 +73,7 @@ http {
|
||||
|
||||
server {
|
||||
listen 8080 default_server;
|
||||
listen [::]:8080 default_server;
|
||||
${PENPOT_IPV6_LISTEN_DIRECTIVE}
|
||||
server_name _;
|
||||
|
||||
client_max_body_size $PENPOT_HTTP_SERVER_MAX_BODY_SIZE;
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
[:> c/navigation-bullets*
|
||||
{:slide slide
|
||||
:navigate navigate
|
||||
:total 4}]
|
||||
:total 3}]
|
||||
|
||||
[:button {:on-click next
|
||||
:class (stl/css :next-btn)} "Continue"]]]]]]
|
||||
@ -118,7 +118,7 @@
|
||||
[:> c/navigation-bullets*
|
||||
{:slide slide
|
||||
:navigate navigate
|
||||
:total 4}]
|
||||
:total 3}]
|
||||
|
||||
[:button {:on-click next
|
||||
:class (stl/css :next-btn)} "Continue"]]]]]]
|
||||
|
||||
@ -16,10 +16,10 @@
|
||||
"fmt": "./scripts/fmt"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@github/copilot": "^1.0.44",
|
||||
"@github/copilot": "^1.0.54",
|
||||
"@types/node": "^25.6.2",
|
||||
"esbuild": "^0.28.0",
|
||||
"nrepl-client": "^0.3.0",
|
||||
"opencode-ai": "^1.15.4"
|
||||
"opencode-ai": "^1.15.11"
|
||||
}
|
||||
}
|
||||
|
||||
196
pnpm-lock.yaml
generated
196
pnpm-lock.yaml
generated
@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
'@github/copilot':
|
||||
specifier: ^1.0.44
|
||||
version: 1.0.44
|
||||
specifier: ^1.0.54
|
||||
version: 1.0.54
|
||||
'@types/node':
|
||||
specifier: ^25.6.2
|
||||
version: 25.6.2
|
||||
@ -21,8 +21,8 @@ importers:
|
||||
specifier: ^0.3.0
|
||||
version: 0.3.0
|
||||
opencode-ai:
|
||||
specifier: ^1.15.4
|
||||
version: 1.15.4
|
||||
specifier: ^1.15.11
|
||||
version: 1.15.11
|
||||
|
||||
packages:
|
||||
|
||||
@ -182,44 +182,60 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@github/copilot-darwin-arm64@1.0.44':
|
||||
resolution: {integrity: sha512-9NqA5sT2spmNsehxhs51GhXRZIZga5nq+WcMl4LG2QrUPJRDwvHf1bDKqETJUBbYvBY8jONGuTKMRofkMI68YQ==}
|
||||
'@github/copilot-darwin-arm64@1.0.54':
|
||||
resolution: {integrity: sha512-ZRiKkxCvDccdGSNB/gmge4UkqMsWWZNIOr0pcim4/x2YUdHbh9cex9RZRjEMXijtUkBTzW5DP/cACuoAqTCyEg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-darwin-x64@1.0.44':
|
||||
resolution: {integrity: sha512-QPD8KtXx07SIKILGBl4JDhPyL2Qo0FMmaTYVxR6nkyHkHnFPsUZD6VWGR+T/KMLkcUXFM85Xc1ba9Y27s4nRrQ==}
|
||||
'@github/copilot-darwin-x64@1.0.54':
|
||||
resolution: {integrity: sha512-DGqs8x5r4y+SebMco890lNsPrqe6L4v2hCmV1IQ1pvYPvD1o1NMVSZPAQhkdvUeR5bqusOg8+0ugIZOQGTFpFQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-linux-arm64@1.0.44':
|
||||
resolution: {integrity: sha512-Z8ScIUP433xS18f68NP9jM9zW320Xzpi2wf7Nig/VyfrwupBy25UTezydQMT0KQHLWTEleHOPcYnASY3HgJXnQ==}
|
||||
'@github/copilot-linux-arm64@1.0.54':
|
||||
resolution: {integrity: sha512-waVKu6RuG8YBvCoGrOgtsOxmnfLaUywvbqZXRgvMya1m4akRkMi5r9B2UDr3+egjChp+FIUJVbGIoXN6ZST0rQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-linux-x64@1.0.44':
|
||||
resolution: {integrity: sha512-KUl6lvJt0HNKaXSx0T0bIWJ3rvrGwgZYMlkDfqMbuMnZatEQJbjPwxmL/IDfp/c0DyKd7K+ajl17wHYcN/hJIQ==}
|
||||
'@github/copilot-linux-x64@1.0.54':
|
||||
resolution: {integrity: sha512-u/ltZa+HDIuhMivkIwkkuylRdEMk5Lp0XjE9w/OityW+BPKjZ+VKAmJ1/1Xm/uUx1IUlZaE3TJnka52wVNOD0A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-win32-arm64@1.0.44':
|
||||
resolution: {integrity: sha512-JVJxZJwAc95ZfapgOXjNFwSqrWlvC3heo128L+CDkdZ6lwpD1dTGMHT/6rMMEeo3xjZmMm8tiynfwsHLDgTtvQ==}
|
||||
'@github/copilot-linuxmusl-arm64@1.0.54':
|
||||
resolution: {integrity: sha512-21LLjoQnD57Y1fvO56G1FGVbkt/ffZNDpHqVe2NW7C4r78Gn0hOTqwp+xWRUMpdmxrGZyKeFjX8jK6qox2uF5w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-linuxmusl-x64@1.0.54':
|
||||
resolution: {integrity: sha512-sbeATKa9vaIetsY1vhQJO0PN/5FgoK48wkGBWCy4BpO8ER/kGYczT22qv6n96gBYrVmC2IZuTFTM4GFpC3bbBw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-win32-arm64@1.0.54':
|
||||
resolution: {integrity: sha512-muOX8qrJSi56BWQejkH0TgXpZYRO8Y9k1qIfMuRojZyLyATn1P4lIKb67ZqDCXJLkcPfVJ5eJYsSAeGwU3Qpww==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot-win32-x64@1.0.44':
|
||||
resolution: {integrity: sha512-Yj3KQ/DqwS50PwRtyQITX2mWIVZeJeX+y0faVSMwUUzG1qxmMcme7wimhKOyc4LSV11DpgVB9MSiBw2xys7iww==}
|
||||
'@github/copilot-win32-x64@1.0.54':
|
||||
resolution: {integrity: sha512-BheXmqrYFmfRXA0iveKkjKks/2wgK5glrEOARomzy3JCbvVMSPIE8YeK+3YysiOh2SUkWjahwJc09cxaBq4+qQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
hasBin: true
|
||||
|
||||
'@github/copilot@1.0.44':
|
||||
resolution: {integrity: sha512-wr/GmNOUaJK/giJK5abyB1oTpEowgFKLi+NJnlyAymKiK/GKCaRlJqiX23H2RetM8vD2hDYUFUFm9lTCooGy0g==}
|
||||
'@github/copilot@1.0.54':
|
||||
resolution: {integrity: sha512-gxiWEQFWxJ3J2Rh67CxKEfER/zayB1z2qaSBUz3RZ0u1iDNJdGPry/1vOQ72X/yHmpGNm+9egucN5VMzyedsIg==}
|
||||
hasBin: true
|
||||
|
||||
'@types/node@25.6.2':
|
||||
@ -228,6 +244,10 @@ packages:
|
||||
bencode@2.0.3:
|
||||
resolution: {integrity: sha512-D/vrAD4dLVX23NalHwb8dSvsUsxeRPO8Y7ToKA015JQYq69MLDOMkC0uGZYA/MPpltLO8rt8eqFC2j8DxjTZ/w==}
|
||||
|
||||
detect-libc@2.1.2:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
esbuild@0.28.0:
|
||||
resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -236,69 +256,69 @@ packages:
|
||||
nrepl-client@0.3.0:
|
||||
resolution: {integrity: sha512-EcROXUrzlGHKOdu/E/5WB0OESCI0iGHhdXeYk9cULYtd72eFJrM/Q1umvjTBfKWlT62y76cnyLG/3CmSCqT12w==}
|
||||
|
||||
opencode-ai@1.15.4:
|
||||
resolution: {integrity: sha512-Z5PeJwFNUW4sFW+jYHQTnJm6858dECvWOATvnG0S66Nn46zwjaaZJEJMKQEPOW7Yog99j6k7xRKvJPPAjKDXfQ==}
|
||||
opencode-ai@1.15.11:
|
||||
resolution: {integrity: sha512-i3DYIATyWT3ukP+5OCyEuXvbCEq7PgBAlVA4yp01+W5BaYeoj/f0bpXdDPP5q9B/Yl8drtyEhWh0YC9UAHF06A==}
|
||||
cpu: [arm64, x64]
|
||||
os: [darwin, linux, win32]
|
||||
hasBin: true
|
||||
|
||||
opencode-darwin-arm64@1.15.4:
|
||||
resolution: {integrity: sha512-d+0sFAAhrDtjQbxRZvYSzy3g/xj/xUDRWUVBWGfkJAx0QEWc/v7cksmnYj3p3l88Gxm/rWeLCh6H32pw1/En8A==}
|
||||
opencode-darwin-arm64@1.15.11:
|
||||
resolution: {integrity: sha512-XuiTIkBj0YKpfT8KHNan4JaX686vROCwXQHDzsZ55g/I7rdyQXG2wdt2CsUhRDaPyQTOkhrM+VqC3uYsT+kZzw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
opencode-darwin-x64-baseline@1.15.4:
|
||||
resolution: {integrity: sha512-Lj9wsEPFyEOgLO6J3DsCXdSu/IAJnW/RjtD1oojAao6uHvhs5uXyj1mrsmK8GrtAfCT4JUh8W38o3YYXGjItSw==}
|
||||
opencode-darwin-x64-baseline@1.15.11:
|
||||
resolution: {integrity: sha512-itb1FRgGyve89/W+sQBqmTVWUoldb0TdH1Qm805c52UbY+nkEW6oE40vveHJEDDPxFHypyzSymYFcJ7wqYBisw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
opencode-darwin-x64@1.15.4:
|
||||
resolution: {integrity: sha512-H412BUw5O+bmXfzLo6UMCWVc3DOYEM0RCI5Kt+Ynqh+Q9878bXK6mwRR7VXgGVBkkH2U4GtT1uDgY0BzSK185Q==}
|
||||
opencode-darwin-x64@1.15.11:
|
||||
resolution: {integrity: sha512-PimsC+uaSmVxszQ3sbrIEjDoba9jUyAwAbydEukY3EoQ7cgLFd8tn9H/8yeA0aY7bh3uiCttDCctoQfMpV+S9Q==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
opencode-linux-arm64-musl@1.15.4:
|
||||
resolution: {integrity: sha512-TO2IVSoYolGKJahf73/hRsJBGxLKOdP/akYPzI0hQQvW4oVrmQkZ3s13jU1+LXIEn4Zbj/TB18QvLzvXrnrEhA==}
|
||||
opencode-linux-arm64-musl@1.15.11:
|
||||
resolution: {integrity: sha512-wLaAM12H0mH93XpdXuFz4+oeNA9+CDj8WEvdL8NNrz/Sfgi/zWIo8g3UMH+lp+pfO0s7PTM84RzxGQTOvcejXg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
opencode-linux-arm64@1.15.4:
|
||||
resolution: {integrity: sha512-V+x/u9JnPOLPEfqbePSCL0OQdin5gs1V35VsVxj19WaZDEwxlMVjOe6HjVKEY64/O6htkPxCCZohmnMU4dVBMQ==}
|
||||
opencode-linux-arm64@1.15.11:
|
||||
resolution: {integrity: sha512-SM+xMU8pUd5p6KD2wdIR2d0q3IRw6axKSGUqlcVrit7ZhFlTjdr3Ca0KqVv3JsUny8Bu8N8Z5b3MHvqRf4nTSQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
opencode-linux-x64-baseline-musl@1.15.4:
|
||||
resolution: {integrity: sha512-xOJ3aHg2+2GrT9F/KmAF0JLB1D6K3SCY/626n+fLjs/AEFvLdmE3TYhoXPEyGH2I9F4kF+4p2xk0pg2b+LVlZQ==}
|
||||
opencode-linux-x64-baseline-musl@1.15.11:
|
||||
resolution: {integrity: sha512-N+geBY9Zv2kfoMKYMnPxJZQ1R9xOrgA55BMa7aMtMHr2x9tkjI5mCT7ese6Igna/cnoicxo216YhkSzyY1+p9A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
opencode-linux-x64-baseline@1.15.4:
|
||||
resolution: {integrity: sha512-dTlV8tAVN8nFdPb7527GR6/BpyIVavAcXJmZ2VbS1daXu4C6k6bpmjiS/ZFKlphRZiKKiEzFrHlimao4BMchVQ==}
|
||||
opencode-linux-x64-baseline@1.15.11:
|
||||
resolution: {integrity: sha512-MX+eaLOkFVO5IA8jA0QLUJma3KBwRzUrzZrCFuv6+vq9U/SsD+F9Jz2Bnfw9iE9v3QwnJ+8Yf/vKCsb5LrrWvQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
opencode-linux-x64-musl@1.15.4:
|
||||
resolution: {integrity: sha512-IbMaM6zrakdtDD55GUhlT/WeXomXmKsVqo3XQuOaGXprBg3W5alsxXh60SZpV3ftbdcMD/eiB/PYtN/ZN8Fa5w==}
|
||||
opencode-linux-x64-musl@1.15.11:
|
||||
resolution: {integrity: sha512-/xbhh8aDFR5E8Ggc00ZG3qXXAwWxosEfWaPXiP04/Y7kDbz8T28a1cSIWniNmY426rYdnYLXgwJzOgpD/ZhDDg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
opencode-linux-x64@1.15.4:
|
||||
resolution: {integrity: sha512-2c20aldKLfNkg6N6nABvvK1fuaCwYLo/HNeL8ikellkFMeGalCGDhkL/VQ8R8KPV3ohVZJtZwG0nkFiA8MeHCg==}
|
||||
opencode-linux-x64@1.15.11:
|
||||
resolution: {integrity: sha512-RuXo1XFiAqW6ypnP4V+rPDmTrdDKh8FuO+3whMpw2qIYs8eVil72QwX1Rv6W96FDCFQkyUZW9R6MK/MGbGWCUQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
opencode-windows-arm64@1.15.4:
|
||||
resolution: {integrity: sha512-kr3nIWmYH7NC0Vgrhgjp9EmCuy5MuxjIRrSjzlfRLMaML6U/a0Hsr3AahBwI1KjT+HEhz5u6xpodZeeEDY3nPQ==}
|
||||
opencode-windows-arm64@1.15.11:
|
||||
resolution: {integrity: sha512-sdWtLGq1aoaCzbTQY8NR7+g56lzYREBBcT7Na81FKg4H/ZybLQHXV+lwbaw+cK/d0aPpM8EAB+TV6Wbe5nEzGw==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
opencode-windows-x64-baseline@1.15.4:
|
||||
resolution: {integrity: sha512-2/elQ163r4Q97bYJRrY09IG+bpqh0AKpfutDGCaokFdLWIWQN/cFvjzb4C+BKzLFsU9LRfoyvPhe4nXMm1+S4A==}
|
||||
opencode-windows-x64-baseline@1.15.11:
|
||||
resolution: {integrity: sha512-Lj9TkJIeUD++idJWIKK5z+k5hvNubAEXItdxzBLM8LlWArSd2tXCGbxbBktsM5URlhFBdAN05ghyiUtAVOcMPg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
opencode-windows-x64@1.15.4:
|
||||
resolution: {integrity: sha512-f6p40u3yLEbiq4pzBOXAwtW/NP/dL8uTurHfraPcfezA4ua5DEm4vSoSePUY0CHtubUPuDe0wRUA1s53sysjPQ==}
|
||||
opencode-windows-x64@1.15.11:
|
||||
resolution: {integrity: sha512-d5jJqLA+d2DmbEzVrriePxoOjLfqjKZar0OYkNgvmUcWHCHeyn1NcL5JH6T7L19s/X3qY1tEDvZZ3uWFqNMdGQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
@ -389,32 +409,42 @@ snapshots:
|
||||
'@esbuild/win32-x64@0.28.0':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-darwin-arm64@1.0.44':
|
||||
'@github/copilot-darwin-arm64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-darwin-x64@1.0.44':
|
||||
'@github/copilot-darwin-x64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-linux-arm64@1.0.44':
|
||||
'@github/copilot-linux-arm64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-linux-x64@1.0.44':
|
||||
'@github/copilot-linux-x64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-win32-arm64@1.0.44':
|
||||
'@github/copilot-linuxmusl-arm64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-win32-x64@1.0.44':
|
||||
'@github/copilot-linuxmusl-x64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot@1.0.44':
|
||||
'@github/copilot-win32-arm64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot-win32-x64@1.0.54':
|
||||
optional: true
|
||||
|
||||
'@github/copilot@1.0.54':
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
'@github/copilot-darwin-arm64': 1.0.44
|
||||
'@github/copilot-darwin-x64': 1.0.44
|
||||
'@github/copilot-linux-arm64': 1.0.44
|
||||
'@github/copilot-linux-x64': 1.0.44
|
||||
'@github/copilot-win32-arm64': 1.0.44
|
||||
'@github/copilot-win32-x64': 1.0.44
|
||||
'@github/copilot-darwin-arm64': 1.0.54
|
||||
'@github/copilot-darwin-x64': 1.0.54
|
||||
'@github/copilot-linux-arm64': 1.0.54
|
||||
'@github/copilot-linux-x64': 1.0.54
|
||||
'@github/copilot-linuxmusl-arm64': 1.0.54
|
||||
'@github/copilot-linuxmusl-x64': 1.0.54
|
||||
'@github/copilot-win32-arm64': 1.0.54
|
||||
'@github/copilot-win32-x64': 1.0.54
|
||||
|
||||
'@types/node@25.6.2':
|
||||
dependencies:
|
||||
@ -422,6 +452,8 @@ snapshots:
|
||||
|
||||
bencode@2.0.3: {}
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
esbuild@0.28.0:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.28.0
|
||||
@ -456,55 +488,55 @@ snapshots:
|
||||
bencode: 2.0.3
|
||||
tree-kill: 1.2.2
|
||||
|
||||
opencode-ai@1.15.4:
|
||||
opencode-ai@1.15.11:
|
||||
optionalDependencies:
|
||||
opencode-darwin-arm64: 1.15.4
|
||||
opencode-darwin-x64: 1.15.4
|
||||
opencode-darwin-x64-baseline: 1.15.4
|
||||
opencode-linux-arm64: 1.15.4
|
||||
opencode-linux-arm64-musl: 1.15.4
|
||||
opencode-linux-x64: 1.15.4
|
||||
opencode-linux-x64-baseline: 1.15.4
|
||||
opencode-linux-x64-baseline-musl: 1.15.4
|
||||
opencode-linux-x64-musl: 1.15.4
|
||||
opencode-windows-arm64: 1.15.4
|
||||
opencode-windows-x64: 1.15.4
|
||||
opencode-windows-x64-baseline: 1.15.4
|
||||
opencode-darwin-arm64: 1.15.11
|
||||
opencode-darwin-x64: 1.15.11
|
||||
opencode-darwin-x64-baseline: 1.15.11
|
||||
opencode-linux-arm64: 1.15.11
|
||||
opencode-linux-arm64-musl: 1.15.11
|
||||
opencode-linux-x64: 1.15.11
|
||||
opencode-linux-x64-baseline: 1.15.11
|
||||
opencode-linux-x64-baseline-musl: 1.15.11
|
||||
opencode-linux-x64-musl: 1.15.11
|
||||
opencode-windows-arm64: 1.15.11
|
||||
opencode-windows-x64: 1.15.11
|
||||
opencode-windows-x64-baseline: 1.15.11
|
||||
|
||||
opencode-darwin-arm64@1.15.4:
|
||||
opencode-darwin-arm64@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-darwin-x64-baseline@1.15.4:
|
||||
opencode-darwin-x64-baseline@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-darwin-x64@1.15.4:
|
||||
opencode-darwin-x64@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-arm64-musl@1.15.4:
|
||||
opencode-linux-arm64-musl@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-arm64@1.15.4:
|
||||
opencode-linux-arm64@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-x64-baseline-musl@1.15.4:
|
||||
opencode-linux-x64-baseline-musl@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-x64-baseline@1.15.4:
|
||||
opencode-linux-x64-baseline@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-x64-musl@1.15.4:
|
||||
opencode-linux-x64-musl@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-linux-x64@1.15.4:
|
||||
opencode-linux-x64@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-windows-arm64@1.15.4:
|
||||
opencode-windows-arm64@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-windows-x64-baseline@1.15.4:
|
||||
opencode-windows-x64-baseline@1.15.11:
|
||||
optional: true
|
||||
|
||||
opencode-windows-x64@1.15.4:
|
||||
opencode-windows-x64@1.15.11:
|
||||
optional: true
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user