Repository navigation
Description
coordinator#1 · hotlong · session_6eb9ec2e0e3f410b91239dab7a337b9e
Filing gate: ③ a task on the maintainer's word. In the coordinator session on 2026-11-06 the maintainer said 「我觉得先把受管软件包的开发循环走顺了」, then 「同意,然后第一步先解决我本地开发的软件包怎么能够方便地发布到云端」.
Reader: domain:cli (packages/cli/src/commands/package/publish.ts, commands/cloud/login.ts, commands/environments/*, utils/cloud-config.ts, utils/active-environment.ts). The epic and the server half are on objectstack-ai/cloud, linked in a comment below once filed. Suggested priority p1: this is the first step the maintainer named. Triage decides.
Dedupe:
- objectstack
activeEnvironmentId: 5 hits, all closed. - objectstack
"os package publish": 40 hits. Open: Marketplace listing shows which languages an app actually supports, derived at publish with coverage, and can be filtered by language #30284 (marketplace language coverage), [Epic] Marketplace and connector auto-shelf — E1 platform prerequisites (openapi/mcp hardening, outbound OAuth, request signing), E2 administrator credential hand-off, E3 author recipes and handbook, E4 the first shelf of official connector apps #27293 (connector auto-shelf epic), seat posts. None is about the local publish loop. - objectstack
0.0.0-dev: 10 hits. Open: ci(release): add the dispatch-onlynextsnapshot lane to release.yml, held at environment: release, never movinglatest(#29466 ruling B) #30591 (the releasenextsnapshot lane, unrelated). - objectstack
os environments switch auto: 39 hits, none open about auto-selecting an environment.
维护者速读
程序员在本地改好一个受管软件包,想马上在云端自己组织的环境里看到效果。现在要过五道坎:先手动 os build;每次手改版本号,否则重复发布会 409;明明组织只有一个环境还得 switch,而 os cloud login 会把记下的环境清掉;--install 找不到环境时只打一行错误,命令照样算成功;装完说「已安装」,其实环境还没换成新版本。这张卡把 CLI 这一侧理顺,「等到真正生效」需要服务器提供信号,那一半在 cloud 卡上。
What happens today (objectstack origin/main a2f523aa)
- No build step.
publish.ts:498-510readsdist/objectstack.jsonor exits with "Runobjectstack buildfirst". - Version.
deriveVersion(publish.ts:221-229):--version, elsemanifest.version, else0.0.0-dev.<YYYYMMDDHHMMSS>.manifest.versionwins, so republishing an unchanged config always gets cloud's 409 "Version '…' already exists … Bump the version and retry" (cloudroutes/package-publish.ts:1230-1236). - Environment.
--env/$OS_ENVIRONMENT_ID, elsecloud.json.activeEnvironmentIdwhen its url matches (publish.ts:795-818,utils/active-environment.ts:115-130).- No auto-select when the organization has exactly one environment (no such fallback anywhere in
cli/srcorclient/src). ADR-0024 (cloud) now gives every organization exactly one environment. os cloud loginrewritescloud.jsonwhole (cloud-config.ts:91-97,login.ts:222-228), soactiveEnvironmentIdis gone after every login.--installwith no environment prints "--installrequires--env <id>… Skipping auto-install." (publish.ts:812-818), publishes anyway, and exits 0.
- No auto-select when the organization has exactly one environment (no such fallback anywhere in
- "Installed" is printed before the environment serves it. The versions call returns after cloud writes the desired state and evicts the kernel. The rebuild happens later (cloud
package-install/install.ts:825-855). The CLI prints "Installed into environment" (publish.ts:858-863) and checks nothing more.
Ask
- Pick the only environment. With
--installand no--env, ask the control plane for the caller's organization's environments. Exactly one → use it, and print which. None or several → refuse (item 3). - Keep the active environment across
os cloud login. Merge intocloud.jsoninstead of overwriting, keepingactiveEnvironmentIdwhen the url is unchanged. --installthat cannot resolve an environment exits non-zero, before the publish call, naming how to pass one. A publish that was asked to install and didn't must not read as success.- Dev builds without hand-bumping.
os package publish --devpublishes<manifest.version>-dev.<YYYYMMDDHHMMSS>(semver pre-release), whatevermanifest.versionsays. Cloud already flags-devversions as pre-release (package-publish.ts:1407); making cloud honour that flag is the cloud card's part. - Build first, optionally.
--buildruns the same compileos buildruns before reading the artifact. Name the flag as the CLI's other commands would. - Wait until live (Blocked-by the cloud card's served-version signal). After
--install, poll until the environment reports serving the new version, or report the build failure the environment reports.--no-waitkeeps today's behaviour. Bounded by a timeout that names what it was waiting for.
Out of scope here, listed on the epic: a watch mode, a change preview before install, os mcp connect.
Acceptance
- Tests pin: the one-environment pick, several-or-none refused,
loginkeepingactiveEnvironmentId,--installwithout an environment exiting non-zero before any write, and--devproducing a semver pre-release from a fixedmanifest.version. - Item 6 has a test against a stubbed control plane: serving the new version → success; a build failure → the reason printed, non-zero.
- On cloud staging, from a checkout with a fixed
manifest.version:os package publish --dev --installrun twice in a row succeeds both times without--env, and the second run's version is what the environment serves.
🤖 Generated with Claude Code
Activity
objectstack-fleet commentedon Nov 6, 2026
coordinator#1 · hotlong · session_6eb9ec2e0e3f410b91239dab7a337b9e
Epic: objectstack-ai/cloud#3652 (managed package dev loop, Phase 1). The server half, including the served-version signal item 6 waits on, is objectstack-ai/cloud#3651. · 2026-11-06T08:03Z
objectstack-fleet commentedon Nov 6, 2026
coordinator#1 · hotlong · session_6eb9ec2e0e3f410b91239dab7a337b9e
Scope amendment: developers should not have to remember a command · 2026-11-06T08:21Z
Maintainer, coordinator session 2026-11-06, in order:
os package publish --build --dev --install: 「你的命令行会不会参数太多啊?」os deploy: 「开发人员也记不住啊」This amendment supersedes the Ask's items 4–6 (
--dev,--build, wait-until-live onos package publish). Items 1–3 stand unchanged and apply to every command that installs: pick the only environment, keep it acrossos cloud login, exit non-zero when no environment resolves.What replaces items 4–6
<manifest.version>-dev.<YYYYMMDDHHMMSS>, installs into the organization's only environment, and waits until the environment serves it (the wait is Blocked-by objectstack-ai/cloud#3651 item 3). A failed build prints the environment's reason and exits non-zero.os deploy(alternativeos push). The lane picks the name. ⛔ Do not reuse the retiredos publishid:publish.ts's header documents it as removed.--envwhen an organization has several environments, and--no-wait.os devoffers it on a key. Once the local dev server is up, its last line says something like 「按d部署到云端环境 」. Pressingdruns item 1 and prints the result in the same terminal. If not logged in, the line offers login and connect instead.os devhas no key handling (packages/cli/src/commands/dev.ts).npm run deploy.create-objectstacktemplates (for examplesrc/templates/blank/package.json, which hasdev/start/buildtoday) gain adeployscript calling item 1.os build, print how to deploy. Running bareoslists the few everyday commands first.skills/, platform/CLI guidance) describes the deploy flow: when to deploy, the command, how to read a failure. This part may route todomain:skillsas its own card; the claiming seat decides.os package publishkeeps its meaning: publish a release version (the manifest's version) to the organization's catalog, with--installoptional. It gets items 1–3 and nothing else.Acceptance (replaces the Ask's acceptance for items 4–6)
manifest.version, the only environment picked, waiting and success on the served version, the reason and a non-zero exit on a failed build (stubbed control plane).os devtest: the deploy key runs the deploy path; with no login it offers login.package.jsonhasdeploy.manifest.version:npm run dev, pressdtwice with an edit between. Both deploy without any flag, and the environment serves the second build.🤖 Generated with Claude Code
objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Claim: PM loop round R5 · 2026-11-06T08:28Z
Session:
session_01Q4EjjRhUZjdy8VXs6Kkur2Account:
hotlong(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-30871-deploy-dev-loopWorktree:
/home/user/w30871/objectstack-issue-30871Domain:
domain:cli(claimed by the epic owner of objectstack-ai/cloud#3652; nodomain:cliseat is posted, and the maintainer told this seat, verbatim, 「专题卡3652相关的任务你也都优先派发」)Seat:
repo:cloud#3File surface:
packages/cli/src/commands/package/publish.ts,commands/cloud/login.ts,commands/environments/*,utils/cloud-config.ts,utils/active-environment.ts, a new deploy command underpackages/cli/src/commands/,commands/dev.ts(the deploy key),create-objectstacktemplates (deployscript), the post-build and bare-oshints, and testsContainer & model:
M,mode:subagent,model: TIER_DEFAULT,effort: highClause-②: no — CLI commands and flags; no spec key, schema or error code is added (re-judged on the diff)
Metadata-protocol: none
Responsibility: the CLI half of the managed-package dev loop, Phase 1 | none | every developer deploying a local package to the organization's environment
Thread-read: 6680520228
Premise: holds — the card's readings on objectstack
origin/maina2f523aa, with the scope amendment 6680520228 (maintainer 「同意」) superseding items 4–6Serial constraints cleared: no in-flight claim on
packages/cli/src/commands/package/publish.tsordev.tsfound. The wait-until-live step depends on objectstack-ai/cloud#3651 item 3 (in flight under this seat); the seat relays that contract, and this PR does not land before the contract is fixed.Carrier: objectstack (CLI) for items 1–3 and the amendment; the served-version signal is cloud's (objectstack-ai/cloud#3651). The amendment's skill part (item 5) routes to
domain:skillsas its own card once the command name is fixed.objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit ·
domain:cli→domain:server· p1 kept · 2026-11-06T08:53Z⛔ Not a claim.
domain:cliis a retired alias ofdomain:server. The card is dispatched; only the lane label changes. pm(scripts): retired lane aliases — mark domain:rest retired in ensure-pm-labels.sh, and have the relay rewrite domain:engine / services / cli / rest to domain:server at write time #30827 makes the relay rewrite this alias at write time.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30871, "status": "done", "branch": "claude/issue-30871-deploy-dev-loop", "pr": "https://github.com/objectstack-ai/objectstack/pull/30933", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "Command name: `os deploy` (not `os push`: it matches the amendment's `npm run deploy` script, it is the verb developers know for put-it-live, and `push` reads as `git push`; the retired `os publish` id stays retired). Usage: `os cloud login` once, then `os deploy` with no flags = build (child `os compile`) -> publish MANIFEST_VERSION-dev.YYYYMMDDHHMMSS (UTC) -> install exactly that version into the organization's only environment -> wait until `data.served.state` is live; flags only `--env ID`, `--no-wait`, `--wait-timeout SECONDS` (default 600), `--server`, `--token`. Card items 1-3 land for every command that installs into a cloud environment (`os package publish --install` and `os deploy`, one resolver `utils/install-target.ts`: --env, then cloud.json's active environment for this plane, then GET /api/v1/cloud/environments with exactly one non-archived non-system row; none/several/unreadable exits 1 before any write); `os cloud login` keeps activeEnvironmentId for the same plane and account. `os dev` offers `d` once the first server listens (TTY only; not logged in -> `os cloud login` then deploy; no save hook; the child drops the local OS_ENVIRONMENT_ID), the create-objectstack blank template and `os init` app template ship `deploy: objectstack deploy`, `os build` prints the next step, bare `os` lists EVERYDAY COMMANDS first. The wait is wired to the seat-relayed cloud#3662 contract (GET .../environments/ID/packages/MANIFEST_ID -> data.served; never the installations probe; one wake request to the environment origin's /api/v1/discovery before each poll; superseded desiredVersionId is exit 1; no `served` key -> says it cannot confirm, exit 0). PR is a draft and must not land before cloud#3662 merges, stated at the top of the body. `os package install` targets a runtime URL and names no environment, so it had nothing to resolve.", "tests": "At b7ea5f21 (final head), lock VERDICT command-exit 0: cli build exit 0; `pnpm --filter @objectstack/cli typecheck` exit 0; 13 targeted files (new deploy/dev-deploy-key/next-steps/cloud-login tests, every package-publish-* file, publish-active-environment-store, init, validate-build-gate-parity, child-env-source-loader.pin) Test Files 13 passed (13), Tests 210 passed (210). At 7664160b (after merging origin/main, 4 commits with no overlap; rebuilt spec, plugin-auth, service-automation, plugin-approvals, cli): `pnpm --filter create-objectstack test` Test Files 24 passed (24), Tests 370 passed (370); create-objectstack typecheck exit 0 at 4d010654. Full cli unit tier `vitest run --project unit --maxWorkers=2` at 4d010654: Test Files 1 failed | 392 passed (393), Tests 1 failed | 5477 passed (5478); the red (validate-build-gate-parity: BUILD_NEXT_STEP imported as an unclassified value) fixed in 8df29def74, file then 33/33. NOT MEASURED at the final head: full cli unit tier, reason: shared lock queue; CI Test Core runs it. Integration tier declared to CI (no integration file, bin entry or serve-process helper touched). Ablations (12, scripts/ablation-replace.mjs WRAP mode, at b7ea5f21; tests import src, no dist leg): A1 only-env pick, A2 refuse-before-write (3 red), A3 login keeps env, A4 dev version, A5 live branch, A6 failed branch, A7 key runs deploy, A8 key offers login, A9 build next step, A10 everyday block, A11 per-poll wake, A12 superseded; every mutation proven on disk (anchor 1 -> 0, blob changed), every named test red, every restore proven by blob equal to HEAD, git diff HEAD and git status empty afterwards. Real `os build` from source on a minimal defineStack fixture printed the next-step line (exit 0).", "gates": "Local: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at b7ea5f210d derived 112 commands; all 112 run with exit captured before any pipe: 112 x exit 0. `--ran` with exit codes: '112 derived famil(ies) accounted for — 112 run, 0 NOT-MEASURED (a DERIVED zero — all 112 recorded an exit code and none of them is 3)'. An earlier run at 08361b30 caught a real finding of this diff (check:system-context-census read a field named isSystem as an elevation read; renamed to infrastructure; census OK). CI on PR head b7ea5f21 at report time: Governed Surface Queue Guard completed/success; Check Changeset, Lint · (ESLint, CI release & engine gates, PM dispatch-gates, docs & code guards, repo & tooling gates, scoped x3), Type Check · (workspace, source gates, consumer gates, debt ledger), PR-body guards, Scaffold outside the monorepo, Scaffold with repo dist, Spec property liveness, Validate Package Dependencies: in_progress; opt-in jobs skipped. Convergence is the seat's read.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no MCP GitHub calls", "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, no labels, no assignees; one earlier attempt refused by write-pace before sending, nothing written) and this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30871/comments). git pushes are not REST writes.", "open_questions": [ { "question": "Which environment request starts a request-driven rebuild? The wait sends GET ORIGIN/api/v1/discovery (origin from data.environment.hostname) before each poll, because /api/v1/health is the container liveness probe and answers without a kernel.", "options": [ "A keep /api/v1/discovery", "B another kernel-served path cloud#3662's author names" ], "recommendation": "A unless cloud#3662's author names a cheaper kernel-served path; the change is one line in wakeEnvironment." }, { "question": "When data.served.desiredVersionId differs from the publish answer's id (another install replaced this deploy), the CLI reports it and exits 1 rather than reporting the other version live. Does the contract intend that reading?", "options": [ "A exit 1, named as superseded (as implemented)", "B treat live as live regardless of desiredVersionId" ], "recommendation": "A, because a deploy that was overwritten did not go live and must not read as success." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat (domain:skills card) · the amendment's item 5, the skill teaching `os deploy`; name and usage are in this report's summary · noted, not filed", "carrier: none · `os package publish --install` still prints 'Installed into environment' on the desired-state answer; by the amendment publish keeps its meaning with no wait · noted in the PR's Acceptance notes", "carrier: none · test/next-steps.test.ts runs `os build` in-process (about 8.8 s of test time on the shared box) and declares no test-budget line; if CI shard timings read it over 10 s it is this lane's card · noted in the PR's Acceptance notes" ] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30871, "status": "done", "branch": "claude/issue-30871-deploy-dev-loop", "pr": "https://github.com/objectstack-ai/objectstack/pull/30933", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "head": "c7aab69d87", "premise_still_valid": true, "summary": "Rework round for the CI red at b7ea5f21 (check:error-code-casing on packages/cli/test/deploy.test.ts:60 'kernel_warming'). Cloud origin/main b59b2748: KernelManager throws KernelWarmingError with its own code 'kernel_warming' and statusCode 503; the framework transport answers that throw with the ADR-0112 envelope 503 SERVICE_UNAVAILABLE, and 'kernel_warming' is only the declared code (packages/rest/src/rest-resolve-environment-single-window.test.ts pins that pair). So the stub now answers { success: false, error: { code: 'SERVICE_UNAVAILABLE', message } }, and the served-version.ts comment says so; no ledger exit used. Commit 6b8079a7fc, then git merge origin/main (11 commits, no file overlap, some on packages/cli generate/lint) = c7aab69d87, pushed normally. Why the red was missed before the push: check:error-code-casing is not in the `--commands` total. dispatch-gates places it among the artifact-roster families (its 21 declared literals are tracked files under packages, so 'silent' is no evidence), and --residue flags it with 'roster under packages, which one of your paths is in'. The --ran output names those 48 roster families as outside the derived total, and I ran only the total. My own os-dev rule ('new error code => check:error-code-casing') did not fire because I did not read a stub's code literal as an emission. This round ran the derived total plus every roster family --residue flags for my paths (authz-resolver, error-code-casing, filter-alias-parity).", "tests": "check:error-code-casing on b7ea5f21: exit 1, '✗ lowercase error-code literal(s) in a code position (ADR-0112 D1): packages/cli/test/deploy.test.ts:60 'kernel_warming' (emission)'. After the fix: exit 0, '✓ no unlisted lowercase error codes in 11554 scanned file(s) (ADR-0112)'. At c7aab69d (lock VERDICT command-exit 0, after rebuilding the cli dependency closure and create-objectstack): `pnpm --filter @objectstack/cli typecheck` exit 0; full cli unit tier `vitest run --project unit --maxWorkers=2` Test Files 393 passed (393), Tests 5528 passed (5528); `pnpm --filter create-objectstack test` Test Files 24 passed (24), Tests 370 passed (370). No behaviour changed this round (a test fixture's wire code and a comment), so no ablation.", "gates": "Local at c7aab69d87: `dispatch-gates --commands --repo objectstack-ai/objectstack` derived 112 (same list as at b7ea5f21), plus the 3 roster families --residue flags for my paths (check:authz-resolver, check:error-code-casing, check:filter-alias-parity) = 115 commands, every one exit 0. 4 first answered exit 3 (built output missing in the fresh worktree: skill-examples, dual-build-cjs-loads, i18n-coverage, type-check-debt); measured after a workspace build under the lock (VERDICT command-exit 0), all 4 exit 0. `--ran` with exit codes: '112 derived famil(ies) accounted for — 112 run, 0 NOT-MEASURED (a DERIVED zero — all 112 recorded an exit code and none of them is 3)'. CI on c7aab69d87, read once: 41 completed/success, 13 completed/skipped, 0 failures, 0 in progress. Lint & Repo Gates, Lint · docs & code guards, TypeScript Type Check, Test Core (8/8 shards), Build Core and Governed Surface Queue Guard all success. UI jobs skipped (no ui/ path).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "1 — this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30871/comments). git pushes are not REST writes. No PR body edit (the seat holds that write; replacement text is in the final report).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
ACCEPT → PR #30933 comment 6686781321 · 2026-11-06T14:09Z ·
os deploy, thedkey,npm run deployand items 1–3 landed together; ready and enqueued (Refs #30871, the seat closes this card on merge). The skill teachingos deploy(amendment item 5) is filed as adomain:skillscard at close-out.objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
LANDED · 2026-11-06T14:33Z
780c6c34(Refs #30871)completedby the seatState:
pm:dispatchedandpm:blockingremoved.os deploy, thedkey inos dev,npm run deployin the scaffold, and items 1–3 are on main. Amendment item 5 (the skill teaches it) is #30968 (domain:skills). Out of scope and still on the epic: watch mode, change preview,os mcp connect.