Skip to content

feat(cli): add read-only basou portfolio listing command#173

Merged
takashi-matsuyama merged 2 commits into
mainfrom
feat/portfolio-list-command
Jul 14, 2026
Merged

feat(cli): add read-only basou portfolio listing command#173
takashi-matsuyama merged 2 commits into
mainfrom
feat/portfolio-list-command

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

Why

An agent oriented in one project has no headless way to discover where a sibling project lives. The portfolio is reachable only via:

  • the basou view --portfolio localhost GUI (unreachable in a non-interactive/headless session — an agent can't open a browser), or
  • reading ~/.basou/portfolio.yaml by hand.

So an agent structurally falls back to globbing the raw filesystem (ls ~/projects/*<name>*) even though basou already holds the label→path mapping. This also fixes the error: unknown command 'portfolio' foot-gun — portfolio is the exact name an agent reaches for.

(Motivation surfaced from a real session where an agent globbed the filesystem to locate a sibling project while ~/.basou/portfolio.yaml already had the answer.)

What

  • New top-level basou portfolio (read-only): lists each registered planning master's label + path, and whether it exists / owns a .basou/ store (initialized).
  • --json for machine consumption. Stable, minimal shape (part of the CLI contract):
    { "configPath": "", "workspaces": [ { "label": "takuhon", "path": "/…/takuhon-planning", "exists": true, "initialized": true } ] }
  • Reuses loadPortfolioConfig; probes only existence + .basou presence. Deliberately does NOT run the basou view --check redundancy/footprint safety preflight — that stays its own surface.
  • A stale entry (path moved away) reports exists:false, initialized:false rather than throwing; a missing/malformed config propagates loadPortfolioConfig's existing user-facing error (exit 1), consistent with basou view --portfolio.

Scope / non-goals

  • Additive only: one new command, no change to any existing command, schema, or ~/.basou/portfolio.yaml format.
  • Not a replacement for basou view --portfolio (GUI) or basou view --check (safety preflight) — it is the lightweight discovery counterpart.

Tests

  • packages/cli/src/commands/portfolio.test.ts (label/path/exists/initialized resolution, stale-entry guard that never probes .basou, --json shape, human render markers, missing-config error).
  • program.test.ts command-tree assertion updated to include portfolio.
  • Local: cli typecheck ✓, 992 cli tests ✓, biome ✓, lint:lang ✓ (English-only), build ✓, and basou portfolio / --json verified end-to-end against the real 12-workspace config.

🤖 Generated with Claude Code

An agent oriented in one project had no headless way to discover where a
sibling project lives: the portfolio was reachable only via the
`basou view --portfolio` localhost GUI (unreachable in a non-interactive
session) or by reading ~/.basou/portfolio.yaml by hand. So an agent
structurally falls back to globbing the filesystem even though basou already
holds the mapping. `basou portfolio` closes that gap, and fixes the
"unknown command 'portfolio'" foot-gun (the name an agent naturally reaches
for).

- New top-level `basou portfolio` (read-only): lists each registered planning
  master's label + path, and whether it exists / owns a `.basou/` store.
- `--json` for machine consumption (stable, minimal shape:
  `{ configPath, workspaces: [{ label, path, exists, initialized }] }`).
- Reuses `loadPortfolioConfig`; probes only existence + `.basou` presence.
  Deliberately does NOT run the `basou view --check` redundancy/footprint
  safety preflight; that stays its own surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takashi-matsuyama
takashi-matsuyama force-pushed the feat/portfolio-list-command branch from 049122b to be33a48 Compare July 14, 2026 15:36
Adversarial review follow-ups on `basou portfolio`:
- A1: `initialized` now requires `.basou` to be a DIRECTORY (statSync
  isDirectory), matching the canonical `hasBasouStore` probe, so a stray
  regular file named `.basou` is not mis-reported as an initialized master.
- A2: pin the `--json` output to single-line minified JSON (no pretty-print),
  so line-oriented consumers stay stable.
- A3: cover the wired `runPortfolioList` entry: a missing config renders the
  error and sets exitCode 1.

Design-reversal findings B1-B7 were reviewed and kept as-is (operator call):
the read-only scope boundary vs `basou view --check` and the exit-code
contract consistent with `basou view --portfolio` stand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takashi-matsuyama
takashi-matsuyama merged commit bb0095f into main Jul 14, 2026
7 checks passed
@takashi-matsuyama
takashi-matsuyama deleted the feat/portfolio-list-command branch July 14, 2026 16:13
takashi-matsuyama added a commit that referenced this pull request Jul 14, 2026
Release v0.35.0: basou portfolio command (#173) + list alias / --check pointer (#174).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant