Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dbe9950
feat(cli): list managed Agent View sessions in qwen sessions ps
yiliang114 Sep 3, 2026
8879852
docs(skills): stop the recency gate from silencing a stalled wiring
yiliang114 Sep 3, 2026
9b14578
fix(cli): keep non-owned supervisor snapshots out of sessions ps
yiliang114 Sep 3, 2026
94610b3
fix(cli): verify managed session pids before listing them
yiliang114 Sep 3, 2026
3e3dac5
test(cli): pin LF and TAB stripping on the ps store-failure note
yiliang114 Sep 3, 2026
4d84fbc
docs(commands): warn that the jq -r example renders session text raw
yiliang114 Sep 3, 2026
6b2c711
fix(cli): keep the sessions ps JSON contract off display wording
yiliang114 Sep 4, 2026
cd68e10
fix(cli): import the task-state type the row test annotates
yiliang114 Sep 4, 2026
853d57b
fix(cli): hold managed session rows to the registry's identity standard
yiliang114 Sep 4, 2026
d02752f
test(cli): give ps.test.ts the identity helpers its subject now calls
yiliang114 Sep 4, 2026
558bd25
fix(cli): correct sessions ps comment claims and pin every STATE label
yiliang114 Sep 4, 2026
32295e3
chore: merge main into feat/agent-view-first-consumer
yiliang114 Sep 4, 2026
b5cf6d9
fix(cli): finish sessions ps review cleanup
yiliang114 Sep 4, 2026
eb7642b
fix(cli): guard sessions ps managed pids by boot id like the registry
yiliang114 Sep 4, 2026
79ca2fc
fix(cli): report the resumable session id spelling in sessions ps
yiliang114 Sep 4, 2026
0783984
fix(cli): carry a deduped record's spelling and pid onto a degraded m…
yiliang114 Sep 5, 2026
075b47d
Merge main into feat/agent-view-first-consumer
yiliang114 Sep 5, 2026
294cbe2
fix(cli): refuse managed pids from a worker file written on another OS
yiliang114 Sep 5, 2026
3b772f1
Merge origin/main (00fe690482) into feat/agent-view-first-consumer
yiliang114 Sep 6, 2026
7c3e095
Merge origin/main into feat/agent-view-first-consumer
yiliang114 Sep 7, 2026
9d891f9
docs: normalize the sessions table padding prettier asks for
yiliang114 Sep 7, 2026
662923e
Merge origin/main into feat/agent-view-first-consumer
yiliang114 Sep 9, 2026
38e77c9
fix(cli): validate resumeSessionId before it becomes a row identity
yiliang114 Sep 19, 2026
10d09db
Merge remote-tracking branch 'origin/main' into pr-10942-sweep
yiliang114 Sep 19, 2026
83b98c1
fix(cli): import process-liveness and session-registry symbols from t…
yiliang114 Sep 19, 2026
8a95fe3
test(cli): intercept the deep process-liveness module in the sessions…
yiliang114 Sep 19, 2026
16c5251
fix(cli): carry the deduped record's name and cwd, and gate resumeSes…
yiliang114 Sep 19, 2026
9a0ca98
docs(skills): key the stalled-wiring probe on the directory basename
yiliang114 Sep 19, 2026
794fcba
Merge origin/main into feat/agent-view-first-consumer
yiliang114 Sep 19, 2026
5d45a51
chore: remove unrelated stalled-wiring guidance
yiliang114 Sep 22, 2026
e499bcf
Merge origin/main into feat/agent-view-first-consumer
yiliang114 Sep 22, 2026
72690a6
fix(cli): narrow managed session listing
yiliang114 Sep 22, 2026
0572adf
Merge remote-tracking branch 'origin/main' into feat/agent-view-first…
yiliang114 Sep 22, 2026
0748743
Merge remote-tracking branch 'origin/feat/agent-view-first-consumer' …
yiliang114 Sep 22, 2026
5eacefa
fix(cli): preserve sessions ps output on stderr failures
yiliang114 Sep 22, 2026
8844d8c
test(cli): make the sessions ps guard-order case able to fail
yiliang114 Sep 23, 2026
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
1 change: 1 addition & 0 deletions .qwen/skills/find-simplifications/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ the issue comment.
| Several strong candidates in one run | File them all; land at most one |
| Report-only territory | File with evidence, marked report-only. Never a PR |
| Path or symbol younger than ~90 days | Drop **silently** — unwired new feature, not rot |
| A young **subsystem** unwired, its wiring PR open and stale | Not a deletion. Report the stall to that PR stack |
| A never-called migrator, validator, guard, or dropped wire-up | Not cleanup. It may be a defect → `/bugfix` or `/review` |
| Any consumer cannot be named | Drop |
| Correct but tiny (one dead import, a typo) | Reject on the ledger: below both skills' intake bar |
Expand Down
47 changes: 41 additions & 6 deletions .qwen/skills/find-simplifications/references/survey.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,27 @@ feature someone is still wiring up. (90 days is a heuristic, not a measured
threshold; widen it for a large subsystem.) Proposing deletion of something
that landed last week is the fastest way to lose a reviewer for good.

