From 535dee7ce0a7a9ca082be1ac3a30e920e133e575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Sun, 18 Jan 2026 21:04:48 +0000 Subject: [PATCH] feat: cli publish (#40) --- apps/cli/README.md | 72 +++++++-------------------- apps/cli/README_internal.md | 77 +++++++++++++++++++++++++++++ apps/cli/package.json | 4 +- apps/cli/src/cli.ts | 7 +++ apps/cli/src/run.ts | 5 +- apps/pnpm-lock.yaml | 10 ++++ scripts/release/package-web.sh | 0 scripts/release/publish-launcher.sh | 0 scripts/release/publish-release.sh | 0 9 files changed, 119 insertions(+), 56 deletions(-) create mode 100644 apps/cli/README_internal.md mode change 100644 => 100755 scripts/release/package-web.sh mode change 100644 => 100755 scripts/release/publish-launcher.sh mode change 100644 => 100755 scripts/release/publish-release.sh diff --git a/apps/cli/README.md b/apps/cli/README.md index 912b6c28f6..9ef856d50a 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -1,66 +1,32 @@ -# Kandev Launcher (npx) +# Kandev -This package powers `npx kandev` by downloading prebuilt release bundles from GitHub Releases and running them locally. It: -- Detects OS/arch and fetches the matching bundle ZIP. -- Verifies the SHA256 checksum when available. -- Extracts the bundle into `~/.kandev/bin///`. -- Starts the backend binary and waits for the `/health` endpoint. -- Starts the Next.js standalone server with runtime `KANDEV_API_BASE_URL`. -- Uses the latest GitHub Release by default, so runtime bundles update automatically. -It also supports local dev runs from a repo checkout. +Kandev is a local-first AI execution platform for software development work. It pairs a kanban-style task surface with live agent orchestration, file/workspace access, and real-time streaming of changes. -## Updates - -On `run`, the launcher checks npm for the latest `kandev` CLI version and prompts: - -``` -Update available: -> . Update now? [y/N] -``` - -If you accept, it re-runs `npx kandev@latest` with the same arguments. -This check is skipped in `dev` mode. - -Note: the runtime bundles are pulled from the latest GitHub Release by default, even if the CLI version is unchanged. So: -- **New runtime release without CLI publish**: users get new runtime automatically, but no update prompt. -- **New CLI publish**: users get an update prompt and then re-run with the new CLI. - -You can disable the prompt with: +## Start locally ```bash -KANDEV_NO_UPDATE_PROMPT=1 npx kandev -``` - -## Usage - -```bash -# Run the latest release bundle npx kandev - -# Run a specific release tag -npx kandev run --version v0.1.0 - -# Local dev (from repo root) -npx kandev dev ``` -## Local Development +The launcher downloads the latest release bundle, starts the backend + web app, and opens your browser. -```bash -pnpm -C apps/cli dev -``` +## What you get -## Build / Publish +- **Task-centric execution**: turn tasks into runnable sessions with streaming updates. +- **Workspace control**: shell, file, and git access scoped to each task. +- **Agent orchestration**: run different agent types and resume sessions. +- **Change visibility**: review diffs and track state per task/session. +- **Live UI**: WebSocket-driven updates across tasks, messages, and outputs. -```bash -pnpm -C apps/cli build -npm publish --access public -``` +## Requirements -The published package name is `kandev`, with a bin entry `kandev`. +- Node.js (for `npx`) +- Git (for repository access) +- Docker (optional; only needed for containerized agents) -## Environment Overrides +## Platforms + +- macOS (Intel + Apple Silicon) +- Linux (x64) +- Windows (x64) (not tested yet) -- `KANDEV_GITHUB_OWNER`, `KANDEV_GITHUB_REPO`: Override the GitHub repo to fetch releases from. -- `KANDEV_GITHUB_TOKEN`: Optional token for GitHub API rate limits. -- `KANDEV_NO_UPDATE_PROMPT=1`: Disable the update prompt. -- `KANDEV_SKIP_UPDATE=1`: Internal guard to avoid update loops. diff --git a/apps/cli/README_internal.md b/apps/cli/README_internal.md new file mode 100644 index 0000000000..1a2daa04c6 --- /dev/null +++ b/apps/cli/README_internal.md @@ -0,0 +1,77 @@ +# Kandev Launcher (npx) + +This package powers `npx kandev` by downloading prebuilt release bundles from GitHub Releases and running them locally. It: +- Detects OS/arch and fetches the matching bundle ZIP. +- Verifies the SHA256 checksum when available. +- Extracts the bundle into `~/.kandev/bin///`. +- Starts the backend binary and waits for the `/health` endpoint. +- Starts the Next.js standalone server with runtime `KANDEV_API_BASE_URL`. +- Uses the latest GitHub Release by default, so runtime bundles update automatically. +It also supports local dev runs from a repo checkout. + +## Updates + +On `run`, the launcher checks npm for the latest `kandev` CLI version and prompts: + +``` +Update available: -> . Update now? [y/N] +``` + +If you accept, it re-runs `npx kandev@latest` with the same arguments. +This check is skipped in `dev` mode. + +Note: the runtime bundles are pulled from the latest GitHub Release by default, even if the CLI version is unchanged. So: +- **New runtime release without CLI publish**: users get new runtime automatically, but no update prompt. +- **New CLI publish**: users get an update prompt and then re-run with the new CLI. + +You can disable the prompt with: + +```bash +KANDEV_NO_UPDATE_PROMPT=1 npx kandev +``` + +## Usage + +```bash +# Run the latest release bundle +npx kandev + +# Run a specific release tag +npx kandev run --version v0.1.0 + +# Local dev (from repo root) +npx kandev dev + + +# Local test the built CLI (from repo root) +pnpm -C apps/cli build +pnpm -C apps/cli start +``` + +## Local Development + +```bash +pnpm -C apps/cli dev +``` + +## Build / Publish + +```bash +pnpm -C apps/cli build +npm publish --access public +``` + +The published package name is `kandev`, with a bin entry `kandev`. + +## Release + +```bash +scripts/release/publish-launcher.sh 0.1.0 +``` + +## Environment Overrides + +- `KANDEV_GITHUB_OWNER`, `KANDEV_GITHUB_REPO`: Override the GitHub repo to fetch releases from. +- `KANDEV_GITHUB_TOKEN`: Optional token for GitHub API rate limits. +- `KANDEV_NO_UPDATE_PROMPT=1`: Disable the update prompt. +- `KANDEV_SKIP_UPDATE=1`: Internal guard to avoid update loops. diff --git a/apps/cli/package.json b/apps/cli/package.json index dfe88f785e..93e3679d8e 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "kandev", - "version": "0.1.0", + "version": "0.1.4", "private": false, "description": "NPX launcher for Kandev", "license": "UNLICENSED", @@ -18,6 +18,7 @@ "tree-kill": "^1.2.2" }, "devDependencies": { + "@types/adm-zip": "^0.5.7", "@types/node": "^20", "tsx": "^4.15.7", "typescript": "^5" @@ -25,6 +26,7 @@ "scripts": { "dev": "tsx src/cli.ts", "build": "tsc -p tsconfig.json", + "start": "node dist/cli.js", "prepublishOnly": "pnpm build" } } diff --git a/apps/cli/src/cli.ts b/apps/cli/src/cli.ts index df49c31a74..81cd7db3ce 100644 --- a/apps/cli/src/cli.ts +++ b/apps/cli/src/cli.ts @@ -94,6 +94,13 @@ function parseArgs(argv: string[]): CliOptions { function findRepoRoot(startDir: string): string | null { let current = path.resolve(startDir); while (true) { + if (current.endsWith(`${path.sep}apps`)) { + const backendInApps = path.join(current, "backend"); + const webInApps = path.join(current, "web"); + if (fs.existsSync(backendInApps) && fs.existsSync(webInApps)) { + return path.dirname(current); + } + } const backendDir = path.join(current, "apps", "backend"); const webDir = path.join(current, "apps", "web"); if (fs.existsSync(backendDir) && fs.existsSync(webDir)) { diff --git a/apps/cli/src/run.ts b/apps/cli/src/run.ts index e00c9bbfad..802be01ae6 100644 --- a/apps/cli/src/run.ts +++ b/apps/cli/src/run.ts @@ -10,7 +10,8 @@ import { DEFAULT_WEB_PORT, HEALTH_TIMEOUT_MS, } from "./constants"; -import { CACHE_DIR, ensureAsset, getRelease } from "./github"; +import { ensureAsset, getRelease } from "./github"; +import { CACHE_DIR } from "./constants"; import { waitForHealth } from "./health"; import { getBinaryName, getPlatformDir } from "./platform"; import { pickAvailablePort } from "./ports"; @@ -139,7 +140,7 @@ function launchReleaseApps(prepared: PreparedRelease): { label: "web", }); - return { supervisor, backendProc, webServerPath, webProc }; + return { supervisor, backendProc, webServerPath }; } export async function runRelease({ version, backendPort, webPort }: RunOptions) { diff --git a/apps/pnpm-lock.yaml b/apps/pnpm-lock.yaml index a44c108ba6..78e747e93f 100644 --- a/apps/pnpm-lock.yaml +++ b/apps/pnpm-lock.yaml @@ -24,6 +24,9 @@ importers: specifier: ^1.2.2 version: 1.2.2 devDependencies: + '@types/adm-zip': + specifier: ^0.5.7 + version: 0.5.7 '@types/node': specifier: ^20 version: 20.19.28 @@ -2410,6 +2413,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/adm-zip@0.5.7': + resolution: {integrity: sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==} + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -7706,6 +7712,10 @@ snapshots: tslib: 2.8.1 optional: true + '@types/adm-zip@0.5.7': + dependencies: + '@types/node': 20.19.28 + '@types/d3-array@3.2.2': {} '@types/d3-color@3.1.3': {} diff --git a/scripts/release/package-web.sh b/scripts/release/package-web.sh old mode 100644 new mode 100755 diff --git a/scripts/release/publish-launcher.sh b/scripts/release/publish-launcher.sh old mode 100644 new mode 100755 diff --git a/scripts/release/publish-release.sh b/scripts/release/publish-release.sh old mode 100644 new mode 100755