Skip to content

Commit 9c4a14c

Browse files
baozhoutaoclaude
andauthored
docs(cli): narrow the dev --fresh isolation claim to what it covers (#5594) (#5640)
`--fresh` 的注释声明 tempdir "owns ALL persistent state for this run", 但 app 自己声明的 cwd 相对路径(如 showcase 的 `showcase_external.db`) 由各自的消费者按进程 cwd 解析,而 `--fresh` 并不移动 cwd —— 这类状态写在 项目树里、退出后仍在。#4968 之后真实覆盖面是「`OS_HOME` 键控的框架态 + CLI 发布的 env 通道(`OS_DATABASE_URL` / `OS_STORAGE_LOCAL_ROOT`)」。 本 PR 只让承诺句变真,不让行为变大:改写 `dev.ts` 的 `--fresh` 注释块与 flag help,并在 `content/docs/deployment/cli.mdx` 的 `os dev` 选项表旁补一段 范围说明。刻意不做 issue 的处置 2(相对路径改锚 `OS_HOME`)—— 那是契约变更。 零行为变更;showcase 的 datasource 声明是刻意设计,未改动。 Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh Co-authored-by: Claude <noreply@anthropic.com>
1 parent b746aa0 commit 9c4a14c

3 files changed

Lines changed: 76 additions & 8 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
`os dev --fresh` states the isolation it actually delivers (#5594)
6+
7+
The `--fresh` block promised its tempdir "owns ALL persistent state for this
8+
run". After #4968 that is true of everything the CLI itself places — the dev
9+
SQLite DB (`OS_HOME``<home>/data/dev.db`, published as `OS_DATABASE_URL`),
10+
the uploads root (published on the settings service's own name
11+
`OS_STORAGE_LOCAL_ROOT`), and any plugin state keyed off `OS_HOME` — but it was
12+
never true of state an **app** reaches by a relative path it declares itself.
13+
Such a path is resolved by its own consumer against the process working
14+
directory, which `--fresh` does not move, so the file lands in the project tree
15+
and is still there after the run exits.
16+
17+
The live specimen is deliberate authoring, not a bug: the showcase's
18+
`showcase-external` datasource declares
19+
`filename: '.objectstack/data/showcase_external.db'` and documents that the path
20+
resolves against the project cwd — so a `--fresh` showcase run leaves that file
21+
(plus `-wal`/`-shm`) behind.
22+
23+
No behaviour changed. The `--fresh` flag help, the source comments, and the
24+
`os dev` flag table in the CLI docs now name the covered surface
25+
(`OS_HOME`-keyed state plus the env channels the CLI publishes) and state
26+
plainly what falls outside it, with a docs note on declaring an absolute path
27+
when a datasource should follow `--fresh`.
28+
29+
Re-anchoring app-declared relative paths on `OS_HOME` is a behaviour change
30+
resting on an open contract question ("relative to cwd" vs "relative to this
31+
run's home") and is deliberately not taken here.

content/docs/deployment/cli.mdx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,29 @@ os dev --database file:./data/test.db --auth-secret $(openssl rand -hex 32)
138138
| `-p, --port <n>` | `OS_PORT` / `PORT` | Listen port (default `3000`). In dev a busy port auto-hops to the next free one; the banner shows the actual port. |
139139
| `--ui` || Force Console UI on (already on by default in dev) |
140140
| `--compile` || Force compiling `objectstack.config.ts``dist/objectstack.json` before starting (auto when the artifact is missing; ignored with `--artifact`) |
141-
| `--fresh` || Ephemeral `OS_HOME` in the OS tempdir (clean DB, uploads, storage), auto-deleted on exit; implies `--seed-admin` |
141+
| `--fresh` || Ephemeral `OS_HOME` in the OS tempdir (clean DB, uploads root, and other `OS_HOME`-keyed state), auto-deleted on exit; implies `--seed-admin`. See the scope note below |
142142
| `--seed-admin` / `--no-seed-admin` || Seed a dev admin (`admin@objectos.ai` / `admin123`) on an empty DB — default on; override with `--admin-email` / `--admin-password` |
143143
| `-v, --verbose` || Verbose output |
144144

145145
By default `os dev` keeps your data between restarts in a project-local SQLite
146146
file at `.objectstack/data/dev.db` (created on first run). Pass `--database`,
147147
set `OS_DATABASE_URL`, or use `--fresh` for a throwaway run.
148148

149+
<Callout type="info" title="What `--fresh` covers">
150+
`--fresh` isolates the state **the CLI places for the run**: everything keyed
151+
off the ephemeral `OS_HOME` (the dev SQLite DB, the uploads root, plugin state
152+
under `OS_HOME`) plus the env channels `os dev` publishes for it —
153+
`OS_DATABASE_URL` and `OS_STORAGE_LOCAL_ROOT`. That tempdir is deleted on exit.
154+
155+
It does **not** relocate state your app reaches by a **relative path it
156+
declares itself** — for example a datasource with
157+
`config: { filename: '.objectstack/data/my.db' }`. Such a path is resolved by
158+
its own consumer against the process working directory, which `--fresh` does
159+
not change, so the file is written into your project tree and is still there
160+
after the run ends. Declare an absolute path (or one derived from `OS_HOME`)
161+
when you want a datasource to follow `--fresh`.
162+
</Callout>
163+
149164
With a file-backed SQLite database, dev also provisions a sibling
150165
`<db>.telemetry.<ext>` file registered as the `telemetry` datasource —
151166
lifecycle-classed system data (activity streams, job runs, notifications,

packages/cli/src/commands/dev.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,18 @@ export default class Dev extends Command {
9797
}),
9898

9999
// ── Ephemeral / fresh-environment helpers ────────────────────────
100-
// `--fresh` creates an isolated tempdir for OS_HOME / DB / uploads
101-
// so every run starts from a clean slate. Combine with `--seed-admin`
100+
// `--fresh` creates an isolated tempdir for OS_HOME / DB / uploads, so
101+
// every run starts from a clean slate for the OS_HOME-keyed state the
102+
// CLI itself places (see the block in `run()` for the exact covered
103+
// surface, and for what an app-declared relative path escapes — #5594).
104+
// Combine with `--seed-admin`
102105
// (default-on when --fresh) to also provision a logged-in admin
103106
// account, so backend debugging never blocks on first-run wizards.
104107
// The seeded admin uses FIXED, well-known credentials by default
105108
// (admin@objectos.ai / admin123) so tooling never has to guess them —
106109
// override with --admin-email / --admin-password when needed.
107110
fresh: Flags.boolean({
108-
description: 'Start with an ephemeral OS_HOME under the OS tempdir (clean DB, uploads, storage); auto-deletes on exit. Implies --seed-admin (admin@objectos.ai / admin123) unless --no-seed-admin is given.',
111+
description: 'Start with an ephemeral OS_HOME under the OS tempdir clean DB, uploads root and other OS_HOME-keyed state for this run, auto-deleted on exit. State an app reaches by its own cwd-relative path (e.g. a datasource `filename: .objectstack/...`) is NOT covered and survives exit. Implies --seed-admin (admin@objectos.ai / admin123) unless --no-seed-admin is given.',
109112
default: false,
110113
}),
111114
'seed-admin': Flags.boolean({
@@ -180,10 +183,29 @@ export default class Dev extends Command {
180183
const environmentId = flags['environment-id'] ?? process.env.OS_ENVIRONMENT_ID ?? 'env_local';
181184

182185
// ── --fresh: ephemeral OS_HOME under the OS tempdir ─────────────
183-
// Creates a unique scratch dir that owns ALL persistent state for
184-
// this run: the SQLite DB (via OS_HOME → <home>/data/...), the
185-
// storage-service uploads root (OS_STORAGE_LOCAL_ROOT), and any other
186-
// state plugins keyed off OS_HOME. Auto-deleted on exit.
186+
// Creates a unique scratch dir that owns the state this command can
187+
// actually place, and nothing more. What it covers, exactly:
188+
// - the dev SQLite DB the CLI resolves for the run
189+
// (OS_HOME → <home>/data/dev.db, published as OS_DATABASE_URL),
190+
// - the storage-service uploads root, published on the settings
191+
// service's own env name OS_STORAGE_LOCAL_ROOT (#4968),
192+
// - any other state a plugin keys off OS_HOME.
193+
// In one sentence: framework-owned, OS_HOME-keyed state plus the env
194+
// channels this block publishes below. Auto-deleted on exit.
195+
//
196+
// NOT covered — state reached by an app-declared RELATIVE path (#5594).
197+
// Such a path is resolved by its own consumer against the process cwd,
198+
// which `--fresh` does not move, so it is written into the project tree
199+
// and survives exit. The live specimen is deliberate authoring, not a
200+
// bug: examples/app-showcase's `showcase-external` datasource declares
201+
// `filename: '.objectstack/data/showcase_external.db'` and says in its
202+
// own comment that the path resolves against the project cwd — so a
203+
// `--fresh` run of the showcase leaves that file (+ -wal/-shm) behind.
204+
// Re-anchoring app-declared relative paths on OS_HOME would be a
205+
// behaviour change resting on an open contract question ("relative to
206+
// cwd" vs "relative to this run's home"); it is deliberately NOT taken
207+
// here, and this comment states the covered surface instead of an
208+
// unqualified promise a reader would rely on for isolation.
187209
//
188210
// The uploads root MUST be published under the name the settings
189211
// service derives for it — `envKeyOf('storage','local_root')` (#4968).

0 commit comments

Comments
 (0)