But "young" is not the fact the gate is reaching for — "still being wired
up" is, and the two come apart. A directory can keep growing for months
while its consumer never lands, and then every re-run of this survey dates
it young again and drops it again, which is how a subsystem gets to five
figures with nothing calling it. So when the gate fires on a **subsystem**
(not a single symbol), date the wiring rather than the code:

```bash
# has anything outside it ever referenced it?
"$RG" -l '<dir>/' --glob '!<dir>/**' packages
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
# and are the PRs that would wire it still open?
gh pr list --repo QwenLM/qwen-code --search '<feature> in:title' --state all
```

Recent commits inside the directory plus no external reference plus an open,
stalled wiring PR is **not** a deletion candidate and **not** a drop. It is a
different finding with a different owner: the wiring stalled. Report it to
that stack — the merged infrastructure has no entry point — and never as a
deletion PR. The code is wanted; the review that would connect it is what is
missing.

**3 — Published-surface escape.** Is the surface reachable from outside the
repo? SKILL.md § Territory is the authoritative list; keep the two in step.
Everything under `packages/core/src` is, via that package's `"./src/*"`
Expand Down Expand Up @@ -262,13 +283,27 @@ registry entry), not in `packages/core`, and `git log` puts it well past the
recency gate. Deletion is the component, its test, and its snapshot entry, in
one commit. This is what a filed candidate should look like.

