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
2 changes: 1 addition & 1 deletion .claude/rules/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ structure from scratch.

## Available examples

Each lives under `examples/<name>/`. Prefer `wdl init <target> --ns <ns>` for
Each lives under `examples/<name>/`. Prefer `wdl init <target> [--ns <ns>]` for
plain workers. Pick and copy the closest example when an example matches the
requested feature set better than the minimal init template.

Expand Down
3 changes: 3 additions & 0 deletions .claude/skills/wdl-deploy/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Open the relevant doc before answering:
commands.
- `docs/secrets.md` — `wdl secret` (worker-level vs namespace-level), runtime
secret precedence, `--json` automation output, anti-patterns.
- `docs/token.md` — `wdl token set/list/use/rm`, the local credential store
(`~/.config/wdl/credentials`), its default namespace, and where it sits in
credential resolution.
- `docs/d1.md` — `[[d1_databases]]` config, `wdl d1` commands, migrations.
- `docs/durable-objects.md` — `[[durable_objects.bindings]]`, migration class
declarations, the DO runtime surface.
Expand Down
12 changes: 12 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ when behavior changes.

## Security & Configuration Tips

Credential resolution layers, highest precedence first: CLI flags, shell/CI env,
the project `./.env` (sectioned by namespace, with a cross-origin guard that
drops a `.env`-supplied endpoint when the effective token is not from the same
`.env`), then the global token store (`~/.config/wdl/credentials`, managed by
`wdl token`). The store is trusted (home directory, same-source token +
endpoint) and not subject to the guard; a project `.env` is not. The namespace
itself follows the same shape — `--ns > shell WDL_NS > project .env WDL_NS >
store default (base WDL_NS)` — so the store's default namespace is the lowest
selector, materialized into `env.WDL_NS` before the per-key gap-fill. Keep that
ordering and the guard intact when touching `loadCliControlEnv` or
`lib/token-store.js`.

Do not commit tenant tokens or generated secrets. Read credentials from the
environment (`ADMIN_TOKEN`, `CONTROL_URL`, `WDL_NS`) and keep example
configuration generic. When adding deploy features, validate unsupported
Expand Down
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
# Changelog

## Unreleased

### Added

