Skip to content

fix!: moved-config runs keep the owner's session; --compact one-line rows; IPv6 model addresses; calls link without memo; cli-base 0.99.0 - #2915

Merged
leemour merged 8 commits into
mainfrom
fix/round-2026-11-13
Nov 13, 2026
Merged

leemour merged 8 commits into
mainfrom
fix/round-2026-11-13

Conversation

@leemour

@leemour leemour commented Nov 13, 2026

Copy link
Copy Markdown
Member

Task

The cli-core round of 2026-11-13: one PR, so every WireCat CLI moves to one release that carries every fix. Source: the
review plan of 2026-11-12 (reports/2026-11-12-cli-family-review.md in cli-private) and whatsapp-cli #386. The
release also carries #2906, #2910, #2912, #2913 and #2914, already on main.

Why

  • SEC, data loss (WC-SECR-24). In a run with only <PREFIX>_CONFIG_DIR moved, the state folder is the owner's.
    0.650.0 kept the files cli-core deletes itself, but account remove still called the tool's own signOut, which
    deletes the session where the run's state folder says: the owner's. wa lost its device this way and guards with
    device.owners. A moved config folder that is a link to the owner's own also let cli-core rewrite the owner's
    config.json.
  • --compact on one item printed key: value lines, though its help promises one line. The owner chose option C:
    an opt-in row.
  • cli-base 0.99.0 adds SHARED_HOSTS to cli-dev manifest, beside cli-core's CORE_HOSTS.
  • An IPv6 model address such as https://[fd00::1] was refused: hostFetch takes no IPv6 literal.
  • The issue link came only from the app definition's issues; max sets none.
  • Calls reached CRM contacts only through memo's people scan.

