@toist/in 0.7.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 +40 -0
- package/README.md +42 -24
- package/package.json +10 -3
- package/src/cli.ts +885 -0
- package/src/index.ts +1 -36
- package/src/runtime.ts +75 -0
- package/src/wizard.ts +67 -120
- package/templates/default/README.md +35 -0
- package/templates/default/_gitignore +7 -0
- package/templates/default/_package.json +13 -0
- package/templates/default/data/.gitkeep +0 -0
- package/templates/default/kinds/custom.ts +23 -0
- package/templates/default/pipelines/.gitkeep +0 -0
- package/templates/default/resources/.gitkeep +0 -0
- package/templates/default/start.ts +14 -0
- 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/index.ts
CHANGED
|
@@ -1,37 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
// @toist/in — interactive setup wizard for Toist.
|
|
4
|
-
//
|
|
5
|
-
// Usage:
|
|
6
|
-
// bunx @toist/in run wizard → writes toist.yml + creates dirs
|
|
7
|
-
// bunx @toist/in upgrade upgrade @toist/* deps in current directory
|
|
8
|
-
|
|
9
|
-
import { wizard } from "./wizard.ts"
|
|
10
|
-
import { upgrade } from "./upgrade.ts"
|
|
11
|
-
|
|
12
|
-
const args = process.argv.slice(2)
|
|
13
|
-
const arg = args[0]
|
|
14
|
-
|
|
15
|
-
if (arg === "--help" || arg === "-h") {
|
|
16
|
-
console.log("bunx @toist/in run setup wizard → writes toist.yml")
|
|
17
|
-
console.log("bunx @toist/in upgrade upgrade @toist/* deps")
|
|
18
|
-
console.log("")
|
|
19
|
-
console.log("To start the runner after setup:")
|
|
20
|
-
console.log(" bunx @toist/aja")
|
|
21
|
-
console.log("")
|
|
22
|
-
console.log("Full docs: https://toist.in")
|
|
23
|
-
process.exit(0)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!arg) {
|
|
27
|
-
await wizard()
|
|
28
|
-
} else if (arg === "upgrade") {
|
|
29
|
-
await upgrade()
|
|
30
|
-
} else {
|
|
31
|
-
console.error(`Unknown command: ${arg}`)
|
|
32
|
-
console.error("")
|
|
33
|
-
console.error("Usage:")
|
|
34
|
-
console.error(" bunx @toist/in run setup wizard")
|
|
35
|
-
console.error(" bunx @toist/in upgrade upgrade @toist/* deps")
|
|
36
|
-
process.exit(1)
|
|
37
|
-
}
|
|
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/wizard.ts
CHANGED
|
@@ -1,144 +1,91 @@
|
|
|
1
1
|
// 2121 toist
|
|
2
|
-
// Interactive setup wizard for @toist/in.
|
|
3
|
-
// Asks a few questions, writes toist.yml, creates directories.
|
|
4
2
|
|
|
5
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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"
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
if (resolve) {
|
|
17
|
-
const r = resolve
|
|
18
|
-
resolve = null
|
|
19
|
-
r(line)
|
|
20
|
-
} else {
|
|
21
|
-
lines.push(line)
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
iface.on("close", () => {
|
|
26
|
-
if (resolve) resolve("")
|
|
27
|
-
})
|
|
13
|
+
type TemplateId = typeof TEMPLATES[number]["id"]
|
|
28
14
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (lines.length > 0) return Promise.resolve(lines.shift()!)
|
|
32
|
-
return new Promise((r) => { resolve = r })
|
|
33
|
-
},
|
|
34
|
-
close() { iface.close() },
|
|
35
|
-
}
|
|
15
|
+
function templatesDir(): string {
|
|
16
|
+
return resolve(import.meta.dir, "..", "templates")
|
|
36
17
|
}
|
|
37
18
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return v || def
|
|
19
|
+
function suggestTemplate(dest: string): TemplateId {
|
|
20
|
+
if (basename(dest) === ".toist") return "embedded"
|
|
21
|
+
return "default"
|
|
42
22
|
}
|
|
43
23
|
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!v) return def
|
|
49
|
-
return v === "y" || v === "yes"
|
|
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"
|
|
50
28
|
}
|
|
51
29
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
}
|
|
65
44
|
|
|
66
|
-
|
|
67
|
-
const
|
|
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
|
+
}
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
53
|
+
async function chooseTemplate(defaultTemplate: TemplateId): Promise<TemplateId> {
|
|
54
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
55
|
+
try {
|
|
71
56
|
console.log("")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
kinds.push(kindFile)
|
|
76
|
-
more = await yn(reader, " Add another? ")
|
|
57
|
+
console.log("How will you run pipelines?")
|
|
58
|
+
for (const [index, template] of TEMPLATES.entries()) {
|
|
59
|
+
console.log(` ${index + 1}) ${template.label}`)
|
|
77
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()
|
|
78
67
|
}
|
|
68
|
+
}
|
|
79
69
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const kindsBlock = kinds.length > 0
|
|
87
|
-
? `\nkinds:\n${kinds.map((k) => ` - ${k}`).join("\n")}`
|
|
88
|
-
: ""
|
|
89
|
-
|
|
90
|
-
const configContent = [
|
|
91
|
-
`# toist.yml — generated by bunx @toist/in`,
|
|
92
|
-
`# Run with: bunx @toist/aja`,
|
|
93
|
-
``,
|
|
94
|
-
`instance: ${name}`,
|
|
95
|
-
`port: ${port}`,
|
|
96
|
-
`pipelines: ./${pipelines}`,
|
|
97
|
-
`resources: ./${resources}`,
|
|
98
|
-
`data: ./${data}`,
|
|
99
|
-
...(kinds.length > 0 ? [``, `kinds:`, ...kinds.map((k) => ` - ${k}`)] : []),
|
|
100
|
-
``,
|
|
101
|
-
].join("\n")
|
|
102
|
-
|
|
103
|
-
const configPath = resolve(cwd, "toist.yml")
|
|
104
|
-
const alreadyExists = existsSync(configPath)
|
|
105
|
-
|
|
106
|
-
console.log("")
|
|
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)
|
|
107
75
|
|
|
108
|
-
if (
|
|
109
|
-
console.
|
|
110
|
-
|
|
111
|
-
writeFileSync(configPath, configContent, "utf8")
|
|
112
|
-
console.log("Wrote toist.yml")
|
|
76
|
+
if (!existsSync(templateDir)) {
|
|
77
|
+
console.error(`Template not found: ${templateId}`)
|
|
78
|
+
process.exit(1)
|
|
113
79
|
}
|
|
114
80
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
for (const dir of [pipelines, resources, data]) {
|
|
120
|
-
const abs = resolve(cwd, dir)
|
|
121
|
-
if (!existsSync(abs)) {
|
|
122
|
-
mkdirSync(abs, { recursive: true })
|
|
123
|
-
// Keep data/ out of git, commit the rest
|
|
124
|
-
if (dir === data) {
|
|
125
|
-
writeFileSync(resolve(abs, ".gitignore"), "*.db\n*.db-shm\n*.db-wal\n.lock/\n")
|
|
126
|
-
} else {
|
|
127
|
-
writeFileSync(resolve(abs, ".gitkeep"), "")
|
|
128
|
-
}
|
|
129
|
-
console.log(`Created ${dir}/`)
|
|
130
|
-
}
|
|
81
|
+
if (existsSync(dest)) {
|
|
82
|
+
console.error(`Destination already exists: ${dest}`)
|
|
83
|
+
process.exit(1)
|
|
131
84
|
}
|
|
132
85
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
86
|
+
copyTemplate(templateDir, dest)
|
|
87
|
+
rewritePackageName(dest)
|
|
136
88
|
|
|
137
|
-
|
|
138
|
-
console.log(
|
|
139
|
-
console.log(" bunx @toist/aja")
|
|
140
|
-
console.log("")
|
|
141
|
-
console.log("Or add a script to package.json:")
|
|
142
|
-
console.log(' "toist": "bunx @toist/aja"')
|
|
143
|
-
console.log("")
|
|
89
|
+
const relative = dest.startsWith(cwd) ? `./${dest.slice(cwd.length).replace(/^\/+/, "") || basename(dest)}` : dest
|
|
90
|
+
console.log(`✓ created ${relative} (${templateId} template)`)
|
|
144
91
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# my-toist-instance
|
|
2
|
+
|
|
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/`.
|
|
8
|
+
|
|
9
|
+
## First run
|
|
10
|
+
|
|
11
|
+
1. `bun install`
|
|
12
|
+
2. `bun start.ts` — runner boots on `http://localhost:3000`.
|
|
13
|
+
|
|
14
|
+
Open `http://localhost:3000` to use the UI.
|
|
15
|
+
|
|
16
|
+
## Layout
|
|
17
|
+
|
|
18
|
+
- `start.ts` — bootstrap; calls `startRunner` from `@toist/aja`
|
|
19
|
+
- `kinds/custom.ts` — register your domain-specific kinds here (or import them from normal workspace code)
|
|
20
|
+
- `pipelines/*.yaml` — pipeline definitions (per pipeline-spec)
|
|
21
|
+
- `toist.yml` — resource config for this Toist home
|
|
22
|
+
- `data/` — runtime SQLite databases (gitignored)
|
|
23
|
+
|
|
24
|
+
## Upgrading
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
bunx @toist/in upgrade
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Run from the instance directory or host repo root. Bumps every
|
|
31
|
+
`@toist/*` dep in `package.json` to the latest version.
|
|
32
|
+
|
|
33
|
+
## More
|
|
34
|
+
|
|
35
|
+
Full quickstart and docs: https://toist.in/docs
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// 2121 toist — register your domain-specific kinds here.
|
|
2
|
+
//
|
|
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/docs for
|
|
5
|
+
// the full contract.
|
|
6
|
+
//
|
|
7
|
+
// Example:
|
|
8
|
+
//
|
|
9
|
+
// import type { NodeKind } from "@toist/spec"
|
|
10
|
+
//
|
|
11
|
+
// export const greet: NodeKind<{ name: string }, { msg: string }> = {
|
|
12
|
+
// id: "demo.greet",
|
|
13
|
+
// params: { name: { type: "string", required: true } },
|
|
14
|
+
// async execute(ctx) {
|
|
15
|
+
// return { msg: `Hello, ${ctx.params.name}!` }
|
|
16
|
+
// },
|
|
17
|
+
// }
|
|
18
|
+
//
|
|
19
|
+
// Then in start.ts:
|
|
20
|
+
// import * as customKinds from "./kinds/custom.ts"
|
|
21
|
+
// register(...Object.values(customKinds))
|
|
22
|
+
|
|
23
|
+
export {}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// 2121 toist instance bootstrap.
|
|
2
|
+
// See https://toist.in/docs for the full quickstart.
|
|
3
|
+
|
|
4
|
+
import { startRunner } from "@toist/aja"
|
|
5
|
+
|
|
6
|
+
// Uncomment to register domain-specific kinds:
|
|
7
|
+
// import { register } from "@toist/aja"
|
|
8
|
+
// import * as customKinds from "./kinds/custom.ts"
|
|
9
|
+
// register(...Object.values(customKinds))
|
|
10
|
+
|
|
11
|
+
await startRunner({
|
|
12
|
+
port: Number(process.env.PORT ?? 3000),
|
|
13
|
+
rootDir: import.meta.dir,
|
|
14
|
+
})
|
|
@@ -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))
|