@toist/in 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/README.md +64 -0
- package/package.json +12 -5
- package/src/cli.ts +885 -0
- package/src/index.ts +1 -37
- package/src/runtime.ts +75 -0
- package/src/upgrade.ts +19 -5
- package/src/wizard.ts +91 -0
- package/templates/default/README.md +11 -7
- package/templates/default/_package.json +2 -2
- package/templates/default/kinds/custom.ts +1 -1
- package/templates/default/start.ts +1 -1
- package/templates/default/toist.yml +2 -0
- package/templates/embedded/README.md +58 -0
- package/templates/embedded/_gitignore +5 -0
- package/templates/embedded/data/.gitkeep +0 -0
- package/templates/embedded/instance.json +4 -0
- package/templates/embedded/pipelines/.gitkeep +0 -0
- package/templates/embedded/resources/.gitkeep +0 -0
- package/templates/embedded/start.ts +24 -0
- package/templates/embedded/toist.yml +2 -0
- package/templates/embedded-memory/README.md +12 -0
- package/templates/embedded-memory/_gitignore +1 -0
- package/templates/embedded-memory/pipelines/hello.yml +12 -0
- package/templates/embedded-memory/start.ts +16 -0
- package/src/scaffold.ts +0 -67
package/src/index.ts
CHANGED
|
@@ -1,38 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
// @toist/in — scaffold a new toist instance, or upgrade an existing one.
|
|
4
|
-
//
|
|
5
|
-
// Usage:
|
|
6
|
-
// bunx @toist/in <path> scaffold a new instance at <path>
|
|
7
|
-
// bunx @toist/in upgrade @toist/* deps in the current directory
|
|
8
|
-
|
|
9
|
-
import { existsSync } from "node:fs"
|
|
10
|
-
import { resolve } from "node:path"
|
|
11
|
-
import { scaffold } from "./scaffold.ts"
|
|
12
|
-
import { upgrade } from "./upgrade.ts"
|
|
13
|
-
|
|
14
|
-
const args = process.argv.slice(2)
|
|
15
|
-
const arg = args[0]
|
|
16
|
-
|
|
17
|
-
if (arg === "--help" || arg === "-h") {
|
|
18
|
-
console.log("bunx @toist/in <path> scaffold a new toist instance at <path>")
|
|
19
|
-
console.log("bunx @toist/in upgrade @toist/* deps in the current directory")
|
|
20
|
-
console.log("")
|
|
21
|
-
console.log("Full docs: https://toist.in")
|
|
22
|
-
process.exit(0)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!arg) {
|
|
26
|
-
// No path given — upgrade if we're inside a toist instance, else error.
|
|
27
|
-
const pkgPath = resolve(process.cwd(), "package.json")
|
|
28
|
-
if (!existsSync(pkgPath)) {
|
|
29
|
-
console.error("No package.json found in the current directory.")
|
|
30
|
-
console.error("")
|
|
31
|
-
console.error("To scaffold a new instance: bunx @toist/in <path>")
|
|
32
|
-
console.error("To upgrade an existing one: run from the instance directory")
|
|
33
|
-
process.exit(1)
|
|
34
|
-
}
|
|
35
|
-
await upgrade()
|
|
36
|
-
} else {
|
|
37
|
-
await scaffold(arg)
|
|
38
|
-
}
|
|
2
|
+
import "./cli.ts"
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { join, resolve, dirname } from "node:path"
|
|
3
|
+
import { homedir } from "node:os"
|
|
4
|
+
import { createMemoryRuntime, runSpec, type ResumableRuntime, type RunSpecResult, type ToistRuntime } from "@toist/core"
|
|
5
|
+
import { createSqliteRuntime } from "@toist/aja"
|
|
6
|
+
|
|
7
|
+
interface RuntimeWithClose extends ToistRuntime {
|
|
8
|
+
close?: () => Promise<void>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface StoredRunDescriptor {
|
|
12
|
+
spec: unknown
|
|
13
|
+
payload: Record<string, unknown>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getCliStateDir(): string {
|
|
17
|
+
const xdg = process.env.XDG_STATE_HOME
|
|
18
|
+
if (xdg) return resolve(xdg, "toist")
|
|
19
|
+
|
|
20
|
+
const home = process.env.HOME || homedir()
|
|
21
|
+
if (home) return resolve(home, ".toist")
|
|
22
|
+
|
|
23
|
+
return resolve(process.cwd(), ".toist")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function getCliRuntime(options: { ephemeral?: boolean } = {}): Promise<RuntimeWithClose> {
|
|
27
|
+
if (options.ephemeral) return createMemoryRuntime()
|
|
28
|
+
|
|
29
|
+
const rootDir = getCliStateDir()
|
|
30
|
+
mkdirSync(rootDir, { recursive: true })
|
|
31
|
+
return await createSqliteRuntime({ rootDir, dataDir: rootDir })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getRunDescriptorPath(runId: number): string {
|
|
35
|
+
return join(getCliStateDir(), "runs", `${runId}.json`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function storeRunDescriptor(runId: number, descriptor: StoredRunDescriptor): void {
|
|
39
|
+
const path = getRunDescriptorPath(runId)
|
|
40
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
41
|
+
writeFileSync(path, JSON.stringify(descriptor, null, 2))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function loadRunDescriptor(runId: number): StoredRunDescriptor | null {
|
|
45
|
+
const path = getRunDescriptorPath(runId)
|
|
46
|
+
if (!existsSync(path)) return null
|
|
47
|
+
return JSON.parse(readFileSync(path, "utf8")) as StoredRunDescriptor
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function deleteRunDescriptor(runId: number): void {
|
|
51
|
+
const path = getRunDescriptorPath(runId)
|
|
52
|
+
if (existsSync(path)) rmSync(path, { force: true })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isResumableRuntime(runtime: ToistRuntime): runtime is ResumableRuntime {
|
|
56
|
+
return typeof (runtime as ResumableRuntime).resumeRun === "function"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function resumeLocalStoredRun(
|
|
60
|
+
runtime: ToistRuntime,
|
|
61
|
+
runId: number,
|
|
62
|
+
descriptor: StoredRunDescriptor,
|
|
63
|
+
response: { taskId: number; token: string; response: unknown; respondedBy?: string },
|
|
64
|
+
): Promise<RunSpecResult> {
|
|
65
|
+
await runtime.tasks.answer(response.taskId, response.token, response.response, response.respondedBy ?? "cli")
|
|
66
|
+
const resumeOutputs = await runtime.outputs.list(runId)
|
|
67
|
+
await runtime.runs.markRunning(runId, { trigger: "resumed", clearCurrentNode: true })
|
|
68
|
+
return await runSpec(descriptor.spec, descriptor.payload, {
|
|
69
|
+
runtime,
|
|
70
|
+
resumeRunId: runId,
|
|
71
|
+
resumeOutputs,
|
|
72
|
+
trigger: "resumed",
|
|
73
|
+
events: true,
|
|
74
|
+
})
|
|
75
|
+
}
|
package/src/upgrade.ts
CHANGED
|
@@ -5,17 +5,31 @@
|
|
|
5
5
|
|
|
6
6
|
import { readFile } from "node:fs/promises"
|
|
7
7
|
import { existsSync } from "node:fs"
|
|
8
|
-
import { resolve } from "node:path"
|
|
8
|
+
import { basename, dirname, resolve } from "node:path"
|
|
9
9
|
import { spawnSync } from "node:child_process"
|
|
10
10
|
|
|
11
|
+
function resolvePackageDir(cwd: string): string | null {
|
|
12
|
+
const localPkg = resolve(cwd, "package.json")
|
|
13
|
+
if (existsSync(localPkg)) return cwd
|
|
14
|
+
|
|
15
|
+
if (basename(cwd) === ".toist") {
|
|
16
|
+
const parent = dirname(cwd)
|
|
17
|
+
if (existsSync(resolve(parent, "package.json"))) return parent
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
export async function upgrade(cwd = process.cwd()): Promise<void> {
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
24
|
+
const packageDir = resolvePackageDir(cwd)
|
|
25
|
+
if (!packageDir) {
|
|
14
26
|
console.error(`No package.json in ${cwd}.`)
|
|
15
|
-
console.error("Run from your toist
|
|
27
|
+
console.error("Run from your host repo root or .toist/ directory.")
|
|
16
28
|
process.exit(1)
|
|
17
29
|
}
|
|
18
30
|
|
|
31
|
+
const pkgPath = resolve(packageDir, "package.json")
|
|
32
|
+
|
|
19
33
|
const pkg = JSON.parse(await readFile(pkgPath, "utf8")) as {
|
|
20
34
|
dependencies?: Record<string, string>
|
|
21
35
|
devDependencies?: Record<string, string>
|
|
@@ -39,7 +53,7 @@ export async function upgrade(cwd = process.cwd()): Promise<void> {
|
|
|
39
53
|
console.log(`Upgrading: ${targets.join(", ")}\n`)
|
|
40
54
|
const result = spawnSync("bun", ["update", "--latest", ...targets], {
|
|
41
55
|
stdio: "inherit",
|
|
42
|
-
cwd,
|
|
56
|
+
cwd: packageDir,
|
|
43
57
|
})
|
|
44
58
|
process.exit(result.status ?? 0)
|
|
45
59
|
}
|
package/src/wizard.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// 2121 toist
|
|
2
|
+
|
|
3
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path"
|
|
5
|
+
import { createInterface } from "node:readline/promises"
|
|
6
|
+
|
|
7
|
+
const TEMPLATES = [
|
|
8
|
+
{ id: "default", label: "Durable runner (default)" },
|
|
9
|
+
{ id: "embedded", label: "Embedded `.toist/` runner" },
|
|
10
|
+
{ id: "embedded-memory", label: "Memory-only (library use)" },
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
type TemplateId = typeof TEMPLATES[number]["id"]
|
|
14
|
+
|
|
15
|
+
function templatesDir(): string {
|
|
16
|
+
return resolve(import.meta.dir, "..", "templates")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function suggestTemplate(dest: string): TemplateId {
|
|
20
|
+
if (basename(dest) === ".toist") return "embedded"
|
|
21
|
+
return "default"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function packageNameFor(dest: string): string {
|
|
25
|
+
const base = basename(dest)
|
|
26
|
+
if (base === ".toist") return `${basename(dirname(dest)) || "toist"}-toist`
|
|
27
|
+
return base || "toist"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function copyTemplate(src: string, dest: string) {
|
|
31
|
+
mkdirSync(dest, { recursive: true })
|
|
32
|
+
for (const entry of readdirSync(src)) {
|
|
33
|
+
const srcPath = join(src, entry)
|
|
34
|
+
const outName = entry === "_gitignore" ? ".gitignore" : entry === "_package.json" ? "package.json" : entry
|
|
35
|
+
const destPath = join(dest, outName)
|
|
36
|
+
const info = statSync(srcPath)
|
|
37
|
+
if (info.isDirectory()) {
|
|
38
|
+
copyTemplate(srcPath, destPath)
|
|
39
|
+
} else {
|
|
40
|
+
copyFileSync(srcPath, destPath)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function rewritePackageName(dest: string) {
|
|
46
|
+
const path = join(dest, "package.json")
|
|
47
|
+
if (!existsSync(path)) return
|
|
48
|
+
const pkg = JSON.parse(readFileSync(path, "utf8")) as { name?: string }
|
|
49
|
+
pkg.name = packageNameFor(dest)
|
|
50
|
+
writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function chooseTemplate(defaultTemplate: TemplateId): Promise<TemplateId> {
|
|
54
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
55
|
+
try {
|
|
56
|
+
console.log("")
|
|
57
|
+
console.log("How will you run pipelines?")
|
|
58
|
+
for (const [index, template] of TEMPLATES.entries()) {
|
|
59
|
+
console.log(` ${index + 1}) ${template.label}`)
|
|
60
|
+
}
|
|
61
|
+
const defaultIndex = TEMPLATES.findIndex((template) => template.id === defaultTemplate) + 1
|
|
62
|
+
const answer = (await rl.question(`Choice [${defaultIndex}]: `)).trim()
|
|
63
|
+
const picked = Number(answer || defaultIndex)
|
|
64
|
+
return TEMPLATES[picked - 1]?.id ?? defaultTemplate
|
|
65
|
+
} finally {
|
|
66
|
+
rl.close()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function wizard(cwd = process.cwd(), destArg?: string): Promise<void> {
|
|
71
|
+
const destName = destArg ?? "toist"
|
|
72
|
+
const templateId = await chooseTemplate(suggestTemplate(destName))
|
|
73
|
+
const templateDir = join(templatesDir(), templateId)
|
|
74
|
+
const dest = resolve(cwd, destName)
|
|
75
|
+
|
|
76
|
+
if (!existsSync(templateDir)) {
|
|
77
|
+
console.error(`Template not found: ${templateId}`)
|
|
78
|
+
process.exit(1)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (existsSync(dest)) {
|
|
82
|
+
console.error(`Destination already exists: ${dest}`)
|
|
83
|
+
process.exit(1)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
copyTemplate(templateDir, dest)
|
|
87
|
+
rewritePackageName(dest)
|
|
88
|
+
|
|
89
|
+
const relative = dest.startsWith(cwd) ? `./${dest.slice(cwd.length).replace(/^\/+/, "") || basename(dest)}` : dest
|
|
90
|
+
console.log(`✓ created ${relative} (${templateId} template)`)
|
|
91
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# my-toist-instance
|
|
2
2
|
|
|
3
|
-
Generated with [`bunx @toist/in`](https://toist.in).
|
|
3
|
+
Generated with [`bunx @toist/in`](https://toist.in/docs).
|
|
4
|
+
|
|
5
|
+
This directory is a Toist home. It can be used either as a dedicated
|
|
6
|
+
instance directory or as an embedded repo-owned home such as
|
|
7
|
+
`<repo>/.toist/`.
|
|
4
8
|
|
|
5
9
|
## First run
|
|
6
10
|
|
|
@@ -12,20 +16,20 @@ Open `http://localhost:3000` to use the UI.
|
|
|
12
16
|
## Layout
|
|
13
17
|
|
|
14
18
|
- `start.ts` — bootstrap; calls `startRunner` from `@toist/aja`
|
|
15
|
-
- `kinds/custom.ts` — register your domain-specific kinds here
|
|
19
|
+
- `kinds/custom.ts` — register your domain-specific kinds here (or import them from normal workspace code)
|
|
16
20
|
- `pipelines/*.yaml` — pipeline definitions (per pipeline-spec)
|
|
17
|
-
- `
|
|
21
|
+
- `toist.yml` — resource config for this Toist home
|
|
18
22
|
- `data/` — runtime SQLite databases (gitignored)
|
|
19
23
|
|
|
20
24
|
## Upgrading
|
|
21
25
|
|
|
22
26
|
```sh
|
|
23
|
-
bunx @toist/in
|
|
27
|
+
bunx @toist/in upgrade
|
|
24
28
|
```
|
|
25
29
|
|
|
26
|
-
Run
|
|
27
|
-
`@toist/*` dep in `package.json`
|
|
30
|
+
Run from the instance directory or host repo root. Bumps every
|
|
31
|
+
`@toist/*` dep in `package.json` to the latest version.
|
|
28
32
|
|
|
29
33
|
## More
|
|
30
34
|
|
|
31
|
-
Full quickstart and docs: https://toist.in
|
|
35
|
+
Full quickstart and docs: https://toist.in/docs
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 2121 toist — register your domain-specific kinds here.
|
|
2
2
|
//
|
|
3
3
|
// Each export should be a NodeKind<P, I>. See the @toist/aja built-ins for
|
|
4
|
-
// reference shapes, and pipeline-spec / kind-spec at https://toist.in for
|
|
4
|
+
// reference shapes, and pipeline-spec / kind-spec at https://toist.in/docs for
|
|
5
5
|
// the full contract.
|
|
6
6
|
//
|
|
7
7
|
// Example:
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# my-repo/.toist
|
|
2
|
+
|
|
3
|
+
Generated with [`bunx @toist/in .toist`](https://toist.in/docs).
|
|
4
|
+
|
|
5
|
+
This directory is the embedded Toist home for an existing repo.
|
|
6
|
+
`@toist/aja` runs pipelines; `.toist/` is the repo-owned local home for
|
|
7
|
+
Toist config, pipeline definitions, and runtime state.
|
|
8
|
+
|
|
9
|
+
## First run
|
|
10
|
+
|
|
11
|
+
1. From the host repo root: `bun add @toist/aja @toist/spec`
|
|
12
|
+
2. Optionally, add a script to your root `package.json`:
|
|
13
|
+
```json
|
|
14
|
+
"scripts": { "toist": "bun .toist/start.ts" }
|
|
15
|
+
```
|
|
16
|
+
3. Start the embedded instance: `bun .toist/start.ts`
|
|
17
|
+
|
|
18
|
+
Open `http://localhost:3000` to use the UI.
|
|
19
|
+
|
|
20
|
+
## Layout
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
.toist/
|
|
24
|
+
start.ts — embedded bootstrap; calls startRunner from @toist/aja
|
|
25
|
+
instance.json — instance name and tier (optional)
|
|
26
|
+
pipelines/ — pipeline YAML files owned by this repo
|
|
27
|
+
toist.yml — resource config for this embedded home
|
|
28
|
+
data/ — runtime SQLite databases (gitignored)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Custom TypeScript kinds stay in your host repo's normal source tree or
|
|
32
|
+
workspace packages. Import and register them from `.toist/start.ts`:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { register } from "@toist/aja"
|
|
36
|
+
import * as myKinds from "../src/toist-kinds.ts"
|
|
37
|
+
register(...Object.values(myKinds))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Environment
|
|
41
|
+
|
|
42
|
+
| Variable | Default | Notes |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `TOIST_PORT` | `3000` | Port the runner listens on |
|
|
45
|
+
| `PORT` | `3000` | Fallback if `TOIST_PORT` is unset |
|
|
46
|
+
|
|
47
|
+
## Upgrading
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
bunx @toist/in upgrade
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Run from `.toist/` or from the host repo root. Finds `package.json`
|
|
54
|
+
and bumps every `@toist/*` dependency to the latest version.
|
|
55
|
+
|
|
56
|
+
## More
|
|
57
|
+
|
|
58
|
+
Full quickstart and docs: https://toist.in/docs
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// 2121 toist — embedded bootstrap for .toist/
|
|
2
|
+
// See https://toist.in/docs for the full quickstart.
|
|
3
|
+
//
|
|
4
|
+
// rootDir is set to this directory (.toist/).
|
|
5
|
+
// The runner resolves all paths relative to it:
|
|
6
|
+
// .toist/pipelines/ — pipeline YAML files
|
|
7
|
+
// .toist/toist.yml — resource config
|
|
8
|
+
// .toist/data/ — runtime SQLite databases (gitignored)
|
|
9
|
+
//
|
|
10
|
+
// Custom kinds belong in your host repo's normal source tree.
|
|
11
|
+
// Import and register them here before calling startRunner.
|
|
12
|
+
//
|
|
13
|
+
// Examples:
|
|
14
|
+
// import * as myKinds from "../src/toist-kinds.ts"
|
|
15
|
+
// import * as myKinds from "../packages/my-kinds/src/index.ts"
|
|
16
|
+
// import { register } from "@toist/aja"
|
|
17
|
+
// register(...Object.values(myKinds))
|
|
18
|
+
|
|
19
|
+
import { startRunner } from "@toist/aja"
|
|
20
|
+
|
|
21
|
+
await startRunner({
|
|
22
|
+
port: Number(process.env.TOIST_PORT ?? process.env.PORT ?? 3000),
|
|
23
|
+
rootDir: import.meta.dir, // = <repo>/.toist/
|
|
24
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# memory-only Toist host
|
|
2
|
+
|
|
3
|
+
Generated with `bunx @toist/in` using the memory-only template.
|
|
4
|
+
|
|
5
|
+
This template uses `runSpec()` and `createMemoryRuntime()` directly. There is no HTTP runner, no UI, and no durable SQLite state.
|
|
6
|
+
|
|
7
|
+
## First run
|
|
8
|
+
|
|
9
|
+
1. Add `@toist/core` and `@toist/spec` to your host repo.
|
|
10
|
+
2. Run `bun start.ts`.
|
|
11
|
+
|
|
12
|
+
The example reads `./pipelines/hello.yml` and prints the result JSON.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { parseYaml } from "@toist/spec"
|
|
4
|
+
import { createMemoryRuntime, runSpec } from "@toist/core"
|
|
5
|
+
|
|
6
|
+
const spec = parseYaml(readFileSync(join(import.meta.dir, "pipelines", "hello.yml"), "utf8"))
|
|
7
|
+
const runtime = createMemoryRuntime()
|
|
8
|
+
const payload = process.argv[2] ? JSON.parse(process.argv[2]) : { name: "world" }
|
|
9
|
+
const result = await runSpec(spec, payload, { runtime, events: true })
|
|
10
|
+
|
|
11
|
+
for await (const event of result.events ?? []) {
|
|
12
|
+
console.error(`[event] ${event.type}`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { events: _events, ...printable } = result
|
|
16
|
+
console.log(JSON.stringify(printable, null, 2))
|
package/src/scaffold.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// 2121 toist
|
|
2
|
-
// Scaffold logic for @toist/in. Recursively copies templates/default/* into
|
|
3
|
-
// the target directory, with two `_`-prefixed filenames renamed at copy time:
|
|
4
|
-
//
|
|
5
|
-
// - `_gitignore` -> `.gitignore`
|
|
6
|
-
// - `_package.json` -> `package.json`
|
|
7
|
-
//
|
|
8
|
-
// The underscore prefix exists because npm strips files like `.gitignore` and
|
|
9
|
-
// (in some configurations) `package.json` from publishable subdirs. Prefixing
|
|
10
|
-
// dodges those rules; the runtime rename produces the real names in the host.
|
|
11
|
-
//
|
|
12
|
-
// Templates live in `<package>/templates/default/`, relative to this file's
|
|
13
|
-
// runtime location. Works whether the package is consumed as a workspace
|
|
14
|
-
// link (in this repo) or from node_modules (in a host repo).
|
|
15
|
-
|
|
16
|
-
import { mkdir, copyFile, readdir, stat } from "node:fs/promises"
|
|
17
|
-
import { existsSync } from "node:fs"
|
|
18
|
-
import { dirname, join, resolve } from "node:path"
|
|
19
|
-
import { fileURLToPath } from "node:url"
|
|
20
|
-
|
|
21
|
-
const __dir = dirname(fileURLToPath(import.meta.url))
|
|
22
|
-
const TEMPLATE_DIR = resolve(__dir, "..", "templates", "default")
|
|
23
|
-
|
|
24
|
-
const RENAMES: Record<string, string> = {
|
|
25
|
-
_gitignore: ".gitignore",
|
|
26
|
-
"_package.json": "package.json",
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function scaffold(target: string): Promise<void> {
|
|
30
|
-
const dest = resolve(process.cwd(), target)
|
|
31
|
-
|
|
32
|
-
if (existsSync(dest)) {
|
|
33
|
-
const entries = await readdir(dest)
|
|
34
|
-
if (entries.length > 0) {
|
|
35
|
-
console.error(`Target directory '${dest}' is not empty. Aborting.`)
|
|
36
|
-
process.exit(1)
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
await mkdir(dest, { recursive: true })
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await copyTree(TEMPLATE_DIR, dest)
|
|
43
|
-
|
|
44
|
-
console.log(`\nScaffolded toist instance at ${dest}\n`)
|
|
45
|
-
console.log("Next:")
|
|
46
|
-
console.log(` cd ${target}`)
|
|
47
|
-
console.log(` bun install`)
|
|
48
|
-
console.log(` bun start.ts`)
|
|
49
|
-
console.log("")
|
|
50
|
-
console.log(`Full docs: https://toist.in`)
|
|
51
|
-
console.log("")
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function copyTree(src: string, dest: string): Promise<void> {
|
|
55
|
-
for (const entry of await readdir(src)) {
|
|
56
|
-
const srcPath = join(src, entry)
|
|
57
|
-
const destName = RENAMES[entry] ?? entry
|
|
58
|
-
const destPath = join(dest, destName)
|
|
59
|
-
const info = await stat(srcPath)
|
|
60
|
-
if (info.isDirectory()) {
|
|
61
|
-
await mkdir(destPath, { recursive: true })
|
|
62
|
-
await copyTree(srcPath, destPath)
|
|
63
|
-
} else {
|
|
64
|
-
await copyFile(srcPath, destPath)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|