Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 127 additions & 2 deletions packages/app-bundle/manifest.json

Large diffs are not rendered by default.

159 changes: 159 additions & 0 deletions packages/app-bundle/overlay/packages/opencode/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"name": "opencode",
"type": "module",
"license": "MIT",
"private": true,
"scripts": {
"typecheck": "tsgo --noEmit",
"test": "bun test --timeout 30000 --only-failures",
"test:httpapi": "bun run script/httpapi-exercise.ts --mode coverage --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode auth --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode effect --fail-on-missing --fail-on-skip",
"bench:test": "bun run script/bench-test-suite.ts",
"profile:test": "bun run script/profile-test-files.ts",
"build": "bun run script/build.ts",
"dev": "bun run --conditions=browser ./src/index.ts",
"dev:temporary": "bun run --conditions=browser ./src/temporary.ts"
},
"bin": {
"opencode": "./bin/opencode"
},
"exports": {
"./*": "./src/*.ts"
},
"imports": {
"#db": {
"bun": "./src/storage/db.bun.ts",
"node": "./src/storage/db.node.ts",
"default": "./src/storage/db.bun.ts"
}
},
"devDependencies": {
"@babel/core": "7.28.4",
"@octokit/webhooks-types": "7.6.1",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/http-recorder": "workspace:*",
"@opencode-ai/script": "workspace:*",
"@standard-schema/spec": "1.0.0",
"@tsconfig/bun": "catalog:",
"@types/babel__core": "7.20.5",
"@types/bun": "catalog:",
"@types/cross-spawn": "catalog:",
"@types/mime-types": "3.0.1",
"@types/npm-package-arg": "6.1.4",
"@types/semver": "^7.5.8",
"@types/turndown": "5.0.5",
"@types/yargs": "17.0.33",
"@typescript/native-preview": "catalog:",
"drizzle-orm": "catalog:",
"prettier": "3.6.2",
"typescript": "catalog:",
"vscode-languageserver-types": "3.17.5",
"why-is-node-running": "3.2.2"
},
"dependencies": {
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.21.0",
"@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.112",
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/azure": "3.0.88",
"@ai-sdk/cerebras": "2.0.60",
"@ai-sdk/cohere": "3.0.27",
"@ai-sdk/deepinfra": "2.0.41",
"@ai-sdk/gateway": "3.0.104",
"@ai-sdk/google": "3.0.73",
"@ai-sdk/google-vertex": "4.0.128",
"@ai-sdk/groq": "3.0.31",
"@ai-sdk/mistral": "3.0.51",
"@ai-sdk/openai": "3.0.84",
"@ai-sdk/openai-compatible": "2.0.41",
"@ai-sdk/perplexity": "3.0.26",
"@ai-sdk/provider": "3.0.8",
"@ai-sdk/togetherai": "2.0.41",
"@ai-sdk/vercel": "2.0.39",
"@ai-sdk/xai": "3.0.102",
"@aws-sdk/credential-providers": "3.1057.0",
"@clack/prompts": "1.0.0-alpha.1",
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
"@ff-labs/fff-bun": "0.9.4",
"@gitlab/opencode-gitlab-auth": "1.3.3",
"@modelcontextprotocol/sdk": "1.29.0",
"@napi-rs/keyring": "1.3.0",
"@octokit/graphql": "9.0.2",
"@octokit/rest": "catalog:",
"@openauthjs/openauth": "catalog:",
"@opencode-ai/codemode": "workspace:*",
"@opencode-ai/llm": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
"@opencode-ai/schema": "workspace:*",
"@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@opencode-ai/server": "workspace:*",
"@opencode-ai/tui": "workspace:*",
"@openrouter/ai-sdk-provider": "2.9.0",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
"@opentelemetry/sdk-trace-base": "2.6.1",
"@opentelemetry/sdk-trace-node": "2.6.1",
"@opentui/core": "catalog:",
"@opentui/keymap": "catalog:",
"@opentui/solid": "catalog:",
"@parcel/watcher": "2.5.1",
"@pierre/diffs": "catalog:",
"@silvia-odwyer/photon-node": "0.3.4",
"@solid-primitives/event-bus": "1.1.2",
"@solid-primitives/scheduled": "1.5.2",
"@standard-schema/spec": "1.0.0",
"@types/ws": "8.18.1",
"@zip.js/zip.js": "2.7.62",
"ai": "catalog:",
"ai-gateway-provider": "3.1.2",
"bonjour-service": "1.3.0",
"chokidar": "4.0.3",
"cross-spawn": "catalog:",
"decimal.js": "10.5.0",
"diff": "catalog:",
"drizzle-orm": "catalog:",
"effect": "catalog:",
"fuzzysort": "3.1.0",
"gitlab-ai-provider": "6.12.1",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"gray-matter": "4.0.3",
"htmlparser2": "8.0.2",
"ignore": "7.0.5",
"immer": "11.1.4",
"jsonc-parser": "3.3.1",
"mime-types": "3.0.2",
"minimatch": "10.0.3",
"npm-package-arg": "13.0.2",
"open": "10.1.2",
"opencode-gitlab-auth": "2.1.0",
"opencode-poe-auth": "0.0.1",
"opentui-spinner": "catalog:",
"partial-json": "0.1.7",
"remeda": "catalog:",
"semver": "^7.6.3",
"solid-js": "catalog:",
"strip-ansi": "7.1.2",
"tree-sitter-bash": "0.25.0",
"tree-sitter-powershell": "0.25.10",
"turndown": "7.2.0",
"ulid": "catalog:",
"venice-ai-sdk-provider": "2.1.1",
"vscode-jsonrpc": "8.2.1",
"web-tree-sitter": "0.25.10",
"ws": "8.21.0",
"xdg-basedir": "5.1.0",
"yargs": "18.0.0",
"zod": "catalog:"
},
"overrides": {
"drizzle-orm": "catalog:"
}
}
89 changes: 89 additions & 0 deletions packages/app-bundle/overlay/packages/opencode/pasqal-live-test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Live Pasqal test for the #194 keychain silent-re-auth workaround.
// Runs the REAL fork-server code paths (submitCredentialResponse /
// revalidateResponse / disconnectResponse) against LIVE Pasqal via the staged
// validator + pasqal_cloud SDK, and the REAL OS keychain. Isolated: token +
// status files go to a temp dir, the keychain uses a "live-test" slot, and
// everything is cleaned up at the end — your real ~/.amico state is untouched.
//
// Driven by pasqal-live-test.sh (which collects the password without echo).
// Credentials arrive via env: PASQAL_LIVE_USER / PASQAL_LIVE_PW / PASQAL_LIVE_PROJECT.
import { mkdtempSync, rmSync, existsSync, readFileSync } from "node:fs"
import { tmpdir } from "node:os"
import path from "node:path"