What

  • account remove: a run whose state folder is the owner's never calls signOut; the sign-in is listed under kept
    with the moved-run reason. The owner's-folder check follows links. Keyring: Credentials with isolated deletes
    only the run's temporary entry (cli-base credentials.js remove), so that part was already safe.
  • RowShape.oneLine: an item answer prints as the row a list of it prints (with the list's header and day line), and
    its sections follow as rows. Nothing changes for a row without it. memo's review show|confirm|reject adopt it in
    memo.
  • cli-base 0.99.0 (dev; the peer range stays >=0.98.0). CORE_HOSTS is typed out as the two model providers plus
    SHARED_HOSTS, and a test keeps the two equal. Importing SHARED_HOSTS instead would stop every CLI still on
    cli-base 0.98 from loading; cli-base cannot read cli-core's list. No CLI reads CORE_HOSTS today.
  • Lint baseline: no row went stale under 0.99.0 (cli-dev lint: 69 violations, all in the baseline, 0 new);
    services/archive.ts and services/project-gathering.ts are still flagged. One row added, an exception for the
    owner:
    src/models/endpoint.ts fetch. The loopback [::1] path always used the global fetch; a ternary hid it
    from the rule, and the new IPv6 path uses it too. It goes once cli-base's hostFetch takes bracketed IPv6 literals.
  • IPv6: a non-loopback IPv6 model address goes through a small fetch with hostFetch's rules: only that host, the
    same deadline, no redirect followed. network.host-undeclared is now registered in cli-core's reasons.
  • doctor reports show|create: without issues, the GitHub repository in the installed package's bugs or
    repository gives <repo>/issues/new. Read only when a report command runs.
  • A meetings sync (pull) that saved callers with a number runs the scan's phone rule for those callers only
    (linkPhones, through the optional MeetingStore.linkCallers). No other rule, no scan cursor moved, so memo's next
    scan still sees them. A failure is a sync warning.

Testing

  • Failing first: account-remove.test.ts (sign-out with only config moved; the linked config folder), endpoint.test.ts
    (IPv6), doctor-reports-command.test.ts (package.json fallback), compact.test.ts (oneLine equals the list row,
    also with a ref prefix and a time column), call-phone-link.test.ts (a sync links the caller without a scan, leaves
    same-name contacts apart, and leaves the scan cursor unset).
  • Missing direct tests added: a call in canonicalPersonContext's meetings; the issue link in the note a person reads.
  • Measured: linkCallers on a store of 20,000 CRM contacts takes 55–70 ms (a store with many messenger identities that
    carry phones reads more rows). Only a sync that saved a caller with a number pays it: today the unpublished beeline.
  • Locally: typecheck, lint, docs:check, docs:lint, schema:check, check:dist, check:agent-process,
    help:examples, standards:check, ci:quick, and the full suite with coverage.

🤖 Generated with Claude Code

leemour and others added 8 commits November 13, 2026 05:24
… tool's sign-out

In a run where only <PREFIX>_CONFIG_DIR (or the cache folder) is moved, the
state folder is the owner's. cli-core 0.650.0 kept the files it removes
itself, but still called the tool's own signOut hook, which deletes the
session where the run's state folder says: the owner's (whatsapp-cli lost
its private.db this way and now refuses with device.owners).

- account remove skips signOut when the run's state folder lies in the
  owner's folders, and lists the sign-in under kept with the moved-run
  reason.
- The owner's-folder check follows links, so a moved config folder that
  is a link to the owner's own no longer rewrites the owner's config.json.

Keyring: Credentials with isolated deletes only the run's temporary entry
(cli-base credentials.js remove), so the owner's entry was already safe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…://[fd00::1]

hostFetch takes no IPv6 literal as a host, so endpointFetch refused every
non-loopback IPv6 model address with "is not a host". Such an address now
goes through a small fetch with hostFetch's rules: only that host, the
same deadline, and no redirect followed. https is required off this
computer and plain http only to [::1], as for IPv4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…D_HOSTS

- cli-base 0.99.0 (peer range >=0.99.0): cli-dev manifest adds the shared
  hosts to every CLI, and same-entity-schema / same-error-reason fail the
  family audit.
- CORE_HOSTS is now cli-base's SHARED_HOSTS plus the two default model
  providers, so the shared hosts are listed in one place. cli-base cannot
  read cli-core's list (the dependency points the other way). The hosts
  cli-core fetches stay covered (release-assets.githubusercontent.com by
  *.githubusercontent.com). No CLI imports CORE_HOSTS today.
- No lint baseline row went stale with 0.99.0 (cli-dev lint: 69 in the
  baseline, 0 new). endpoint.ts joins the raw-network baseline: its
  loopback and IPv6-literal paths use the global fetch, because hostFetch
  takes no IP literal in brackets; the ternary had hidden it from the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he CLI's package.json

doctor reports show/create named an issue page only when the app
definition set `issues`, so max (which sets none) printed no link.
issuesPage reads the installed package's `bugs` or `repository` when it is
on GitHub and gives its /issues/new; the link fills the issue through
GitHub's own parameters, so another host gets none. It reads the file only
when a report command runs.

Tests: the fallback, the issue link in the note a person reads, and a
call in canonicalPersonContext's meetings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pe.oneLine)

--compact promises one line per item, but an item answer (a show, a
decision) printed as key: value lines on purpose. The owner chose an
opt-in (option C): a RowShape with oneLine draws the item as the one row a
list of it draws, and its sections still follow as rows, so a decision
result lists one line per decision. Nothing changes for a row without it.

memo's review show / confirm / reject adopt it in memo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…number, without memo

Only memo ran the people scan (memo people scan / memo sync), so without
memo no call reached its CRM contact. pull now collects the callers it
saved with a number and, through the optional MeetingStore.linkCallers,
runs the scan's phone rule alone for them (linkPhones): no name, email or
chat rule, no scan cursor moved, so memo's next scan still sees them. It
reads the store's numbers once: 55-70 ms for 20,000 CRM contacts. A
linking failure is a sync warning.

Also: CORE_HOSTS is typed out equal to cli-base's SHARED_HOSTS plus the
two model providers, with a test that keeps them equal, instead of
importing SHARED_HOSTS: an import would stop every CLI still on cli-base
0.98 from loading. The peer range stays >=0.98.0. Changelog fragment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the callers' proposals first; endpoint branch tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dress's off-host request raises

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@leemour
leemour merged commit 91acec7 into main Nov 13, 2026
49 checks passed
@leemour
leemour deleted the fix/round-2026-11-13 branch November 13, 2026 04:42
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