**2. Everything says dead; `git` says five days old.** `packages/cli/src/agent-view`
is ~6,000 lines whose entry flag is passed to a spawned process but parsed
nowhere; every static signal calls it rot. Then:
**2. Everything says dead; `git` says five days old — and says it again a
month later.** `packages/cli/src/agent-view` was ~6,000 lines whose entry flag
is passed to a spawned process but parsed nowhere; every static signal called
it rot. Then:
`git log --follow --diff-filter=A --format=%ad --date=short -- packages/cli/src/agent-view
| tail -1` → `2026-08-01`, five days before HEAD. It is a feature mid-wiring.
**Drop silently.** Do not file it, do not mention it — a "should we delete
your new subsystem?" question costs more trust than the finding is worth.
| tail -1` → `2026-08-01`, five days before HEAD. A feature mid-wiring, so:
**do not file a deletion.** A "should we delete your new subsystem?" question
costs more trust than the finding is worth.

What this example originally got wrong was the second half — "do not mention
it". Measured again on 2026-09-04: **11,004 production lines, still zero
external references**, up ~8,000 in four weeks. The five merged PRs of its
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
stack shipped the supervisor, the PTY workers and the lifecycle; the two that
would give it an entry point (#7802 commands, #7803 roster TUI) have been
open since 2026-07-27, the second at +31,699 lines across 104 files and
conflicting. The recency gate kept firing and the survey kept dropping it, so
nothing ever said out loud that a five-figure subsystem had no caller.

The deletion verdict was right and stays right. The silence was not: this is
the stalled-wiring finding above, owed to that PR stack, not to a cleanup
list.

**3. The naive count is wrong in both directions.**
`eslint.legacy-filenames.mjs` lists 559 bare basenames. Checking "does a
Expand Down
61 changes: 46 additions & 15 deletions docs/users/features/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -707,10 +707,10 @@ These commands are run from the shell as `qwen <subcommand>` before starting an

### Session Management

| Command | Description | Usage Examples |
| -------------------- | ------------------------------------------- | ------------------------------------------------------------ |
| `qwen sessions list` | List recent conversation sessions | `qwen sessions list`, `qwen sessions list --json --limit 50` |
| `qwen sessions ps` | List interactive sessions running right now | `qwen sessions ps`, `qwen sessions ps --json` |
| Command | Description | Usage Examples |
| -------------------- | ----------------------------------- | ------------------------------------------------------------ |
| `qwen sessions list` | List recent conversation sessions | `qwen sessions list`, `qwen sessions list --json --limit 50` |
| `qwen sessions ps` | List the sessions running right now | `qwen sessions ps`, `qwen sessions ps --json` |

#### `qwen sessions list`

Expand Down Expand Up @@ -752,12 +752,19 @@ qwen sessions list --json | jq .

#### `qwen sessions ps`

Lists the interactive Qwen Code sessions running on this machine right
now. `sessions list` walks saved transcripts ("what have I worked on");
this walks the live-process registry ("what is running at this moment").
Records left behind by a killed session are swept as they are found.
Headless sessions (`qwen -p`) do not register with the live-process
registry, so they are not shown.
Lists the Qwen Code sessions running on this machine right now.
`sessions list` walks saved transcripts ("what have I worked on"); this
answers "what is running at this moment".

Two kinds of session are listed. An **interactive** session is one you
started in a terminal; it registers in the live-process registry, and
records left behind by a killed session are swept as they are found. A
**managed** session is an Agent View session owned by a supervisor: it
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
writes no registry record, so it used to be invisible here. Managed
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
sessions are listed first, because one of them may be waiting for an
answer.

Headless sessions (`qwen -p`) register nowhere and are not shown.

**Flags:**

Expand All @@ -767,20 +774,38 @@ registry, so they are not shown.

**Human-readable output (default):**

A table with columns: NAME, PID, AGE, DIRECTORY.
A table with columns: NAME, PID, AGE, STATE, DIRECTORY.

STATE is `interactive` for a session you started yourself. For a managed
session it is what that session is actually doing — `needs input`,
`working`, `ready`, `stopped` or `failed`. PID and AGE print `-` for a
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
managed session with no process behind it (one that has exited, or has
not started its worker yet).
Comment thread
yiliang114 marked this conversation as resolved.
Resolved

**JSON output (`--json`):**

Outputs JSON Lines on stdout, newest session first. Each line is a JSON
object with fields:
Outputs JSON Lines on stdout, managed sessions first. Every line carries
a `managed` field saying which kind it is.

An interactive session is emitted as its whole registry record, plus
`managed: false`:

```
schemaVersion, pid, procStart, pidNs, sessionId, cwd, name, startedAt,
qwenVersion
qwenVersion, managed
```

A managed session has no such record and is emitted as the row itself:

```
name, pid, startedAt, cwd, state, sessionId, managed
```

Nothing else is written to stdout — an empty listing prints nothing at
all — so `qwen sessions ps --json | jq .` is safe to script against.
all — so `qwen sessions ps --json | jq .` is safe to script against. If
the supervisor's own bookkeeping cannot be read, the interactive half is
still listed and the reason is reported on stderr, which leaves stdout
parseable.

JSON output is raw data: field values are emitted exactly as recorded,
with no terminal sanitization. Treat them as data, and sanitize before
Expand All @@ -796,6 +821,12 @@ qwen sessions ps
# Note: `jq -r` renders the raw recorded value in your terminal (see the
# raw-data note above); pipe through a sanitizer if the path is untrusted.
qwen sessions ps --json | jq -r .cwd

# Which background sessions are waiting on me?
# Note: `jq -r` renders the raw recorded value in your terminal (see the
# raw-data note above); a session name is session-generated text, so pipe
# through a sanitizer if it is untrusted.
qwen sessions ps --json | jq -r 'select(.state == "needs input") | .name'
```

## 6. Messaging Another Running Session
Expand Down
11 changes: 10 additions & 1 deletion packages/cli/src/agent-view/presentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ import type {
AgentViewSessionStateFile,
} from './protocol.js';

/**
* Title shown for a session that has produced nothing to name it by.
*
* Exported because a caller that cannot afford an unidentifiable row —
* a one-line listing, where there is nothing to arrow onto — has to be
* able to recognize the placeholder and substitute the session id.
*/
export const AGENT_VIEW_UNTITLED_TITLE = 'Untitled session';

export type AgentViewTaskState =
| 'running'
| 'waiting'
Expand Down Expand Up @@ -326,7 +335,7 @@ function deriveTitle(
cleanText(rosterEntry?.displayName) ??
cleanRuntimeSummary(activity?.summary) ??
cleanText(launch?.initialPrompt) ??
'Untitled session'
AGENT_VIEW_UNTITLED_TITLE
);
}

Expand Down
Loading