const user = process.env.PASQAL_LIVE_USER ?? ""
const pw = process.env.PASQAL_LIVE_PW ?? ""
const project = process.env.PASQAL_LIVE_PROJECT ?? ""
if (!user || !pw || !project) {
console.error("missing PASQAL_LIVE_USER / PASQAL_LIVE_PW / PASQAL_LIVE_PROJECT — run via pasqal-live-test.sh")
process.exit(2)
}

// Isolate at-rest state to a temp dir BEFORE importing the module (it reads
// these env vars on first use). Keychain is isolated by using a distinct slot.
const dir = mkdtempSync(path.join(tmpdir(), "pasqal-live-"))
process.env.AMICO_PASQAL_FILE = path.join(dir, "pasqal.json")
process.env.AMICODE_CONNECTIONS_FILE = path.join(dir, "connections.json")
// AMICODE_OPS_DIR + AMICO_PYTHON left at defaults so the REAL staged validator
// (~/.amico/amicode/scripts/pasqal-connector/pasqal_validate.py) + pasqal_cloud run.

const { submitCredentialResponse, revalidateResponse, disconnectResponse, PASQAL_SECRET_ACCOUNT } = await import(
"./src/server/amicode/connections.ts"
)
const { keychainSecretStore, setPasqalSecretStore } = await import("./src/server/amicode/pasqal-secret.ts")

// Re-point the keychain slot to a test account so we never touch "default".
const LIVE_ACCOUNT = "live-test"
setPasqalSecretStore({
read: (a) => keychainSecretStore.read(a === PASQAL_SECRET_ACCOUNT ? LIVE_ACCOUNT : a),
write: (a, s) => keychainSecretStore.write(a === PASQAL_SECRET_ACCOUNT ? LIVE_ACCOUNT : a, s),
clear: (a) => keychainSecretStore.clear(a === PASQAL_SECRET_ACCOUNT ? LIVE_ACCOUNT : a),
})

