feat(sessions): add teamai save-session — monthly session logs + digest feed#192
Conversation
|
Thanks for this — the feature is well-scoped and the reuse of the existing event stream ( 1. Why the pipeline is red (root cause found)It is not the fake API tokens in the test fixtures, as one might assume for a redaction PR. The internal open-source scan (CodeCC / semgrep) flags a single rule:
The Fix: change the connection-string fixture so it no longer matches the mdb-client DSN pattern, while still exercising the
One thing to double-check: this exact line is anchored to commit 2.
|
jeff-r2026
left a comment
There was a problem hiding this comment.
Requesting changes — see my detailed comment above. Blocking items:
- CI red — internal scan rule
inner-mdb-normal-clientflags the connection-string fixture atredact.test.ts:97-98. Rebase onto currentmain(drops the #191 commit) and reshape the DSN fixture so it no longer matches. - Command placement — fold the top-level
save-sessioninto ateamai session savesubcommand group. - Commit hygiene — after #191 is merged, rebase so this PR is a single self-contained commit for the save-session change.
2ae6b18 to
647551c
Compare
|
Thanks for the thorough review — all three blocking items and the privacy note are addressed. The branch is now a single self-contained commit rebased onto current 1. CI red (DSN scanner). Root cause confirmed — the 2. Command placement. 3. Commit hygiene. Rebased onto Privacy note (well taken). The team upload now defaults to counts + tools only; the redacted first-prompt line is opt-in behind Re-verified: |
…DSN scanner (#207) The internal CodeCC/semgrep scan rule `inner-mdb-normal-client` ("mdb normal client string leak", severity 严重) flags the connection-string test fixture in redact.test.ts — the `user:pass@host` DSN shape matches even though it's an obviously-synthetic test value, blocking CI on every PR that touches this tree (surfaced on #192). Assemble the DSN from fragments at runtime and compute the expected output, so no contiguous `user:password@host` literal appears in source while the test still exercises CONNECTION_STRING_PATTERN redaction. No production code change. Test Plan: - npx vitest run src/__tests__/redact.test.ts (21 pass) - grep confirms no literal DSN shape remains in the file Claude-Session: https://claude.ai/code/session_01GEV81Xj6mhPzSPsyBrDPSd Co-authored-by: Eyre921 <Eyre921@users.noreply.github.com>
Review notesClean design overall — reuses the dashboard's existing event stream plus A few suggestions: 1. Command-name mismatch (suggest fixing before merge)The command registers as
The docstring references (L272 / L444 / L676) are worth aligning too. 2.
|
…est feed
Implements Features 1 & 5 from docs/designs/team-intelligence-platform.md,
which were accepted ("ENG LOCKED") but never built — digest.ts's
getRecentSessions() has been reading an always-empty sessions/ directory.
`teamai session save` folds the dashboard's existing per-session event stream
(tool sequence, prompt turns, interventions) into a compact markdown summary and
appends it to a local monthly log (~/.teamai/session-logs/<year-month>.md). With
`--push`, a "valuable" session (interventions or substantial tool use, per
Decision 8) is committed to the team repo at sessions/<user>/<month>.md — the
path digest already reads, so "Session Highlights" lights up with no change to
digest.ts.
Reuses existing infrastructure rather than a new collection path:
- dashboard-collector readEvents() + aggregateSessionMetrics() for the data
- utils/git pushRepoDirectly() for the direct team commit (no MR), like contribute
- redact() (from Tencent#191) on the only free text included (the first-prompt line)
Review feedback addressed (round 1):
- Placed under a `session` subcommand group (`teamai session save`) instead of a
top-level verb, matching how `roles` / `source` are organized, leaving room
for `session list` / `session show` later.
- Team upload defaults to counts + tools only; the redacted first-prompt line is
opt-in via `--include-prompt`, since redact() is best-effort. Local logs keep it.
Review feedback addressed (round 2):
- Fixed user-facing command strings that still said `teamai save-session` (an
unknown command): the read-only error hint and the retry hint now say
`teamai session save --push`; aligned docstrings in save-session.ts /
session-collector.ts / types.ts and the design-doc references.
- `assertNotReadOnly` on the --push path is now wrapped in try/catch: an
HTTP-mode (read-only) team prints a friendly message and keeps the local log
instead of throwing an uncaught stack trace.
- Idempotency key is now the full session id in a non-rendering HTML comment
(`<!-- teamai:session <id> -->`) rather than the 8-char short id, removing the
~1-in-4B same-month prefix collision that could silently drop a session.
- Replaced the ad-hoc `Promise.race`/`setTimeout` push guard with the shared
`withTimeout()` helper (src/utils/async.ts, from Tencent#211), which clears its timer
in a finally so the process doesn't linger after a fast push.
Team upload is opt-in; local logs are pruned after 90 days (Feature 5 retention).
Test Plan:
- npx tsc --noEmit
- npx vitest run (145 files, 1801 tests; 15 in session-collector.test.ts,
incl. a new "distinct sessions sharing an 8-char id prefix" case)
- npm run build
- real-CLI E2E: seeded ~/.teamai/dashboard/events.jsonl, ran
`node dist/index.js session save --session-id <sid>`; wrote
~/.teamai/session-logs/2026-07.md with folded stats + full-id marker, a `ghp_`
token in the prompt came out `<REDACTED:gh_tok>`, a second run was idempotent;
`--push` against a read-only HTTP team printed the graceful message (exit 0, no
stack trace); old `save-session` errors as unknown; `--include-prompt` appears
in `session save --help`.
647551c to
6b439f1
Compare
|
Thanks for the round-2 review — all four items are addressed, and the branch is rebased onto current 1. Command-name mismatch (fix before merge). Every user-facing
A full-tree grep now shows no 2. 3. Idempotency marker collision. Switched the dedup key from the 8-char short id to the full session id in a non-rendering HTML comment ( 4. Re-verified: Ready for another look when you have a moment. |
Follow-up doc pass for #208 (CNB provider) and #192 (session save), which shipped without doc coverage. - docs/providers.md: provider count 两个 → 三个; add `cnb` to the table and the auto-detection block; new "CNB Provider(cnb.cool)" section — auth via `cnb login` / `CNB_TOKEN`, operations delegated to @cnbcool/cnb-cli, nested paths, and the cnb.cool-only scope + TEAMAI_CNB_HOST/CNB_API_ENDPOINT note. - README.md / README.zh-CN.md: add CNB to the git-host list. - docs/usage-guide.md / .zh-CN.md: add CNB to the create-repo step and prerequisites; new "Session Save" section for `teamai session save` (--push / --force / --include-prompt, local ~/.teamai/session-logs path, 90-day retention, "valuable" heuristic, digest Session Highlights, privacy). Docs-only, bilingual kept in sync. Built and verified the documented surface: `session save --help` shows the flags; the cnb.cool host mapping is in the build. Co-authored-by: Eyre921 <Eyre921@users.noreply.github.com>
Summary
Implements Features 1 & 5 from
docs/designs/team-intelligence-platform.md— accepted ("ENG LOCKED") in that design but never built.digest.ts'sgetRecentSessions()has been reading an always-emptysessions/directory; this PR gives it data.teamai save-sessionfolds the dashboard's existing per-session event stream (tool sequence, prompt turns, interventions) into a compact, privacy-scrubbed markdown summary, appends it to a local monthly log, and — with--push— commits a valuable session to the team repo at the exact pathdigestalready reads, so "Session Highlights" lights up.Type of Change
What it does
~/.teamai/session-logs/<year-month>.md(dedicated dir; not the shared~/.teamai/sessions/which holds contribute-state.json). Idempotent per session; pruned after 90 days (Feature 5 retention).--push, opt-in):sessions/<user>/<year-month>.md, direct commit (no MR), likecontribute. This is the pathdigest'sgetRecentSessions()already globs — no change todigest.tsneeded.--force.Design decisions honored
redact()(from feat(privacy): add secret-redaction utility, scrub dashboard stopped-output #191). Consistent with the "counts only, no prompt text" posture.Reuses existing infrastructure (no new collection path)
dashboard-collectorreadEvents()+aggregateSessionMetrics()for the datautils/gitpushRepoDirectly()for the direct team commitread-onlyassertNotReadOnly()so HTTP-mode teams can't pushredact()for the only free text includedTest Plan
npx tsc --noEmitnpx vitest run— 140 files, 1741 tests (12 new insession-collector.test.ts)npm run build~/.teamai/dashboard/events.jsonl, rannode dist/index.js save-session --session-id <sid>. Result:~/.teamai/session-logs/2026-07.mdwritten with folded stats; aghp_…token in the prompt came out<REDACTED:gh_tok>(0 raw leaks); a second run was idempotent ("already recorded");--pushwithout init failed gracefully while keeping the local log.Notes for Reviewers
save-sessionis a command only (manual / agent-invoked). Auto-saving on the Stop hook is a natural follow-up but intentionally left out here to keep the injected-hook surface unchanged.~/.teamai/session-logs/rather than the design's literal~/.teamai/sessions/<year-month>.md, to avoid mixing with the contribute-state.jsonfiles already insessions/. Happy to change if you prefer the literal path.digest.tsis deliberately untouched — the feature works by supplying the data its existing reader expects.