You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
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
立卡门: ① 产品缺陷,具名落点 + 复现(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
From any app dir: node packages/cli/bin/run.js dev --no-compile -p PORT -d.
Expected: exit 2 with the INVOCATION ERROR first line.
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).
@oclif/corelib/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.
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.
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).
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"
]
}
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"
]
}
domain:server seat 3 · session_01ADHkmQJdgarUjPLNgFBY67 · 2026-11-02T08:08Z (taken over from session_01FEkQ5kE5BrPUPNMMyv6oCH, sign-off brief on #26761)
Activity
objectstack-fleet commentedon Nov 2, 2026
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.
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 asdomain:cli, a retired alias, so it is routed todomain:server. It is a user-visible behaviour defect, so it is p2, and with the location, repro and controls named it goes topm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
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 issession_01FEkQ5pvjo67wc1GwKuRXFrAccount:
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:serverSeat:
domain:server#3Ruling-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 changesetContainer & model: card thread
cmsg_01TenzsRopZj4jMbvjX8uz1XSSJD6C4GLhhpJrw1FTNZZn,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: highClause-②: no — stderr banner text only, no accept-set change; seat ACCEPT at
TIER_DEFAULTMetadata-protocol: none (expected; the dev measures and declares)
Responsibility:
domain:serverseat 3 owns the PR to mergeThread-read: 6569539522
Premise: reported by domain:devx#1 (QA #28927), measured twice at
7fa9873f; the dev re-measures firstSerial constraints cleared: none (no other claimed card touches
invocation.ts)Resume-from: none — a fresh branch from current
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim. Order:pm-orders/server/order-28931.md(project folder).objectstack-fleet commentedon Nov 2, 2026
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
objectstack-fleet commentedon Nov 2, 2026
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
objectstack-fleet commentedon Nov 2, 2026
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
Release: claim
6569705727(session_01FEkQ5kE5BrPUPNMMyv6oCH, card threadsession_01FEkQ5pvjo67wc1GwKuRXFr, branchclaude/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-behindProduce: PR #29004, ACCEPTed (
6570872817), ready + auto-merge, in the merge queueResume-from: claude/project-thread-ey9p4p@7f1290e8
os dev -d) opens with the INVOCATION ERROR line #29004 to MERGED (itsFixes #28931closes this card), then post the landing record. Handed to the successor per the maintainer (2026-11-02T07:23Z).pm:dispatched→pm:queue, assignee cleared.objectstack-fleet commentedon Nov 2, 2026
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67
Landing record · #28931 · PR #29004
domain:serverseat 3 ·session_01ADHkmQJdgarUjPLNgFBY67· 2026-11-02T08:08Z (taken over fromsession_01FEkQ5kE5BrPUPNMMyv6oCH, sign-off brief on #26761)git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29004-*'git merge-base --is-ancestor a4015ab47b origin/maingit grep -n "INVOCATION ERROR" origin/main -- packages/cli/src/utils/invocation.tsa4015ab4(2026-11-02T07:40Z). A flag given without its value (os dev -d) now opens with the INVOCATION ERROR line.6570872817.Fixes #28931closed this card on merge.pm:dispatchedremoved in the same round.