feat: combine TUI UX from alexhancock/tui-goodness with publishing config from jackamadeo/package-tui (#7683)
Co-authored-by: Jack Amadeo <jamadeo@squareup.com>
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
*/bin/
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Native Binary Packages
|
||||||
|
|
||||||
|
This directory contains the npm package scaffolding for distributing the
|
||||||
|
`goose-acp-server` Rust binary as platform-specific npm packages.
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
| Package | Platform |
|
||||||
|
|---------|----------|
|
||||||
|
| `@block/goose-acp-server-darwin-arm64` | macOS Apple Silicon |
|
||||||
|
| `@block/goose-acp-server-darwin-x64` | macOS Intel |
|
||||||
|
| `@block/goose-acp-server-linux-arm64` | Linux ARM64 |
|
||||||
|
| `@block/goose-acp-server-linux-x64` | Linux x64 |
|
||||||
|
| `@block/goose-acp-server-win32-x64` | Windows x64 |
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
From the repository root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build for all platforms (requires cross-compilation toolchains)
|
||||||
|
./ui/text/scripts/build-native-packages.sh
|
||||||
|
|
||||||
|
# Build for a single platform
|
||||||
|
./ui/text/scripts/build-native-packages.sh darwin-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
The built binaries are placed into `npm/goose-acp-server-{platform}/bin/`.
|
||||||
|
These directories are git-ignored.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./ui/text/scripts/publish.sh
|
||||||
|
```
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@block/goose-acp-server-darwin-arm64",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Goose ACP server binary for macOS ARM64",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"bin/goose-acp-server"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@block/goose-acp-server-darwin-x64",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Goose ACP server binary for macOS x64",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"bin/goose-acp-server"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@block/goose-acp-server-linux-arm64",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Goose ACP server binary for Linux ARM64",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"bin/goose-acp-server"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@block/goose-acp-server-linux-x64",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Goose ACP server binary for Linux x64",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"bin/goose-acp-server"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@block/goose-acp-server-win32-x64",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Goose ACP server binary for Windows x64",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"bin/goose-acp-server.exe"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
+7
-4
@@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "goose-acp-types",
|
"name": "@block/goose-acp",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./src/index.ts",
|
"main": "./dist/index.js",
|
||||||
"types": "./src/index.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
"generate": "tsx generate-schema.ts",
|
"generate": "tsx generate-schema.ts",
|
||||||
"lint": "tsc --noEmit",
|
"lint": "tsc --noEmit",
|
||||||
"format": "prettier --write src/"
|
"format": "prettier --write src/"
|
||||||
|
|||||||
@@ -27,12 +27,17 @@ import {
|
|||||||
type SetSessionModelResponse,
|
type SetSessionModelResponse,
|
||||||
} from "@agentclientprotocol/sdk";
|
} from "@agentclientprotocol/sdk";
|
||||||
import { GooseExtClient } from "./generated/client.gen.js";
|
import { GooseExtClient } from "./generated/client.gen.js";
|
||||||
|
import { createHttpStream } from "./http-stream.js";
|
||||||
|
|
||||||
export class GooseClient {
|
export class GooseClient {
|
||||||
private conn: ClientSideConnection;
|
private conn: ClientSideConnection;
|
||||||
private ext: GooseExtClient;
|
private ext: GooseExtClient;
|
||||||
|
|
||||||
constructor(toClient: () => Client, stream: Stream) {
|
constructor(toClient: () => Client, streamOrUrl: Stream | string) {
|
||||||
|
const stream =
|
||||||
|
typeof streamOrUrl === "string"
|
||||||
|
? createHttpStream(streamOrUrl)
|
||||||
|
: streamOrUrl;
|
||||||
this.conn = new ClientSideConnection(toClient, stream);
|
this.conn = new ClientSideConnection(toClient, stream);
|
||||||
this.ext = new GooseExtClient(this.conn);
|
this.ext = new GooseExtClient(this.conn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export function createHttpStream(serverUrl: string): Stream {
|
|||||||
const msg = JSON.parse(line.slice(6)) as AnyMessage;
|
const msg = JSON.parse(line.slice(6)) as AnyMessage;
|
||||||
pushMessage(msg);
|
pushMessage(msg);
|
||||||
} catch {
|
} catch {
|
||||||
|
// ignore malformed JSON
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,10 +52,6 @@ export function createHttpStream(serverUrl: string): Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST initialize (no session header) opens a long-lived SSE stream that receives
|
|
||||||
// ALL subsequent responses and notifications. Later POSTs with the session header
|
|
||||||
// are fire-and-forget for requests (responses arrive on the first stream) or
|
|
||||||
// return 202 immediately for notifications/responses.
|
|
||||||
let isFirstRequest = true;
|
let isFirstRequest = true;
|
||||||
|
|
||||||
const readable = new ReadableStream<AnyMessage>({
|
const readable = new ReadableStream<AnyMessage>({
|
||||||
@@ -69,7 +66,10 @@ export function createHttpStream(serverUrl: string): Stream {
|
|||||||
const writable = new WritableStream<AnyMessage>({
|
const writable = new WritableStream<AnyMessage>({
|
||||||
async write(msg) {
|
async write(msg) {
|
||||||
const isRequest =
|
const isRequest =
|
||||||
"method" in msg && "id" in msg && msg.id !== undefined && msg.id !== null;
|
"method" in msg &&
|
||||||
|
"id" in msg &&
|
||||||
|
msg.id !== undefined &&
|
||||||
|
msg.id !== null;
|
||||||
|
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from "./generated/types.gen.js";
|
export * from "./generated/types.gen.js";
|
||||||
export * from "./generated/zod.gen.js";
|
export * from "./generated/zod.gen.js";
|
||||||
export { GooseClient } from "./goose-client.js";
|
export { GooseClient } from "./goose-client.js";
|
||||||
|
export { createHttpStream } from "./http-stream.js";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ClientSideConnection,
|
ClientSideConnection,
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "ESNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "nodenext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
"rootDir": "./src",
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"],
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2335
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"workspaces": [
|
||||||
|
"acp",
|
||||||
|
"text"
|
||||||
|
]
|
||||||
|
}
|
||||||
Executable
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Publishes @block/goose-acp, @block/goose, and all native binary packages to npm.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./ui/scripts/publish.sh # publish all (dry-run)
|
||||||
|
# ./ui/scripts/publish.sh --real # publish for real
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - npm login to the @block scope
|
||||||
|
# - Native binaries built via build-native-packages.sh
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
NPM_DIR="${REPO_ROOT}/npm"
|
||||||
|
ACP_DIR="${REPO_ROOT}/ui/acp"
|
||||||
|
TEXT_DIR="${REPO_ROOT}/ui/text"
|
||||||
|
|
||||||
|
DRY_RUN="--dry-run"
|
||||||
|
if [[ "${1:-}" == "--real" ]]; then
|
||||||
|
DRY_RUN=""
|
||||||
|
echo "==> Publishing for real"
|
||||||
|
else
|
||||||
|
echo "==> Dry run (pass --real to publish)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build and publish @block/goose-acp first (dependency of @block/goose)
|
||||||
|
echo "==> Building @block/goose-acp"
|
||||||
|
(cd "${ACP_DIR}" && npm run build)
|
||||||
|
|
||||||
|
echo "==> Publishing @block/goose-acp"
|
||||||
|
(cd "${ACP_DIR}" && npm publish --access public ${DRY_RUN})
|
||||||
|
|
||||||
|
# Build @block/goose
|
||||||
|
echo "==> Building @block/goose"
|
||||||
|
(cd "${TEXT_DIR}" && npm run build)
|
||||||
|
|
||||||
|
NATIVE_PACKAGES=(
|
||||||
|
"goose-acp-server-darwin-arm64"
|
||||||
|
"goose-acp-server-darwin-x64"
|
||||||
|
"goose-acp-server-linux-arm64"
|
||||||
|
"goose-acp-server-linux-x64"
|
||||||
|
"goose-acp-server-win32-x64"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Publish native binary packages
|
||||||
|
for pkg in "${NATIVE_PACKAGES[@]}"; do
|
||||||
|
pkg_dir="${NPM_DIR}/${pkg}"
|
||||||
|
|
||||||
|
if [ ! -f "${pkg_dir}/bin/goose-acp-server" ] && [ ! -f "${pkg_dir}/bin/goose-acp-server.exe" ]; then
|
||||||
|
echo " SKIP ${pkg} (no binary found — run build-native-packages.sh first)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Publishing @block/${pkg}"
|
||||||
|
(cd "${pkg_dir}" && npm publish --access public ${DRY_RUN})
|
||||||
|
done
|
||||||
|
|
||||||
|
# Publish the main package
|
||||||
|
echo "==> Publishing @block/goose"
|
||||||
|
(cd "${TEXT_DIR}" && npm publish --access public ${DRY_RUN})
|
||||||
|
|
||||||
|
echo "==> Done"
|
||||||
@@ -1 +1,3 @@
|
|||||||
dist
|
dist
|
||||||
|
node_modules
|
||||||
|
server-binary.json
|
||||||
|
|||||||
Generated
+648
-130
@@ -1,49 +1,50 @@
|
|||||||
{
|
{
|
||||||
"name": "goose-text",
|
"name": "@block/goose",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "goose-text",
|
"name": "@block/goose",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
"bundleDependencies": [
|
||||||
|
"@block/goose-acp"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agentclientprotocol/sdk": "^0.14.1",
|
"@agentclientprotocol/sdk": "^0.14.1",
|
||||||
"@goose/acp": "file:../acp",
|
"@block/goose-acp": "file:../acp",
|
||||||
"ink": "^5.1.0",
|
"ink": "^5.1.0",
|
||||||
"ink-text-input": "^6.0.0",
|
"ink-text-input": "^6.0.0",
|
||||||
"meow": "^13.2.0",
|
"meow": "^13.2.0",
|
||||||
"react": "^18.3.1"
|
"react": "^18.3.1"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"goose": "dist/tui.js"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.2.3",
|
"@types/node": "^25.2.3",
|
||||||
"@types/react": "^18.3.0",
|
"@types/react": "^18.3.0",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.7.0"
|
"typescript": "^5.7.0"
|
||||||
}
|
|
||||||
},
|
|
||||||
"../acp": {
|
|
||||||
"name": "goose-acp-types",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"dependencies": {
|
|
||||||
"zod": "^3.25.76"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"optionalDependencies": {
|
||||||
"@agentclientprotocol/sdk": "^0.14.1",
|
"@block/goose-acp-server-darwin-arm64": "0.1.0",
|
||||||
"@hey-api/openapi-ts": "^0.92.3",
|
"@block/goose-acp-server-darwin-x64": "0.1.0",
|
||||||
"prettier": "^3.8.1",
|
"@block/goose-acp-server-linux-arm64": "0.1.0",
|
||||||
"tsx": "^4.21.0",
|
"@block/goose-acp-server-linux-x64": "0.1.0",
|
||||||
"typescript": "~5.9.3"
|
"@block/goose-acp-server-win32-x64": "0.1.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@agentclientprotocol/sdk": "*"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@agentclientprotocol/sdk": {
|
"node_modules/@agentclientprotocol/sdk": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.14.1.tgz",
|
||||||
"integrity": "sha512-b6r3PS3Nly+Wyw9U+0nOr47bV8tfS476EgyEMhoKvJCZLbgqoDFN7DJwkxL88RR0aiOqOYV1ZnESHqb+RmdH8w==",
|
"integrity": "sha512-b6r3PS3Nly+Wyw9U+0nOr47bV8tfS476EgyEMhoKvJCZLbgqoDFN7DJwkxL88RR0aiOqOYV1ZnESHqb+RmdH8w==",
|
||||||
|
"inBundle": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"zod": "^3.25.0 || ^4.0.0"
|
"zod": "^3.25.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
@@ -61,10 +62,46 @@
|
|||||||
"node": ">=14.13.1"
|
"node": ">=14.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@block/goose-acp": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "file:../acp",
|
||||||
|
"inBundle": true,
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^3.25.76"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@agentclientprotocol/sdk": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp-server-darwin-arm64": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp-server-darwin-x64": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp-server-linux-arm64": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp-server-linux-x64": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp-server-win32-x64": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@block/goose-acp/node_modules/zod": {
|
||||||
|
"version": "3.25.76",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||||
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
"integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
|
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -79,9 +116,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
||||||
"integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
|
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -96,9 +133,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
|
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -113,9 +150,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
|
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -130,9 +167,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
|
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -147,9 +184,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
|
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -164,9 +201,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
|
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -181,9 +218,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
|
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -198,9 +235,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
||||||
"integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
|
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -215,9 +252,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
|
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -232,9 +269,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
||||||
"integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
|
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -249,9 +286,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
||||||
"integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
|
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@@ -266,9 +303,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
||||||
"integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
|
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
@@ -283,9 +320,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
||||||
"integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
|
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -300,9 +337,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
||||||
"integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
|
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -317,9 +354,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
||||||
"integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
|
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -334,9 +371,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
|
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -351,9 +388,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-arm64": {
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
|
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -368,9 +405,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
|
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -385,9 +422,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-arm64": {
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
|
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -402,9 +439,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
|
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -419,9 +456,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openharmony-arm64": {
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
|
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -436,9 +473,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
|
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -453,9 +490,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
|
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -470,9 +507,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
||||||
"integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
|
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -487,9 +524,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
|
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -503,10 +540,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@goose/acp": {
|
|
||||||
"resolved": "../acp",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.2.3",
|
"version": "25.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
||||||
@@ -715,9 +748,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.27.3",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
||||||
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
|
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -728,32 +761,32 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.27.3",
|
"@esbuild/aix-ppc64": "0.25.12",
|
||||||
"@esbuild/android-arm": "0.27.3",
|
"@esbuild/android-arm": "0.25.12",
|
||||||
"@esbuild/android-arm64": "0.27.3",
|
"@esbuild/android-arm64": "0.25.12",
|
||||||
"@esbuild/android-x64": "0.27.3",
|
"@esbuild/android-x64": "0.25.12",
|
||||||
"@esbuild/darwin-arm64": "0.27.3",
|
"@esbuild/darwin-arm64": "0.25.12",
|
||||||
"@esbuild/darwin-x64": "0.27.3",
|
"@esbuild/darwin-x64": "0.25.12",
|
||||||
"@esbuild/freebsd-arm64": "0.27.3",
|
"@esbuild/freebsd-arm64": "0.25.12",
|
||||||
"@esbuild/freebsd-x64": "0.27.3",
|
"@esbuild/freebsd-x64": "0.25.12",
|
||||||
"@esbuild/linux-arm": "0.27.3",
|
"@esbuild/linux-arm": "0.25.12",
|
||||||
"@esbuild/linux-arm64": "0.27.3",
|
"@esbuild/linux-arm64": "0.25.12",
|
||||||
"@esbuild/linux-ia32": "0.27.3",
|
"@esbuild/linux-ia32": "0.25.12",
|
||||||
"@esbuild/linux-loong64": "0.27.3",
|
"@esbuild/linux-loong64": "0.25.12",
|
||||||
"@esbuild/linux-mips64el": "0.27.3",
|
"@esbuild/linux-mips64el": "0.25.12",
|
||||||
"@esbuild/linux-ppc64": "0.27.3",
|
"@esbuild/linux-ppc64": "0.25.12",
|
||||||
"@esbuild/linux-riscv64": "0.27.3",
|
"@esbuild/linux-riscv64": "0.25.12",
|
||||||
"@esbuild/linux-s390x": "0.27.3",
|
"@esbuild/linux-s390x": "0.25.12",
|
||||||
"@esbuild/linux-x64": "0.27.3",
|
"@esbuild/linux-x64": "0.25.12",
|
||||||
"@esbuild/netbsd-arm64": "0.27.3",
|
"@esbuild/netbsd-arm64": "0.25.12",
|
||||||
"@esbuild/netbsd-x64": "0.27.3",
|
"@esbuild/netbsd-x64": "0.25.12",
|
||||||
"@esbuild/openbsd-arm64": "0.27.3",
|
"@esbuild/openbsd-arm64": "0.25.12",
|
||||||
"@esbuild/openbsd-x64": "0.27.3",
|
"@esbuild/openbsd-x64": "0.25.12",
|
||||||
"@esbuild/openharmony-arm64": "0.27.3",
|
"@esbuild/openharmony-arm64": "0.25.12",
|
||||||
"@esbuild/sunos-x64": "0.27.3",
|
"@esbuild/sunos-x64": "0.25.12",
|
||||||
"@esbuild/win32-arm64": "0.27.3",
|
"@esbuild/win32-arm64": "0.25.12",
|
||||||
"@esbuild/win32-ia32": "0.27.3",
|
"@esbuild/win32-ia32": "0.25.12",
|
||||||
"@esbuild/win32-x64": "0.27.3"
|
"@esbuild/win32-x64": "0.25.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escape-string-regexp": {
|
"node_modules/escape-string-regexp": {
|
||||||
@@ -1138,6 +1171,490 @@
|
|||||||
"fsevents": "~2.3.3"
|
"fsevents": "~2.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"aix"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/openharmony-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx/node_modules/esbuild": {
|
||||||
|
"version": "0.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
|
||||||
|
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.27.3",
|
||||||
|
"@esbuild/android-arm": "0.27.3",
|
||||||
|
"@esbuild/android-arm64": "0.27.3",
|
||||||
|
"@esbuild/android-x64": "0.27.3",
|
||||||
|
"@esbuild/darwin-arm64": "0.27.3",
|
||||||
|
"@esbuild/darwin-x64": "0.27.3",
|
||||||
|
"@esbuild/freebsd-arm64": "0.27.3",
|
||||||
|
"@esbuild/freebsd-x64": "0.27.3",
|
||||||
|
"@esbuild/linux-arm": "0.27.3",
|
||||||
|
"@esbuild/linux-arm64": "0.27.3",
|
||||||
|
"@esbuild/linux-ia32": "0.27.3",
|
||||||
|
"@esbuild/linux-loong64": "0.27.3",
|
||||||
|
"@esbuild/linux-mips64el": "0.27.3",
|
||||||
|
"@esbuild/linux-ppc64": "0.27.3",
|
||||||
|
"@esbuild/linux-riscv64": "0.27.3",
|
||||||
|
"@esbuild/linux-s390x": "0.27.3",
|
||||||
|
"@esbuild/linux-x64": "0.27.3",
|
||||||
|
"@esbuild/netbsd-arm64": "0.27.3",
|
||||||
|
"@esbuild/netbsd-x64": "0.27.3",
|
||||||
|
"@esbuild/openbsd-arm64": "0.27.3",
|
||||||
|
"@esbuild/openbsd-x64": "0.27.3",
|
||||||
|
"@esbuild/openharmony-arm64": "0.27.3",
|
||||||
|
"@esbuild/sunos-x64": "0.27.3",
|
||||||
|
"@esbuild/win32-arm64": "0.27.3",
|
||||||
|
"@esbuild/win32-ia32": "0.27.3",
|
||||||
|
"@esbuild/win32-x64": "0.27.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "4.41.0",
|
"version": "4.41.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
|
||||||
@@ -1234,6 +1751,7 @@
|
|||||||
"version": "4.3.6",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
||||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||||
|
"inBundle": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
|
|||||||
+29
-4
@@ -1,24 +1,49 @@
|
|||||||
{
|
{
|
||||||
"name": "goose-text",
|
"name": "@block/goose",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"description": "Goose - an open-source AI agent",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/block/goose.git"
|
||||||
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"goose": "dist/tui.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"scripts/postinstall.mjs",
|
||||||
|
"server-binary.json"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "tsx src/cli.tsx",
|
"start": "tsx src/tui.tsx",
|
||||||
|
"postinstall": "node scripts/postinstall.mjs",
|
||||||
"lint": "tsc --noEmit"
|
"lint": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agentclientprotocol/sdk": "^0.14.1",
|
"@agentclientprotocol/sdk": "^0.14.1",
|
||||||
"@goose/acp": "file:../acp",
|
"@block/goose-acp": "^0.1.0",
|
||||||
"ink": "^5.1.0",
|
"ink": "^5.1.0",
|
||||||
"ink-text-input": "^6.0.0",
|
"ink-text-input": "^6.0.0",
|
||||||
|
"marked": "^15.0.12",
|
||||||
|
"marked-terminal": "^7.3.0",
|
||||||
"meow": "^13.2.0",
|
"meow": "^13.2.0",
|
||||||
"react": "^18.3.1"
|
"react": "^18.3.1"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@block/goose-acp-server-darwin-arm64": "0.1.0",
|
||||||
|
"@block/goose-acp-server-darwin-x64": "0.1.0",
|
||||||
|
"@block/goose-acp-server-linux-arm64": "0.1.0",
|
||||||
|
"@block/goose-acp-server-linux-x64": "0.1.0",
|
||||||
|
"@block/goose-acp-server-win32-x64": "0.1.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/marked-terminal": "^6.1.1",
|
||||||
"@types/node": "^25.2.3",
|
"@types/node": "^25.2.3",
|
||||||
"@types/react": "^18.3.0",
|
"@types/react": "^18.3.0",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.7.0"
|
"typescript": "^5.7.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Builds the goose-acp-server binary for each target platform and places it
|
||||||
|
# into the corresponding npm package directory under npm/.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./ui/text/scripts/build-native-packages.sh # build all targets
|
||||||
|
# ./ui/text/scripts/build-native-packages.sh darwin-arm64 # build one target
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - Rust cross-compilation toolchains installed for each target
|
||||||
|
# - Run from the repository root
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||||
|
NPM_DIR="${REPO_ROOT}/npm"
|
||||||
|
|
||||||
|
declare -A RUST_TARGETS=(
|
||||||
|
["darwin-arm64"]="aarch64-apple-darwin"
|
||||||
|
["darwin-x64"]="x86_64-apple-darwin"
|
||||||
|
["linux-arm64"]="aarch64-unknown-linux-gnu"
|
||||||
|
["linux-x64"]="x86_64-unknown-linux-gnu"
|
||||||
|
["win32-x64"]="x86_64-pc-windows-msvc"
|
||||||
|
)
|
||||||
|
|
||||||
|
build_target() {
|
||||||
|
local platform="$1"
|
||||||
|
local rust_target="${RUST_TARGETS[$platform]}"
|
||||||
|
local pkg_dir="${NPM_DIR}/goose-acp-server-${platform}"
|
||||||
|
local bin_dir="${pkg_dir}/bin"
|
||||||
|
|
||||||
|
echo "==> Building goose-acp-server for ${platform} (${rust_target})"
|
||||||
|
|
||||||
|
cargo build --release --target "${rust_target}" --bin goose-acp-server
|
||||||
|
|
||||||
|
mkdir -p "${bin_dir}"
|
||||||
|
|
||||||
|
local ext=""
|
||||||
|
if [[ "$platform" == win32-* ]]; then
|
||||||
|
ext=".exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp "${REPO_ROOT}/target/${rust_target}/release/goose-acp-server${ext}" "${bin_dir}/goose-acp-server${ext}"
|
||||||
|
chmod +x "${bin_dir}/goose-acp-server${ext}"
|
||||||
|
|
||||||
|
echo " Placed binary at ${bin_dir}/goose-acp-server${ext}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
# Build specific target(s)
|
||||||
|
for target in "$@"; do
|
||||||
|
if [[ -z "${RUST_TARGETS[$target]+x}" ]]; then
|
||||||
|
echo "Unknown target: ${target}"
|
||||||
|
echo "Valid targets: ${!RUST_TARGETS[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
build_target "$target"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# Build all targets
|
||||||
|
for platform in "${!RUST_TARGETS[@]}"; do
|
||||||
|
build_target "$platform"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Done. Native packages staged in ${NPM_DIR}/"
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// Resolves the path to the goose-acp-server binary from the platform-specific
|
||||||
|
// optional dependency. Writes the result to a JSON file that the CLI reads at
|
||||||
|
// startup so it can spawn the server automatically.
|
||||||
|
|
||||||
|
import { writeFileSync, mkdirSync } from "node:fs";
|
||||||
|
import { createRequire } from "node:module";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
const PLATFORMS = {
|
||||||
|
"darwin-arm64": "@block/goose-acp-server-darwin-arm64",
|
||||||
|
"darwin-x64": "@block/goose-acp-server-darwin-x64",
|
||||||
|
"linux-arm64": "@block/goose-acp-server-linux-arm64",
|
||||||
|
"linux-x64": "@block/goose-acp-server-linux-x64",
|
||||||
|
"win32-x64": "@block/goose-acp-server-win32-x64",
|
||||||
|
};
|
||||||
|
|
||||||
|
const key = `${process.platform}-${process.arch}`;
|
||||||
|
const pkg = PLATFORMS[key];
|
||||||
|
|
||||||
|
if (!pkg) {
|
||||||
|
console.warn(
|
||||||
|
`@block/goose: no prebuilt goose-acp-server binary for ${key}. ` +
|
||||||
|
`You will need to provide a server URL manually with --server.`,
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let binaryPath;
|
||||||
|
try {
|
||||||
|
// Resolve the package directory, then point at the binary inside it
|
||||||
|
const pkgDir = dirname(require.resolve(`${pkg}/package.json`));
|
||||||
|
const binName =
|
||||||
|
process.platform === "win32" ? "goose-acp-server.exe" : "goose-acp-server";
|
||||||
|
binaryPath = join(pkgDir, "bin", binName);
|
||||||
|
} catch {
|
||||||
|
// The optional dependency wasn't installed (e.g. wrong platform). That's fine.
|
||||||
|
console.warn(
|
||||||
|
`@block/goose: optional dependency ${pkg} not installed. ` +
|
||||||
|
`You will need to provide a server URL manually with --server.`,
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const outDir = join(__dirname, "..");
|
||||||
|
mkdirSync(outDir, { recursive: true });
|
||||||
|
writeFileSync(
|
||||||
|
join(outDir, "server-binary.json"),
|
||||||
|
JSON.stringify({ binaryPath }, null, 2) + "\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`@block/goose: found native server binary at ${binaryPath}`);
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
import React from "react";
|
|
||||||
import { render } from "ink";
|
|
||||||
import meow from "meow";
|
|
||||||
import App from "./app.js";
|
|
||||||
|
|
||||||
const cli = meow(
|
|
||||||
`
|
|
||||||
Usage
|
|
||||||
$ goose-text
|
|
||||||
|
|
||||||
Options
|
|
||||||
--server, -s Server URL (default: http://127.0.0.1:3284)
|
|
||||||
--text, -t Send a single prompt and exit
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
importMeta: import.meta,
|
|
||||||
flags: {
|
|
||||||
server: { type: "string", shortFlag: "s", default: "http://127.0.0.1:3284" },
|
|
||||||
text: { type: "string", shortFlag: "t" },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
render(<App serverUrl={cli.flags.server} initialPrompt={cli.flags.text} />);
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const CRANBERRY = "#C0354A";
|
||||||
|
export const TEAL = "#3A7D7B";
|
||||||
|
export const GOLD = "#C4883A";
|
||||||
|
export const TEXT_PRIMARY = "#E8E4DF";
|
||||||
|
export const TEXT_SECONDARY = "#8FA4BD";
|
||||||
|
export const TEXT_DIM = "#5A6D84";
|
||||||
|
export const RULE_COLOR = "#2E3D54";
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { marked } from "marked";
|
||||||
|
import { markedTerminal } from "marked-terminal";
|
||||||
|
|
||||||
|
marked.use(markedTerminal({ width: 76, reflowText: true, tab: 2 }) as any);
|
||||||
|
|
||||||
|
export function renderMarkdown(src: string): string {
|
||||||
|
if (!src) return "";
|
||||||
|
const rendered = marked.parse(src) as string;
|
||||||
|
return rendered.replace(/\n+$/, "");
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Box, Text } from "ink";
|
||||||
|
import type {
|
||||||
|
ToolCallContent,
|
||||||
|
ToolCallStatus,
|
||||||
|
ToolKind,
|
||||||
|
} from "@agentclientprotocol/sdk";
|
||||||
|
import { CRANBERRY, TEAL, GOLD, TEXT_SECONDARY, TEXT_DIM } from "./colors.js";
|
||||||
|
|
||||||
|
export interface ToolCallInfo {
|
||||||
|
toolCallId: string;
|
||||||
|
title: string;
|
||||||
|
status: ToolCallStatus;
|
||||||
|
kind?: ToolKind;
|
||||||
|
rawInput?: unknown;
|
||||||
|
rawOutput?: unknown;
|
||||||
|
content?: ToolCallContent[];
|
||||||
|
locations?: Array<{ path: string; line?: number | null }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CEDAR = "#6B5344";
|
||||||
|
|
||||||
|
const KIND_ICONS: Record<string, string> = {
|
||||||
|
read: "📖",
|
||||||
|
edit: "✏️",
|
||||||
|
delete: "🗑",
|
||||||
|
move: "📦",
|
||||||
|
search: "🔍",
|
||||||
|
execute: "▶",
|
||||||
|
think: "💭",
|
||||||
|
fetch: "🌐",
|
||||||
|
switch_mode: "🔀",
|
||||||
|
other: "⚙",
|
||||||
|
};
|
||||||
|
|
||||||
|
const STATUS_INDICATORS: Record<string, { icon: string; color: string }> = {
|
||||||
|
pending: { icon: "○", color: TEXT_DIM },
|
||||||
|
in_progress: { icon: "◑", color: GOLD },
|
||||||
|
completed: { icon: "●", color: TEAL },
|
||||||
|
failed: { icon: "✗", color: CRANBERRY },
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatJsonCompact(value: unknown, maxWidth: number): string[] {
|
||||||
|
if (value === undefined || value === null) return [];
|
||||||
|
let raw: string;
|
||||||
|
try {
|
||||||
|
raw = JSON.stringify(value, null, 2);
|
||||||
|
} catch {
|
||||||
|
raw = String(value);
|
||||||
|
}
|
||||||
|
const lines = raw.split("\n");
|
||||||
|
const result: string[] = [];
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line.length <= maxWidth) {
|
||||||
|
result.push(line);
|
||||||
|
} else {
|
||||||
|
let remaining = line;
|
||||||
|
while (remaining.length > maxWidth) {
|
||||||
|
result.push(remaining.slice(0, maxWidth));
|
||||||
|
remaining = remaining.slice(maxWidth);
|
||||||
|
}
|
||||||
|
if (remaining) result.push(remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTextFromContent(content: ToolCallContent[]): string[] {
|
||||||
|
const lines: string[] = [];
|
||||||
|
for (const item of content) {
|
||||||
|
if (item.type === "content" && item.content) {
|
||||||
|
const block = item.content as any;
|
||||||
|
if (block.type === "text" && block.text) {
|
||||||
|
lines.push(...block.text.split("\n"));
|
||||||
|
}
|
||||||
|
} else if (item.type === "diff") {
|
||||||
|
const diff = item as any;
|
||||||
|
lines.push(`diff: ${diff.path || "unknown"}`);
|
||||||
|
} else if (item.type === "terminal") {
|
||||||
|
const term = item as any;
|
||||||
|
lines.push(`terminal: ${term.terminalId || "unknown"}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
function summarizeContent(info: ToolCallInfo): string {
|
||||||
|
const parts: string[] = [];
|
||||||
|
|
||||||
|
if (info.locations && info.locations.length > 0) {
|
||||||
|
for (const loc of info.locations) {
|
||||||
|
parts.push(loc.path + (loc.line ? `:${loc.line}` : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.content && info.content.length > 0) {
|
||||||
|
const textLines = extractTextFromContent(info.content);
|
||||||
|
if (textLines.length > 0) {
|
||||||
|
const first = textLines[0]!.trim();
|
||||||
|
if (first.length > 60) {
|
||||||
|
parts.push(first.slice(0, 57) + "…");
|
||||||
|
} else if (first) {
|
||||||
|
parts.push(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.length === 0 && info.rawOutput !== undefined && info.rawOutput !== null) {
|
||||||
|
const raw = String(
|
||||||
|
typeof info.rawOutput === "string" ? info.rawOutput : JSON.stringify(info.rawOutput),
|
||||||
|
);
|
||||||
|
const firstLine = raw.split("\n")[0] ?? "";
|
||||||
|
if (firstLine.length > 60) {
|
||||||
|
parts.push(firstLine.slice(0, 57) + "…");
|
||||||
|
} else if (firstLine) {
|
||||||
|
parts.push(firstLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(" · ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_PREVIEW_LINES = 8;
|
||||||
|
|
||||||
|
export function findFeaturedToolCallId(
|
||||||
|
toolCallOrder: string[],
|
||||||
|
toolCalls: Map<string, ToolCallInfo>,
|
||||||
|
): string | undefined {
|
||||||
|
for (let i = toolCallOrder.length - 1; i >= 0; i--) {
|
||||||
|
const tc = toolCalls.get(toolCallOrder[i]!);
|
||||||
|
if (tc && (tc.status === "pending" || tc.status === "in_progress")) {
|
||||||
|
return toolCallOrder[i]!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toolCallOrder[toolCallOrder.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildToolCallCardLines(
|
||||||
|
info: ToolCallInfo,
|
||||||
|
indent: number,
|
||||||
|
totalWidth: number,
|
||||||
|
expanded: boolean,
|
||||||
|
keyPrefix: string = "card",
|
||||||
|
): React.ReactNode[] {
|
||||||
|
const cardWidth = Math.min(totalWidth - indent - 2, 72);
|
||||||
|
const innerWidth = cardWidth - 2;
|
||||||
|
const contentWidth = innerWidth - 2;
|
||||||
|
const kindIcon = KIND_ICONS[info.kind ?? "other"] ?? "⚙";
|
||||||
|
const statusInfo = STATUS_INDICATORS[info.status] ?? STATUS_INDICATORS.pending!;
|
||||||
|
const borderColor = info.status === "failed" ? CRANBERRY : CEDAR;
|
||||||
|
const dimBorder = info.status !== "failed";
|
||||||
|
|
||||||
|
const hasInput = info.rawInput !== undefined && info.rawInput !== null;
|
||||||
|
const hasOutput = info.rawOutput !== undefined && info.rawOutput !== null;
|
||||||
|
const hasContent = info.content && info.content.length > 0;
|
||||||
|
const hasLocations = info.locations && info.locations.length > 0;
|
||||||
|
|
||||||
|
const inputLines = hasInput ? formatJsonCompact(info.rawInput, contentWidth - 6) : [];
|
||||||
|
const outputLines = hasOutput ? formatJsonCompact(info.rawOutput, contentWidth - 6) : [];
|
||||||
|
const contentLines = hasContent ? extractTextFromContent(info.content!) : [];
|
||||||
|
|
||||||
|
const shownInput = expanded ? inputLines : inputLines.slice(0, MAX_PREVIEW_LINES);
|
||||||
|
const shownOutput = expanded ? outputLines : outputLines.slice(0, MAX_PREVIEW_LINES);
|
||||||
|
const shownContent = expanded ? contentLines : contentLines.slice(0, MAX_PREVIEW_LINES);
|
||||||
|
|
||||||
|
const hasTruncated =
|
||||||
|
inputLines.length > MAX_PREVIEW_LINES ||
|
||||||
|
outputLines.length > MAX_PREVIEW_LINES ||
|
||||||
|
contentLines.length > MAX_PREVIEW_LINES;
|
||||||
|
|
||||||
|
const bodyRows: Array<{ text: string; color?: string; italic?: boolean }> = [];
|
||||||
|
|
||||||
|
const runningText = info.status === "in_progress" ? " running…" : "";
|
||||||
|
const tabHint = hasTruncated && !expanded ? "tab ↔" : "";
|
||||||
|
bodyRows.push({ text: "__HEADER__" });
|
||||||
|
|
||||||
|
if (hasLocations) {
|
||||||
|
for (const loc of info.locations!) {
|
||||||
|
bodyRows.push({ text: ` 📁 ${loc.path}${loc.line ? `:${loc.line}` : ""}`, color: TEXT_DIM });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSection(label: string, lines: string[], totalCount: number) {
|
||||||
|
if (lines.length === 0) return;
|
||||||
|
bodyRows.push({ text: ` ▸ ${label}:`, color: TEXT_DIM });
|
||||||
|
for (const line of lines) {
|
||||||
|
bodyRows.push({ text: ` ${line}`, color: TEXT_DIM });
|
||||||
|
}
|
||||||
|
if (!expanded && totalCount > MAX_PREVIEW_LINES) {
|
||||||
|
const remaining = totalCount - MAX_PREVIEW_LINES;
|
||||||
|
bodyRows.push({ text: ` ▸ ${remaining} more lines (tab to expand)`, color: GOLD, italic: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSection("input", shownInput, inputLines.length);
|
||||||
|
addSection("output", shownOutput, outputLines.length);
|
||||||
|
addSection("content", shownContent, contentLines.length);
|
||||||
|
|
||||||
|
const result: React.ReactNode[] = [];
|
||||||
|
const topBorder = "╭" + "─".repeat(innerWidth) + "╮";
|
||||||
|
const botBorder = "╰" + "─".repeat(innerWidth) + "╯";
|
||||||
|
|
||||||
|
result.push(
|
||||||
|
<Box key={`${keyPrefix}-top`} marginLeft={indent} height={1}>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}>{topBorder}</Text>
|
||||||
|
</Box>,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < bodyRows.length; i++) {
|
||||||
|
const row = bodyRows[i]!;
|
||||||
|
|
||||||
|
if (row.text === "__HEADER__") {
|
||||||
|
result.push(
|
||||||
|
<Box key={`${keyPrefix}-row-${i}`} marginLeft={indent} width={cardWidth} height={1}>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}>│ </Text>
|
||||||
|
<Box flexGrow={1} justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Text color={statusInfo.color}>{statusInfo.icon} </Text>
|
||||||
|
<Text>{kindIcon} </Text>
|
||||||
|
<Text color={TEXT_SECONDARY} bold>{info.title}</Text>
|
||||||
|
{runningText ? <Text color={TEXT_DIM} italic>{runningText}</Text> : null}
|
||||||
|
</Box>
|
||||||
|
{tabHint ? <Text color={TEXT_DIM} italic>{tabHint}</Text> : null}
|
||||||
|
</Box>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}> │</Text>
|
||||||
|
</Box>,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(
|
||||||
|
<Box key={`${keyPrefix}-row-${i}`} marginLeft={indent} width={cardWidth} height={1}>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}>│</Text>
|
||||||
|
<Box flexGrow={1}>
|
||||||
|
<Text color={row.color} italic={row.italic}> {row.text}</Text>
|
||||||
|
</Box>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}>│</Text>
|
||||||
|
</Box>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(
|
||||||
|
<Box key={`${keyPrefix}-bot`} marginLeft={indent} height={1}>
|
||||||
|
<Text color={borderColor} dimColor={dimBorder}>{botBorder}</Text>
|
||||||
|
</Box>,
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ToolCallCompact({
|
||||||
|
info,
|
||||||
|
indent,
|
||||||
|
width,
|
||||||
|
}: {
|
||||||
|
info: ToolCallInfo;
|
||||||
|
indent: number;
|
||||||
|
width: number;
|
||||||
|
}) {
|
||||||
|
const statusInfo = STATUS_INDICATORS[info.status] ?? STATUS_INDICATORS.pending!;
|
||||||
|
const kindIcon = KIND_ICONS[info.kind ?? "other"] ?? "⚙";
|
||||||
|
const summary = summarizeContent(info);
|
||||||
|
const maxSummaryWidth = width - indent - 12 - info.title.length;
|
||||||
|
const trimmedSummary =
|
||||||
|
summary.length > maxSummaryWidth && maxSummaryWidth > 3
|
||||||
|
? summary.slice(0, maxSummaryWidth - 1) + "…"
|
||||||
|
: summary;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box marginLeft={indent} height={1}>
|
||||||
|
<Text color={statusInfo.color}>{statusInfo.icon} </Text>
|
||||||
|
<Text>{kindIcon} </Text>
|
||||||
|
<Text color={TEXT_SECONDARY}>{info.title}</Text>
|
||||||
|
{trimmedSummary ? (
|
||||||
|
<Text color={TEXT_DIM}> — {trimmedSummary}</Text>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,26 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||||
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
import { Box, Text, render, useApp, useInput, useStdout, measureElement } from "ink";
|
||||||
|
import type { DOMElement } from "ink";
|
||||||
import TextInput from "ink-text-input";
|
import TextInput from "ink-text-input";
|
||||||
|
import meow from "meow";
|
||||||
|
import { spawn } from "node:child_process";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
import type {
|
import type {
|
||||||
SessionNotification,
|
SessionNotification,
|
||||||
RequestPermissionRequest,
|
RequestPermissionRequest,
|
||||||
RequestPermissionResponse,
|
RequestPermissionResponse,
|
||||||
|
ToolCallContent,
|
||||||
|
ToolCallStatus,
|
||||||
|
ToolKind,
|
||||||
} from "@agentclientprotocol/sdk";
|
} from "@agentclientprotocol/sdk";
|
||||||
import { GooseClient } from "@goose/acp";
|
import { GooseClient } from "@block/goose-acp";
|
||||||
import { createHttpStream } from "./transport.js";
|
import { renderMarkdown } from "./markdown.js";
|
||||||
|
import { buildToolCallCardLines, ToolCallCompact, findFeaturedToolCallId } from "./toolcall.js";
|
||||||
|
import type { ToolCallInfo } from "./toolcall.js";
|
||||||
|
import { CRANBERRY, TEAL, GOLD, TEXT_PRIMARY, TEXT_SECONDARY, TEXT_DIM, RULE_COLOR } from "./colors.js";
|
||||||
|
|
||||||
interface PendingPermission {
|
interface PendingPermission {
|
||||||
toolTitle: string;
|
toolTitle: string;
|
||||||
@@ -15,15 +28,16 @@ interface PendingPermission {
|
|||||||
resolve: (response: RequestPermissionResponse) => void;
|
resolve: (response: RequestPermissionResponse) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRANBERRY = "#C0354A";
|
interface Turn {
|
||||||
const TEAL = "#3A7D7B";
|
userText: string;
|
||||||
const GOLD = "#C4883A";
|
toolCalls: Map<string, ToolCallInfo>;
|
||||||
const CEDAR = "#6B5344";
|
toolCallOrder: string[];
|
||||||
|
agentText: string;
|
||||||
|
}
|
||||||
|
|
||||||
const TEXT_PRIMARY = "#E8E4DF";
|
function isErrorStatus(status: string): boolean {
|
||||||
const TEXT_SECONDARY = "#8FA4BD";
|
return status.startsWith("error") || status.startsWith("failed");
|
||||||
const TEXT_DIM = "#5A6D84";
|
}
|
||||||
const RULE_COLOR = "#2E3D54";
|
|
||||||
|
|
||||||
const GOOSE_FRAMES = [
|
const GOOSE_FRAMES = [
|
||||||
[
|
[
|
||||||
@@ -104,30 +118,11 @@ const PERMISSION_KEYS: Record<string, string> = {
|
|||||||
reject_always: "N",
|
reject_always: "N",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Turn {
|
|
||||||
userText: string;
|
|
||||||
toolCalls: string[];
|
|
||||||
agentText: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Layout constants ───────────────────────────────────────────────────────
|
|
||||||
//
|
|
||||||
// Every element indents by a multiple of INDENT (3 spaces). This keeps the
|
|
||||||
// left edge of user prompts, agent prose, and tool-call badges on a
|
|
||||||
// predictable grid so the eye can scan vertically without friction.
|
|
||||||
//
|
|
||||||
// col 0 rule / header
|
|
||||||
// col 3 user prompt caret + text, input caret + text
|
|
||||||
// col 5 agent prose, tool badges, loading spinner, permission dialog
|
|
||||||
|
|
||||||
const INDENT = 3;
|
const INDENT = 3;
|
||||||
const CONTENT_INDENT = 5;
|
const CONTENT_INDENT = 5;
|
||||||
const MAX_PROSE_WIDTH = 76;
|
|
||||||
|
|
||||||
function Rule({ width }: { width: number }) {
|
function Rule({ width }: { width: number }) {
|
||||||
return (
|
return <Text color={RULE_COLOR}>{"─".repeat(Math.max(width, 1))}</Text>;
|
||||||
<Text color={RULE_COLOR}>{"─".repeat(Math.max(width, 1))}</Text>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Spinner({ idx }: { idx: number }) {
|
function Spinner({ idx }: { idx: number }) {
|
||||||
@@ -153,9 +148,7 @@ function Header({
|
|||||||
hasPendingPermission: boolean;
|
hasPendingPermission: boolean;
|
||||||
turnInfo?: { current: number; total: number };
|
turnInfo?: { current: number; total: number };
|
||||||
}) {
|
}) {
|
||||||
const isError =
|
const statusColor = status === "ready" ? TEAL : isErrorStatus(status) ? CRANBERRY : TEXT_DIM;
|
||||||
status.startsWith("error") || status.startsWith("failed");
|
|
||||||
const statusColor = status === "ready" ? TEAL : isError ? CRANBERRY : TEXT_DIM;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box flexDirection="column" width={width}>
|
<Box flexDirection="column" width={width}>
|
||||||
@@ -167,7 +160,10 @@ function Header({
|
|||||||
<Text color={RULE_COLOR}> · </Text>
|
<Text color={RULE_COLOR}> · </Text>
|
||||||
<Text color={statusColor}>{status}</Text>
|
<Text color={statusColor}>{status}</Text>
|
||||||
{loading && !hasPendingPermission && (
|
{loading && !hasPendingPermission && (
|
||||||
<Text> <Spinner idx={spinIdx} /></Text>
|
<Text>
|
||||||
|
{" "}
|
||||||
|
<Spinner idx={spinIdx} />
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -198,25 +194,6 @@ function UserPrompt({ text }: { text: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolBadge({ title, width }: { title: string; width: number }) {
|
|
||||||
const badgeWidth = Math.min(width - CONTENT_INDENT - 2, 68);
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
marginLeft={CONTENT_INDENT}
|
|
||||||
paddingX={1}
|
|
||||||
borderStyle="round"
|
|
||||||
borderColor={CEDAR}
|
|
||||||
borderDimColor
|
|
||||||
width={badgeWidth}
|
|
||||||
>
|
|
||||||
<Text color={TEAL}>⚙ </Text>
|
|
||||||
<Text color={TEXT_SECONDARY} italic>
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function PermissionDialog({
|
function PermissionDialog({
|
||||||
toolTitle,
|
toolTitle,
|
||||||
options,
|
options,
|
||||||
@@ -286,16 +263,6 @@ function QueuedMessage({ text }: { text: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputBarHeight(input: string, width: number, queued: boolean): number {
|
|
||||||
// Inner text width: width minus border (2), paddingX (2), prompt "❯ " (2)
|
|
||||||
const textWidth = Math.max(width - 2 - 2 - 2, 1);
|
|
||||||
// +1 for the trailing cursor character
|
|
||||||
const contentLen = input.length + 1;
|
|
||||||
const wrappedLines = Math.max(Math.ceil(contentLen / textWidth), 1);
|
|
||||||
const queuedLine = queued ? 1 : 0;
|
|
||||||
return 2 + wrappedLines + queuedLine + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function InputBar({
|
function InputBar({
|
||||||
width,
|
width,
|
||||||
input,
|
input,
|
||||||
@@ -327,9 +294,7 @@ function InputBar({
|
|||||||
</Text>
|
</Text>
|
||||||
<TextInput value={input} onChange={onChange} onSubmit={onSubmit} />
|
<TextInput value={input} onChange={onChange} onSubmit={onSubmit} />
|
||||||
</Box>
|
</Box>
|
||||||
{scrollHint && (
|
{scrollHint && <Text color={TEXT_DIM}>shift+↑↓ history</Text>}
|
||||||
<Text color={TEXT_DIM}>shift+↑↓ history</Text>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
{queued && (
|
{queued && (
|
||||||
<Box>
|
<Box>
|
||||||
@@ -343,77 +308,70 @@ function InputBar({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapText(text: string, width: number): string[] {
|
function buildTurnBodyLines({
|
||||||
if (width <= 0) return [text];
|
|
||||||
const result: string[] = [];
|
|
||||||
for (const rawLine of text.split("\n")) {
|
|
||||||
if (rawLine.length === 0) {
|
|
||||||
result.push("");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let remaining = rawLine;
|
|
||||||
while (remaining.length > width) {
|
|
||||||
let breakAt = remaining.lastIndexOf(" ", width);
|
|
||||||
if (breakAt <= 0) breakAt = width;
|
|
||||||
result.push(remaining.slice(0, breakAt));
|
|
||||||
remaining = remaining.slice(breakAt).replace(/^ /, "");
|
|
||||||
}
|
|
||||||
result.push(remaining);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TurnResponseBody({
|
|
||||||
turn,
|
turn,
|
||||||
width,
|
width,
|
||||||
height,
|
|
||||||
scrollOffset,
|
|
||||||
loading,
|
loading,
|
||||||
status,
|
status,
|
||||||
spinIdx,
|
spinIdx,
|
||||||
pendingPermission,
|
pendingPermission,
|
||||||
permissionIdx,
|
permissionIdx,
|
||||||
|
expandedToolCall,
|
||||||
}: {
|
}: {
|
||||||
turn: Turn;
|
turn: Turn;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
|
||||||
scrollOffset: number;
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
spinIdx: number;
|
spinIdx: number;
|
||||||
pendingPermission: PendingPermission | null;
|
pendingPermission: PendingPermission | null;
|
||||||
permissionIdx: number;
|
permissionIdx: number;
|
||||||
}) {
|
expandedToolCall: string | null;
|
||||||
const allLines: React.ReactNode[] = [];
|
}): React.ReactNode[] {
|
||||||
const proseWidth = Math.min(width - CONTENT_INDENT - 1, MAX_PROSE_WIDTH);
|
const toolCallIds = turn.toolCallOrder;
|
||||||
|
const toolCalls = turn.toolCalls;
|
||||||
|
const featuredId = findFeaturedToolCallId(toolCallIds, toolCalls);
|
||||||
|
|
||||||
// blank line between user prompt and response content
|
const lines: React.ReactNode[] = [];
|
||||||
allLines.push(<Box key="gap-top" height={1} />);
|
|
||||||
|
|
||||||
for (const tc of turn.toolCalls) {
|
lines.push(<Box key="gap-top" height={1} />);
|
||||||
allLines.push(
|
|
||||||
<ToolBadge key={`tc-${allLines.length}`} title={tc} width={width} />,
|
for (const tcId of toolCallIds) {
|
||||||
);
|
const tc = toolCalls.get(tcId);
|
||||||
|
if (!tc) continue;
|
||||||
|
|
||||||
|
if (tcId === featuredId || expandedToolCall === tcId) {
|
||||||
|
const cardLines = buildToolCallCardLines(tc, CONTENT_INDENT, width, expandedToolCall === tcId, `tc-${tcId}`);
|
||||||
|
lines.push(...cardLines);
|
||||||
|
} else {
|
||||||
|
lines.push(
|
||||||
|
<ToolCallCompact
|
||||||
|
key={`tc-${tcId}`}
|
||||||
|
info={tc}
|
||||||
|
indent={CONTENT_INDENT}
|
||||||
|
width={width}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (turn.agentText) {
|
if (turn.agentText) {
|
||||||
// visual break between tool calls and prose
|
if (toolCallIds.length > 0) {
|
||||||
if (turn.toolCalls.length > 0) {
|
lines.push(<Box key="gap-agent" height={1} />);
|
||||||
allLines.push(<Box key="gap-tools" height={1} />);
|
|
||||||
}
|
}
|
||||||
const wrapped = wrapText(turn.agentText, proseWidth);
|
const rendered = renderMarkdown(turn.agentText);
|
||||||
for (const line of wrapped) {
|
const mdLines = rendered.split("\n");
|
||||||
allLines.push(
|
for (let i = 0; i < mdLines.length; i++) {
|
||||||
<Box key={`al-${allLines.length}`} paddingLeft={CONTENT_INDENT}>
|
lines.push(
|
||||||
<Text color={TEXT_PRIMARY}>{line}</Text>
|
<Box key={`md-${i}`} paddingLeft={CONTENT_INDENT}>
|
||||||
|
<Text>{mdLines[i]}</Text>
|
||||||
</Box>,
|
</Box>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading && !pendingPermission) {
|
if (loading && !pendingPermission) {
|
||||||
allLines.push(
|
lines.push(
|
||||||
<Box key={`load-${allLines.length}`} paddingLeft={CONTENT_INDENT} marginTop={turn.agentText ? 0 : 0}>
|
<Box key="loading" paddingLeft={CONTENT_INDENT}>
|
||||||
<Spinner idx={spinIdx} />
|
<Spinner idx={spinIdx} />
|
||||||
<Text color={TEXT_DIM} italic>
|
<Text color={TEXT_DIM} italic>
|
||||||
{" "}
|
{" "}
|
||||||
@@ -424,9 +382,9 @@ function TurnResponseBody({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pendingPermission) {
|
if (pendingPermission) {
|
||||||
allLines.push(
|
lines.push(
|
||||||
<PermissionDialog
|
<PermissionDialog
|
||||||
key={`perm-${allLines.length}`}
|
key="permission"
|
||||||
toolTitle={pendingPermission.toolTitle}
|
toolTitle={pendingPermission.toolTitle}
|
||||||
options={pendingPermission.options}
|
options={pendingPermission.options}
|
||||||
selectedIdx={permissionIdx}
|
selectedIdx={permissionIdx}
|
||||||
@@ -435,25 +393,64 @@ function TurnResponseBody({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalLines = allLines.length;
|
return lines;
|
||||||
const visibleCount = Math.max(height, 1);
|
}
|
||||||
const maxOffset = Math.max(totalLines - visibleCount, 0);
|
|
||||||
const offset = Math.min(Math.max(scrollOffset, 0), maxOffset);
|
function ScrollableBody({
|
||||||
const visible = allLines.slice(offset, offset + visibleCount);
|
lines,
|
||||||
const hasAbove = offset > 0;
|
width,
|
||||||
const hasBelow = offset + visibleCount < totalLines;
|
scrollOffset,
|
||||||
|
}: {
|
||||||
|
lines: React.ReactNode[];
|
||||||
|
width: number;
|
||||||
|
scrollOffset: number;
|
||||||
|
}) {
|
||||||
|
const ref = useRef<DOMElement>(null);
|
||||||
|
const [measured, setMeasured] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
const { height } = measureElement(ref.current);
|
||||||
|
if (height !== measured) setMeasured(height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const total = lines.length;
|
||||||
|
const availableHeight = measured || total;
|
||||||
|
const needsScroll = total > availableHeight;
|
||||||
|
const viewSize = needsScroll
|
||||||
|
? Math.max(availableHeight - 2, 1)
|
||||||
|
: availableHeight;
|
||||||
|
const maxOffset = Math.max(total - viewSize, 0);
|
||||||
|
const clampedOffset = Math.min(Math.max(scrollOffset, 0), maxOffset);
|
||||||
|
const endIdx = total - clampedOffset;
|
||||||
|
const startIdx = Math.max(endIdx - viewSize, 0);
|
||||||
|
const visible = lines.slice(startIdx, endIdx);
|
||||||
|
|
||||||
|
const hiddenAbove = startIdx;
|
||||||
|
const hiddenBelow = Math.max(total - endIdx, 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box flexDirection="column" height={height} overflowY="hidden">
|
<Box ref={ref} flexDirection="column" flexGrow={1}>
|
||||||
{hasAbove && (
|
{needsScroll && (
|
||||||
<Box justifyContent="center" width={width}>
|
<Box justifyContent="center" width={width} height={1}>
|
||||||
<Text color={TEXT_DIM}>▲ more</Text>
|
{hiddenAbove > 0 ? (
|
||||||
|
<Text color={TEXT_DIM}>▲ {hiddenAbove} more (↑)</Text>
|
||||||
|
) : (
|
||||||
|
<Text> </Text>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{visible}
|
<Box flexDirection="column" flexGrow={1} overflowY="hidden">
|
||||||
{hasBelow && !hasAbove && visible.length > 1 && (
|
{visible}
|
||||||
<Box justifyContent="center" width={width}>
|
</Box>
|
||||||
<Text color={TEXT_DIM}>▼ more</Text>
|
{needsScroll && (
|
||||||
|
<Box justifyContent="center" width={width} height={1}>
|
||||||
|
{hiddenBelow > 0 ? (
|
||||||
|
<Text color={TEXT_DIM}>▼ {hiddenBelow} more (↓)</Text>
|
||||||
|
) : (
|
||||||
|
<Text> </Text>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -484,9 +481,7 @@ function SplashScreen({
|
|||||||
onInputSubmit: (v: string) => void;
|
onInputSubmit: (v: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const frame = GOOSE_FRAMES[animFrame % GOOSE_FRAMES.length]!;
|
const frame = GOOSE_FRAMES[animFrame % GOOSE_FRAMES.length]!;
|
||||||
const isError =
|
const statusColor = status === "ready" ? TEAL : isErrorStatus(status) ? CRANBERRY : TEXT_DIM;
|
||||||
status.startsWith("error") || status.startsWith("failed");
|
|
||||||
const statusColor = status === "ready" ? TEAL : isError ? CRANBERRY : TEXT_DIM;
|
|
||||||
const inputWidth = Math.min(56, width - 8);
|
const inputWidth = Math.min(56, width - 8);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -497,7 +492,6 @@ function SplashScreen({
|
|||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
>
|
>
|
||||||
{/* Goose art */}
|
|
||||||
<Box flexDirection="column" alignItems="center">
|
<Box flexDirection="column" alignItems="center">
|
||||||
{frame.map((line, i) => (
|
{frame.map((line, i) => (
|
||||||
<Text key={i} color={TEXT_PRIMARY}>
|
<Text key={i} color={TEXT_PRIMARY}>
|
||||||
@@ -506,7 +500,6 @@ function SplashScreen({
|
|||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Title + subtitle */}
|
|
||||||
<Box marginTop={1}>
|
<Box marginTop={1}>
|
||||||
<Text color={TEXT_PRIMARY} bold>
|
<Text color={TEXT_PRIMARY} bold>
|
||||||
goose
|
goose
|
||||||
@@ -514,7 +507,6 @@ function SplashScreen({
|
|||||||
</Box>
|
</Box>
|
||||||
<Text color={TEXT_DIM}>your on-machine AI agent</Text>
|
<Text color={TEXT_DIM}>your on-machine AI agent</Text>
|
||||||
|
|
||||||
{/* Input or status */}
|
|
||||||
{showInput ? (
|
{showInput ? (
|
||||||
<Box flexDirection="column" alignItems="center" marginTop={2}>
|
<Box flexDirection="column" alignItems="center" marginTop={2}>
|
||||||
<Box width={inputWidth}>
|
<Box width={inputWidth}>
|
||||||
@@ -546,7 +538,7 @@ function SplashScreen({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function App({
|
function App({
|
||||||
serverUrl,
|
serverUrl,
|
||||||
initialPrompt,
|
initialPrompt,
|
||||||
}: {
|
}: {
|
||||||
@@ -571,6 +563,7 @@ export default function App({
|
|||||||
const [queuedMessages, setQueuedMessages] = useState<string[]>([]);
|
const [queuedMessages, setQueuedMessages] = useState<string[]>([]);
|
||||||
|
|
||||||
const [viewTurnIdx, setViewTurnIdx] = useState(-1);
|
const [viewTurnIdx, setViewTurnIdx] = useState(-1);
|
||||||
|
const [expandedToolCall, setExpandedToolCall] = useState<string | null>(null);
|
||||||
const [scrollOffset, setScrollOffset] = useState(0);
|
const [scrollOffset, setScrollOffset] = useState(0);
|
||||||
|
|
||||||
const clientRef = useRef<GooseClient | null>(null);
|
const clientRef = useRef<GooseClient | null>(null);
|
||||||
@@ -592,10 +585,10 @@ export default function App({
|
|||||||
if (turns.length > 0) setBannerVisible(false);
|
if (turns.length > 0) setBannerVisible(false);
|
||||||
}, [turns]);
|
}, [turns]);
|
||||||
|
|
||||||
const turnsLen = turns.length;
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (viewTurnIdx === -1) setScrollOffset(0);
|
setExpandedToolCall(null);
|
||||||
}, [turnsLen, viewTurnIdx]);
|
setScrollOffset(0);
|
||||||
|
}, [viewTurnIdx, turns.length]);
|
||||||
|
|
||||||
const appendAgent = useCallback((text: string) => {
|
const appendAgent = useCallback((text: string) => {
|
||||||
setTurns((prev) => {
|
setTurns((prev) => {
|
||||||
@@ -606,21 +599,89 @@ export default function App({
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const appendToolCall = useCallback((title: string) => {
|
const handleToolCall = useCallback(
|
||||||
setTurns((prev) => {
|
(tc: {
|
||||||
if (prev.length === 0) return prev;
|
toolCallId: string;
|
||||||
const last = { ...prev[prev.length - 1]! };
|
title: string;
|
||||||
last.toolCalls = [...last.toolCalls, title];
|
status?: ToolCallStatus;
|
||||||
return [...prev.slice(0, -1), last];
|
kind?: ToolKind;
|
||||||
});
|
rawInput?: unknown;
|
||||||
}, []);
|
rawOutput?: unknown;
|
||||||
|
content?: ToolCallContent[];
|
||||||
|
locations?: Array<{ path: string; line?: number | null }>;
|
||||||
|
}) => {
|
||||||
|
setTurns((prev) => {
|
||||||
|
if (prev.length === 0) return prev;
|
||||||
|
const last = { ...prev[prev.length - 1]! };
|
||||||
|
const newMap = new Map(last.toolCalls);
|
||||||
|
const info: ToolCallInfo = {
|
||||||
|
toolCallId: tc.toolCallId,
|
||||||
|
title: tc.title,
|
||||||
|
status: tc.status ?? "pending",
|
||||||
|
kind: tc.kind,
|
||||||
|
rawInput: tc.rawInput,
|
||||||
|
rawOutput: tc.rawOutput,
|
||||||
|
content: tc.content,
|
||||||
|
locations: tc.locations,
|
||||||
|
};
|
||||||
|
newMap.set(tc.toolCallId, info);
|
||||||
|
const newOrder = last.toolCallOrder.includes(tc.toolCallId)
|
||||||
|
? last.toolCallOrder
|
||||||
|
: [...last.toolCallOrder, tc.toolCallId];
|
||||||
|
return [
|
||||||
|
...prev.slice(0, -1),
|
||||||
|
{ ...last, toolCalls: newMap, toolCallOrder: newOrder },
|
||||||
|
];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleToolCallUpdate = useCallback(
|
||||||
|
(update: {
|
||||||
|
toolCallId: string;
|
||||||
|
title?: string | null;
|
||||||
|
status?: ToolCallStatus | null;
|
||||||
|
kind?: ToolKind | null;
|
||||||
|
rawInput?: unknown;
|
||||||
|
rawOutput?: unknown;
|
||||||
|
content?: ToolCallContent[] | null;
|
||||||
|
locations?: Array<{ path: string; line?: number | null }> | null;
|
||||||
|
}) => {
|
||||||
|
setTurns((prev) => {
|
||||||
|
if (prev.length === 0) return prev;
|
||||||
|
const last = { ...prev[prev.length - 1]! };
|
||||||
|
const newMap = new Map(last.toolCalls);
|
||||||
|
const existing = newMap.get(update.toolCallId);
|
||||||
|
if (!existing) return prev;
|
||||||
|
const updated: ToolCallInfo = { ...existing };
|
||||||
|
if (update.title != null) updated.title = update.title;
|
||||||
|
if (update.status != null) updated.status = update.status;
|
||||||
|
if (update.kind != null) updated.kind = update.kind;
|
||||||
|
if (update.rawInput !== undefined) updated.rawInput = update.rawInput;
|
||||||
|
if (update.rawOutput !== undefined)
|
||||||
|
updated.rawOutput = update.rawOutput;
|
||||||
|
if (update.content != null) updated.content = update.content;
|
||||||
|
if (update.locations != null) updated.locations = update.locations;
|
||||||
|
newMap.set(update.toolCallId, updated);
|
||||||
|
return [...prev.slice(0, -1), { ...last, toolCalls: newMap }];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const addUserTurn = useCallback((text: string) => {
|
const addUserTurn = useCallback((text: string) => {
|
||||||
setTurns((prev) => [
|
setTurns((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{ userText: text, toolCalls: [], agentText: "" },
|
{
|
||||||
|
userText: text,
|
||||||
|
toolCalls: new Map(),
|
||||||
|
toolCallOrder: [],
|
||||||
|
agentText: "",
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
setViewTurnIdx(-1);
|
setViewTurnIdx(-1);
|
||||||
|
setExpandedToolCall(null);
|
||||||
setScrollOffset(0);
|
setScrollOffset(0);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -641,48 +702,7 @@ export default function App({
|
|||||||
[pendingPermission],
|
[pendingPermission],
|
||||||
);
|
);
|
||||||
|
|
||||||
const processQueue = useCallback(async () => {
|
const executePrompt = useCallback(
|
||||||
if (isProcessingRef.current) return;
|
|
||||||
isProcessingRef.current = true;
|
|
||||||
|
|
||||||
while (queueRef.current.length > 0) {
|
|
||||||
const next = queueRef.current.shift()!;
|
|
||||||
setQueuedMessages([...queueRef.current]);
|
|
||||||
|
|
||||||
const client = clientRef.current;
|
|
||||||
const sid = sessionIdRef.current;
|
|
||||||
if (!client || !sid) break;
|
|
||||||
|
|
||||||
addUserTurn(next);
|
|
||||||
setLoading(true);
|
|
||||||
setStatus("thinking…");
|
|
||||||
streamBuf.current = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await client.prompt({
|
|
||||||
sessionId: sid,
|
|
||||||
prompt: [{ type: "text", text: next }],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (streamBuf.current) appendAgent("");
|
|
||||||
|
|
||||||
setStatus(
|
|
||||||
result.stopReason === "end_turn"
|
|
||||||
? "ready"
|
|
||||||
: `stopped: ${result.stopReason}`,
|
|
||||||
);
|
|
||||||
} catch (e: unknown) {
|
|
||||||
const errMsg = e instanceof Error ? e.message : String(e);
|
|
||||||
setStatus(`error: ${errMsg}`);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isProcessingRef.current = false;
|
|
||||||
}, [appendAgent, addUserTurn]);
|
|
||||||
|
|
||||||
const sendPrompt = useCallback(
|
|
||||||
async (text: string) => {
|
async (text: string) => {
|
||||||
const client = clientRef.current;
|
const client = clientRef.current;
|
||||||
const sid = sessionIdRef.current;
|
const sid = sessionIdRef.current;
|
||||||
@@ -711,10 +731,30 @@ export default function App({
|
|||||||
setStatus(`error: ${errMsg}`);
|
setStatus(`error: ${errMsg}`);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (queueRef.current.length > 0) processQueue();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[appendAgent, addUserTurn, processQueue],
|
[appendAgent, addUserTurn],
|
||||||
|
);
|
||||||
|
|
||||||
|
const processQueue = useCallback(async () => {
|
||||||
|
if (isProcessingRef.current) return;
|
||||||
|
isProcessingRef.current = true;
|
||||||
|
|
||||||
|
while (queueRef.current.length > 0) {
|
||||||
|
const next = queueRef.current.shift()!;
|
||||||
|
setQueuedMessages([...queueRef.current]);
|
||||||
|
await executePrompt(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcessingRef.current = false;
|
||||||
|
}, [executePrompt]);
|
||||||
|
|
||||||
|
const sendPrompt = useCallback(
|
||||||
|
async (text: string) => {
|
||||||
|
await executePrompt(text);
|
||||||
|
if (queueRef.current.length > 0) processQueue();
|
||||||
|
},
|
||||||
|
[executePrompt, processQueue],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -723,7 +763,6 @@ export default function App({
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
setStatus("initializing…");
|
setStatus("initializing…");
|
||||||
const stream = createHttpStream(serverUrl);
|
|
||||||
|
|
||||||
const client = new GooseClient(
|
const client = new GooseClient(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -736,7 +775,27 @@ export default function App({
|
|||||||
appendAgent(update.content.text);
|
appendAgent(update.content.text);
|
||||||
}
|
}
|
||||||
} else if (update.sessionUpdate === "tool_call") {
|
} else if (update.sessionUpdate === "tool_call") {
|
||||||
appendToolCall(update.title || "tool");
|
handleToolCall({
|
||||||
|
toolCallId: update.toolCallId,
|
||||||
|
title: update.title,
|
||||||
|
status: update.status,
|
||||||
|
kind: update.kind,
|
||||||
|
rawInput: update.rawInput,
|
||||||
|
rawOutput: update.rawOutput,
|
||||||
|
content: update.content,
|
||||||
|
locations: update.locations,
|
||||||
|
});
|
||||||
|
} else if (update.sessionUpdate === "tool_call_update") {
|
||||||
|
handleToolCallUpdate({
|
||||||
|
toolCallId: update.toolCallId,
|
||||||
|
title: update.title,
|
||||||
|
status: update.status,
|
||||||
|
kind: update.kind,
|
||||||
|
rawInput: update.rawInput,
|
||||||
|
rawOutput: update.rawOutput,
|
||||||
|
content: update.content,
|
||||||
|
locations: update.locations,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
requestPermission: async (
|
requestPermission: async (
|
||||||
@@ -754,7 +813,7 @@ export default function App({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
stream,
|
serverUrl,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
@@ -783,7 +842,7 @@ export default function App({
|
|||||||
if (initialPrompt && !sentInitialPrompt.current) {
|
if (initialPrompt && !sentInitialPrompt.current) {
|
||||||
sentInitialPrompt.current = true;
|
sentInitialPrompt.current = true;
|
||||||
await sendPrompt(initialPrompt);
|
await sendPrompt(initialPrompt);
|
||||||
if (initialPrompt) setTimeout(() => exit(), 100);
|
setTimeout(() => exit(), 100);
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
@@ -796,7 +855,15 @@ export default function App({
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [serverUrl, initialPrompt, sendPrompt, appendAgent, appendToolCall, exit]);
|
}, [
|
||||||
|
serverUrl,
|
||||||
|
initialPrompt,
|
||||||
|
sendPrompt,
|
||||||
|
appendAgent,
|
||||||
|
handleToolCall,
|
||||||
|
handleToolCallUpdate,
|
||||||
|
exit,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
@@ -804,6 +871,7 @@ export default function App({
|
|||||||
if (!trimmed) return;
|
if (!trimmed) return;
|
||||||
setInput("");
|
setInput("");
|
||||||
setViewTurnIdx(-1);
|
setViewTurnIdx(-1);
|
||||||
|
setExpandedToolCall(null);
|
||||||
setScrollOffset(0);
|
setScrollOffset(0);
|
||||||
|
|
||||||
if (loading || isProcessingRef.current) {
|
if (loading || isProcessingRef.current) {
|
||||||
@@ -825,7 +893,6 @@ export default function App({
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permission navigation
|
|
||||||
if (pendingPermission) {
|
if (pendingPermission) {
|
||||||
const opts = pendingPermission.options;
|
const opts = pendingPermission.options;
|
||||||
|
|
||||||
@@ -857,13 +924,34 @@ export default function App({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn navigation: shift+arrow
|
if (key.tab) {
|
||||||
|
const effectiveIdx =
|
||||||
|
viewTurnIdx === -1 ? turns.length - 1 : viewTurnIdx;
|
||||||
|
const currentTurn = turns[effectiveIdx];
|
||||||
|
if (!currentTurn || currentTurn.toolCallOrder.length === 0) return;
|
||||||
|
|
||||||
|
const featuredId = findFeaturedToolCallId(currentTurn.toolCallOrder, currentTurn.toolCalls);
|
||||||
|
if (!featuredId) return;
|
||||||
|
|
||||||
|
setExpandedToolCall((prev) => (prev === featuredId ? null : featuredId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.upArrow && !key.shift && !key.meta) {
|
||||||
|
setScrollOffset((prev) => prev + 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key.downArrow && !key.shift && !key.meta) {
|
||||||
|
setScrollOffset((prev) => Math.max(prev - 3, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (key.upArrow && key.shift) {
|
if (key.upArrow && key.shift) {
|
||||||
setTurns((currentTurns) => {
|
setTurns((currentTurns) => {
|
||||||
if (currentTurns.length <= 1) return currentTurns;
|
if (currentTurns.length <= 1) return currentTurns;
|
||||||
setViewTurnIdx((prev) => {
|
setViewTurnIdx((prev) => {
|
||||||
const effectiveIdx = prev === -1 ? currentTurns.length - 1 : prev;
|
const effectiveIdx =
|
||||||
setScrollOffset(0);
|
prev === -1 ? currentTurns.length - 1 : prev;
|
||||||
return Math.max(effectiveIdx - 1, 0);
|
return Math.max(effectiveIdx - 1, 0);
|
||||||
});
|
});
|
||||||
return currentTurns;
|
return currentTurns;
|
||||||
@@ -876,44 +964,16 @@ export default function App({
|
|||||||
setViewTurnIdx((prev) => {
|
setViewTurnIdx((prev) => {
|
||||||
if (prev === -1) return -1;
|
if (prev === -1) return -1;
|
||||||
const next = prev + 1;
|
const next = prev + 1;
|
||||||
setScrollOffset(0);
|
|
||||||
return next >= currentTurns.length ? -1 : next;
|
return next >= currentTurns.length ? -1 : next;
|
||||||
});
|
});
|
||||||
return currentTurns;
|
return currentTurns;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll within turn
|
|
||||||
if (key.pageUp || (key.upArrow && key.meta)) {
|
|
||||||
setScrollOffset((prev) => Math.max(prev - 5, 0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (key.pageDown || (key.downArrow && key.meta)) {
|
|
||||||
setScrollOffset((prev) => prev + 5);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Layout math ───────────────────────────────────────────────────────
|
|
||||||
//
|
|
||||||
// The vertical budget is:
|
|
||||||
// header (2 lines: title row + rule)
|
|
||||||
// user prompt (2 lines: blank line above + prompt text)
|
|
||||||
// body (flex: remaining space)
|
|
||||||
// input bar (dynamic: border top/bottom + wrapped content lines + margin bottom) — absent in pipe mode
|
|
||||||
|
|
||||||
const GUTTER = 2;
|
const GUTTER = 2;
|
||||||
const innerWidth = Math.max(termWidth - GUTTER * 2, 20);
|
const innerWidth = Math.max(termWidth - GUTTER * 2, 20);
|
||||||
const headerLines = 2;
|
|
||||||
const userPromptLines = 2;
|
|
||||||
const inputLines = initialPrompt
|
|
||||||
? 0
|
|
||||||
: inputBarHeight(input, innerWidth, queuedMessages.length > 0);
|
|
||||||
const bodyHeight = Math.max(
|
|
||||||
termHeight - headerLines - userPromptLines - inputLines - 1,
|
|
||||||
3,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (bannerVisible) {
|
if (bannerVisible) {
|
||||||
return (
|
return (
|
||||||
@@ -941,6 +1001,33 @@ export default function App({
|
|||||||
viewTurnIdx !== -1 && viewTurnIdx < turns.length - 1;
|
viewTurnIdx !== -1 && viewTurnIdx < turns.length - 1;
|
||||||
const isLatest = !isViewingHistory;
|
const isLatest = !isViewingHistory;
|
||||||
|
|
||||||
|
const emptyTurn: Turn = {
|
||||||
|
userText: "",
|
||||||
|
toolCalls: new Map(),
|
||||||
|
toolCallOrder: [],
|
||||||
|
agentText: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const bodyLines = buildTurnBodyLines({
|
||||||
|
turn: currentTurn ?? emptyTurn,
|
||||||
|
width: innerWidth,
|
||||||
|
loading: isLatest && loading,
|
||||||
|
status,
|
||||||
|
spinIdx,
|
||||||
|
pendingPermission: isLatest ? pendingPermission : null,
|
||||||
|
permissionIdx,
|
||||||
|
expandedToolCall,
|
||||||
|
});
|
||||||
|
|
||||||
|
const allBodyLines = isLatest
|
||||||
|
? [
|
||||||
|
...bodyLines,
|
||||||
|
...queuedMessages.map((text, i) => (
|
||||||
|
<QueuedMessage key={`q-${i}`} text={text} />
|
||||||
|
)),
|
||||||
|
]
|
||||||
|
: bodyLines;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
@@ -965,36 +1052,14 @@ export default function App({
|
|||||||
<>
|
<>
|
||||||
<UserPrompt text={currentTurn.userText} />
|
<UserPrompt text={currentTurn.userText} />
|
||||||
|
|
||||||
<Box flexDirection="column" flexGrow={1} height={bodyHeight}>
|
<ScrollableBody
|
||||||
<TurnResponseBody
|
lines={allBodyLines}
|
||||||
turn={currentTurn}
|
width={innerWidth}
|
||||||
width={innerWidth}
|
scrollOffset={scrollOffset}
|
||||||
height={
|
/>
|
||||||
bodyHeight -
|
|
||||||
(isLatest && queuedMessages.length > 0
|
|
||||||
? queuedMessages.length
|
|
||||||
: 0)
|
|
||||||
}
|
|
||||||
scrollOffset={scrollOffset}
|
|
||||||
loading={isLatest && loading}
|
|
||||||
status={status}
|
|
||||||
spinIdx={spinIdx}
|
|
||||||
pendingPermission={isLatest ? pendingPermission : null}
|
|
||||||
permissionIdx={permissionIdx}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{isLatest &&
|
|
||||||
queuedMessages.map((text, i) => (
|
|
||||||
<QueuedMessage key={`q-${i}`} text={text} />
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box flexDirection="column" flexGrow={1} />
|
||||||
flexDirection="column"
|
|
||||||
flexGrow={1}
|
|
||||||
height={bodyHeight + userPromptLines}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isViewingHistory && (
|
{isViewingHistory && (
|
||||||
@@ -1022,3 +1087,123 @@ export default function App({
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cli = meow(
|
||||||
|
`
|
||||||
|
Usage
|
||||||
|
$ goose
|
||||||
|
|
||||||
|
Options
|
||||||
|
--server, -s Server URL (default: auto-launch bundled server)
|
||||||
|
--text, -t Send a single prompt and exit
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
importMeta: import.meta,
|
||||||
|
flags: {
|
||||||
|
server: { type: "string", shortFlag: "s" },
|
||||||
|
text: { type: "string", shortFlag: "t" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const DEFAULT_PORT = 3284;
|
||||||
|
const DEFAULT_URL = `http://127.0.0.1:${DEFAULT_PORT}`;
|
||||||
|
|
||||||
|
function findServerBinary(): string | null {
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const candidates = [
|
||||||
|
join(__dirname, "..", "server-binary.json"),
|
||||||
|
join(__dirname, "server-binary.json"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(readFileSync(candidate, "utf-8"));
|
||||||
|
return data.binaryPath ?? null;
|
||||||
|
} catch {
|
||||||
|
// not found here, try next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForServer(url: string, timeoutMs = 10_000): Promise<void> {
|
||||||
|
const start = Date.now();
|
||||||
|
while (Date.now() - start < timeoutMs) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${url}/status`);
|
||||||
|
if (res.ok) return;
|
||||||
|
} catch {
|
||||||
|
// server not ready yet
|
||||||
|
}
|
||||||
|
await new Promise((r) => setTimeout(r, 200));
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Server did not become ready at ${url} within ${timeoutMs}ms`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let serverProcess: ReturnType<typeof spawn> | null = null;
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
let serverUrl = cli.flags.server;
|
||||||
|
|
||||||
|
if (!serverUrl) {
|
||||||
|
const binary = findServerBinary();
|
||||||
|
if (binary) {
|
||||||
|
serverProcess = spawn(binary, ["--port", String(DEFAULT_PORT)], {
|
||||||
|
stdio: "ignore",
|
||||||
|
detached: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
serverProcess.on("error", (err) => {
|
||||||
|
console.error(`Failed to start goose-acp-server: ${err.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await waitForServer(DEFAULT_URL);
|
||||||
|
} catch (err) {
|
||||||
|
console.error((err as Error).message);
|
||||||
|
serverProcess.kill();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverUrl = DEFAULT_URL;
|
||||||
|
} else {
|
||||||
|
serverUrl = DEFAULT_URL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { waitUntilExit } = render(
|
||||||
|
<App serverUrl={serverUrl} initialPrompt={cli.flags.text} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitUntilExit();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
if (serverProcess && !serverProcess.killed) {
|
||||||
|
serverProcess.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on("exit", cleanup);
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
cleanup();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
cleanup();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
cleanup();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user