Skip to content

cli: a flag missing its value (os dev -d) exits 2 without the INVOCATION ERROR banner, so a backgrounded boot looks like one that died #28931

Closed

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbZpHPpovxXPremPLtv

立卡门: ① 产品缺陷,具名落点 + 复现(reach: 公开入口 CLI os dev -d 实测一次错误结果)
业务理由: 在后台启动 os dev 的用户和 agent 依赖 #10181 的 INVOCATION ERROR 首行,来分辨「命令根本没跑」和「应用起来又挂了」;缺值这一类解析失败没有这一行,读的人就会去排查一个从没启动的应用。不修,这个假象会持续让人和 agent 白跑一圈。
动手的读者: domain:cli 席,packages/cli/src/utils/invocation.ts 的 isInvocationError() 识别 oclif 的「expects a value」CLIError,附 cli 单测。
查重: repo is:issue "expects a value" 3 命中(#11669、#7635、#21333,都不相关)、INVOCATION ERROR banner flag 109(均含已关);最近邻 #24192 不是本现象。

QA-source: #28927 · cli.dev-boot-contract · observed beside the clauses

What happens

Since #10181 every parse failure is meant to open with one line, "objectstack: INVOCATION ERROR — … The command never ran: nothing was started and nothing is listening." A flag given without its value skips that banner: os dev … -d exits 2 with stdout empty and one stderr line, " › Error: Flag --database expects a value". Backgrounded, that is the "booted and died" lookalike the banner exists to prevent (RUNNER environment facts, the --no-ui entry).

Measured at framework 7fa9873f (main, 2026-11-02), twice, from a scratch copy of examples/app-showcase.

Reproduction

  1. From any app dir: node packages/cli/bin/run.js dev --no-compile -p PORT -d.
  2. Expected: exit 2 with the INVOCATION ERROR first line.
  3. Actual: exit 2, stdout empty, stderr " › Error: Flag --database expects a value", no banner.

Controls that do print the banner: serve --artifact x (nonexistent flag) and dev --database-driver memory (refused value).

Mechanism (read at 7fa9873, a guess)

@oclif/core lib/parser/parse.js (around L137) throws a plain CLIError ("Flag --X expects a value"). isInvocationError() in packages/cli/src/utils/invocation.ts matches only CLIParseError-shaped errors (own parse and showHelp fields), so this parse failure falls through.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: cli.dev-boot-contract

    Triage: priority:p2 · domain:server · pm:queue · 2026-11-02T05:06Z

    ⛔ Not a claim.

    • Read fresh. isInvocationError() (packages/cli/src/utils/invocation.ts) only recognises CLIParseError-shaped errors, so oclif's plain "Flag --X expects a value" CLIError exits 2 without the fix(cli): make the two invocation failures that read as a crashed boot say so #10181 INVOCATION ERROR banner. The card names the seat as domain:cli, a retired alias, so it is routed to domain:server. It is a user-visible behaviour defect, so it is p2, and with the location, repro and controls named it goes to pm:queue.

    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Claim: PM loop round 1 · card thread · 2026-11-02T05:19Z
    Session: session_01FEkQ5kE5BrPUPNMMyv6oCH (the seat); the card thread is session_01FEkQ5pvjo67wc1GwKuRXFr
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-ey9p4p (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#3
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」, and 2026-11-01T06:39Z 「server 队列还是很多任务,再开一个席位吧」. Seat 1 split the server queue and gave this card to seat 3 under the maintainer's 2026-11-02T05:15Z 「队列进了很多任务,抓紧派发」.
    File surface: packages/cli/src/utils/invocation.ts, a cli test (unit; one spawn pin only in an existing spawn file), a changeset
    Container & model: card thread cmsg_01TenzsRopZj4jMbvjX8uz1XSSJD6C4GLhhpJrw1FTNZZn, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: high
    Clause-②: no — stderr banner text only, no accept-set change; seat ACCEPT at TIER_DEFAULT
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: domain:server seat 3 owns the PR to merge
    Thread-read: 6569539522
    Premise: reported by domain:devx#1 (QA #28927), measured twice at 7fa9873f; the dev re-measures first
    Serial constraints cleared: none (no other claimed card touches invocation.ts)
    Resume-from: none — a fresh branch from current origin/main

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim. Order: pm-orders/server/order-28931.md (project folder).

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5pvjo67wc1GwKuRXFr

    os-dev-report
    {
    "issue": 28931,
    "status": "done",
    "branch": "claude/project-thread-ey9p4p",
    "pr": "#29004",
    "session": "session_01FEkQ5pvjo67wc1GwKuRXFr",
    "premise_still_valid": true,
    "summary": "isInvocationError() in packages/cli/src/utils/invocation.ts now also recognises a parse failure by its THROW SITE: a frame inside @oclif/core/lib/parser/ on the error's own stack. Premise measured on main 135054e with the built bin/run.js: dev -d, serve --port and migrate meta --from exit 2 with no banner; so do three more plain-CLIError parse classes (bare option-list flag --log-level, single-valued flag given twice, Flags.integer refusal on lint --eval-min abc), all now covered; missing required flag, missing required arg and unexpected arg already printed the banner (CLIParseError) and stay covered. Mechanism hypothesis partly refuted: the order's candidate readings (class / own fields / oclif.exit 2) do NOT separate these from a runtime this.error() in a command that parsed — measured and pinned: same CLIError class, same own fields (stack,message,code,oclif,skipOclifErrorHandling,suggestions), oclif {exit:2}; the throw site is the structural reading that exists, and no English message text is matched. Exit code, accept set and oclif's own lines unchanged; runtime failures (dev -p abc exit 1, plugin uninstall no-such-plugin exit 1, a real Command's this.error()) get no banner.",
    "tests": "Head 45c1b2f. Unit src/utils/invocation.test.ts: 26 passed (26); spawn test/invocation-loudness.e2e.test.ts (nightly tier, OS_TEST_TIERS=nightly, +1 spawn dev -d): 14 passed (14). Red-first on base source: unit 5 failed | 21 passed (four parse-time recognitions + the dev -d line; negatives green on base), spawn 1 failed | 13 passed. Ablation 1 via ablation-replace.mjs (throw-site reading forced false, marker ABL28931): unit 5 failed | 21 passed, spawn 1 failed | 13 passed; restored blob 78901ca1 == HEAD, git diff HEAD empty. Ablation 2, negative pin (every Error claimed, marker ABL28931N): unit 5 failed | 21 passed, exactly the five runtime-not-claimed cases; restored blob == HEAD, diff empty. Both files import src (spawn runs bin/run-dev.js under tsx), so no dist leg. Real-binary probe table on rebuilt bin/run.js (12 invocations, main vs head) in the PR body. cli unit tier: 368 passed (368) files, 5205 passed (5205) tests, lock VERDICT command-exit 0. cli typecheck incl check:test-typecheck exit 0. eslint --no-inline-config packages/cli exit 0.",
    "gates": "dispatch-gates --commands at 45c1b2f: 61 derived; --ran reconciliation exit 0: 60 run exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET: every package dist). check:i18n-coverage first exit 3 (examples' plugin dist absent), exit 0 after the turbo build it names. check-plugin-teardown-shape --self-test after git fetch --depth=1 of 621a487. check:nul-bytes exit 0. Record: /mnt/project-files/pm-orders/server/28931-gates-ran.txt. CI check-runs on #29004: not waited on at report time, per os-dev.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "0 — no GitHub MCP calls (card and PR read through gh api REST GETs)",
    "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls via run 41397656757, read-back identical, no labels, no assignees), this os-dev-report comment (POST /repos//issues/28931/comments); plus 1 git push (not REST)",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a (user-visible text) · reach: public CLI door, os plugin keygen on main prints 'INVOCATION ERROR — The following error occurred:.' and, with this PR, os lint --eval-min abc prints 'INVOCATION ERROR — Parsing --eval-min.': reasonOf() takes only the first line of oclif's message, so for multi-line oclif messages the banner drops the actual reason (it is on oclif's lines below) · evidence: head probe table in PR #29004 · dedupe words: INVOCATION ERROR reason first line, reasonOf multi-line, 'The following error occurred', Parsing --flag banner · carrier: seat 3 to file or fold"
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5pvjo67wc1GwKuRXFr

    os-dev-report
    {
    "issue": 28931,
    "status": "done",
    "branch": "claude/project-thread-ey9p4p",
    "pr": "#29004",
    "session": "session_01FEkQ5pvjo67wc1GwKuRXFr",
    "premise_still_valid": true,
    "summary": "Rework round per seat 3: the out-of-scope finding is folded in. reasonOf() in packages/cli/src/utils/invocation.ts now joins oclif's whole message into one line (whitespace collapsed, SGR colour codes and the 'See more help with --help' tail dropped; a line after a header ending in ':' joined by a space, any other by '; '; capped at 200 chars) instead of keeping line one. Measured on the rebuilt bin/run.js: os plugin keygen reads 'The following error occurred: Missing required flag out', os lint --eval-min abc reads 'Parsing --eval-min; Expected an integer but received: abc', os plugin uninstall reads 'Missing 1 required arg: id The installed plugin id'; single-line messages (dev -d, serve --artifact x, --database-driver memory) unchanged. One changeset paragraph added; declarations unchanged (Clause-② no, Metadata-protocol none, patch).",
    "tests": "Head 7f1290e. Unit src/utils/invocation.test.ts: 30 passed (30); red on 45c1b2f: 4 failed | 26 passed (keygen reason, --eval-min reason, required-arg join without newline/help tail/colour codes, 200-char cap). Ablation via ablation-replace.mjs (reason sliced back to line one, marker ABL28931R): 4 failed | 26 passed, the same four; restored blob 507563b1 == HEAD, git diff HEAD empty. Spawn e2e (OS_TEST_TIERS=nightly): 14 passed (14). cli unit tier after rebuild: 368 passed (368) files, 5209 passed (5209) tests, lock VERDICT command-exit 0. cli typecheck exit 0. eslint --no-inline-config on touched files exit 0.",
    "gates": "dispatch-gates --commands at 7f1290e: 61 derived (same list as 45c1b2f); --ran exit 0: 60 run exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, every package dist). check:i18n-coverage first exit 3, exit 0 after the turbo build it names. Record: /mnt/project-files/pm-orders/server/28931-rework-gates-ran.txt. CI check-runs on #29004 at 7f1290e: not waited on, per os-dev.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "0",
    "api_writes": "1 this round — this os-dev-report comment (POST /repos//issues/28931/comments); plus 1 git push (not REST). PR body NOT patched (os-dev: dev writes the body once); the seat-applied addition is /mnt/project-files/pm-orders/server/28931-pr-body-addition.md. Cumulative: 3 REST writes, 2 pushes.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: none · the earlier reasonOf finding is folded into this PR at the seat's request · carrier: PR #29004"
    ]
    }


    Generated by Claude Code

  7. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Release: claim 6569705727 (session_01FEkQ5kE5BrPUPNMMyv6oCH, card thread session_01FEkQ5pvjo67wc1GwKuRXFr, branch claude/project-thread-ey9p4p) · 2026-11-02T07:39Z · seat 3 shift close (maintainer 2026-11-02T07:10Z 「尽快提交代码,然后收工」, 2026-11-02T07:33Z 「pm-dispatch 中车道下班的流程,都要走完」); handed back, no stay-behind
    Produce: PR #29004, ACCEPTed (6570872817), ready + auto-merge, in the merge queue
    Resume-from: claude/project-thread-ey9p4p@7f1290e8

  8. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 2, 2026
  9. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  10. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67

    Landing record · #28931 · PR #29004

    domain:server seat 3 · session_01ADHkmQJdgarUjPLNgFBY67 · 2026-11-02T08:08Z (taken over from session_01FEkQ5kE5BrPUPNMMyv6oCH, sign-off brief on #26761)

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29004-*' 0 refs (released)
    Ancestry git merge-base --is-ancestor a4015ab47b origin/main yes
    Content git grep -n "INVOCATION ERROR" origin/main -- packages/cli/src/utils/invocation.ts banner at line 247
    • Landed: merged as a4015ab4 (2026-11-02T07:40Z). A flag given without its value (os dev -d) now opens with the INVOCATION ERROR line.
    • Seat ACCEPT 6570872817. Fixes #28931 closed this card on merge.
    • State: pm:dispatched removed in the same round.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions