spawnfile 0.1.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/LICENSE +21 -0
- package/README.md +464 -0
- package/dist/.env.example +5 -0
- package/dist/Dockerfile +21 -0
- package/dist/auth/importers.d.ts +8 -0
- package/dist/auth/importers.js +93 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/paths.d.ts +6 -0
- package/dist/auth/paths.js +18 -0
- package/dist/auth/profileStore.d.ts +10 -0
- package/dist/auth/profileStore.js +125 -0
- package/dist/auth/runtimeCredentials.d.ts +14 -0
- package/dist/auth/runtimeCredentials.js +76 -0
- package/dist/auth/types.d.ts +22 -0
- package/dist/auth/types.js +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/runCli.d.ts +27 -0
- package/dist/cli/runCli.js +314 -0
- package/dist/compiler/addProjectNode.d.ts +21 -0
- package/dist/compiler/addProjectNode.js +126 -0
- package/dist/compiler/agentSurfaces.d.ts +4 -0
- package/dist/compiler/agentSurfaces.js +70 -0
- package/dist/compiler/buildCompilePlan.d.ts +2 -0
- package/dist/compiler/buildCompilePlan.js +258 -0
- package/dist/compiler/buildProject.d.ts +20 -0
- package/dist/compiler/buildProject.js +52 -0
- package/dist/compiler/compilePlanHelpers.d.ts +7 -0
- package/dist/compiler/compilePlanHelpers.js +39 -0
- package/dist/compiler/compileProject.d.ts +11 -0
- package/dist/compiler/compileProject.js +182 -0
- package/dist/compiler/containerArtifacts.d.ts +4 -0
- package/dist/compiler/containerArtifacts.js +64 -0
- package/dist/compiler/containerArtifactsPlans.d.ts +4 -0
- package/dist/compiler/containerArtifactsPlans.js +154 -0
- package/dist/compiler/containerArtifactsRender.d.ts +6 -0
- package/dist/compiler/containerArtifactsRender.js +237 -0
- package/dist/compiler/containerArtifactsTypes.d.ts +42 -0
- package/dist/compiler/containerArtifactsTypes.js +1 -0
- package/dist/compiler/discordSurface.d.ts +4 -0
- package/dist/compiler/discordSurface.js +28 -0
- package/dist/compiler/executionDefaults.d.ts +2 -0
- package/dist/compiler/executionDefaults.js +9 -0
- package/dist/compiler/helpers.d.ts +7 -0
- package/dist/compiler/helpers.js +35 -0
- package/dist/compiler/index.d.ts +9 -0
- package/dist/compiler/index.js +9 -0
- package/dist/compiler/initProject.d.ts +9 -0
- package/dist/compiler/initProject.js +46 -0
- package/dist/compiler/modelAuth.d.ts +2 -0
- package/dist/compiler/modelAuth.js +17 -0
- package/dist/compiler/modelEnv.d.ts +10 -0
- package/dist/compiler/modelEnv.js +97 -0
- package/dist/compiler/runProject.d.ts +34 -0
- package/dist/compiler/runProject.js +197 -0
- package/dist/compiler/runProjectAuth.d.ts +9 -0
- package/dist/compiler/runProjectAuth.js +59 -0
- package/dist/compiler/surfaceSupport.d.ts +2 -0
- package/dist/compiler/surfaceSupport.js +13 -0
- package/dist/compiler/surfaces.d.ts +21 -0
- package/dist/compiler/surfaces.js +59 -0
- package/dist/compiler/syncProjectAuth.d.ts +7 -0
- package/dist/compiler/syncProjectAuth.js +65 -0
- package/dist/compiler/types.d.ts +134 -0
- package/dist/compiler/types.js +1 -0
- package/dist/compiler/updateProjectModels.d.ts +20 -0
- package/dist/compiler/updateProjectModels.js +181 -0
- package/dist/container/rootfs/var/lib/spawnfile/instances/picoclaw/agent-assistant/picoclaw/config.json +16 -0
- package/dist/container/rootfs/var/lib/spawnfile/instances/picoclaw/agent-assistant/picoclaw/workspace/AGENTS.md +1 -0
- package/dist/e2e/cli.d.ts +1 -0
- package/dist/e2e/cli.js +40 -0
- package/dist/e2e/dockerAuth.d.ts +18 -0
- package/dist/e2e/dockerAuth.js +212 -0
- package/dist/e2e/fixtures.d.ts +2 -0
- package/dist/e2e/fixtures.js +49 -0
- package/dist/e2e/index.d.ts +4 -0
- package/dist/e2e/index.js +4 -0
- package/dist/e2e/runtimePrompts.d.ts +13 -0
- package/dist/e2e/runtimePrompts.js +132 -0
- package/dist/e2e/scenarios.d.ts +3 -0
- package/dist/e2e/scenarios.js +84 -0
- package/dist/e2e/types.d.ts +35 -0
- package/dist/e2e/types.js +1 -0
- package/dist/entrypoint.sh +71 -0
- package/dist/filesystem/index.d.ts +2 -0
- package/dist/filesystem/index.js +2 -0
- package/dist/filesystem/io.d.ts +11 -0
- package/dist/filesystem/io.js +57 -0
- package/dist/filesystem/paths.d.ts +6 -0
- package/dist/filesystem/paths.js +30 -0
- package/dist/manifest/index.d.ts +5 -0
- package/dist/manifest/index.js +5 -0
- package/dist/manifest/loadManifest.d.ts +12 -0
- package/dist/manifest/loadManifest.js +208 -0
- package/dist/manifest/renderSpawnfile.d.ts +2 -0
- package/dist/manifest/renderSpawnfile.js +211 -0
- package/dist/manifest/scaffold.d.ts +16 -0
- package/dist/manifest/scaffold.js +41 -0
- package/dist/manifest/schemas.d.ts +989 -0
- package/dist/manifest/schemas.js +314 -0
- package/dist/manifest/skillFrontmatter.d.ts +5 -0
- package/dist/manifest/skillFrontmatter.js +32 -0
- package/dist/manifest/surfaceSchemas.d.ts +148 -0
- package/dist/manifest/surfaceSchemas.js +162 -0
- package/dist/report/createDiagnostic.d.ts +2 -0
- package/dist/report/createDiagnostic.js +4 -0
- package/dist/report/createReport.d.ts +2 -0
- package/dist/report/createReport.js +7 -0
- package/dist/report/index.d.ts +4 -0
- package/dist/report/index.js +4 -0
- package/dist/report/types.d.ts +50 -0
- package/dist/report/types.js +1 -0
- package/dist/report/writeReport.d.ts +2 -0
- package/dist/report/writeReport.js +9 -0
- package/dist/runtime/common.d.ts +13 -0
- package/dist/runtime/common.js +63 -0
- package/dist/runtime/container.d.ts +8 -0
- package/dist/runtime/container.js +67 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/install.d.ts +51 -0
- package/dist/runtime/install.js +167 -0
- package/dist/runtime/openclaw/adapter.d.ts +2 -0
- package/dist/runtime/openclaw/adapter.js +194 -0
- package/dist/runtime/openclaw/runAuth.d.ts +2 -0
- package/dist/runtime/openclaw/runAuth.js +125 -0
- package/dist/runtime/openclaw/scaffold-assets/AGENTS.md +120 -0
- package/dist/runtime/openclaw/scaffold-assets/CLAUDE.md +5 -0
- package/dist/runtime/openclaw/scaffold-assets/IDENTITY.md +23 -0
- package/dist/runtime/openclaw/scaffold-assets/SOUL.md +36 -0
- package/dist/runtime/openclaw/scaffold.d.ts +2 -0
- package/dist/runtime/openclaw/scaffold.js +28 -0
- package/dist/runtime/openclaw/surfaces.d.ts +5 -0
- package/dist/runtime/openclaw/surfaces.js +253 -0
- package/dist/runtime/picoclaw/adapter.d.ts +2 -0
- package/dist/runtime/picoclaw/adapter.js +204 -0
- package/dist/runtime/picoclaw/runAuth.d.ts +2 -0
- package/dist/runtime/picoclaw/runAuth.js +117 -0
- package/dist/runtime/picoclaw/scaffold-assets/AGENTS.md +3 -0
- package/dist/runtime/picoclaw/scaffold-assets/CLAUDE.md +5 -0
- package/dist/runtime/picoclaw/scaffold-assets/IDENTITY.md +3 -0
- package/dist/runtime/picoclaw/scaffold-assets/SOUL.md +3 -0
- package/dist/runtime/picoclaw/scaffold.d.ts +2 -0
- package/dist/runtime/picoclaw/scaffold.js +28 -0
- package/dist/runtime/picoclaw/surfaces.d.ts +5 -0
- package/dist/runtime/picoclaw/surfaces.js +111 -0
- package/dist/runtime/registry.d.ts +41 -0
- package/dist/runtime/registry.js +134 -0
- package/dist/runtime/scaffoldAssets.d.ts +1 -0
- package/dist/runtime/scaffoldAssets.js +2 -0
- package/dist/runtime/tinyclaw/adapter.d.ts +2 -0
- package/dist/runtime/tinyclaw/adapter.js +263 -0
- package/dist/runtime/tinyclaw/runAuth.d.ts +2 -0
- package/dist/runtime/tinyclaw/runAuth.js +22 -0
- package/dist/runtime/tinyclaw/scaffold-assets/AGENTS.md +160 -0
- package/dist/runtime/tinyclaw/scaffold-assets/CLAUDE.md +5 -0
- package/dist/runtime/tinyclaw/scaffold-assets/SOUL.md +177 -0
- package/dist/runtime/tinyclaw/scaffold.d.ts +2 -0
- package/dist/runtime/tinyclaw/scaffold.js +24 -0
- package/dist/runtime/tinyclaw/surfaces.d.ts +8 -0
- package/dist/runtime/tinyclaw/surfaces.js +86 -0
- package/dist/runtime/types.d.ts +87 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtimes/picoclaw/agents/assistant/config.json +16 -0
- package/dist/runtimes/picoclaw/agents/assistant/workspace/AGENTS.md +1 -0
- package/dist/shared/constants.d.ts +7 -0
- package/dist/shared/constants.js +7 -0
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.js +9 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/shared/types.d.ts +9 -0
- package/dist/shared/types.js +1 -0
- package/dist/spawnfile-report.json +71 -0
- package/package.json +41 -0
- package/runtimes.yaml +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Noopolis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
# Spawnfile
|
|
2
|
+
|
|
3
|
+
> *Canonical source for autonomous agents. Write once. Compile to any runtime.*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What Spawnfile Is
|
|
8
|
+
|
|
9
|
+
Spawnfile is a spec and source format for declaring autonomous agents and teams independently of the runtime that will host them.
|
|
10
|
+
|
|
11
|
+
A Spawnfile source project is a directory you own and version. It describes the portable parts of an agent: markdown identity docs, skills, MCP connections, runtime binding, execution intent, and team structure.
|
|
12
|
+
|
|
13
|
+
`spawnfile compile` lowers that canonical source into runtime-specific config and workspace files. It is not a runtime-to-runtime translator. The compiler starts from the canonical source and emits each declared adapter's output.
|
|
14
|
+
It also emits runnable container artifacts for the compiled output: `Dockerfile`, `entrypoint.sh`, `.env.example`, and a prebuilt `container/rootfs/` tree.
|
|
15
|
+
`spawnfile build` turns that output into a Docker image using the pinned compiled runtime artifacts from `runtimes.yaml`, and `spawnfile run` is the auth-aware wrapper over `docker run`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## V0.1 Scope
|
|
20
|
+
|
|
21
|
+
Spawnfile v0.1 targets **autonomous agent runtimes** — systems that host agents as long-lived services with markdown workspace identity. It focuses on the portable surface shared across compatible runtimes:
|
|
22
|
+
|
|
23
|
+
- identity and personality docs (SOUL.md, IDENTITY.md, AGENTS.md)
|
|
24
|
+
- memory and heartbeat intent docs
|
|
25
|
+
- skills with SKILL.md
|
|
26
|
+
- MCP declarations
|
|
27
|
+
- runtime binding
|
|
28
|
+
- execution intent (model, workspace, sandbox)
|
|
29
|
+
- team structure (members, hierarchy, shared surfaces)
|
|
30
|
+
- agent-level Discord, Telegram, WhatsApp, and Slack surfaces
|
|
31
|
+
|
|
32
|
+
v0.1 does not try to standardize every runtime-native feature. Beyond the initial Discord, Telegram, WhatsApp, and Slack surfaces, communication surfaces, memory engines, task schedulers, UI surfaces, and other runtime-specific features stay adapter-defined for now.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Companion Docs
|
|
37
|
+
|
|
38
|
+
- `specs/INDEX.md` - map of all specs with status and relationships
|
|
39
|
+
- `specs/SPEC.md` - canonical Spawnfile source spec
|
|
40
|
+
- `specs/COMPILER.md` - v0.1 compiler architecture, graph resolution, and adapter contract
|
|
41
|
+
- `specs/CONTAINERS.md` - container compilation spec
|
|
42
|
+
- `specs/RUNTIMES.md` - runtime registry, version pinning, and adapter lifecycle
|
|
43
|
+
- `specs/research/` - per-runtime research notes and adapter strategies
|
|
44
|
+
- `fixtures/` - canonical v0.1 source projects for compiler validation
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Technology
|
|
49
|
+
|
|
50
|
+
Spawnfile v0.1 is implemented as a Node.js CLI in TypeScript.
|
|
51
|
+
|
|
52
|
+
- runtime: Node.js 22+
|
|
53
|
+
- CLI: `commander`
|
|
54
|
+
- manifest parsing: `yaml` + `zod`
|
|
55
|
+
- tests: `vitest`
|
|
56
|
+
|
|
57
|
+
That gives us fast iteration, a conventional `bin`-based CLI, and a clean path to future install surfaces such as npm or a shell bootstrapper.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
From a repository checkout:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
nvm use
|
|
67
|
+
npm install
|
|
68
|
+
npm run build
|
|
69
|
+
npm link
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or use the bootstrap script:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
./scripts/install.sh
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Then:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
spawnfile --help
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
To clone the target runtimes and generate reference blueprints:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm run runtimes:sync
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This clones each runtime at the version pinned in `runtimes.yaml` and generates blueprints showing the expected config and workspace layout. See `blueprints/` for the output.
|
|
91
|
+
|
|
92
|
+
These clones are for local research, blueprint generation, and adapter work. `spawnfile compile` itself does not need local runtime clones.
|
|
93
|
+
|
|
94
|
+
For local development without linking globally:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm run dev -- validate fixtures/single-agent
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Why
|
|
103
|
+
|
|
104
|
+
The autonomous agent runtimes are different, but they already share a meaningful core: markdown workspace identity, skill folders, MCP, model selection, and workspace isolation. Today that core is re-authored by hand for each runtime. Spawnfile makes it canonical.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## How It Works
|
|
109
|
+
|
|
110
|
+
You write a source project once. Then you compile it:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
spawnfile init
|
|
114
|
+
spawnfile init --runtime tinyclaw
|
|
115
|
+
spawnfile validate
|
|
116
|
+
spawnfile compile
|
|
117
|
+
spawnfile auth sync --profile dev --env-file .env
|
|
118
|
+
spawnfile build
|
|
119
|
+
spawnfile run --auth-profile dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For a single agent, the compiler uses that manifest's declared runtime. For a team, it walks the member graph and compiles each member using that member's declared runtime.
|
|
123
|
+
|
|
124
|
+
Each adapter maps the canonical project into runtime-native forms. If a runtime cannot preserve a declaration, the compiler reports `supported`, `degraded`, or `unsupported` according to the project's compile policy.
|
|
125
|
+
|
|
126
|
+
Each compile also produces a machine-readable report describing the resolved graph, chosen runtimes, output locations, and capability outcomes.
|
|
127
|
+
|
|
128
|
+
The portable model stays intentionally small:
|
|
129
|
+
|
|
130
|
+
- `runtime` names the host runtime and may carry runtime-specific options
|
|
131
|
+
- `execution` carries portable intent like model, workspace, and sandbox
|
|
132
|
+
- `agent` may hold internal `subagents`
|
|
133
|
+
- `team` is for first-class agents that coordinate as a group
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Project Structure
|
|
138
|
+
|
|
139
|
+
A source project has a `kind` - either `agent` or `team`.
|
|
140
|
+
|
|
141
|
+
### Agent
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
my-agent/
|
|
145
|
+
├── Spawnfile
|
|
146
|
+
├── IDENTITY.md
|
|
147
|
+
├── SOUL.md
|
|
148
|
+
├── AGENTS.md
|
|
149
|
+
├── MEMORY.md
|
|
150
|
+
├── HEARTBEAT.md
|
|
151
|
+
├── subagents/
|
|
152
|
+
│ └── researcher/
|
|
153
|
+
│ └── Spawnfile
|
|
154
|
+
└── skills/
|
|
155
|
+
├── web_search/
|
|
156
|
+
│ └── SKILL.md
|
|
157
|
+
└── memory_store/
|
|
158
|
+
└── SKILL.md
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Not every file is required. Spawnfile names portable document roles; adapters decide how to lower them into target-native surfaces.
|
|
162
|
+
|
|
163
|
+
### Team
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
my-team/
|
|
167
|
+
├── Spawnfile
|
|
168
|
+
├── TEAM.md
|
|
169
|
+
├── shared/
|
|
170
|
+
│ └── skills/
|
|
171
|
+
│ └── web_search/
|
|
172
|
+
│ └── SKILL.md
|
|
173
|
+
└── agents/
|
|
174
|
+
├── orchestrator/
|
|
175
|
+
│ ├── Spawnfile
|
|
176
|
+
│ └── AGENTS.md
|
|
177
|
+
├── researcher/
|
|
178
|
+
│ ├── Spawnfile
|
|
179
|
+
│ └── SOUL.md
|
|
180
|
+
└── writer/
|
|
181
|
+
├── Spawnfile
|
|
182
|
+
└── SOUL.md
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Teams can reference agents or other teams. Team structure (hierarchy, leadership) is part of the canonical model, but preservation is target-dependent and explicitly reported by the compiler.
|
|
186
|
+
Team members may be on the same runtime or on different runtimes depending on what each member declares.
|
|
187
|
+
|
|
188
|
+
An `agent` may also declare internal `subagents`. Those are not the same as a `team`: they are helper agents owned by a parent agent and lowered according to that runtime's own delegation or subagent model.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Policy
|
|
193
|
+
|
|
194
|
+
Not every target supports every declared capability. Spawnfile makes that explicit:
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
policy:
|
|
198
|
+
mode: strict
|
|
199
|
+
on_degrade: error
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The compiler reports one of three outcomes per declared capability: `supported`, `degraded`, or `unsupported`.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## The CLI
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
spawnfile init
|
|
210
|
+
spawnfile init --runtime tinyclaw
|
|
211
|
+
spawnfile init --team
|
|
212
|
+
spawnfile add agent writer
|
|
213
|
+
spawnfile add subagent critic
|
|
214
|
+
spawnfile add team platform
|
|
215
|
+
spawnfile validate
|
|
216
|
+
spawnfile compile
|
|
217
|
+
spawnfile auth
|
|
218
|
+
spawnfile build
|
|
219
|
+
spawnfile run
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
For example:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
spawnfile init --runtime picoclaw ./agents/researcher
|
|
226
|
+
spawnfile add agent writer ./my-team --runtime tinyclaw
|
|
227
|
+
spawnfile add subagent critic ./my-agent
|
|
228
|
+
spawnfile add team platform ./my-team
|
|
229
|
+
spawnfile validate fixtures/single-agent
|
|
230
|
+
spawnfile compile fixtures/single-agent --out ./bundle/example
|
|
231
|
+
spawnfile auth sync fixtures/single-agent --profile dev --env-file ./.env
|
|
232
|
+
spawnfile build fixtures/single-agent --out ./bundle/example --tag example-agent
|
|
233
|
+
spawnfile run fixtures/single-agent --tag example-agent --auth-profile dev
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Without `--out`, the compiler writes generated artifacts under `.spawn/`. `spawnfile init` also ensures `.spawn/` is ignored in the project `.gitignore`.
|
|
237
|
+
|
|
238
|
+
The compiler emits runtime-specific artifacts under `.spawn/runtimes/...` by default and writes a machine-readable `spawnfile-report.json`.
|
|
239
|
+
|
|
240
|
+
`spawnfile init` defaults agent scaffolds to `openclaw`. Use `spawnfile init --runtime <name>` to scaffold an agent for a different bundled runtime. `spawnfile init --team` stays runtime-neutral.
|
|
241
|
+
|
|
242
|
+
`spawnfile add` grows an existing manifest graph in place. The target `[path]` is optional and defaults to the current directory. It must point to the parent project directory (or its `Spawnfile`):
|
|
243
|
+
|
|
244
|
+
- `spawnfile add agent <id> [path]` adds `agents/<id>/` under a team
|
|
245
|
+
If `--runtime` is omitted, it uses the same default agent runtime as `spawnfile init`.
|
|
246
|
+
- `spawnfile add subagent <id> [path]` adds `subagents/<id>/` under an agent
|
|
247
|
+
- `spawnfile add team <id> [path]` adds `teams/<id>/` under a team
|
|
248
|
+
|
|
249
|
+
The CLI rejects invalid parent kinds: `add agent` and `add team` only work on team projects, and `add subagent` only works on agent projects.
|
|
250
|
+
|
|
251
|
+
`spawnfile model` edits model intent in place and rewrites touched manifests to the canonical inline shape:
|
|
252
|
+
|
|
253
|
+
- `spawnfile model set <provider> <name> [path]` sets the primary model
|
|
254
|
+
- `spawnfile model add-fallback <provider> <name> [path]` appends a fallback model
|
|
255
|
+
- `spawnfile model clear-fallbacks [path]` removes fallback models
|
|
256
|
+
- if `[path]` points to a team project, `--recursive` is required and only descendant agent manifests are updated; the team manifest itself is left unchanged
|
|
257
|
+
- the first positional argument is always the model provider, not the auth method
|
|
258
|
+
|
|
259
|
+
Team manifests should not declare `execution`. Model, sandbox, and workspace intent belong to agent manifests, not teams.
|
|
260
|
+
|
|
261
|
+
Agent manifests may declare portable communication surfaces under `surfaces`. The first standardized surfaces are Discord, Telegram, WhatsApp, and Slack:
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
surfaces:
|
|
265
|
+
discord:
|
|
266
|
+
access:
|
|
267
|
+
users:
|
|
268
|
+
- "987654321098765432"
|
|
269
|
+
bot_token_secret: DISCORD_BOT_TOKEN
|
|
270
|
+
telegram:
|
|
271
|
+
access:
|
|
272
|
+
users:
|
|
273
|
+
- "123456789"
|
|
274
|
+
chats:
|
|
275
|
+
- "-1001234567890"
|
|
276
|
+
bot_token_secret: TELEGRAM_BOT_TOKEN
|
|
277
|
+
whatsapp:
|
|
278
|
+
access:
|
|
279
|
+
users:
|
|
280
|
+
- "15551234567"
|
|
281
|
+
groups:
|
|
282
|
+
- "120363400000000000@g.us"
|
|
283
|
+
slack:
|
|
284
|
+
access:
|
|
285
|
+
users:
|
|
286
|
+
- "U1234567890"
|
|
287
|
+
channels:
|
|
288
|
+
- "C1234567890"
|
|
289
|
+
bot_token_secret: SLACK_BOT_TOKEN
|
|
290
|
+
app_token_secret: SLACK_APP_TOKEN
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Discord access may declare:
|
|
294
|
+
|
|
295
|
+
- `mode: pairing | allowlist | open`
|
|
296
|
+
- `users`
|
|
297
|
+
- `guilds`
|
|
298
|
+
- `channels`
|
|
299
|
+
|
|
300
|
+
Telegram access may declare:
|
|
301
|
+
|
|
302
|
+
- `mode: pairing | allowlist | open`
|
|
303
|
+
- `users`
|
|
304
|
+
- `chats`
|
|
305
|
+
|
|
306
|
+
WhatsApp access may declare:
|
|
307
|
+
|
|
308
|
+
- `mode: pairing | allowlist | open`
|
|
309
|
+
- `users`
|
|
310
|
+
- `groups`
|
|
311
|
+
|
|
312
|
+
Slack access may declare:
|
|
313
|
+
|
|
314
|
+
- `mode: pairing | allowlist | open`
|
|
315
|
+
- `users`
|
|
316
|
+
- `channels`
|
|
317
|
+
|
|
318
|
+
If `mode` is omitted and any allowlist fields are present, Spawnfile infers `allowlist`.
|
|
319
|
+
If you want portable runtime behavior, set `access.mode` explicitly. Leaving `access` unset delegates to runtime defaults, which are not identical across runtimes.
|
|
320
|
+
If `bot_token_secret` is omitted, Spawnfile defaults to `DISCORD_BOT_TOKEN` for Discord, `TELEGRAM_BOT_TOKEN` for Telegram, and `SLACK_BOT_TOKEN` for Slack. If `app_token_secret` is omitted on Slack, Spawnfile defaults to `SLACK_APP_TOKEN`.
|
|
321
|
+
WhatsApp has no portable token-secret field in v0.1; session or QR-style auth remains runtime-defined.
|
|
322
|
+
`spawnfile auth sync ... --env-file .env` will collect that env name into the selected auth profile, and `spawnfile run --auth-profile ...` will validate it before container startup.
|
|
323
|
+
|
|
324
|
+
Runtime support is narrower than the portable schema:
|
|
325
|
+
|
|
326
|
+
- `openclaw` supports `pairing`, `allowlist`, and `open` for Discord, Telegram, WhatsApp, and Slack
|
|
327
|
+
- `picoclaw` supports `open` and user allowlists for Discord, Telegram, WhatsApp, and Slack
|
|
328
|
+
- `tinyclaw` supports `pairing` only for Discord, Telegram, and WhatsApp, and does not support Slack in Spawnfile v0.1
|
|
329
|
+
|
|
330
|
+
Practical notes from the current live smoke matrix:
|
|
331
|
+
|
|
332
|
+
- Discord was verified end to end on OpenClaw and PicoClaw, and as a paired DM surface on TinyClaw
|
|
333
|
+
- Telegram was verified end to end on all three runtimes
|
|
334
|
+
- `tinyclaw` required first-contact pairing on Telegram
|
|
335
|
+
- `openclaw` and `picoclaw` both worked on Telegram with `access.mode: open`
|
|
336
|
+
- WhatsApp was verified end to end on OpenClaw
|
|
337
|
+
- `picoclaw` WhatsApp remains blocked in the pinned artifact because `whatsapp_native` is not compiled into the shipped binary
|
|
338
|
+
- `tinyclaw` WhatsApp remains blocked in the shipped container because the upstream client needs a browser runtime
|
|
339
|
+
- Slack was verified end to end on OpenClaw
|
|
340
|
+
- Slack was verified end to end on PicoClaw
|
|
341
|
+
- `picoclaw` replies to channel messages in a Slack thread; direct messages reply inline
|
|
342
|
+
|
|
343
|
+
Useful options:
|
|
344
|
+
|
|
345
|
+
- `--auth <api_key|claude-code|codex|none>` sets the auth method on the edited model target
|
|
346
|
+
- `--key <ENV_NAME>` sets the env var name used by `api_key` auth for custom/local models
|
|
347
|
+
- `--compat <openai|anthropic>` and `--base-url <url>` configure local/custom endpoint targets
|
|
348
|
+
- `--recursive` updates the target project and every descendant manifest in the graph
|
|
349
|
+
|
|
350
|
+
Examples:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
spawnfile model set anthropic claude-opus-4-6 --auth claude-code
|
|
354
|
+
spawnfile model set openai gpt-5.4 --auth codex
|
|
355
|
+
spawnfile model set local qwen2.5:14b --auth none --compat openai --base-url http://host.docker.internal:11434/v1
|
|
356
|
+
spawnfile model set anthropic claude-opus-4-6 . --auth claude-code --recursive
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
`spawnfile compile` also emits under the output root:
|
|
360
|
+
|
|
361
|
+
- final container filesystem output under `.spawn/container/rootfs/...` by default
|
|
362
|
+
- `Dockerfile`, `entrypoint.sh`, `.env.example`
|
|
363
|
+
|
|
364
|
+
`spawnfile build` is the happy path for compile + Docker image build. It compiles the project, then runs `docker build` against the emitted output directory. The generated Dockerfile installs the pinned compiled runtime artifacts for the resolved runtimes; it does not rebuild runtime sources during image build.
|
|
365
|
+
|
|
366
|
+
`spawnfile build` remains secrets-free by default. Runtime and model auth should be prepared locally, then applied at `spawnfile run` time.
|
|
367
|
+
|
|
368
|
+
Model auth can be imported into a local Spawnfile auth profile:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
spawnfile auth sync fixtures/single-agent --profile dev --env-file ./.env
|
|
372
|
+
spawnfile auth show --profile dev
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Projects declare model auth on each model entry in the Spawnfile, for example:
|
|
376
|
+
|
|
377
|
+
```yaml
|
|
378
|
+
execution:
|
|
379
|
+
model:
|
|
380
|
+
primary:
|
|
381
|
+
provider: anthropic
|
|
382
|
+
name: claude-opus-4-6
|
|
383
|
+
auth:
|
|
384
|
+
method: claude-code
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
For local and custom endpoints, the model entry can also declare `endpoint`:
|
|
388
|
+
|
|
389
|
+
```yaml
|
|
390
|
+
execution:
|
|
391
|
+
model:
|
|
392
|
+
primary:
|
|
393
|
+
provider: local
|
|
394
|
+
name: qwen2.5:14b
|
|
395
|
+
auth:
|
|
396
|
+
method: none
|
|
397
|
+
endpoint:
|
|
398
|
+
compatibility: openai
|
|
399
|
+
base_url: http://host.docker.internal:11434/v1
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`spawnfile auth sync` reads that declared intent and imports the matching local auth material into the selected profile. The lower-level `spawnfile auth import env`, `spawnfile auth import claude-code`, and `spawnfile auth import codex` commands remain available for manual profile editing. The older top-level `execution.model.auth` form is still accepted for compatibility, but inline per-model auth is the canonical shape.
|
|
403
|
+
|
|
404
|
+
`env` auth is the primary path for provider API keys. `claude-code` and `codex` imports mount existing local CLI credential stores into runtime homes at `spawnfile run` time.
|
|
405
|
+
|
|
406
|
+
Then run the built image with that profile:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
spawnfile run fixtures/single-agent --tag example-agent --auth-profile dev
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Manual Docker remains valid against the compile output:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
spawnfile build fixtures/single-agent --out ./bundle/example --tag example-agent
|
|
416
|
+
cp ./bundle/example/.env.example ./bundle/example/.env
|
|
417
|
+
docker run --env-file ./bundle/example/.env -p 18789:18789 example-agent
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Equivalent manual flow:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
spawnfile compile fixtures/single-agent --out ./bundle/example
|
|
424
|
+
cd ./bundle/example
|
|
425
|
+
docker build -t example-agent .
|
|
426
|
+
docker run --env-file .env -p 18789:18789 example-agent
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Docker E2E
|
|
430
|
+
|
|
431
|
+
The repo also includes an opt-in Docker auth E2E harness.
|
|
432
|
+
It builds compiled images, starts them with a local Spawnfile auth profile, waits for runtime readiness, sends real prompts, and fails unless the expected sentinel reply comes back.
|
|
433
|
+
|
|
434
|
+
Examples:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
npm run test:e2e:docker-auth -- --scenario openclaw-codex
|
|
438
|
+
npm run test:e2e:docker-auth -- --scenario team-multi-runtime --env-file ../headhunter/.env
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
This is intentionally separate from `npm test`.
|
|
442
|
+
It requires Docker, network access, and real model credentials.
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## The Builder
|
|
447
|
+
|
|
448
|
+
**spawnfile.ai** is a web-based authoring surface for the canonical format. It walks through docs, skills, MCP, runtime binding, execution intent, and team composition, then produces a source project you own and can edit by hand.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## The Name
|
|
453
|
+
|
|
454
|
+
**Spawn** - in computing, you spawn a process. In games, you spawn a character. In biology, you spawn life. Deliberate creation. Independent existence from that point forward.
|
|
455
|
+
|
|
456
|
+
**File** - the atomic unit of software. Something you can read, version, fork, check into git, and own completely. It anchors a project - a directory, a complete picture of what something is.
|
|
457
|
+
|
|
458
|
+
Together: *a canonical source project that spawns an agent and can be compiled into the runtimes that can host it.*
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
*One source format. Many runtimes. Manifest-driven compilation.*
|
|
463
|
+
|
|
464
|
+
**spawnfile.ai** · **github.com/noopolis/spawnfile**
|
package/dist/Dockerfile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
FROM debian:bookworm-slim
|
|
2
|
+
USER root
|
|
3
|
+
|
|
4
|
+
WORKDIR /opt/spawnfile
|
|
5
|
+
RUN apt-get update && apt-get install -y --no-install-recommends bash ca-certificates curl nodejs npm tar && rm -rf /var/lib/apt/lists/*
|
|
6
|
+
|
|
7
|
+
RUN npm install -g --omit=dev --no-fund --no-audit @anthropic-ai/claude-code @openai/codex
|
|
8
|
+
|
|
9
|
+
RUN mkdir -p /opt/spawnfile/runtime-installs/picoclaw/bin
|
|
10
|
+
RUN arch="$(dpkg --print-architecture)" && case "$arch" in amd64) asset="picoclaw_Linux_x86_64.tar.gz" ;; arm64) asset="picoclaw_Linux_arm64.tar.gz" ;; *) echo "Unsupported PicoClaw release architecture: $arch" >&2; exit 1 ;; esac && url="https://github.com/sipeed/picoclaw/releases/download/v0.2.3/$asset" && curl -fsSL -o /tmp/picoclaw.tar.gz "$url" && rm -rf /tmp/picoclaw-extract && mkdir -p /tmp/picoclaw-extract && tar -xzf /tmp/picoclaw.tar.gz -C /tmp/picoclaw-extract && binary_path="$(find /tmp/picoclaw-extract -type f -name "picoclaw" | head -n 1)" && [ -n "$binary_path" ] && install -m 0755 "$binary_path" /opt/spawnfile/runtime-installs/picoclaw/bin/picoclaw && ln -sf /opt/spawnfile/runtime-installs/picoclaw/bin/picoclaw /usr/local/bin/picoclaw && rm -rf /tmp/picoclaw.tar.gz /tmp/picoclaw-extract
|
|
11
|
+
|
|
12
|
+
RUN if ! id -u spawnfile >/dev/null 2>&1; then useradd --create-home --home-dir /home/spawnfile --shell /bin/bash spawnfile; fi
|
|
13
|
+
|
|
14
|
+
COPY container/rootfs/ /
|
|
15
|
+
COPY .env.example /opt/spawnfile/.env.example
|
|
16
|
+
COPY entrypoint.sh /opt/spawnfile/entrypoint.sh
|
|
17
|
+
RUN chmod +x /opt/spawnfile/entrypoint.sh
|
|
18
|
+
RUN mkdir -p /var/lib/spawnfile && chown -R spawnfile:spawnfile /var/lib/spawnfile /opt/spawnfile
|
|
19
|
+
EXPOSE 18790
|
|
20
|
+
USER spawnfile
|
|
21
|
+
ENTRYPOINT ["/opt/spawnfile/entrypoint.sh"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface ClaudeCodeImportOptions {
|
|
2
|
+
readKeychainCredentials?: () => Promise<string | null>;
|
|
3
|
+
}
|
|
4
|
+
export declare const parseEnvFile: (content: string) => Record<string, string>;
|
|
5
|
+
export declare const importEnvFile: (profileName: string, envFilePath: string) => Promise<import("./types.js").ResolvedAuthProfile>;
|
|
6
|
+
export declare const importCodexAuth: (profileName: string, sourceDirectory?: string) => Promise<import("./types.js").ResolvedAuthProfile>;
|
|
7
|
+
export declare const importClaudeCodeAuth: (profileName: string, sourceDirectory?: string, options?: ClaudeCodeImportOptions) => Promise<import("./types.js").ResolvedAuthProfile>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import { ensureDirectory, fileExists, readUtf8File, writeUtf8File } from "../filesystem/index.js";
|
|
4
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
5
|
+
import { registerImportedAuth, setAuthProfileEnv } from "./profileStore.js";
|
|
6
|
+
const ENV_LINE_PATTERN = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/;
|
|
7
|
+
const CLAUDE_CODE_KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
8
|
+
const stripWrappedQuotes = (value) => {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
11
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
12
|
+
return trimmed.slice(1, -1);
|
|
13
|
+
}
|
|
14
|
+
return trimmed;
|
|
15
|
+
};
|
|
16
|
+
export const parseEnvFile = (content) => {
|
|
17
|
+
const entries = {};
|
|
18
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
19
|
+
const line = rawLine.trim();
|
|
20
|
+
if (line.length === 0 || line.startsWith("#")) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const match = rawLine.match(ENV_LINE_PATTERN);
|
|
24
|
+
if (!match) {
|
|
25
|
+
throw new SpawnfileError("validation_error", `Invalid env line: ${rawLine}`);
|
|
26
|
+
}
|
|
27
|
+
entries[match[1]] = stripWrappedQuotes(match[2] ?? "");
|
|
28
|
+
}
|
|
29
|
+
return entries;
|
|
30
|
+
};
|
|
31
|
+
export const importEnvFile = async (profileName, envFilePath) => {
|
|
32
|
+
if (!(await fileExists(envFilePath))) {
|
|
33
|
+
throw new SpawnfileError("validation_error", `Env file does not exist: ${envFilePath}`);
|
|
34
|
+
}
|
|
35
|
+
return setAuthProfileEnv(profileName, parseEnvFile(await readUtf8File(envFilePath)));
|
|
36
|
+
};
|
|
37
|
+
const resolveHomeRelativePath = (defaultRelativePath, inputPath) => {
|
|
38
|
+
if (inputPath) {
|
|
39
|
+
return path.resolve(inputPath);
|
|
40
|
+
}
|
|
41
|
+
return path.join(os.homedir(), defaultRelativePath);
|
|
42
|
+
};
|
|
43
|
+
const resolveCodexSourceDirectory = (sourceDirectory) => path.resolve(sourceDirectory ?? process.env.CODEX_HOME ?? resolveHomeRelativePath(".codex"));
|
|
44
|
+
const resolveClaudeSourceDirectory = (sourceDirectory) => resolveHomeRelativePath(".claude", sourceDirectory);
|
|
45
|
+
const readClaudeCodeKeychainCredentials = async () => {
|
|
46
|
+
try {
|
|
47
|
+
const { execFile } = await import("node:child_process");
|
|
48
|
+
const { promisify } = await import("node:util");
|
|
49
|
+
const execFileAsync = promisify(execFile);
|
|
50
|
+
const { stdout } = await execFileAsync("security", [
|
|
51
|
+
"find-generic-password",
|
|
52
|
+
"-s",
|
|
53
|
+
CLAUDE_CODE_KEYCHAIN_SERVICE,
|
|
54
|
+
"-w"
|
|
55
|
+
]);
|
|
56
|
+
const content = stdout.trim();
|
|
57
|
+
return content.length > 0 ? content : null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
export const importCodexAuth = async (profileName, sourceDirectory) => {
|
|
64
|
+
const resolvedSource = resolveCodexSourceDirectory(sourceDirectory);
|
|
65
|
+
const authFilePath = path.join(resolvedSource, "auth.json");
|
|
66
|
+
if (!(await fileExists(authFilePath))) {
|
|
67
|
+
throw new SpawnfileError("validation_error", `Codex auth file does not exist: ${authFilePath}`);
|
|
68
|
+
}
|
|
69
|
+
const { directory, profile } = await registerImportedAuth(profileName, "codex");
|
|
70
|
+
await writeUtf8File(path.join(directory, "auth.json"), await readUtf8File(authFilePath));
|
|
71
|
+
return profile;
|
|
72
|
+
};
|
|
73
|
+
export const importClaudeCodeAuth = async (profileName, sourceDirectory, options = {}) => {
|
|
74
|
+
const resolvedSource = resolveClaudeSourceDirectory(sourceDirectory);
|
|
75
|
+
const credentialsPath = path.join(resolvedSource, ".credentials.json");
|
|
76
|
+
let credentialsContent = null;
|
|
77
|
+
if (await fileExists(credentialsPath)) {
|
|
78
|
+
credentialsContent = await readUtf8File(credentialsPath);
|
|
79
|
+
}
|
|
80
|
+
if (!credentialsContent && !sourceDirectory) {
|
|
81
|
+
const keychainCredentials = await (options.readKeychainCredentials ?? readClaudeCodeKeychainCredentials)();
|
|
82
|
+
if (keychainCredentials) {
|
|
83
|
+
credentialsContent = keychainCredentials;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!credentialsContent) {
|
|
87
|
+
throw new SpawnfileError("validation_error", `Claude Code credentials file does not exist: ${credentialsPath} and macOS Keychain service ${CLAUDE_CODE_KEYCHAIN_SERVICE} was unavailable`);
|
|
88
|
+
}
|
|
89
|
+
const { directory, profile } = await registerImportedAuth(profileName, "claude-code");
|
|
90
|
+
await ensureDirectory(directory);
|
|
91
|
+
await writeUtf8File(path.join(directory, ".credentials.json"), credentialsContent);
|
|
92
|
+
return profile;
|
|
93
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const resolveSpawnfileHome: () => string;
|
|
2
|
+
export declare const resolveAuthHome: () => string;
|
|
3
|
+
export declare const resolveProfilesRoot: () => string;
|
|
4
|
+
export declare const resolveProfileDirectory: (profileName: string) => string;
|
|
5
|
+
export declare const resolveProfilePath: (profileName: string) => string;
|
|
6
|
+
export declare const resolveImportedAuthDirectory: (profileName: string, kind: "claude-code" | "codex") => string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const DEFAULT_SPAWNFILE_HOME = "~/.spawnfile";
|
|
4
|
+
const expandHomePath = (inputPath) => {
|
|
5
|
+
if (inputPath === "~") {
|
|
6
|
+
return os.homedir();
|
|
7
|
+
}
|
|
8
|
+
if (inputPath.startsWith("~/")) {
|
|
9
|
+
return path.join(os.homedir(), inputPath.slice(2));
|
|
10
|
+
}
|
|
11
|
+
return inputPath;
|
|
12
|
+
};
|
|
13
|
+
export const resolveSpawnfileHome = () => path.resolve(expandHomePath(process.env.SPAWNFILE_HOME ?? DEFAULT_SPAWNFILE_HOME));
|
|
14
|
+
export const resolveAuthHome = () => path.join(resolveSpawnfileHome(), "auth");
|
|
15
|
+
export const resolveProfilesRoot = () => path.join(resolveAuthHome(), "profiles");
|
|
16
|
+
export const resolveProfileDirectory = (profileName) => path.join(resolveProfilesRoot(), profileName);
|
|
17
|
+
export const resolveProfilePath = (profileName) => path.join(resolveProfileDirectory(profileName), "profile.json");
|
|
18
|
+
export const resolveImportedAuthDirectory = (profileName, kind) => path.join(resolveProfileDirectory(profileName), "imports", kind);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthProfile, ImportedAuthKind, ResolvedAuthProfile } from "./types.js";
|
|
2
|
+
export declare const createResolvedAuthProfile: (profileName: string, profile: AuthProfile) => ResolvedAuthProfile;
|
|
3
|
+
export declare const loadAuthProfile: (profileName: string) => Promise<ResolvedAuthProfile | null>;
|
|
4
|
+
export declare const requireAuthProfile: (profileName: string) => Promise<ResolvedAuthProfile>;
|
|
5
|
+
export declare const ensureAuthProfile: (profileName: string) => Promise<ResolvedAuthProfile>;
|
|
6
|
+
export declare const setAuthProfileEnv: (profileName: string, env: Record<string, string>) => Promise<ResolvedAuthProfile>;
|
|
7
|
+
export declare const registerImportedAuth: (profileName: string, kind: ImportedAuthKind) => Promise<{
|
|
8
|
+
directory: string;
|
|
9
|
+
profile: ResolvedAuthProfile;
|
|
10
|
+
}>;
|