- `wdl token set/list/use/rm` manages a local credential store at
`~/.config/wdl/credentials` (`$XDG_CONFIG_HOME`/`%APPDATA%` honored), so
commands resolve a control URL and token without a per-shell `ADMIN_TOKEN`
export or a token in every project's `.env`. `set` reads the token from stdin
(hidden on a TTY) and validates it against `/whoami` before storing it under
the namespace; `rm` deletes the local copy without revoking it. The store is
the same `dotenv`/INI dialect as a project `.env`, written `0600`, and is the
lowest-precedence credential layer:
`flag > shell env > project .env > token store`. It is trusted (home
directory, same-source token + endpoint) and is not subject to the
cross-origin `.env` guard, while a project `.env` endpoint is still dropped
when the token comes from the store. `wdl config explain` shows
`token store [<ns>].…` as a value's source.
- The store carries a default namespace (a base `WDL_NS`, the analogue of a
project `.env`'s base `WDL_NS`): the first stored namespace becomes the
default, `wdl token set --default` and `wdl token use <ns>` change it, and
`wdl token list` marks it with `*`. With a default set, commands resolve a
namespace without `--ns`; the selection chain is
`--ns > shell WDL_NS > project .env WDL_NS > store default`, and
`wdl config explain` shows `token store default` as the namespace source.

### Changed

- `wdl init`'s `--ns` is now optional. With `--ns`, the scaffolded `npm run
deploy` keeps `wdl deploy . --ns <ns>`; without it the script is
`wdl deploy .` and the namespace is resolved at deploy time (`--ns` / `WDL_NS`
/ project `.env` / a `wdl token` default). `init` also no longer autoloads
control credentials, so a corrupt token store cannot block scaffolding.

### Removed

- **BREAKING:** the `--admin` flag and the `ADMIN_URL` environment variable —
legacy compatibility aliases for the control endpoint — are removed. Use
`--control-url <url>` and the `CONTROL_URL` environment variable instead.
`--admin` is now an unknown option and `ADMIN_URL` is no longer read from the
shell or `.env`.

### Fixed

- `wdl secret put` no longer echoes the typed secret on a TTY: input is read in
raw mode (hidden), and fails closed — it errors rather than echo if the
terminal cannot hide input.
- `.env` values containing literal backslash escape sequences (e.g. a token
with a backslash followed by `n`) now round-trip correctly instead of being
decoded as control characters.

## 1.0.0

Initial open-source release.
Expand Down
8 changes: 4 additions & 4 deletions GUIDE-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ ADMIN_TOKEN=<acme-token>
ADMIN_TOKEN=<acme-staging-token>
```

CLI 只会从 `.env` 读取 WDL 平台变量:`ADMIN_TOKEN`、`ADMIN_URL`、 `CONTROL_URL`、`CONTROL_CONNECT_HOST`、`WDL_NS`。优先级是 `CLI flag > shell/CI env > [resolved-ns] section > base .env`,都没有提供时命令直接报错——没有内置默认值。namespace 解析顺序是 `--ns`,然后是 shell 或 base `.env` 里的 `WDL_NS`。section 名可以是 `[acme]` 这类 tenant namespace,也可以是 `[__name__]` 这种运维保留的不透明 section。Tenant Wrangler 配置默认仍使用普通 tenant namespace 语法,除非运维方明确给了这种 namespace token;否则不要把 `__name__` 形态写进 `[[services]].ns`、`allowed_callers` 或命令示例。如果没有解析出 namespace,section 会全部跳过;后续命令如果需要 namespace 或 token,会按正常校验报错。只有临时切换 namespace 时才需要显式传 `--ns`。不带 scheme 的生产 control host(例如 `api.wdl.dev`)默认补 `https://`;`localhost:8080` 或 `*.test:8080` 这类本地开发地址默认补 `http://`。任何不带 scheme 的 `:8080` control URL 都会按本地 HTTP 处理。需要强制使用其它协议时,显式写 scheme。
CLI 只会从 `.env` 读取 WDL 平台变量:`ADMIN_TOKEN`、`CONTROL_URL`、`CONTROL_CONNECT_HOST`、`WDL_NS`。优先级是 `CLI flag > shell/CI env > [resolved-ns] section > base .env > wdl token store`,都没有提供时命令直接报错——没有内置默认值。namespace 解析顺序是 `--ns`,然后是 shell 或 base `.env` 里的 `WDL_NS`,再然后是 token store 的默认 namespace。section 名可以是 `[acme]` 这类 tenant namespace,也可以是 `[__name__]` 这种运维保留的不透明 section。Tenant Wrangler 配置默认仍使用普通 tenant namespace 语法,除非运维方明确给了这种 namespace token;否则不要把 `__name__` 形态写进 `[[services]].ns`、`allowed_callers` 或命令示例。如果没有解析出 namespace,section 会全部跳过;后续命令如果需要 namespace 或 token,会按正常校验报错。只有临时切换 namespace 时才需要显式传 `--ns`。不带 scheme 的生产 control host(例如 `api.wdl.dev`)默认补 `https://`;`localhost:8080` 或 `*.test:8080` 这类本地开发地址默认补 `http://`。任何不带 scheme 的 `:8080` control URL 都会按本地 HTTP 处理。需要强制使用其它协议时,显式写 scheme。

目前这些凭证来自 shell`.env` 文件或命令行标志。后续版本(1.1)会新增 `wdl auth login`,用隐藏输入读取 token 并存入托管配置文件,使其不进入 shell 历史、也不落在项目文件里。
推荐的做法是把这些凭证放进托管存储,而不是 shell export 或项目 `.env``wdl token set --ns <ns> --control-url <url>` 用隐藏输入读取 token、调 `/whoami` 校验后按 namespace 存入 `~/.config/wdl/credentials`(不进 shell 历史、也不落在项目文件里)。存储是优先级最低的层——命令行标志、shell env、项目 `.env` 仍然胜出——`wdl token list` / `wdl token rm` 管理它。第一个存入的 namespace 成为默认(一行 base `WDL_NS`,和项目 `.env` 一样),命令不带 `--ns` 也能跑;`wdl token use <ns>` 切换默认。详见 [token-zh.md](./docs/token-zh.md)

用 `wdl config explain` 查看最终 namespace、control URL、脱敏 token 以及每个值的来源。用 `wdl whoami` 调 control-plane `/whoami`,查看当前 authenticated principal、token id、platform version、最低支持 CLI version 和 URL hints。用 `wdl doctor` 做本地可用性检查,包括 Node.js、wdl-cli、Wrangler、配置文件是否存在、凭据是否能解析,以及 `/whoami` 是否可达。当 control plane 暴露 `/whoami` 时,`doctor` 可以发现 token 是否有效、principal namespace、platform version 和 CLI compatibility;更细的 capability 检查仍需要额外的 control endpoint。

Expand All @@ -99,7 +99,7 @@ npm install

它会写入:

- `package.json` —— `npm run deploy` 已把 `--ns` 烤进去,另有 `npm run dry-run` 本地打包检查;devDependencies 固定 `wrangler@^4` 和 `@wdl-dev/cli`。
- `package.json` —— 传了 `--ns` 时 `npm run deploy` 会把它烤进去,否则就是 `wdl deploy .`(namespace 在部署期解析),另有 `npm run dry-run` 本地打包检查;devDependencies 固定 `wrangler@^4` 和 `@wdl-dev/cli`。
- `wrangler.jsonc` —— 顶层 `name` 是 worker 名(默认等于目录名,可用 `--worker <name>` 覆盖)。
- `src/index.js`、`.gitignore`,以及 `AGENTS.md`/`CLAUDE.md`,方便 AI 代理找到 `node_modules/@wdl-dev/cli/docs/` 下的分主题文档。

Expand Down Expand Up @@ -766,7 +766,7 @@ wdl tail hello

| 现象 | 可能原因 | 检查方式 |
| --- | --- | --- |
| `Missing admin token` | 没有提供 tenant token | 设置 `ADMIN_TOKEN`,或传 `--token` |
| `Missing admin token` | 没有提供 tenant token | 运行 `wdl token set --ns <ns> --control-url <url>`(推荐),或设 `ADMIN_TOKEN` / 传 `--token` |
| `wrangler build failed` | Wrangler 无法打包 Worker 项目 | 在 Worker 项目目录执行 `npx wrangler deploy --dry-run`,先修本地构建或配置错误 |
| deploy 成功但 promote 失败 | route、自定义 host 或 binding 在 promote 阶段校验失败 | 确认自定义 host 已为你的 namespace 开通,service binding 目标存在 |
| Worker URL 返回 404 | URL 形态或 worker name 不对 | 使用 `https://<namespace>.<platform-domain>/<worker-name>/`,不要漏掉 worker name 这一段路径 |
Expand Down
32 changes: 20 additions & 12 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,11 @@ ADMIN_TOKEN=<acme-staging-token>
```

The CLI loads only WDL platform variables from `.env`: `ADMIN_TOKEN`,
`ADMIN_URL`, `CONTROL_URL`, `CONTROL_CONNECT_HOST`, and `WDL_NS`. Precedence is
`CLI flag > shell/CI env > [resolved-ns] section > base .env`, and if none
supplies a value the command fails — there is no built-in default. Namespace
resolution is `--ns`, then `WDL_NS` from your shell or base `.env`. Section
`CONTROL_URL`, `CONTROL_CONNECT_HOST`, and `WDL_NS`. Precedence is
`CLI flag > shell/CI env > [resolved-ns] section > base .env > wdl token store`,
and if none supplies a value the command fails — there is no built-in default.
Namespace resolution is `--ns`, then `WDL_NS` from your shell or base `.env`,
then the token store's default namespace. Section
names may be normal tenant namespaces, such as `[acme]`, or opaque
operator-reserved sections shaped like `[__name__]`. Tenant Wrangler config
still uses normal tenant namespace grammar unless your operator explicitly gave
Expand All @@ -112,10 +113,16 @@ namespace resolves, section values are skipped and the command will fail
normally if it needs a namespace or token. Pass `--ns` when you want to override
the default for one command.

Today these credentials come from your shell, a `.env` file, or flags. A future
release (1.1) will add `wdl auth login`, which reads the token with hidden input
and stores it in a managed config file, so it never lands in shell history or a
project file.
The recommended setup keeps these credentials in a managed store rather than a
shell export or a project `.env`: `wdl token set --ns <ns> --control-url <url>`
reads the token with
hidden input, validates it against `/whoami`, and stores it under the namespace
in `~/.config/wdl/credentials` (so it never lands in shell history or a project
file). The store is the lowest-precedence layer — flags, shell env, and a
project `.env` still win — and `wdl token list` / `wdl token rm` manage it. The
first stored namespace becomes the default (a base `WDL_NS`, like a project
`.env`'s), so commands run without `--ns`; `wdl token use <ns>` switches it. See
[token.md](./docs/token.md).

Use `wdl config explain` to inspect the final namespace, control URL, masked
token, and where each value came from. Use `wdl whoami` to call control-plane
Expand All @@ -139,9 +146,10 @@ npm install

It writes:

- `package.json` — `npm run deploy` with `--ns` baked in, plus an
`npm run dry-run` local bundle check; pins `wrangler@^4` and `@wdl-dev/cli` as
devDependencies.
- `package.json` — `npm run deploy` with `--ns` baked in when you pass it
(otherwise just `wdl deploy .`, with the namespace resolved at deploy time),
plus an `npm run dry-run` local bundle check; pins `wrangler@^4` and
`@wdl-dev/cli` as devDependencies.
- `wrangler.jsonc` — top-level `name` is the worker name (defaults to the
directory name; override with `--worker <name>`).
- `src/index.js`, `.gitignore`, and `AGENTS.md`/`CLAUDE.md` so AI agents can
Expand Down Expand Up @@ -997,7 +1005,7 @@ wdl tail hello

| Symptom | Likely cause | What to check |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `Missing admin token` | No tenant token was provided | Set `ADMIN_TOKEN` or pass `--token` |
| `Missing admin token` | No tenant token was provided | Run `wdl token set --ns <ns> --control-url <url>` (recommended), set `ADMIN_TOKEN`, or pass `--token` |
| `wrangler build failed` | Wrangler could not bundle the Worker project | Run `npx wrangler deploy --dry-run` inside the Worker project and fix local build/config errors |
| Deploy succeeds but promote fails | Route, custom host, or binding validation failed at promotion time | Check that custom hosts are enabled for your namespace and service-binding targets exist |
| Worker URL returns 404 | URL shape or worker name is wrong | Use `https://<namespace>.<platform-domain>/<worker-name>/`; include the worker name path segment |
Expand Down
11 changes: 7 additions & 4 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,18 @@ wdl tail hello # 边访问 URL 边看实时日志

Worker 此时位于 `https://<namespace>.<platform-domain>/hello/`。

凭证也可以放进带命名空间分段的 `.env` 文件——复制 [`.env.example`](https://github.com/wdl-dev/cli/blob/main/.env.example),来源优先级(flag 高于 shell env,高于 `.env`)见 [docs/deploy.md](https://github.com/wdl-dev/cli/blob/main/docs/deploy.md)。
凭证也可以放进带命名空间分段的 `.env` 文件——复制 [`.env.example`](https://github.com/wdl-dev/cli/blob/main/.env.example),来源优先级(flag 高于 shell env,高于 `.env`,高于 `wdl token` store)见 [docs/deploy.md](https://github.com/wdl-dev/cli/blob/main/docs/deploy.md)。

## 命令

```bash
wdl init <target> --ns <ns> [--worker <name>]
wdl init <target> [--ns <ns>] [--worker <name>]
wdl deploy <project-dir> [--ns <namespace>] [--env <name>] [--verbose]
wdl tail <worker> [<worker>...] [--ns <namespace>] [--raw]
wdl workers [--ns <namespace>]
wdl secret <put|list|delete> (--worker <name> | --scope ns) [KEY] [--json]
wdl token set --ns <ns> [--control-url <url>] [--label <text>] [--default]
wdl token list [--json] / wdl token use <ns> / wdl token rm --ns <ns>
wdl d1 <create|list|delete|execute|migrations> ...
wdl r2 buckets list / wdl r2 objects <list|head|get|delete> ...
wdl workflows <list|instances|status|pause|resume|restart|terminate> ...
Expand Down Expand Up @@ -124,9 +126,10 @@ Worker/项目目录名:[如果已知就填,例如 hello-counter;不知道
步骤:

1. 检查 Node.js >= 22 和 npm。缺 `wdl` 时执行 `npm i -g @wdl-dev/cli`;安装后确认 `command -v wdl` 可用。
2. 确认 `WDL_NS`、`ADMIN_TOKEN`、`CONTROL_URL`。CLI 没有内置控制面地址,三个值都必须配置——由运维方提供。如果有缺失,引导我写入当前 shell 的 rc 文件(先看 `$SHELL`:zsh → `~/.zshrc`,bash → `~/.bashrc` 或 `~/.bash_profile`,fish → `~/.config/fish/config.fish`),然后让当前 shell 生效;已设置就跳过
2. 确认 namespace 和 control 凭证能解析出来——跑 `wdl doctor`。它们可以来自 shell/CI env(`WDL_NS`、`ADMIN_TOKEN`、`CONTROL_URL`)、项目 `.env`,或 `wdl token` store;control URL 和 token 由运维方提供(CLI 没有内置控制面地址)。都解析不出来时,最干净的做法是让我跑 `wdl token set --ns <ns> --control-url <url>`,在隐藏提示里输入 token——它会经校验、以 `0600` 存入,并成为默认 namespace,之后 `wdl deploy` 不用再带 `--ns`。优先用这个,而不是把 token 写进 shell rc 文件
3. 确认项目目录名以字母开头,后续只含字母、数字和连字符。执行:
`wdl init <name> --ns "$WDL_NS" && cd <name> && npm install`
`wdl init <name> && cd <name> && npm install`
(给 `wdl init` 加 `--ns <ns>` 可把 namespace 烤进 deploy 脚本;否则部署期从 `wdl token` 默认或 `--ns` 解析。)
4. 立刻打开并阅读新目录里的 `AGENTS.md`,再根据我的功能打开 `node_modules/@wdl-dev/cli/docs/` 下相关文档和示例。注意:session 中新生成的 `AGENTS.md` 不会自动加载,必须显式读取。
5. 根据功能修改 `wrangler.jsonc` 和 `src/`。需要第三方 API 鉴权 secret 时用 `wdl secret put --worker <worker-name> <KEY>` 写入,不要把 token 放进源码、`wrangler.jsonc` 或 `.env`。
6. 先跑 `npm run dry-run` 修复本地 bundle 问题,再跑 `npm run deploy` 部署。
Expand Down
Loading