From 9d147242e06a88f2dbd0f43205dbe6ee5f41e399 Mon Sep 17 00:00:00 2001 From: ywkj Date: Mon, 30 Mar 2026 08:00:56 +0800 Subject: [PATCH] fix: restore auth-cli.ts and install.sh for org CI registration The shared-actions/register-skill workflow requires auth-runtime client-key integration. Restores auth-cli.ts and auth-rt auto-install. Co-Authored-By: Claude Opus 4.6 --- install.sh | 24 ++++++++-- src/auth-cli.ts | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/auth-cli.ts diff --git a/install.sh b/install.sh index 7beffc6..01cd899 100755 --- a/install.sh +++ b/install.sh @@ -2,8 +2,26 @@ set -euo pipefail cd "$(dirname "$0")" +# Auto-install auth-rt if not found +if ! command -v auth-rt &>/dev/null && [ ! -x "$HOME/.local/bin/auth-rt" ]; then + echo "auth-rt not found, installing..." + _FORGEJO="http://192.168.0.108:3030" + _OS="$(uname -s | tr '[:upper:]' '[:lower:]')" + _ARCH="$(uname -m)"; case "$_ARCH" in x86_64) _ARCH="amd64";; aarch64) _ARCH="arm64";; esac + _URL="$_FORGEJO/agent-skills/auth-runtime/releases/download/latest/auth-rt-${_OS}-${_ARCH}" + mkdir -p "$HOME/.local/bin" + if curl -fsSL "$_URL" -o "$HOME/.local/bin/auth-rt" 2>/dev/null; then + chmod +x "$HOME/.local/bin/auth-rt" + echo "auth-rt installed (downloaded)" + else + echo "Download failed, building from source..." + _SRC="$HOME/.local/share/auth-runtime" + if [ -d "$_SRC/.git" ]; then git -C "$_SRC" pull --ff-only + else git clone --depth 1 "$_FORGEJO/agent-skills/auth-runtime.git" "$_SRC" + fi + bash "$_SRC/install.sh" + fi +fi + bun install echo "1688-logistics-scraper installed." -echo "" -echo "Prerequisites: Chrome must be running with remote debugging:" -echo " /Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --remote-debugging-port=9222" diff --git a/src/auth-cli.ts b/src/auth-cli.ts new file mode 100644 index 0000000..d072a88 --- /dev/null +++ b/src/auth-cli.ts @@ -0,0 +1,119 @@ +/** + * Thin CLI wrapper for auth-runtime. + * + * Copy this file into your skill's src/ directory. It calls the + * `auth-rt` binary (a standalone Go executable), so the skill has + * zero npm/runtime dependency on auth-runtime. + * + * Prerequisites: + * `auth-rt` must be in PATH or at ~/.local/bin/auth-rt + * (install.sh handles this automatically) + * + * Usage: + * import { createSkillClient } from './auth-cli.ts'; + * const client = createSkillClient(); + * const res = await client.post('/ecom/tasks/scrape', { url: '...' }); + */ + +import { spawnSync } from 'child_process'; +import * as path from 'path'; +import * as os from 'os'; + +const home = process.env.HOME || os.homedir(); +const AUTH_RT_BIN = process.env.AUTH_RT_BIN + || (() => { + // Check if auth-rt is in PATH + const which = spawnSync('which', ['auth-rt'], { encoding: 'utf-8' }); + if (which.status === 0 && which.stdout.trim()) { + return which.stdout.trim(); + } + return path.join(home, '.local', 'bin', 'auth-rt'); + })(); + +export interface ApiResponse { + status: number; + body: string; +} + +export interface SessionResponse { + accessToken: string; + expiresIn: number; + ownerSessionToken?: string; + hookUrl?: string; + hookToken?: string; +} + +export interface SkillClientOptions { + apiBase?: string; + dryRun?: boolean; +} + +function runCli(...args: string[]): string { + const result = spawnSync(AUTH_RT_BIN, args, { + encoding: 'utf-8', + timeout: 60_000, + }); + + if (result.error) { + throw new Error(`auth-rt spawn failed: ${result.error.message}`); + } + if (result.status !== 0) { + throw new Error(`auth-rt failed (exit ${result.status}): ${(result.stderr || '').trim()}`); + } + return (result.stdout || '').trim(); +} + +export class SkillClient { + private readonly apiBase?: string; + private readonly dryRun: boolean; + + constructor(options: SkillClientOptions = {}) { + this.apiBase = options.apiBase; + this.dryRun = options.dryRun ?? false; + } + + async session(): Promise { + if (this.dryRun) { + return { accessToken: '', expiresIn: 900 }; + } + return JSON.parse(runCli('session')); + } + + async get(urlPath: string): Promise { + return this.request('GET', urlPath); + } + + async post(urlPath: string, body?: unknown): Promise { + return this.request('POST', urlPath, body); + } + + async put(urlPath: string, body?: unknown): Promise { + return this.request('PUT', urlPath, body); + } + + async patch(urlPath: string, body?: unknown): Promise { + return this.request('PATCH', urlPath, body); + } + + async delete(urlPath: string, body?: unknown): Promise { + return this.request('DELETE', urlPath, body); + } + + private async request(method: string, urlPath: string, body?: unknown): Promise { + if (this.dryRun) { + return { status: 200, body: JSON.stringify({ dryRun: true, method, path: urlPath }) }; + } + const args = ['request', method, urlPath]; + if (body != null) { + args.push('--body', JSON.stringify(body)); + } + if (this.apiBase) { + args.push('--api-base', this.apiBase); + } + return JSON.parse(runCli(...args)); + } +} + +export function createSkillClient(options?: SkillClientOptions): SkillClient { + return new SkillClient(options); +}