const line = (b) => JSON.parse(b).connection ?? JSON.parse(b)
const show = (label, b) => {
const c = line(b)
console.log(`\n${label}`)
console.log(" state :", c.state)
console.log(" identity :", c.identity ?? "—")
console.log(" devices :", (c.devices ?? []).map((d) => d.name).join(", ") || "—")
console.log(" expires :", c.expires_at ?? "—")
if (JSON.parse(b).error) console.log(" note :", JSON.parse(b).error)
}
const tokenOnDisk = () =>
existsSync(process.env.AMICO_PASQAL_FILE) ? JSON.parse(readFileSync(process.env.AMICO_PASQAL_FILE, "utf8")).token : null

try {
console.log("=== #194 live Pasqal test — real validator, real Pasqal, real keychain (isolated) ===")

// 1) LIVE connect: real ROPC against Pasqal via the staged validator.
const body = JSON.stringify({ id: "pasqal-cloud", username: user, password: pw, project_id: project })
show("1) Connect (live password grant)", await submitCredentialResponse(body))
const t1 = tokenOnDisk()
const stored = keychainSecretStore.read(LIVE_ACCOUNT)
console.log(" token minted & on disk:", t1 ? `yes (${t1.slice(0, 6)}…, ${t1.length} chars)` : "NO")
console.log(" password in keychain :", stored ? `yes (${stored.username})` : "NO")
if (!t1) {
console.log("\nConnect did not mint a token — check the credentials/project and the validator output above.")
process.exit(1)
}

// 2) Force the token expired on disk, then revalidate → SILENT RE-MINT (a
// second real ROPC from the keychain password, no prompt).
const cred = JSON.parse(readFileSync(process.env.AMICO_PASQAL_FILE, "utf8"))
cred.expires_at = "2020-01-01T00:00:00+00:00"
;(await import("node:fs")).writeFileSync(process.env.AMICO_PASQAL_FILE, JSON.stringify(cred))
console.log("\n2) Forced token expiry on disk (simulating the ~24h lapse)…")
show(" Revalidate (silent re-mint from keychain)", await revalidateResponse(JSON.stringify({ id: "pasqal-cloud" })))
const t2 = tokenOnDisk()
console.log(" token re-minted:", t2 && t2 !== cred.token ? "yes (fresh token, no prompt)" : t2 ? "same value returned" : "NO")
console.log(" → this is the workaround: an expired token renewed itself with zero user interaction.")

// 3) Disconnect wipes the keychain slot.
show("3) Disconnect", disconnectResponse(JSON.stringify({ id: "pasqal-cloud" })))
console.log(" keychain after disconnect:", keychainSecretStore.read(LIVE_ACCOUNT) ?? "wiped ✓")
console.log("\n=== done — live connect + silent re-mint + disconnect all exercised ===")
} finally {
keychainSecretStore.clear(LIVE_ACCOUNT) // belt-and-suspenders: never leave a test secret behind
rmSync(dir, { recursive: true, force: true })
}
18 changes: 18 additions & 0 deletions packages/app-bundle/overlay/packages/opencode/pasqal-live-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Live test for the #194 Pasqal keychain silent-re-auth workaround.
# Collects your Pasqal credentials WITHOUT echoing the password, then runs the
# real server code against live Pasqal + the real macOS keychain (isolated to a
# temp token file and a "live-test" keychain slot — your real ~/.amico state is
# never touched). Nothing is written to shell history or any argv.
set -euo pipefail
cd "$(dirname "$0")"

DEFAULT_PROJECT="8b948e29-93cb-4042-b5dc-6916f379d575" # Harmoniqs Tests (Jack's notes)

read -r -p "Pasqal username (email): " PASQAL_LIVE_USER
read -r -s -p "Pasqal password (hidden): " PASQAL_LIVE_PW; echo
read -r -p "Project ID [${DEFAULT_PROJECT}]: " PASQAL_LIVE_PROJECT
PASQAL_LIVE_PROJECT="${PASQAL_LIVE_PROJECT:-$DEFAULT_PROJECT}"
export PASQAL_LIVE_USER PASQAL_LIVE_PW PASQAL_LIVE_PROJECT

PATH="$HOME/.bun/bin:$PATH" bun ./pasqal-live-test.mjs
Loading
Loading