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
16 changes: 16 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json",
"changelog": [
"@changesets/changelog-github",
{
"repo": "SpawnDock/create-spawn-dock"
}
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
22 changes: 22 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Setup
description: Perform standard setup and install dependencies using pnpm.

inputs:
node-version:
description: The version of Node.js to install
required: true
default: 22.12.0

runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install node
uses: actions/setup-node@v6
with:
cache: pnpm
node-version: ${{ inputs.node-version }}
- name: Install dependencies
shell: bash
run: pnpm install
26 changes: 26 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Check

on:
workflow_dispatch:
pull_request:
branches: [main]
push:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions: {}

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install dependencies
uses: ./.github/actions/setup
- run: pnpm typecheck
- run: pnpm test
- run: pnpm build
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
packages/*/dist
coverage
*.log
.DS_Store
36 changes: 24 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,43 @@

SpawnDock bootstrap CLI for local TMA projects.

## Usage
This repository now follows an `effect-template`-style layout:

```bash
npx create-spawn-dock --token <pairing-token> [project-dir]
```
- root workspace with `packages/app`
- TypeScript + Effect entrypoint
- no embedded TMA starter overlay inside the CLI repo

The canonical TMA starter lives only in `https://github.com/SpawnDock/tma-project`.
`create-spawn-dock` clones that repo and writes only project-specific runtime files.

## Usage

Until the npm package is published, run it directly from GitHub:

```bash
npx --yes github:SpawnDock/create-spawn-dock#main --token <pairing-token> [project-dir]
```

## What it does
After npm publish, the intended short form remains:

```bash
npx create-spawn-dock --token <pairing-token> [project-dir]
```

- clones `SpawnDock/tma-project`
- claims the pairing token against the control plane
- writes `spawndock.config.json`, `.env.local`, `spawndock.dev-tunnel.json`, and `opencode.json`
- installs dependencies in the generated project
## What it writes

## Generated MCP URL
- `spawndock.config.json`
- `.env.local`
- `spawndock.dev-tunnel.json`
- `opencode.json`
- `public/tonconnect-manifest.json`

The bootstrap writes `MCP_SERVER_URL` to `<controlPlaneUrl>/mcp/sse`.
Generated MCP config points to `<controlPlaneUrl>/mcp/sse`.

## Development

```bash
npm test
pnpm install
pnpm test
pnpm build
```
37 changes: 26 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"name": "create-spawn-dock",
"version": "0.1.0",
"version": "0.2.0",
"type": "module",
"description": "SpawnDock CLI for bootstrapping local TMA projects",
"description": "SpawnDock bootstrap CLI for local TMA projects",
"license": "ISC",
"packageManager": "pnpm@10.32.1",
"workspaces": [
"packages/*"
],
"repository": {
"type": "git",
"url": "git+https://github.com/SpawnDock/create-spawn-dock.git"
Expand All @@ -15,20 +19,31 @@
"publishConfig": {
"access": "public"
},
"exports": {
".": "./src/index.mjs",
"./run": "./src/run.mjs"
},
"files": [
"README.md",
"src",
"template-nextjs-overlay"
"packages/app/dist"
],
"bin": {
"create-spawn-dock": "./src/main.mjs"
"create-spawn-dock": "./packages/app/dist/src/app/main.js"
},
"scripts": {
"prepack": "npm test",
"test": "node --test tests/*.test.mjs"
"prepare": "corepack pnpm build",
"build": "pnpm --filter @create-spawn-dock/app build",
"check": "pnpm --filter @create-spawn-dock/app check",
"test": "pnpm --filter @create-spawn-dock/app test",
"typecheck": "pnpm --filter @create-spawn-dock/app typecheck",
"start": "pnpm --filter @create-spawn-dock/app start"
},
"dependencies": {
"@effect/platform-node": "^0.106.0",
"@effect/schema": "^0.75.5",
"effect": "^3.21.0"
},
"devDependencies": {
"@changesets/changelog-github": "^0.6.0",
"@changesets/cli": "^2.30.0",
"@types/node": "^24.12.0",
"typescript": "^5.9.3",
"vitest": "^4.1.0"
}
}
13 changes: 13 additions & 0 deletions packages/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@create-spawn-dock/app",
"version": "0.2.0",
"private": true,
"type": "module",
"scripts": {
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && chmod +x dist/src/app/main.js",
"check": "pnpm run typecheck",
"start": "node dist/src/app/main.js",
"test": "vitest run",
"typecheck": "tsc --noEmit -p tsconfig.json"
}
}
8 changes: 8 additions & 0 deletions packages/app/src/app/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect, pipe } from "effect"
import { program } from "./program.js"

const main = pipe(program, Effect.provide(NodeContext.layer))

NodeRuntime.runMain(main)
27 changes: 27 additions & 0 deletions packages/app/src/app/program.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Console, Effect, pipe } from "effect"
import type { BootstrapSummary } from "../core/bootstrap.js"
import { bootstrapProject } from "../shell/bootstrap.js"
import { formatUsage, readCliOptions } from "../shell/cli.js"

const formatSuccess = (summary: BootstrapSummary): string =>
[
"",
`SpawnDock project created at ${summary.projectDir}`,
`Project: ${summary.projectName}`,
`Preview URL: ${summary.previewOrigin}`,
`Run: cd "${summary.projectDir}" && npm run dev`,
].join("\n")

const cliProgram = pipe(
readCliOptions,
Effect.flatMap((options) =>
options.token.length > 0
? bootstrapProject(options)
: Effect.fail(new Error(formatUsage())),
),
)

export const program = Effect.matchEffect(cliProgram, {
onFailure: (error) => Console.error(error.message),
onSuccess: (summary) => Console.log(formatSuccess(summary)),
})
Loading
Loading