mirror of https://github.com/jackwener/wx-cli.git
Merge eebc9e97b7 into 12740afb53
commit
45baadea65
|
|
@ -0,0 +1 @@
|
|||
[]
|
||||
|
|
@ -28,3 +28,30 @@ __pycache__/
|
|||
Thumbs.db
|
||||
find_all_keys_macos
|
||||
.claude/worktrees/
|
||||
|
||||
# ── GSD baseline (auto-generated) ──
|
||||
.gsd
|
||||
.gsd-id
|
||||
.mcp.json
|
||||
.bg-shell/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.idea/
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
node_modules/
|
||||
.next/
|
||||
dist/
|
||||
build/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
vendor/
|
||||
*.log
|
||||
coverage/
|
||||
.cache/
|
||||
tmp/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
# Codebase Map
|
||||
|
||||
Generated: 2026-05-13T05:22:55Z | Files: 52 | Described: 0/52
|
||||
<!-- gsd:codebase-meta {"generatedAt":"2026-05-13T05:22:55Z","fingerprint":"3306bb8206b573a313a49bde0ead8c4bf8f719b8","fileCount":52,"truncated":false} -->
|
||||
|
||||
### (root)/
|
||||
- `.gitignore`
|
||||
- `AGENTS.md`
|
||||
- `Cargo.toml`
|
||||
- `CLAUDE.md`
|
||||
- `config.example.json`
|
||||
- `install.ps1`
|
||||
- `install.sh`
|
||||
- `LICENSE`
|
||||
- `README.md`
|
||||
- `SKILL.md`
|
||||
|
||||
### .github/workflows/
|
||||
- `.github/workflows/release.yml`
|
||||
|
||||
### docs/
|
||||
- `docs/macos-3x-vs-4x-decryption-guide.md`
|
||||
- `docs/macos-permission-guide.md`
|
||||
|
||||
### npm/platforms/darwin-arm64/
|
||||
- `npm/platforms/darwin-arm64/package.json`
|
||||
|
||||
### npm/platforms/darwin-x64/
|
||||
- `npm/platforms/darwin-x64/package.json`
|
||||
|
||||
### npm/platforms/linux-arm64/
|
||||
- `npm/platforms/linux-arm64/package.json`
|
||||
|
||||
### npm/platforms/linux-x64/
|
||||
- `npm/platforms/linux-x64/package.json`
|
||||
|
||||
### npm/platforms/win32-x64/
|
||||
- `npm/platforms/win32-x64/package.json`
|
||||
|
||||
### npm/wx-cli/
|
||||
- `npm/wx-cli/install.js`
|
||||
- `npm/wx-cli/package.json`
|
||||
|
||||
### npm/wx-cli/bin/
|
||||
- `npm/wx-cli/bin/wx.js`
|
||||
|
||||
### src/
|
||||
- `src/config.rs`
|
||||
- `src/ipc.rs`
|
||||
- `src/main.rs`
|
||||
|
||||
### src/cli/
|
||||
- `src/cli/contacts.rs`
|
||||
- `src/cli/daemon_cmd.rs`
|
||||
- `src/cli/export.rs`
|
||||
- `src/cli/favorites.rs`
|
||||
- `src/cli/history.rs`
|
||||
- `src/cli/init.rs`
|
||||
- `src/cli/members.rs`
|
||||
- `src/cli/mod.rs`
|
||||
- `src/cli/new_messages.rs`
|
||||
- `src/cli/output.rs`
|
||||
- `src/cli/search.rs`
|
||||
- `src/cli/sessions.rs`
|
||||
- `src/cli/sns_feed.rs`
|
||||
- `src/cli/sns_notifications.rs`
|
||||
- `src/cli/sns_search.rs`
|
||||
- `src/cli/stats.rs`
|
||||
- `src/cli/transport.rs`
|
||||
- `src/cli/unread.rs`
|
||||
|
||||
### src/crypto/
|
||||
- `src/crypto/mod.rs`
|
||||
- `src/crypto/wal.rs`
|
||||
|
||||
### src/daemon/
|
||||
- `src/daemon/cache.rs`
|
||||
- `src/daemon/mod.rs`
|
||||
- `src/daemon/query.rs`
|
||||
- `src/daemon/server.rs`
|
||||
|
||||
### src/scanner/
|
||||
- `src/scanner/linux.rs`
|
||||
- `src/scanner/macos.rs`
|
||||
- `src/scanner/mod.rs`
|
||||
- `src/scanner/windows.rs`
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Project Context
|
||||
|
||||
Auto-detected by GSD init wizard. Edit or expand as needed.
|
||||
|
||||
## Language / Stack
|
||||
|
||||
Primary: rust
|
||||
|
||||
## Project Files
|
||||
|
||||
- Cargo.toml
|
||||
- .github/workflows
|
||||
|
||||
## CI/CD
|
||||
|
||||
CI configuration detected.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Decisions Register
|
||||
|
||||
<!-- Append-only. Never edit or remove existing rows.
|
||||
To reverse a decision, add a new row that supersedes it.
|
||||
Read this file at the start of any planning or research phase. -->
|
||||
|
||||
| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |
|
||||
|---|------|-------|----------|--------|-----------|------------|---------|
|
||||
| D001 | | architecture | Transport abstraction via traits | Listener and Connector traits with shared protocol.rs, implementations for Unix/Windows/TCP | Eliminates ~50 lines of duplicated JSON-line protocol handling, provides clear extension point for future transports | Yes | collaborative |
|
||||
| D002 | | architecture | Global --tcp CLI flag for transport selection | Global clap flag on root Cli struct, inherited by all subcommands | Discoverable, consistent UX. User specifies once, affects all commands | Yes | human |
|
||||
| D003 | | architecture | No built-in TCP security | No TLS, no auth tokens, no IP whitelist in this milestone. Bind exactly as user specifies. | User handles firewall/ACL at OS level. TLS adds cert management and dependency complexity. Can be added later non-breaking. | Yes | collaborative |
|
||||
| D004 | | architecture | One request per connection protocol model | One JSON-line request per connection, no keepalive or pooling | Matches existing behavior, minimal complexity, sufficient for CLI usage patterns | Yes | agent |
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
version: 1
|
||||
mode: solo
|
||||
git:
|
||||
isolation: worktree
|
||||
main_branch: main
|
||||
auto_push: true
|
||||
verification_commands:
|
||||
- cargo test
|
||||
- cargo clippy
|
||||
---
|
||||
# GSD Project Preferences
|
||||
|
||||
Generated by `/gsd init`. Edit directly or use `/gsd prefs project` to modify.
|
||||
|
||||
See `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation.
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# wx-cli
|
||||
|
||||
## What This Is
|
||||
|
||||
A cross-platform Rust CLI tool for extracting and querying local WeChat 4.x data. Decrypts SQLCipher-encrypted databases, caches decrypted copies with mtime-aware invalidation, and provides a daemon-based IPC architecture for fast repeated queries. Currently uses Unix sockets (macOS/Linux) and Windows named pipes for local-only communication.
|
||||
|
||||
## Core Value
|
||||
|
||||
Query your local WeChat chat history, contacts, and moments from the command line with millisecond response times — data never leaves your machine.
|
||||
|
||||
## Project Shape
|
||||
|
||||
- **Complexity:** simple
|
||||
- **Why:** Well-defined scope, existing codebase with clear module boundaries, single transport addition with refactoring
|
||||
|
||||
## Current State
|
||||
|
||||
Version 0.1.10. Fully functional CLI with 17 subcommands. Daemon auto-starts on first query. Cross-platform (macOS, Linux, Windows). No integration tests. Local IPC only.
|
||||
|
||||
## Architecture / Key Patterns
|
||||
|
||||
- Single binary: client and daemon (`WX_DAEMON_MODE` env var)
|
||||
- Daemon uses tokio async runtime, Unix socket / Windows named pipe IPC
|
||||
- JSON-line protocol: one request per connection
|
||||
- mtime-aware decryption cache in `~/.wx-cli/cache/`
|
||||
- Platform-specific memory scanners for SQLCipher key extraction
|
||||
- All queries executed via rusqlite on decrypted DBs
|
||||
|
||||
## Capability Contract
|
||||
|
||||
See `.gsd/REQUIREMENTS.md` for the explicit capability contract.
|
||||
|
||||
## Milestone Sequence
|
||||
|
||||
- [ ] M001: TCP Transport — Add `--tcp host:port` global flag and TCP transport support to daemon and client
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
# Requirements
|
||||
|
||||
## Active
|
||||
|
||||
### R001 — TCP transport on server
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Daemon listens on TCP when `--tcp host:port` is specified, in addition to local transport
|
||||
- Why it matters: Enables remote clients to query WeChat data over network
|
||||
- Source: user
|
||||
- Primary owning slice: M001/S01
|
||||
- Supporting slices: M001/S02
|
||||
- Validation: unmapped
|
||||
- Notes: Bind exactly as user specifies, no TLS, no IP whitelist
|
||||
|
||||
### R002 — TCP transport on client
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Client connects via TCP when `--tcp host:port` is specified, with no local fallback
|
||||
- Why it matters: Users explicitly choosing TCP must connect to that address
|
||||
- Source: user
|
||||
- Primary owning slice: M001/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Hard error if connection fails, no silent fallback
|
||||
|
||||
### R003 — Transport abstraction layer
|
||||
- Class: quality-attribute
|
||||
- Status: active
|
||||
- Description: Transport layer uses trait-based abstraction (Listener/Connector) to eliminate platform duplication
|
||||
- Why it matters: Makes adding new transports (TCP, future TLS) easy without duplicating protocol logic
|
||||
- Source: inferred
|
||||
- Primary owning slice: M001/S01
|
||||
- Supporting slices: M001/S02, M001/S03
|
||||
- Validation: unmapped
|
||||
- Notes: Must support Unix socket, Windows named pipe, and TCP
|
||||
|
||||
### R004 — Global `--tcp` CLI flag
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: `--tcp host:port` is a global CLI flag, affecting all commands including `daemon status`, `daemon logs`, and all query commands
|
||||
- Why it matters: Discoverable, consistent interface for TCP across all commands
|
||||
- Source: user
|
||||
- Primary owning slice: M001/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Replaces env var approach, cleaner UX
|
||||
|
||||
### R005 — Daemon start command
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: New `wx daemon start` subcommand to explicitly start the daemon with configurable options
|
||||
- Why it matters: Currently daemon auto-starts on first query; explicit start gives user control over transport config
|
||||
- Source: user
|
||||
- Primary owning slice: M001/S01
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Should support `--tcp` flag
|
||||
|
||||
### R006 — Cross-platform compilation
|
||||
- Class: constraint
|
||||
- Status: active
|
||||
- Description: Code compiles on macOS, Linux, and Windows (`cargo check` on all targets)
|
||||
- Why it matters: Project is cross-platform by design, TCP must work on all three
|
||||
- Source: inferred
|
||||
- Primary owning slice: M001/S01
|
||||
- Supporting slices: M001/S02, M001/S03
|
||||
- Validation: unmapped
|
||||
- Notes: TcpListener/TcpStream are std library, should be trivial
|
||||
|
||||
### R007 — Error handling for TCP failures
|
||||
- Class: failure-visibility
|
||||
- Status: active
|
||||
- Description: TCP bind/connect failures produce clear error messages with no silent fallback
|
||||
- Why it matters: Users need to know when transport configuration fails
|
||||
- Source: inferred
|
||||
- Primary owning slice: M001/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: 15s connect timeout, 120s read/write timeout
|
||||
|
||||
### R008 — Integration: CLI ↔ daemon over TCP
|
||||
- Class: integration
|
||||
- Status: active
|
||||
- Description: End-to-end verification: CLI and daemon communicate successfully over TCP on localhost
|
||||
- Why it matters: Proves the transport actually works, not just compiles
|
||||
- Source: inferred
|
||||
- Primary owning slice: M001/S04
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Manual smoke test sufficient, no automated integration tests
|
||||
|
||||
## Deferred
|
||||
|
||||
### R020 — TLS encryption for TCP transport
|
||||
- Class: compliance/security
|
||||
- Status: deferred
|
||||
- Description: Optional TLS encryption on TCP transport for secure remote access
|
||||
- Why it matters: Plaintext TCP exposes chat data to network sniffing
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Deferred — adds tokio-rustls dependency and cert management complexity
|
||||
|
||||
### R021 — Authentication tokens for TCP
|
||||
- Class: compliance/security
|
||||
- Status: deferred
|
||||
- Description: Token-based authentication for TCP connections
|
||||
- Why it matters: Prevents unauthorized access to WeChat data over network
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Deferred — requires protocol change (Auth request type)
|
||||
|
||||
### R022 — TCP connection keepalive
|
||||
- Class: quality-attribute
|
||||
- Status: deferred
|
||||
- Description: Persistent TCP connections with keepalive for reduced latency
|
||||
- Why it matters: Current one-request-per-connection model has connection overhead
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Deferred — requires protocol and connection management changes
|
||||
|
||||
## Out of Scope
|
||||
|
||||
### R030 — Network-level access control
|
||||
- Class: constraint
|
||||
- Status: out-of-scope
|
||||
- Description: IP whitelisting, firewall rules, or network ACLs within the application
|
||||
- Why it matters: Prevents scope creep into network security management
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: n/a
|
||||
- Notes: User handles firewall/ACL at OS level
|
||||
|
||||
## Traceability
|
||||
|
||||
| ID | Class | Status | Primary owner | Supporting | Proof |
|
||||
|---|---|---|---|---|---|
|
||||
| R001 | core-capability | active | M001/S01 | M001/S02 | unmapped |
|
||||
| R002 | core-capability | active | M001/S02 | none | unmapped |
|
||||
| R003 | quality-attribute | active | M001/S01 | M001/S02, M001/S03 | unmapped |
|
||||
| R004 | primary-user-loop | active | M001/S02 | none | unmapped |
|
||||
| R005 | primary-user-loop | active | M001/S01 | none | unmapped |
|
||||
| R006 | constraint | active | M001/S01 | M001/S02, M001/S03 | unmapped |
|
||||
| R007 | failure-visibility | active | M001/S02 | none | unmapped |
|
||||
| R008 | integration | active | M001/S04 | none | unmapped |
|
||||
| R020 | compliance/security | deferred | none | none | unmapped |
|
||||
| R021 | compliance/security | deferred | none | none | unmapped |
|
||||
| R022 | quality-attribute | deferred | none | none | unmapped |
|
||||
| R030 | constraint | out-of-scope | none | none | n/a |
|
||||
|
||||
## Coverage Summary
|
||||
|
||||
- Active requirements: 8
|
||||
- Mapped to slices: 8
|
||||
- Validated: 0
|
||||
- Unmapped active requirements: 0
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# GSD State
|
||||
|
||||
**Active Milestone:** M001: TCP Transport
|
||||
**Active Slice:** S01: Transport abstraction layer
|
||||
**Phase:** planning
|
||||
**Requirements Status:** 0 active · 0 validated · 0 deferred · 0 out of scope
|
||||
|
||||
## Milestone Registry
|
||||
- 🔄 **M001:** TCP Transport
|
||||
|
||||
## Recent Decisions
|
||||
- None recorded
|
||||
|
||||
## Blockers
|
||||
- None
|
||||
|
||||
## Next Action
|
||||
Slice S01 has no DB tasks. Plan slice tasks before execution.
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{"version":"1","eventId":"35a18d2d-ef3f-4957-8fa0-e018c9091b9b","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.292Z","payload":{"modelId":"claude-haiku-4.5","provider":"github-copilot","api":"anthropic-messages","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"bab2980a-198e-447a-a9aa-dd1e5d508edb","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.298Z","payload":{"modelId":"claude-sonnet-4.6","provider":"github-copilot","api":"anthropic-messages","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"54bb4aac-5585-47cc-9589-dec03ac30905","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.300Z","payload":{"modelId":"gemini-3.1-pro-preview","provider":"github-copilot","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"05db147d-4818-4a9d-be76-1945e659b5c8","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.303Z","payload":{"modelId":"gpt-4.1","provider":"github-copilot","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"1a145816-1b1d-4d84-8d1d-6a08c629e27c","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.305Z","payload":{"modelId":"gpt-4o","provider":"github-copilot","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"dc301e36-8e87-4b0e-9a7e-64cbc907480c","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.308Z","payload":{"modelId":"gpt-5-mini","provider":"github-copilot","api":"openai-responses","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"99fca380-cec0-412e-ba94-7b16c5496616","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.310Z","payload":{"modelId":"gpt-5.2-codex","provider":"github-copilot","api":"openai-responses","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"45fb32d0-10b3-43e6-9f4e-1a12eb2782d3","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.313Z","payload":{"modelId":"gpt-5.4","provider":"github-copilot","api":"openai-responses","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"996a6fef-9644-4881-be02-c3dffbfd5cf0","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.315Z","payload":{"modelId":"gpt-5.4-mini","provider":"github-copilot","api":"openai-responses","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"cf87b34b-c148-4eda-b6df-f688da404221","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.318Z","payload":{"modelId":"grok-code-fast-1","provider":"github-copilot","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"5b87f7ba-7eec-4bb4-900a-be5d84e0e5bd","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.320Z","payload":{"modelId":"groq/compound","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"db19cee6-e80d-48fa-aa6e-199508e92d78","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.323Z","payload":{"modelId":"groq/compound-mini","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"37e1b2cb-e7ad-4417-84ad-4f5c84ef5581","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.325Z","payload":{"modelId":"llama-3.1-8b-instant","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"d03691e7-7a88-45a1-85db-889e3e99a183","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.328Z","payload":{"modelId":"llama-3.3-70b-versatile","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"d956e2fd-0780-4d8a-891a-0f78cf4fb885","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.330Z","payload":{"modelId":"meta-llama/llama-4-scout-17b-16e-instruct","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"c96af6c7-6ab8-49f7-9b2e-63ccc3b679be","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.332Z","payload":{"modelId":"openai/gpt-oss-120b","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"1162b48d-9843-48ba-91db-58cf417d2b69","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.335Z","payload":{"modelId":"openai/gpt-oss-20b","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"0eb90b03-3888-46a8-82d0-e7ec7ed69c92","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.337Z","payload":{"modelId":"openai/gpt-oss-safeguard-20b","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"c1fd584d-bfdd-4245-a351-d81f8961474d","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.340Z","payload":{"modelId":"qwen/qwen3-32b","provider":"groq","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"ef3e9541-3dfe-4290-a5d0-ca5094a2a4ee","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.343Z","payload":{"modelId":"llm-p710","provider":"p710","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"988b326e-91d3-48ea-9f73-b90a60536d94","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.345Z","payload":{"modelId":"qwen3.6-plus","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"0a79bcf8-24ab-4f40-a1f5-f3c3ee43928f","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.347Z","payload":{"modelId":"qwen3.5-plus","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"b927da73-de27-4d01-be2a-9bbdeed206b6","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.350Z","payload":{"modelId":"qwen3-max-2026-01-23","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"06f49f12-432f-45e5-a5cf-8d0c4b9e4630","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.352Z","payload":{"modelId":"qwen3-coder-next","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"3b2834be-fa85-44e5-828d-7886bb24a1f5","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.355Z","payload":{"modelId":"qwen3-coder-plus","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"48ad4516-199b-48a3-aa1e-308a90de7d01","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.357Z","payload":{"modelId":"MiniMax-M2.5","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"d14885db-88a6-4c0f-9f25-d9a03e5002de","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.360Z","payload":{"modelId":"glm-5","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"39852010-4285-4fec-81c7-db5578eb845e","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.362Z","payload":{"modelId":"glm-4.7","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
{"version":"1","eventId":"84dc0529-e1d2-483c-81ef-edb89fcbba8f","traceId":"model:59b3413b-c62a-487e-acdb-3c4eddecc0a3:1778648805290","turnId":"discuss-milestone:","category":"model-policy","type":"model-policy-allow","ts":"2026-05-13T05:06:45.364Z","payload":{"modelId":"kimi-k2.5","provider":"bailian","api":"openai-completions","reason":"allowed","unitType":"discuss-milestone","requirements":{"reasoning":0.6,"instruction":0.7}}}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"pid": 42440,
|
||||
"startedAt": "2026-05-13T05:32:05.812Z",
|
||||
"unitType": "starting",
|
||||
"unitId": "bootstrap",
|
||||
"unitStartedAt": "2026-05-13T05:32:05.812Z"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"v":2,"cmd":"plan-milestone","params":{"milestoneId":"M001"},"ts":"2026-05-13T05:31:30.650Z","actor":"agent","actor_name":"executor-01","trigger_reason":"plan-phase complete","hash":"e7646f64e62daa33","session_id":"dbe22dc5-e220-475e-aa1b-14d620ab6d6d"}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
# M001: TCP Transport
|
||||
|
||||
**Gathered:** 2026-01-13
|
||||
**Status:** Ready for planning
|
||||
|
||||
## Project Description
|
||||
|
||||
Add TCP socket transport to wx-cli's daemon communication layer, enabling remote clients to query WeChat data over the network. Refactor the existing platform-specific IPC code into a trait-based abstraction to eliminate duplication and make future transport additions easy.
|
||||
|
||||
## Why This Milestone
|
||||
|
||||
Currently wx-cli only supports local IPC (Unix sockets on macOS/Linux, named pipes on Windows). This limits usage to the same machine as the WeChat daemon. Adding TCP transport enables remote access, containerized deployments, and multi-machine setups.
|
||||
|
||||
## User-Visible Outcome
|
||||
|
||||
### When this milestone is complete, the user can:
|
||||
|
||||
- Start the daemon with TCP listening: `wx daemon start --tcp 127.0.0.1:9876`
|
||||
- Query WeChat data over TCP: `wx sessions --tcp 127.0.0.1:9876`
|
||||
- Use all existing commands without `--tcp` and get unchanged local behavior
|
||||
- Check daemon status and logs over TCP: `wx daemon status --tcp 127.0.0.1:9876`
|
||||
|
||||
### Entry point / environment
|
||||
|
||||
- Entry point: `wx` CLI command with global `--tcp host:port` flag
|
||||
- Environment: local dev or remote machine (TCP network)
|
||||
- Live dependencies involved: wx-daemon process
|
||||
|
||||
## Completion Class
|
||||
|
||||
- Contract complete means: Transport traits defined, all three implementations compile, protocol handling is shared
|
||||
- Integration complete means: Daemon listens on local + TCP simultaneously, client connects via TCP and gets correct response
|
||||
- Operational complete means: Daemon starts with `--tcp`, handles bind errors cleanly, client fails with clear error when TCP unreachable
|
||||
|
||||
## Final Integrated Acceptance
|
||||
|
||||
To call this milestone complete, we must prove:
|
||||
|
||||
- `cargo check` passes on macOS, Linux, and Windows targets
|
||||
- Daemon started with `--tcp 127.0.0.1:9876` accepts TCP connections and responds correctly
|
||||
- Client with `--tcp 127.0.0.1:9876` returns same results as local transport
|
||||
- Client with `--tcp 127.0.0.1:9999` (unreachable) fails with clear error within 15s
|
||||
- Commands without `--tcp` still work via local transport (no regression)
|
||||
|
||||
## Architectural Decisions
|
||||
|
||||
### Transport abstraction via traits
|
||||
|
||||
**Decision:** Use `Listener` and `Connector` traits to abstract transport primitives, implement for Unix socket, Windows named pipe, and TCP.
|
||||
|
||||
**Rationale:** Current code has ~50 lines of duplicated JSON-line protocol handling across Unix/Windows. Traits eliminate duplication and provide clear extension point for future transports (TLS, WebSocket).
|
||||
|
||||
**Alternatives Considered:**
|
||||
- Continue #[cfg] branching — current approach, hard to extend, duplicative
|
||||
- `interprocess` crate for all transports — doesn't support TCP natively
|
||||
- Abstract at protocol level only — would still need per-platform listener/connection code
|
||||
|
||||
### One request per connection (unchanged)
|
||||
|
||||
**Decision:** Keep existing protocol model — one JSON-line request per connection, no keepalive or pooling.
|
||||
|
||||
**Rationale:** Matches existing behavior, minimal complexity, sufficient for CLI usage patterns.
|
||||
|
||||
**Alternatives Considered:**
|
||||
- Persistent connections with multiplexing — adds protocol complexity, not needed for CLI
|
||||
- Connection pooling — overkill for single-client CLI tool
|
||||
|
||||
### Global CLI flag for TCP
|
||||
|
||||
**Decision:** `--tcp host:port` as global clap flag on root `Cli` struct, inherited by all subcommands.
|
||||
|
||||
**Rationale:** Discoverable, consistent UX. User specifies once, affects all commands.
|
||||
|
||||
**Alternatives Considered:**
|
||||
- Environment variables — hidden, harder to discover
|
||||
- Per-subcommand flag — repetitive, inconsistent
|
||||
- Config file only — requires edit before use
|
||||
|
||||
### No built-in TCP security
|
||||
|
||||
**Decision:** No TLS, no auth tokens, no IP whitelist in this milestone. Bind exactly as user specifies.
|
||||
|
||||
**Rationale:** User handles firewall/ACL at OS level. Adding TLS requires cert management, tokio-rustls dependency, and significantly more complexity. Can be added later non-breaking.
|
||||
|
||||
**Alternatives Considered:**
|
||||
- Default to localhost-only — too restrictive, user should control bind address
|
||||
- Built-in IP whitelist — adds config complexity, OS firewall is better tool
|
||||
|
||||
## Error Handling Strategy
|
||||
|
||||
- **TCP bind failure:** `"TCP bind failed on {addr}: {reason}"` — daemon aborts startup
|
||||
- **TCP connection failure:** `"Failed to connect to {addr}: {reason}"` — hard error, no fallback
|
||||
- **Connection timeout:** 15s connect, 120s read/write (matches existing)
|
||||
- **Connection dropped mid-request:** `"Connection lost: daemon closed or network error"`
|
||||
- **Mixed transport mismatch:** `"No daemon listening on {addr}"` — same as current "daemon not alive" path
|
||||
- **No `--tcp`:** Existing local transport behavior, no change
|
||||
|
||||
## Risks and Unknowns
|
||||
|
||||
- Windows named pipe refactoring may require `interprocess` crate changes — the crate's API differs from std Unix sockets
|
||||
- `daemon start` subcommand needs to handle existing auto-start behavior (currently daemon starts on first query via `ensure_daemon()`)
|
||||
|
||||
## Existing Codebase / Prior Art
|
||||
|
||||
- `src/daemon/server.rs` — current IPC server, needs refactoring to use Listener trait
|
||||
- `src/cli/transport.rs` — current IPC client, needs refactoring to use Connector trait
|
||||
- `src/ipc.rs` — protocol types (Request/Response), well-abstracted, no changes needed
|
||||
- `src/config.rs` — needs tcp_addr field extension
|
||||
|
||||
## Relevant Requirements
|
||||
|
||||
- R001 — TCP transport on server (M001/S01)
|
||||
- R002 — TCP transport on client (M001/S02)
|
||||
- R003 — Transport abstraction layer (M001/S01)
|
||||
- R004 — Global `--tcp` CLI flag (M001/S02)
|
||||
- R005 — Daemon start command (M001/S01)
|
||||
- R006 — Cross-platform compilation (M001/S01)
|
||||
- R007 — Error handling for TCP failures (M001/S02)
|
||||
- R008 — Integration: CLI ↔ daemon over TCP (M001/S04)
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- Trait-based transport abstraction (Listener, Connector)
|
||||
- TCP implementation (TcpListener, TcpStream)
|
||||
- Global `--tcp host:port` CLI flag
|
||||
- `wx daemon start` subcommand
|
||||
- Error handling for TCP failures
|
||||
- Cross-platform compilation
|
||||
|
||||
### Out of Scope / Non-Goals
|
||||
|
||||
- TLS encryption
|
||||
- Authentication tokens
|
||||
- IP whitelisting
|
||||
- Connection pooling / keepalive
|
||||
- Changing the JSON-line protocol
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
- Must maintain backwards compatibility: no `--tcp` = existing behavior
|
||||
- tokio is already a dependency (TcpListener/TcpStream available)
|
||||
- `interprocess` crate for Windows named pipes — API differs from std
|
||||
|
||||
## Integration Points
|
||||
|
||||
- `src/daemon/server.rs` → `src/transport/` — server uses Listener trait
|
||||
- `src/cli/transport.rs` → `src/transport/` — client uses Connector trait
|
||||
- `src/config.rs` → optional tcp_addr field
|
||||
- `src/cli/mod.rs` → global --tcp flag on Cli struct
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
- `cargo check` on x86_64-unknown-linux-gnu, x86_64-pc-windows-msvc, and current platform
|
||||
- Unit tests for transport::protocol.rs (JSON round-trip)
|
||||
- Existing scanner tests continue passing
|
||||
- Manual smoke test: daemon on TCP, client queries over TCP
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- S01: Transport traits defined, all implementations compile on all platforms, existing behavior unchanged
|
||||
- S02: `wx daemon start --tcp 127.0.0.1:9876` starts daemon listening on TCP
|
||||
- S03: `wx sessions --tcp 127.0.0.1:9876` connects via TCP and returns correct results
|
||||
- S04: End-to-end TCP communication verified manually on localhost
|
||||
|
||||
## Open Questions
|
||||
|
||||
- None — scope confirmed, architecture agreed, error strategy defined
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# M001: TCP Transport
|
||||
|
||||
**Vision:** Add TCP socket transport to wx-cli's daemon communication layer with trait-based abstraction, enabling remote clients to query WeChat data over the network.
|
||||
|
||||
## Slices
|
||||
|
||||
- [ ] **S01: Transport abstraction layer** `risk:high` `depends:[]`
|
||||
> After this: Refactor complete, `cargo check` passes on all platforms, existing behavior unchanged. Transport traits defined and implemented for Unix socket + Windows named pipe.
|
||||
|
||||
- [ ] **S02: TCP server support** `risk:medium` `depends:[S01]`
|
||||
> After this: `wx daemon start --tcp 127.0.0.1:9876` starts daemon listening on TCP port 9876
|
||||
|
||||
- [ ] **S03: TCP client + global --tcp flag** `risk:medium` `depends:[S01]`
|
||||
> After this: `wx sessions --tcp 127.0.0.1:9876` connects via TCP and returns session data
|
||||
|
||||
- [ ] **S04: Integration smoke test** `risk:low` `depends:[S02,S03]`
|
||||
> After this: Daemon on TCP + client queries return same data as local transport
|
||||
|
||||
## Boundary Map
|
||||
|
||||
Not provided.
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{"id":"ba5f368a-35d5-4624-bf93-53fd53117126","ts":"2026-05-13T04:37:51.107Z","severity":"info","message":"Use /gsd prefs project to update project preferences.","source":"notify","read":false}
|
||||
{"id":"826493b3-d1b2-481a-8989-db9d9c4217b7","ts":"2026-05-13T04:37:57.391Z","severity":"info","message":"Using existing global GSD skill preferences at C:\\Users\\david\\.gsd\\PREFERENCES.md","source":"notify","read":false}
|
||||
{"id":"25bd9781-bb82-4209-bb02-1a8b8b4d710a","ts":"2026-05-13T04:37:57.395Z","severity":"info","message":"GSD preferences (global) — pick a category to configure.","source":"notify","read":false}
|
||||
{"id":"bedf9f7f-38b0-4724-abd0-2f044eb0a7d2","ts":"2026-05-13T04:40:53.586Z","severity":"info","message":"Saved global preferences to C:\\Users\\david\\.gsd\\PREFERENCES.md","source":"notify","read":false}
|
||||
{"id":"2c83aa1f-d2a4-4faf-903e-9bc1b361a665","ts":"2026-05-13T04:41:31.640Z","severity":"warning","message":"[migration] Provider-specific default fallback used without an explicit available model; configure provider-aware model preferences before removing defaults.","source":"workflow-logger","read":false}
|
||||
{"id":"07df36ac-fb0f-4895-a3d9-845e563b47f3","ts":"2026-05-13T05:02:59.382Z","severity":"info","message":"Using existing global GSD skill preferences at C:\\Users\\david\\.gsd\\PREFERENCES.md","source":"notify","read":false}
|
||||
{"id":"0bf8cebb-68d5-4d14-9c6a-6cdda12b33e2","ts":"2026-05-13T05:02:59.385Z","severity":"info","message":"GSD preferences (global) — pick a category to configure.","source":"notify","read":false}
|
||||
{"id":"b91acb14-a891-4934-a0e2-4bec6e0ed178","ts":"2026-05-13T05:03:22.769Z","severity":"info","message":"Mode: solo — defaults: auto_push=true, push_branches=false, pre_merge_check=auto, merge_strategy=squash, isolation=worktree, unique_milestone_ids=false","source":"notify","read":false}
|
||||
{"id":"24385a47-fae4-433a-83c8-238dd1ee450d","ts":"2026-05-13T05:05:30.603Z","severity":"info","message":"Saved global preferences to C:\\Users\\david\\.gsd\\PREFERENCES.md","source":"notify","read":false}
|
||||
{"id":"52a852d3-aada-423a-9c23-0802a0735162","ts":"2026-05-13T05:05:41.228Z","severity":"info","message":"GSD — Get Shit Done\n\nQUICK START\n /gsd start <tpl> Start a workflow template\n /gsd Run next unit (same as /gsd next)\n /gsd auto Run all queued units continuously\n /gsd pause Pause auto-mode\n /gsd stop Stop auto-mode gracefully\n\nVISIBILITY\n /gsd status Dashboard (Ctrl+Alt+G / Ctrl+Shift+G)\n /gsd parallel watch Parallel monitor (Ctrl+Alt+P)\n /gsd notifications Notification history (Ctrl+Alt+N / Ctrl+Shift+N)\n /gsd visualize Intera…","source":"notify","read":false}
|
||||
{"id":"3d539aca-9626-4add-9792-45a220fde9ae","ts":"2026-05-13T05:05:44.707Z","severity":"info","message":"Project detected:\n rust project\n Project files: Cargo.toml, .github/workflows\n CI/CD: detected\n Verification: cargo test, cargo clippy","source":"notify","read":false}
|
||||
{"id":"1c077a14-1cba-4370-9e08-d3d4842b766e","ts":"2026-05-13T05:06:30.925Z","severity":"info","message":"Installing Rust, Skill Authoring, Document Handling skills...","source":"notify","read":false}
|
||||
{"id":"9da47155-1524-4474-8692-48e3e15ba878","ts":"2026-05-13T05:06:30.935Z","severity":"info","message":"Installing Rust Async Patterns, CI/CD Automation, Code Review & Quality, Git Advanced Workflows skills...","source":"notify","read":false}
|
||||
{"id":"dbdce8ef-473c-4855-b3ce-42b1040e74a3","ts":"2026-05-13T05:06:30.943Z","severity":"info","message":"Installing Skill Discovery skills...","source":"notify","read":false}
|
||||
{"id":"0d1ff703-1a0f-432b-9fac-4033d5069a2f","ts":"2026-05-13T05:06:30.950Z","severity":"info","message":"Failed to install Rust — try manually: npx skills add anthropics/skills","source":"notify","read":false}
|
||||
{"id":"8faf17c7-fa9f-4088-be28-583abc163801","ts":"2026-05-13T05:06:30.951Z","severity":"info","message":"Failed to install Rust Async Patterns — try manually: npx skills add wshobson/agents","source":"notify","read":false}
|
||||
{"id":"66f7d6e4-4ef7-46ab-901e-0de1faa4890c","ts":"2026-05-13T05:06:30.952Z","severity":"info","message":"Failed to install CI/CD Automation — try manually: npx skills add wshobson/agents","source":"notify","read":false}
|
||||
{"id":"3380ca5b-612f-48f4-8355-8c9096a0e43f","ts":"2026-05-13T05:06:30.952Z","severity":"info","message":"Failed to install Skill Discovery — try manually: npx skills add vercel-labs/skills","source":"notify","read":false}
|
||||
{"id":"99a403d9-4270-4dc7-a250-8a938736f717","ts":"2026-05-13T05:06:30.953Z","severity":"info","message":"Failed to install Skill Authoring — try manually: npx skills add anthropics/skills","source":"notify","read":false}
|
||||
{"id":"2939bc3a-0d64-431e-ae46-3823d62df1c0","ts":"2026-05-13T05:06:30.954Z","severity":"info","message":"Failed to install Document Handling — try manually: npx skills add anthropics/skills","source":"notify","read":false}
|
||||
{"id":"2f34be20-36b9-4d3f-815a-14f18e148396","ts":"2026-05-13T05:06:30.954Z","severity":"info","message":"Failed to install Code Review & Quality — try manually: npx skills add wshobson/agents","source":"notify","read":false}
|
||||
{"id":"f983e68f-0ee7-4af4-9e4a-04222c6f27e5","ts":"2026-05-13T05:06:30.955Z","severity":"info","message":"Failed to install Git Advanced Workflows — try manually: npx skills add wshobson/agents","source":"notify","read":false}
|
||||
{"id":"f246d948-6cff-405c-b6dd-a88d72c014ef","ts":"2026-05-13T05:06:43.256Z","severity":"info","message":"Codebase map generated: 52 files","source":"notify","read":false}
|
||||
{"id":"a6ccb4fe-fc00-4162-bbd3-2e8a1a8684c4","ts":"2026-05-13T05:06:43.514Z","severity":"info","message":"GSD initialized. Starting your first milestone...","source":"notify","read":false}
|
||||
{"id":"29a93a25-8daa-44a1-8eb5-4a4e9b01e59d","ts":"2026-05-13T05:06:45.030Z","severity":"info","message":"Analyzing codebase...","source":"notify","read":false}
|
||||
{"id":"6a93a35a-02cf-4b7e-8367-79fa01bfed6e","ts":"2026-05-13T05:06:45.043Z","severity":"success","message":"✓ Analyzed codebase","source":"notify","read":false}
|
||||
{"id":"853a2d66-548f-4b18-84fe-71c74b8741b5","ts":"2026-05-13T05:06:45.044Z","severity":"info","message":"Reviewing prior context...","source":"notify","read":false}
|
||||
{"id":"39321b35-1395-4a4b-8f04-63a8d9d8129b","ts":"2026-05-13T05:06:45.053Z","severity":"success","message":"✓ Reviewed prior context","source":"notify","read":false}
|
||||
{"id":"0fa5db21-6a50-4fec-9ddd-c0020c8c35f4","ts":"2026-05-13T05:23:12.475Z","severity":"info","message":"discuss-milestone M001 is waiting for your approval - pausing before more tool calls run.","source":"notify","read":false}
|
||||
{"id":"24d68af1-955c-4fbd-a841-357605a9c2f0","ts":"2026-05-13T05:25:36.823Z","severity":"info","message":"discuss-milestone M001 is waiting for your approval - pausing before more tool calls run.","source":"notify","read":false}
|
||||
{"id":"b8ff6fb1-2775-4790-a494-2c0da94f8ee1","ts":"2026-05-13T05:32:05.786Z","severity":"success","message":"Milestone M001 ready.","source":"notify","read":false}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"version": 1,
|
||||
"exported_at": "2026-05-13T05:31:30.649Z",
|
||||
"milestones": [
|
||||
{
|
||||
"id": "M001",
|
||||
"title": "TCP Transport",
|
||||
"status": "active",
|
||||
"depends_on": [],
|
||||
"created_at": "2026-05-13T05:31:30.629Z",
|
||||
"completed_at": null,
|
||||
"vision": "Add TCP socket transport to wx-cli's daemon communication layer with trait-based abstraction, enabling remote clients to query WeChat data over the network.",
|
||||
"success_criteria": [],
|
||||
"key_risks": [
|
||||
{
|
||||
"risk": "Windows named pipe refactoring may require interprocess crate API changes",
|
||||
"whyItMatters": "interprocess crate API differs from std Unix sockets, may need adaptation for trait compatibility"
|
||||
},
|
||||
{
|
||||
"risk": "Daemon start subcommand conflicts with existing auto-start behavior",
|
||||
"whyItMatters": "Currently daemon auto-starts on first query via ensure_daemon(). New explicit start must coexist."
|
||||
}
|
||||
],
|
||||
"proof_strategy": [
|
||||
{
|
||||
"riskOrUnknown": "Windows named pipe trait compatibility with interprocess crate",
|
||||
"retireIn": "S01",
|
||||
"whatWillBeProven": "Transport traits work for Unix socket and named pipe"
|
||||
},
|
||||
{
|
||||
"riskOrUnknown": "TCP bind and accept behavior on all platforms",
|
||||
"retireIn": "S02",
|
||||
"whatWillBeProven": "TCP listener accepts connections and handles requests correctly"
|
||||
},
|
||||
{
|
||||
"riskOrUnknown": "Protocol works identically over TCP as over local transport",
|
||||
"retireIn": "S04",
|
||||
"whatWillBeProven": "End-to-end TCP communication returns correct results"
|
||||
}
|
||||
],
|
||||
"verification_contract": "- Contract verification: `cargo check` on all three targets, unit tests for protocol handling\n- Integration verification: Manual smoke test of CLI ↔ daemon over TCP on localhost\n- Operational verification: Daemon starts/stops cleanly with TCP, handles bind errors\n- UAT / human verification: Verify TCP results match local transport results",
|
||||
"verification_integration": "Manual smoke test: daemon on TCP + client queries return same data as local transport",
|
||||
"verification_operational": "Daemon starts with --tcp, binds to specified address, handles errors cleanly. Client connects via TCP, fails clearly on unreachable address.",
|
||||
"verification_uat": "",
|
||||
"definition_of_done": [
|
||||
"All slice deliverables complete",
|
||||
"Transport abstraction layer wired into daemon and client",
|
||||
"cargo check passes on macOS, Linux, and Windows targets",
|
||||
"Daemon can listen on local + TCP simultaneously",
|
||||
"Client connects via TCP with --tcp, errors clearly on failure",
|
||||
"wx daemon start subcommand works",
|
||||
"Manual smoke test passes: CLI ↔ daemon over TCP on localhost",
|
||||
"No regression to local-only transport"
|
||||
],
|
||||
"requirement_coverage": "Covers: R001, R002, R003, R004, R005, R006, R007, R008\nPartially covers: none\nLeaves for later: R020 (TLS), R021 (Auth), R022 (Keepalive)\nOrphan risks: none",
|
||||
"boundary_map_markdown": "Not provided.",
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"slices": [
|
||||
{
|
||||
"milestone_id": "M001",
|
||||
"id": "S01",
|
||||
"title": "Transport abstraction layer",
|
||||
"status": "pending",
|
||||
"risk": "high",
|
||||
"depends": [],
|
||||
"demo": "Refactor complete, `cargo check` passes on all platforms, existing behavior unchanged. Transport traits defined and implemented for Unix socket + Windows named pipe.",
|
||||
"created_at": "2026-05-13T05:31:30.630Z",
|
||||
"completed_at": null,
|
||||
"full_summary_md": "",
|
||||
"full_uat_md": "",
|
||||
"goal": "Refactor transport layer into trait-based abstraction, eliminating platform-specific duplication. Implement Unix socket and Windows named pipe using new traits. Add `wx daemon start` subcommand.",
|
||||
"success_criteria": "- `cargo check` passes on all three target platforms\n- Existing CLI commands work unchanged (no regression)\n- Transport traits (Listener, Connector) defined in `src/transport/traits.rs`\n- Protocol handling shared in `src/transport/protocol.rs`\n- `wx daemon start` subcommand exists and starts daemon",
|
||||
"proof_level": "contract",
|
||||
"integration_closure": "Daemon starts via `wx daemon start` and listens on local transport (Unix socket / named pipe). Client queries work via local transport as before.",
|
||||
"observability_impact": "Daemon startup logs show which transports are active",
|
||||
"sequence": 1,
|
||||
"replan_triggered_at": null,
|
||||
"is_sketch": 0,
|
||||
"sketch_scope": ""
|
||||
},
|
||||
{
|
||||
"milestone_id": "M001",
|
||||
"id": "S02",
|
||||
"title": "TCP server support",
|
||||
"status": "pending",
|
||||
"risk": "medium",
|
||||
"depends": [
|
||||
"S01"
|
||||
],
|
||||
"demo": "`wx daemon start --tcp 127.0.0.1:9876` starts daemon listening on TCP port 9876",
|
||||
"created_at": "2026-05-13T05:31:30.630Z",
|
||||
"completed_at": null,
|
||||
"full_summary_md": "",
|
||||
"full_uat_md": "",
|
||||
"goal": "Implement TCP server support. Add `--tcp` flag to daemon start. Daemon listens on local transport AND TCP simultaneously when --tcp is specified.",
|
||||
"success_criteria": "- `wx daemon start --tcp 127.0.0.1:9876` starts daemon on both local and TCP\n- TCP connections accepted and handled correctly\n- TCP bind failure produces clear error message\n- `cargo check` passes on all platforms",
|
||||
"proof_level": "contract",
|
||||
"integration_closure": "Daemon accepts TCP connections. JSON-line protocol works over TCP. Bind errors are clear.",
|
||||
"observability_impact": "Daemon logs show TCP bind address and accepted connections",
|
||||
"sequence": 2,
|
||||
"replan_triggered_at": null,
|
||||
"is_sketch": 0,
|
||||
"sketch_scope": ""
|
||||
},
|
||||
{
|
||||
"milestone_id": "M001",
|
||||
"id": "S03",
|
||||
"title": "TCP client + global --tcp flag",
|
||||
"status": "pending",
|
||||
"risk": "medium",
|
||||
"depends": [
|
||||
"S01"
|
||||
],
|
||||
"demo": "`wx sessions --tcp 127.0.0.1:9876` connects via TCP and returns session data",
|
||||
"created_at": "2026-05-13T05:31:30.630Z",
|
||||
"completed_at": null,
|
||||
"full_summary_md": "",
|
||||
"full_uat_md": "",
|
||||
"goal": "Implement TCP client support. Add global `--tcp host:port` flag to CLI. Client connects directly via TCP when flag is specified, with no local fallback.",
|
||||
"success_criteria": "- `wx sessions --tcp 127.0.0.1:9876` connects via TCP and returns results\n- `wx sessions --tcp 127.0.0.1:9999` fails with clear error within 15s\n- `wx daemon status --tcp 127.0.0.1:9876` works over TCP\n- `wx daemon logs --tcp 127.0.0.1:9876` works over TCP\n- All commands without --tcp still work via local transport",
|
||||
"proof_level": "contract",
|
||||
"integration_closure": "Client connects via TCP to running daemon. All query commands work. Error messages clear on failure.",
|
||||
"observability_impact": "Client error messages show TCP address when connection fails",
|
||||
"sequence": 3,
|
||||
"replan_triggered_at": null,
|
||||
"is_sketch": 0,
|
||||
"sketch_scope": ""
|
||||
},
|
||||
{
|
||||
"milestone_id": "M001",
|
||||
"id": "S04",
|
||||
"title": "Integration smoke test",
|
||||
"status": "pending",
|
||||
"risk": "low",
|
||||
"depends": [
|
||||
"S02",
|
||||
"S03"
|
||||
],
|
||||
"demo": "Daemon on TCP + client queries return same data as local transport",
|
||||
"created_at": "2026-05-13T05:31:30.630Z",
|
||||
"completed_at": null,
|
||||
"full_summary_md": "",
|
||||
"full_uat_md": "",
|
||||
"goal": "End-to-end integration verification. Daemon on TCP, client queries over TCP, results match local transport.",
|
||||
"success_criteria": "- Manual smoke test: daemon started with --tcp, client queries over TCP\n- TCP and local transport return identical results\n- No regression to local-only mode\n- All cargo check targets pass",
|
||||
"proof_level": "integration",
|
||||
"integration_closure": "Full end-to-end: CLI ↔ daemon over TCP on localhost, same results as local transport.",
|
||||
"observability_impact": "Observable end-to-end TCP communication between CLI and daemon",
|
||||
"sequence": 4,
|
||||
"replan_triggered_at": null,
|
||||
"is_sketch": 0,
|
||||
"sketch_scope": ""
|
||||
}
|
||||
],
|
||||
"tasks": [],
|
||||
"decisions": [],
|
||||
"verification_evidence": []
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# wx-cli
|
||||
|
||||
## What This Is
|
||||
|
||||
A cross-platform Rust CLI tool for extracting and querying local WeChat 4.x data. Decrypts SQLCipher-encrypted databases, caches decrypted copies with mtime-aware invalidation, and provides a daemon-based IPC architecture for fast repeated queries. Supports Unix sockets (macOS/Linux), Windows named pipes, and TCP for remote access.
|
||||
|
||||
## Core Value
|
||||
|
||||
Query your local WeChat chat history, contacts, and moments from the command line with millisecond response times — data never leaves your machine.
|
||||
|
||||
## Project Shape
|
||||
|
||||
- **Complexity:** simple
|
||||
- **Why:** Well-defined scope, existing codebase with clear module boundaries, trait-based transport abstraction
|
||||
|
||||
## Current State
|
||||
|
||||
Version 0.1.10. Fully functional CLI with 17 subcommands. Daemon auto-starts on first query. Cross-platform (macOS, Linux, Windows). TCP transport added with trait-based abstraction (Listener/Connector traits). Integration tests cover TCP round-trip, connection refused, and TCP-vs-local comparison. Local IPC + TCP simultaneously supported.
|
||||
|
||||
## Architecture / Key Patterns
|
||||
|
||||
- Single binary: client and daemon (`WX_DAEMON_MODE` env var)
|
||||
- Daemon uses tokio async runtime, Unix socket / Windows named pipe / TCP IPC
|
||||
- Transport abstraction via `Listener` and `Connector` object-safe traits
|
||||
- Generic `handle_connection` function shared across all transport types
|
||||
- JSON-line protocol: one request per connection
|
||||
- Blocking `std::net::TcpStream` for TCP transport (matches sync CLI architecture)
|
||||
- mtime-aware decryption cache in `~/.wx-cli/cache/`
|
||||
- Platform-specific memory scanners for SQLCipher key extraction
|
||||
- All queries executed via rusqlite on decrypted DBs
|
||||
|
||||
## Capability Contract
|
||||
|
||||
See `.gsd/REQUIREMENTS.md` for the explicit capability contract.
|
||||
|
||||
## Milestone Sequence
|
||||
|
||||
- [x] M001: TCP Transport — Add `--tcp host:port` global flag and TCP transport support to daemon and client
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "00fdc60b-9e50-4884-9a68-a9f51878e212",
|
||||
"runtime": "bash",
|
||||
"purpose": "Get test failure details",
|
||||
"script_chars": 59,
|
||||
"started_at": "2026-05-13T06:56:38.704Z",
|
||||
"finished_at": "2026-05-13T06:56:58.965Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 20261,
|
||||
"stdout_bytes": 1189,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\00fdc60b-9e50-4884-9a68-a9f51878e212.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\00fdc60b-9e50-4884-9a68-a9f51878e212.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
test cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- cli::transport::integration_tests::test_send_tcp_round_trip stdout ----
|
||||
|
||||
thread 'cli::transport::integration_tests::test_send_tcp_round_trip' (2000) panicked at src/cli/transport.rs:374:81:
|
||||
called `Result::unwrap()` on an `Err` value: 连接 TCP daemon (127.0.0.1:45175) 失败
|
||||
|
||||
Caused by:
|
||||
connection timed out
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
---- cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip stdout ----
|
||||
[test] spawned daemon PID 2085
|
||||
|
||||
thread 'cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip' (2002) panicked at src/cli/transport.rs:466:13:
|
||||
daemon did not become ready on 127.0.0.1:46229 within 15s (PID 2085)
|
||||
|
||||
|
||||
failures:
|
||||
cli::transport::integration_tests::test_send_tcp_round_trip
|
||||
cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip
|
||||
|
||||
test result: FAILED. 35 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 17.69s
|
||||
|
||||
error: test failed, to rerun pass `--bin wx`
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "047f8098-b32f-48a9-8f03-614ec48dca30",
|
||||
"runtime": "bash",
|
||||
"purpose": "S02: check cargo run help for tcp flag",
|
||||
"script_chars": 67,
|
||||
"started_at": "2026-05-13T06:14:24.162Z",
|
||||
"finished_at": "2026-05-13T06:14:44.107Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 19945,
|
||||
"stdout_bytes": 98,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\047f8098-b32f-48a9-8f03-614ec48dca30.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\047f8098-b32f-48a9-8f03-614ec48dca30.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
--tcp <TCP> 通过 TCP 连接 daemon(如 127.0.0.1:9876)
|
||||
-h, --help Print help
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "0ab02356-ed5d-4746-8044-f4cf980ae17d",
|
||||
"runtime": "bash",
|
||||
"purpose": "S01 codebase structure scan",
|
||||
"script_chars": 145,
|
||||
"started_at": "2026-05-13T05:32:23.949Z",
|
||||
"finished_at": "2026-05-13T05:32:33.000Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 9051,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 151,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0ab02356-ed5d-4746-8044-f4cf980ae17d.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0ab02356-ed5d-4746-8044-f4cf980ae17d.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: /c/Users/david/Work/wx-cli/.gsd/worktrees/M001: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "0c2c8672-29d0-4244-a93e-e00b2bc5a8f8",
|
||||
"runtime": "bash",
|
||||
"purpose": "Check daemon start help and existing tests count",
|
||||
"script_chars": 189,
|
||||
"started_at": "2026-05-13T06:18:53.254Z",
|
||||
"finished_at": "2026-05-13T06:19:09.286Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 16032,
|
||||
"stdout_bytes": 1689,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0c2c8672-29d0-4244-a93e-e00b2bc5a8f8.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0c2c8672-29d0-4244-a93e-e00b2bc5a8f8.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
=== DAEMON START HELP ===
|
||||
warning: unused config key `net.timeout` in `/mnt/c/Users/david/.cargo/config.toml`
|
||||
warning: unused config key `http.low-speed-timeout` in `/mnt/c/Users/david/.cargo/config.toml`
|
||||
warning: unused import: `bail`
|
||||
--> src/scanner/linux.rs:6:14
|
||||
|
|
||||
6 | use anyhow::{bail, Context, Result};
|
||||
| ^^^^
|
||||
|
|
||||
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: `wx-cli` (bin "wx") generated 1 warning (run `cargo fix --bin "wx" -p wx-cli` to apply 1 suggestion)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.70s
|
||||
Running `target/debug/wx daemon start --help`
|
||||
启动 daemon
|
||||
|
||||
Usage: wx daemon start [OPTIONS]
|
||||
|
||||
Options:
|
||||
--tcp <TCP> 同时监听 TCP 地址(如 127.0.0.1:9876)
|
||||
-h, --help Print help
|
||||
=== TEST COUNT ===
|
||||
test transport::tests::transport_addr_variants ... ok
|
||||
test transport::tests::tcp_listener_implements_listener ... ok
|
||||
test scanner::tests::test_collect_db_salts_ignores_non_db_extensions ... ok
|
||||
test scanner::tests::test_collect_db_salts_multiple_files_unique_salts ... ok
|
||||
test scanner::tests::test_collect_db_salts_skips_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_collect_db_salts_recursive ... ok
|
||||
test scanner::tests::test_read_db_salt_encrypted ... ok
|
||||
test scanner::tests::test_read_db_salt_exactly_16_bytes ... ok
|
||||
test scanner::tests::test_read_db_salt_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_read_db_salt_too_short ... ok
|
||||
test scanner::tests::test_collect_db_salts_empty_dir ... ok
|
||||
test scanner::tests::test_collect_db_salts_finds_encrypted ... ok
|
||||
|
||||
test result: ok. 32 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "0e618abb-b0a8-484a-89b2-c602f41a4332",
|
||||
"runtime": "python",
|
||||
"purpose": "check tasks table schema",
|
||||
"script_chars": 390,
|
||||
"started_at": "2026-05-13T07:43:33.710Z",
|
||||
"finished_at": "2026-05-13T07:43:33.895Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 185,
|
||||
"stdout_bytes": 8334,
|
||||
"stderr_bytes": 0,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0e618abb-b0a8-484a-89b2-c602f41a4332.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\0e618abb-b0a8-484a-89b2-c602f41a4332.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
Tables: ['schema_version', 'decisions', 'sqlite_sequence', 'requirements', 'artifacts', 'memories', 'memory_processed_units', 'memory_sources', 'memory_embeddings', 'memory_relations', 'memories_fts', 'memories_fts_data', 'memories_fts_idx', 'memories_fts_docsize', 'memories_fts_config', 'milestones', 'slices', 'tasks', 'verification_evidence', 'replan_history', 'assessments', 'quality_gates', 'slice_dependencies', 'gate_runs', 'turn_git_transactions', 'milestone_commit_attributions', 'audit_events', 'audit_turn_index', 'workers', 'milestone_leases', 'unit_dispatches', 'cancellation_requests', 'command_queue', 'runtime_kv']
|
||||
|
||||
schema_version: [('version', 'INTEGER'), ('applied_at', 'TEXT')]
|
||||
|
||||
decisions: [('seq', 'INTEGER'), ('id', 'TEXT'), ('when_context', 'TEXT'), ('scope', 'TEXT'), ('decision', 'TEXT'), ('choice', 'TEXT'), ('rationale', 'TEXT'), ('revisable', 'TEXT'), ('made_by', 'TEXT'), ('source', 'TEXT'), ('superseded_by', 'TEXT')]
|
||||
|
||||
sqlite_sequence: [('name', ''), ('seq', '')]
|
||||
|
||||
requirements: [('id', 'TEXT'), ('class', 'TEXT'), ('status', 'TEXT'), ('description', 'TEXT'), ('why', 'TEXT'), ('source', 'TEXT'), ('primary_owner', 'TEXT'), ('supporting_slices', 'TEXT'), ('validation', 'TEXT'), ('notes', 'TEXT'), ('full_content', 'TEXT'), ('superseded_by', 'TEXT')]
|
||||
|
||||
artifacts: [('path', 'TEXT'), ('artifact_type', 'TEXT'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('full_content', 'TEXT'), ('imported_at', 'TEXT'), ('content_hash', 'TEXT')]
|
||||
|
||||
memories: [('seq', 'INTEGER'), ('id', 'TEXT'), ('category', 'TEXT'), ('content', 'TEXT'), ('confidence', 'REAL'), ('source_unit_type', 'TEXT'), ('source_unit_id', 'TEXT'), ('created_at', 'TEXT'), ('updated_at', 'TEXT'), ('superseded_by', 'TEXT'), ('hit_count', 'INTEGER'), ('scope', 'TEXT'), ('tags', 'TEXT'), ('structured_fields', 'TEXT'), ('last_hit_at', 'TEXT')]
|
||||
|
||||
memory_processed_units: [('unit_key', 'TEXT'), ('activity_file', 'TEXT'), ('processed_at', 'TEXT')]
|
||||
|
||||
memory_sources: [('id', 'TEXT'), ('kind', 'TEXT'), ('uri', 'TEXT'), ('title', 'TEXT'), ('content', 'TEXT'), ('content_hash', 'TEXT'), ('imported_at', 'TEXT'), ('scope', 'TEXT'), ('tags', 'TEXT')]
|
||||
|
||||
memory_embeddings: [('memory_id', 'TEXT'), ('model', 'TEXT'), ('dim', 'INTEGER'), ('vector', 'BLOB'), ('updated_at', 'TEXT')]
|
||||
|
||||
memory_relations: [('from_id', 'TEXT'), ('to_id', 'TEXT'), ('rel', 'TEXT'), ('confidence', 'REAL'), ('created_at', 'TEXT')]
|
||||
|
||||
memories_fts: [('content', '')]
|
||||
|
||||
memories_fts_data: [('id', 'INTEGER'), ('block', 'BLOB')]
|
||||
|
||||
memories_fts_idx: [('segid', ''), ('term', ''), ('pgno', '')]
|
||||
|
||||
memories_fts_docsize: [('id', 'INTEGER'), ('sz', 'BLOB')]
|
||||
|
||||
memories_fts_config: [('k', ''), ('v', '')]
|
||||
|
||||
milestones: [('id', 'TEXT'), ('title', 'TEXT'), ('status', 'TEXT'), ('depends_on', 'TEXT'), ('created_at', 'TEXT'), ('completed_at', 'TEXT'), ('vision', 'TEXT'), ('success_criteria', 'TEXT'), ('key_risks', 'TEXT'), ('proof_strategy', 'TEXT'), ('verification_contract', 'TEXT'), ('verification_integration', 'TEXT'), ('verification_operational', 'TEXT'), ('verification_uat', 'TEXT'), ('definition_of_done', 'TEXT'), ('requirement_coverage', 'TEXT'), ('boundary_map_markdown', 'TEXT'), ('sequence', 'INTEGER')]
|
||||
|
||||
slices: [('milestone_id', 'TEXT'), ('id', 'TEXT'), ('title', 'TEXT'), ('status', 'TEXT'), ('risk', 'TEXT'), ('depends', 'TEXT'), ('demo', 'TEXT'), ('created_at', 'TEXT'), ('completed_at', 'TEXT'), ('full_summary_md', 'TEXT'), ('full_uat_md', 'TEXT'), ('goal', 'TEXT'), ('success_criteria', 'TEXT'), ('proof_level', 'TEXT'), ('integration_closure', 'TEXT'), ('observability_impact', 'TEXT'), ('sequence', 'INTEGER'), ('replan_triggered_at', 'TEXT'), ('is_sketch', 'INTEGER'), ('sketch_scope', 'TEXT')]
|
||||
|
||||
tasks: [('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('id', 'TEXT'), ('title', 'TEXT'), ('status', 'TEXT'), ('one_liner', 'TEXT'), ('narrative', 'TEXT'), ('verification_result', 'TEXT'), ('duration', 'TEXT'), ('completed_at', 'TEXT'), ('blocker_discovered', 'INTEGER'), ('blocker_source', 'TEXT'), ('escalation_pending', 'INTEGER'), ('escalation_awaiting_review', 'INTEGER'), ('escalation_artifact_path', 'TEXT'), ('escalation_override_applied_at', 'TEXT'), ('deviations', 'TEXT'), ('known_issues', 'TEXT'), ('key_files', 'TEXT'), ('key_decisions', 'TEXT'), ('full_summary_md', 'TEXT'), ('description', 'TEXT'), ('estimate', 'TEXT'), ('files', 'TEXT'), ('verify', 'TEXT'), ('inputs', 'TEXT'), ('expected_output', 'TEXT'), ('observability_impact', 'TEXT'), ('full_plan_md', 'TEXT'), ('sequence', 'INTEGER')]
|
||||
|
||||
verification_evidence: [('id', 'INTEGER'), ('task_id', 'TEXT'), ('slice_id', 'TEXT'), ('milestone_id', 'TEXT'), ('command', 'TEXT'), ('exit_code', 'INTEGER'), ('verdict', 'TEXT'), ('duration_ms', 'INTEGER'), ('created_at', 'TEXT')]
|
||||
|
||||
replan_history: [('id', 'INTEGER'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('summary', 'TEXT'), ('previous_artifact_path', 'TEXT'), ('replacement_artifact_path', 'TEXT'), ('created_at', 'TEXT')]
|
||||
|
||||
assessments: [('path', 'TEXT'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('status', 'TEXT'), ('scope', 'TEXT'), ('full_content', 'TEXT'), ('created_at', 'TEXT')]
|
||||
|
||||
quality_gates: [('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('gate_id', 'TEXT'), ('scope', 'TEXT'), ('task_id', 'TEXT'), ('status', 'TEXT'), ('verdict', 'TEXT'), ('rationale', 'TEXT'), ('findings', 'TEXT'), ('evaluated_at', 'TEXT')]
|
||||
|
||||
slice_dependencies: [('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('depends_on_slice_id', 'TEXT')]
|
||||
|
||||
gate_runs: [('id', 'INTEGER'), ('trace_id', 'TEXT'), ('turn_id', 'TEXT'), ('gate_id', 'TEXT'), ('gate_type', 'TEXT'), ('unit_type', 'TEXT'), ('unit_id', 'TEXT'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('outcome', 'TEXT'), ('failure_class', 'TEXT'), ('rationale', 'TEXT'), ('findings', 'TEXT'), ('attempt', 'INTEGER'), ('max_attempts', 'INTEGER'), ('retryable', 'INTEGER'), ('evaluated_at', 'TEXT')]
|
||||
|
||||
turn_git_transactions: [('trace_id', 'TEXT'), ('turn_id', 'TEXT'), ('unit_type', 'TEXT'), ('unit_id', 'TEXT'), ('stage', 'TEXT'), ('action', 'TEXT'), ('push', 'INTEGER'), ('status', 'TEXT'), ('error', 'TEXT'), ('metadata_json', 'TEXT'), ('updated_at', 'TEXT')]
|
||||
|
||||
milestone_commit_attributions: [('commit_sha', 'TEXT'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('source', 'TEXT'), ('confidence', 'REAL'), ('files_json', 'TEXT'), ('created_at', 'TEXT')]
|
||||
|
||||
audit_events: [('event_id', 'TEXT'), ('trace_id', 'TEXT'), ('turn_id', 'TEXT'), ('caused_by', 'TEXT'), ('category', 'TEXT'), ('type', 'TEXT'), ('ts', 'TEXT'), ('payload_json', 'TEXT')]
|
||||
|
||||
audit_turn_index: [('trace_id', 'TEXT'), ('turn_id', 'TEXT'), ('first_ts', 'TEXT'), ('last_ts', 'TEXT'), ('event_count', 'INTEGER')]
|
||||
|
||||
workers: [('worker_id', 'TEXT'), ('host', 'TEXT'), ('pid', 'INTEGER'), ('started_at', 'TEXT'), ('version', 'TEXT'), ('last_heartbeat_at', 'TEXT'), ('status', 'TEXT'), ('project_root_realpath', 'TEXT')]
|
||||
|
||||
milestone_leases: [('milestone_id', 'TEXT'), ('worker_id', 'TEXT'), ('fencing_token', 'INTEGER'), ('acquired_at', 'TEXT'), ('expires_at', 'TEXT'), ('status', 'TEXT')]
|
||||
|
||||
unit_dispatches: [('id', 'INTEGER'), ('trace_id', 'TEXT'), ('turn_id', 'TEXT'), ('worker_id', 'TEXT'), ('milestone_lease_token', 'INTEGER'), ('milestone_id', 'TEXT'), ('slice_id', 'TEXT'), ('task_id', 'TEXT'), ('unit_type', 'TEXT'), ('unit_id', 'TEXT'), ('status', 'TEXT'), ('attempt_n', 'INTEGER'), ('started_at', 'TEXT'), ('ended_at', 'TEXT'), ('exit_reason', 'TEXT'), ('error_summary', 'TEXT'), ('verification_evidence_id', 'INTEGER'), ('next_run_at', 'TEXT'), ('retry_after_ms', 'INTEGER'), ('max_attempts', 'INTEGER'), ('last_error_code', 'TEXT'), ('last_error_at', 'TEXT')]
|
||||
|
||||
cancellation_requests: [('id', 'INTEGER'), ('requested_at', 'TEXT'), ('requested_by', 'TEXT'), ('scope', 'TEXT'), ('scope_id', 'TEXT'), ('dispatch_id', 'INTEGER'), ('reason', 'TEXT'), ('status', 'TEXT'), ('acked_at', 'TEXT'), ('acked_worker_id', 'TEXT')]
|
||||
|
||||
command_queue: [('id', 'INTEGER'), ('target_worker', 'TEXT'), ('command', 'TEXT'), ('args_json', 'TEXT'), ('enqueued_at', 'TEXT'), ('claimed_at', 'TEXT'), ('claimed_by', 'TEXT'), ('completed_at', 'TEXT'), ('result_json', 'TEXT')]
|
||||
|
||||
runtime_kv: [('scope', 'TEXT'), ('scope_id', 'TEXT'), ('key', 'TEXT'), ('value_json', 'TEXT'), ('updated_at', 'TEXT')]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "18432e08-a9f0-4b64-8ab4-b6a7e4af54bc",
|
||||
"runtime": "bash",
|
||||
"purpose": "Check git status for code changes",
|
||||
"script_chars": 52,
|
||||
"started_at": "2026-05-13T06:49:30.218Z",
|
||||
"finished_at": "2026-05-13T06:49:30.408Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 190,
|
||||
"stdout_bytes": 127,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\18432e08-a9f0-4b64-8ab4-b6a7e4af54bc.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\18432e08-a9f0-4b64-8ab4-b6a7e4af54bc.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1 @@
|
|||
fatal: not a git repository: /mnt/c/Users/david/Work/wx-cli/.gsd/worktrees/M001/C:/Users/david/Work/wx-cli/.git/worktrees/M001
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "18cc4733-2dde-4985-b855-2ebf8720ac83",
|
||||
"runtime": "bash",
|
||||
"purpose": "cargo check for M001 verification",
|
||||
"script_chars": 80,
|
||||
"started_at": "2026-05-13T06:55:34.803Z",
|
||||
"finished_at": "2026-05-13T06:55:39.487Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 4684,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 151,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\18cc4733-2dde-4985-b855-2ebf8720ac83.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\18cc4733-2dde-4985-b855-2ebf8720ac83.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: /c/Users/david/Work/wx-cli/.gsd/worktrees/M001: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "1de5a18b-7aeb-4853-9e82-a7134825ff11",
|
||||
"runtime": "bash",
|
||||
"purpose": "detailed test failure output",
|
||||
"script_chars": 51,
|
||||
"started_at": "2026-05-13T07:36:18.984Z",
|
||||
"finished_at": "2026-05-13T07:36:36.791Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 17807,
|
||||
"stdout_bytes": 709,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\1de5a18b-7aeb-4853-9e82-a7134825ff11.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\1de5a18b-7aeb-4853-9e82-a7134825ff11.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- cli::transport::integration_tests::test_send_tcp_round_trip stdout ----
|
||||
|
||||
thread 'cli::transport::integration_tests::test_send_tcp_round_trip' (2039) panicked at src/cli/transport.rs:374:81:
|
||||
called `Result::unwrap()` on an `Err` value: 连接 TCP daemon (127.0.0.1:44697) 失败
|
||||
|
||||
Caused by:
|
||||
connection timed out
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
|
||||
failures:
|
||||
cli::transport::integration_tests::test_send_tcp_round_trip
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 37 filtered out; finished in 15.04s
|
||||
|
||||
error: test failed, to rerun pass `--bin wx`
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "1f0820e5-c1cb-4200-8751-0f6d00dd3321",
|
||||
"runtime": "bash",
|
||||
"purpose": "S02: Verify TCP artifacts in source code",
|
||||
"script_chars": 300,
|
||||
"started_at": "2026-05-13T06:12:57.539Z",
|
||||
"finished_at": "2026-05-13T06:13:57.561Z",
|
||||
"exit_code": null,
|
||||
"signal": "SIGKILL",
|
||||
"timed_out": true,
|
||||
"duration_ms": 60022,
|
||||
"stdout_bytes": 82,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\1f0820e5-c1cb-4200-8751-0f6d00dd3321.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\1f0820e5-c1cb-4200-8751-0f6d00dd3321.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
=== CLI tcp flag ===
|
||||
2
|
||||
=== send_tcp ===
|
||||
2
|
||||
=== is_alive_tcp ===
|
||||
2
|
||||
=== help tcp ===
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "214caeab-b507-4328-ba39-2afbca1e9292",
|
||||
"runtime": "bash",
|
||||
"purpose": "S02 planning: discover current TCP/server code state",
|
||||
"script_chars": 525,
|
||||
"started_at": "2026-05-13T05:59:58.550Z",
|
||||
"finished_at": "2026-05-13T06:00:00.807Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 2257,
|
||||
"stdout_bytes": 3234,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\214caeab-b507-4328-ba39-2afbca1e9292.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\214caeab-b507-4328-ba39-2afbca1e9292.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
=== Source tree structure ===
|
||||
./src/cli/contacts.rs
|
||||
./src/cli/daemon_cmd.rs
|
||||
./src/cli/export.rs
|
||||
./src/cli/favorites.rs
|
||||
./src/cli/history.rs
|
||||
./src/cli/init.rs
|
||||
./src/cli/members.rs
|
||||
./src/cli/mod.rs
|
||||
./src/cli/new_messages.rs
|
||||
./src/cli/output.rs
|
||||
./src/cli/search.rs
|
||||
./src/cli/sessions.rs
|
||||
./src/cli/sns_feed.rs
|
||||
./src/cli/sns_notifications.rs
|
||||
./src/cli/sns_search.rs
|
||||
./src/cli/stats.rs
|
||||
./src/cli/transport.rs
|
||||
./src/cli/unread.rs
|
||||
./src/config.rs
|
||||
./src/crypto/mod.rs
|
||||
./src/crypto/wal.rs
|
||||
./src/daemon/cache.rs
|
||||
./src/daemon/mod.rs
|
||||
./src/daemon/query.rs
|
||||
./src/daemon/server.rs
|
||||
./src/ipc.rs
|
||||
./src/main.rs
|
||||
./src/scanner/linux.rs
|
||||
./src/scanner/macos.rs
|
||||
./src/scanner/mod.rs
|
||||
./src/scanner/windows.rs
|
||||
./src/transport/mod.rs
|
||||
|
||||
=== Cargo.toml ===
|
||||
[package]
|
||||
name = "wx-cli"
|
||||
version = "0.1.10"
|
||||
edition = "2021"
|
||||
description = "WeChat 4.x (macOS/Linux) local data CLI — decrypt SQLCipher DBs, query chat history, watch new messages"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/jackwener/wx-cli"
|
||||
keywords = ["wechat", "sqlcipher", "decrypt", "cli"]
|
||||
categories = ["command-line-utilities"]
|
||||
readme = "README.md"
|
||||
|
||||
[[bin]]
|
||||
name = "wx"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
# CLI
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
|
||||
# 异步
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
# 序列化
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "=1.0.140"
|
||||
serde_yaml = "0.9"
|
||||
|
||||
# SQLite
|
||||
rusqlite = { version = "0.31", features = ["bundled"] }
|
||||
|
||||
# 加密
|
||||
aes = "0.8"
|
||||
cbc = { version = "0.1", features = ["alloc"] }
|
||||
hmac = "0.12"
|
||||
sha2 = "0.10"
|
||||
pbkdf2 = "0.12"
|
||||
|
||||
# 解压
|
||||
zstd = "0.13"
|
||||
|
||||
# 错误处理
|
||||
anyhow = "1"
|
||||
|
||||
# 时间
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
# 跨平台路径
|
||||
dirs = "5"
|
||||
|
||||
# MD5 (联系人表名 Msg_<md5>)
|
||||
md5 = "0.7"
|
||||
|
||||
# 正则表达式
|
||||
regex = "1"
|
||||
roxmltree = "0.20"
|
||||
|
||||
# IPC Windows named pipe(Unix 直接用 tokio::net::UnixListener)
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
interprocess = { version = "2", features = ["tokio"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows = { version = "0.58", features = [
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_Diagnostics_ToolHelp",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Foundation",
|
||||
"Win32_System_Memory",
|
||||
] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
strip = true
|
||||
|
||||
=== src/main.rs - CLI structure ===
|
||||
mod config;
|
||||
mod ipc;
|
||||
mod crypto;
|
||||
mod scanner;
|
||||
mod daemon;
|
||||
mod cli;
|
||||
pub mod transport;
|
||||
|
||||
fn main() {
|
||||
if std::env::var("WX_DAEMON_MODE").is_ok() {
|
||||
daemon::run();
|
||||
} else {
|
||||
cli::run();
|
||||
}
|
||||
}
|
||||
|
||||
=== src/daemon/ - all files ===
|
||||
total 112
|
||||
drwxrwxrwx 1 david david 4096 May 13 13:32 .
|
||||
drwxrwxrwx 1 david david 4096 May 13 13:44 ..
|
||||
-rwxrwxrwx 1 david david 7309 May 13 13:32 cache.rs
|
||||
-rwxrwxrwx 1 david david 6034 May 13 13:55 mod.rs
|
||||
-rwxrwxrwx 1 david david 91997 May 13 13:32 query.rs
|
||||
-rwxrwxrwx 1 david david 3820 May 13 13:55 server.rs
|
||||
|
||||
=== src/transport/ - all files ===
|
||||
total 12
|
||||
drwxrwxrwx 1 david david 4096 May 13 13:44 .
|
||||
drwxrwxrwx 1 david david 4096 May 13 13:44 ..
|
||||
-rwxrwxrwx 1 david david 9555 May 13 13:45 mod.rs
|
||||
|
||||
=== src/lib.rs ===
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "2233059d-9bc0-48ce-9405-134324fc7753",
|
||||
"runtime": "python",
|
||||
"purpose": "complete S04 tasks via Python sqlite3",
|
||||
"script_chars": 698,
|
||||
"started_at": "2026-05-13T07:43:07.197Z",
|
||||
"finished_at": "2026-05-13T07:43:07.540Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 343,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 364,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2233059d-9bc0-48ce-9405-134324fc7753.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2233059d-9bc0-48ce-9405-134324fc7753.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Traceback (most recent call last):
|
||||
File "<string>", line 9, in <module>
|
||||
cur.execute("SELECT task_id, status FROM tasks WHERE milestone_id = 'M001' AND slice_id = 'S04' ORDER BY task_id")
|
||||
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
sqlite3.OperationalError: no such table: tasks
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "2514da35-7c9b-4c12-9fa0-a0d706019ff1",
|
||||
"runtime": "bash",
|
||||
"purpose": "cargo test M001",
|
||||
"script_chars": 88,
|
||||
"started_at": "2026-05-13T06:56:15.570Z",
|
||||
"finished_at": "2026-05-13T06:56:35.757Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 20187,
|
||||
"stdout_bytes": 1350,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2514da35-7c9b-4c12-9fa0-a0d706019ff1.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2514da35-7c9b-4c12-9fa0-a0d706019ff1.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
test transport::tests::tcp_connector_rejects_non_tcp_addr ... ok
|
||||
test transport::tests::tcp_listener_implements_listener ... ok
|
||||
test transport::tests::transport_addr_variants ... ok
|
||||
test scanner::tests::test_read_db_salt_nonexistent ... ok
|
||||
test scanner::tests::test_collect_db_salts_recursive ... ok
|
||||
test scanner::tests::test_collect_db_salts_finds_encrypted ... ok
|
||||
test scanner::tests::test_collect_db_salts_skips_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_collect_db_salts_multiple_files_unique_salts ... ok
|
||||
test scanner::tests::test_collect_db_salts_ignores_non_db_extensions ... ok
|
||||
test scanner::tests::test_collect_db_salts_empty_dir ... ok
|
||||
test scanner::tests::test_read_db_salt_encrypted ... ok
|
||||
test scanner::tests::test_read_db_salt_exactly_16_bytes ... ok
|
||||
test scanner::tests::test_read_db_salt_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_read_db_salt_too_short ... ok
|
||||
test cli::transport::integration_tests::test_is_alive_tcp_false ... ok
|
||||
test cli::transport::integration_tests::test_send_tcp_connection_refused ... ok
|
||||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
test cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip ... FAILED
|
||||
test result: FAILED. 35 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 17.64s
|
||||
error: test failed, to rerun pass `--bin wx`
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "286d4d17-d5ff-4f5d-a267-9640361f3f55",
|
||||
"runtime": "bash",
|
||||
"purpose": "S04 cargo test verification",
|
||||
"script_chars": 83,
|
||||
"started_at": "2026-05-13T06:41:23.492Z",
|
||||
"finished_at": "2026-05-13T06:42:23.172Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 59680,
|
||||
"stdout_bytes": 2799,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\286d4d17-d5ff-4f5d-a267-9640361f3f55.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\286d4d17-d5ff-4f5d-a267-9640361f3f55.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
running 38 tests
|
||||
test daemon::query::sns_tests::escape_like_pattern_combined ... ok
|
||||
test daemon::query::sns_tests::escape_like_pattern_no_special_chars_unchanged ... ok
|
||||
test daemon::query::sns_tests::escape_like_pattern_escapes_backslash_first ... ok
|
||||
test cli::transport::tcp_integration_tests::test_tcp_daemon_connection_refused ... ok
|
||||
test daemon::query::sns_tests::parse_decodes_xml_entities_in_content ... ok
|
||||
test daemon::query::sns_tests::parse_when_both_column_and_xml_username_empty_returns_empty_author ... ok
|
||||
test daemon::query::sns_tests::parse_malformed_xml_falls_back_to_string_fields_when_column_present ... ok
|
||||
test daemon::query::sns_tests::parse_malformed_xml_can_still_use_xml_username_when_column_empty ... ok
|
||||
test daemon::query::sns_tests::single_image_media ... ok
|
||||
test daemon::query::sns_tests::parse_without_timeline_object_falls_back_to_string_fields ... ok
|
||||
test daemon::query::sns_tests::parse_handles_missing_create_time ... ok
|
||||
test daemon::query::sns_tests::malformed_xml ... ok
|
||||
test daemon::query::sns_tests::parse_counts_media_and_extracts_location ... ok
|
||||
test daemon::query::sns_tests::parse_falls_back_to_xml_username_when_column_empty ... ok
|
||||
test daemon::query::sns_tests::parse_uses_user_name_column_when_present ... ok
|
||||
test daemon::query::sns_tests::size_without_total_size_omits_total_size_key ... ok
|
||||
test daemon::query::sns_tests::text_only_post ... ok
|
||||
test daemon::query::sns_tests::video_media ... ok
|
||||
test daemon::query::sns_tests::three_images_media ... ok
|
||||
test transport::tests::tcp_connector_rejects_non_tcp_addr ... ok
|
||||
test transport::tests::tcp_listener_implements_listener ... ok
|
||||
test scanner::tests::test_read_db_salt_nonexistent ... ok
|
||||
test transport::tests::transport_addr_variants ... ok
|
||||
test scanner::tests::test_collect_db_salts_empty_dir ... ok
|
||||
test scanner::tests::test_collect_db_salts_skips_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_read_db_salt_plaintext_sqlite ... ok
|
||||
test scanner::tests::test_collect_db_salts_recursive ... ok
|
||||
test scanner::tests::test_collect_db_salts_ignores_non_db_extensions ... ok
|
||||
test scanner::tests::test_collect_db_salts_multiple_files_unique_salts ... ok
|
||||
test scanner::tests::test_collect_db_salts_finds_encrypted ... ok
|
||||
test scanner::tests::test_read_db_salt_encrypted ... ok
|
||||
test scanner::tests::test_read_db_salt_exactly_16_bytes ... ok
|
||||
test scanner::tests::test_read_db_salt_too_short ... ok
|
||||
test cli::transport::integration_tests::test_send_tcp_connection_refused ... ok
|
||||
test cli::transport::integration_tests::test_is_alive_tcp_false ... ok
|
||||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
test cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip ... FAILED
|
||||
test result: FAILED. 35 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 44.87s
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "2d28cbe5-beec-4484-828e-b252af093f44",
|
||||
"runtime": "bash",
|
||||
"purpose": "Run specific TCP integration test to diagnose failures",
|
||||
"script_chars": 101,
|
||||
"started_at": "2026-05-13T06:52:13.464Z",
|
||||
"finished_at": "2026-05-13T06:52:39.855Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 26391,
|
||||
"stdout_bytes": 721,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2d28cbe5-beec-4484-828e-b252af093f44.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\2d28cbe5-beec-4484-828e-b252af093f44.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Running unittests src/main.rs (target/debug/deps/wx-485d0482e3ff8755)
|
||||
|
||||
running 1 test
|
||||
|
||||
thread 'cli::transport::integration_tests::test_send_tcp_round_trip' (1760) panicked at src/cli/transport.rs:374:81:
|
||||
called `Result::unwrap()` on an `Err` value: 连接 TCP daemon (127.0.0.1:45285) 失败
|
||||
|
||||
Caused by:
|
||||
connection timed out
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
failures:
|
||||
cli::transport::integration_tests::test_send_tcp_round_trip
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 37 filtered out; finished in 15.03s
|
||||
|
||||
error: test failed, to rerun pass `--bin wx`
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "33e558f3-ad48-4013-b04e-cebb9c2ae2ef",
|
||||
"runtime": "bash",
|
||||
"purpose": "cargo check native + test",
|
||||
"script_chars": 148,
|
||||
"started_at": "2026-05-13T07:35:05.489Z",
|
||||
"finished_at": "2026-05-13T07:35:14.673Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 9184,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 131,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\33e558f3-ad48-4013-b04e-cebb9c2ae2ef.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\33e558f3-ad48-4013-b04e-cebb9c2ae2ef.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: /c/Users/david/Work/wx-cli: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "3a425359-7ce1-4dcb-bd25-edff25d28f47",
|
||||
"runtime": "bash",
|
||||
"purpose": "Check for integration test infrastructure",
|
||||
"script_chars": 314,
|
||||
"started_at": "2026-05-13T06:19:43.644Z",
|
||||
"finished_at": "2026-05-13T06:19:51.740Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 8096,
|
||||
"stdout_bytes": 1752,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\3a425359-7ce1-4dcb-bd25-edff25d28f47.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\3a425359-7ce1-4dcb-bd25-edff25d28f47.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
=== TESTS DIR ===
|
||||
=== INTEGRATION TESTS ===
|
||||
=== Cargo.toml ===
|
||||
[package]
|
||||
name = "wx-cli"
|
||||
version = "0.1.10"
|
||||
edition = "2021"
|
||||
description = "WeChat 4.x (macOS/Linux) local data CLI — decrypt SQLCipher DBs, query chat history, watch new messages"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/jackwener/wx-cli"
|
||||
keywords = ["wechat", "sqlcipher", "decrypt", "cli"]
|
||||
categories = ["command-line-utilities"]
|
||||
readme = "README.md"
|
||||
|
||||
[[bin]]
|
||||
name = "wx"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
# CLI
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
|
||||
# 异步
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
# 序列化
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "=1.0.140"
|
||||
serde_yaml = "0.9"
|
||||
|
||||
# SQLite
|
||||
rusqlite = { version = "0.31", features = ["bundled"] }
|
||||
|
||||
# 加密
|
||||
aes = "0.8"
|
||||
cbc = { version = "0.1", features = ["alloc"] }
|
||||
hmac = "0.12"
|
||||
sha2 = "0.10"
|
||||
pbkdf2 = "0.12"
|
||||
|
||||
# 解压
|
||||
zstd = "0.13"
|
||||
|
||||
# 错误处理
|
||||
anyhow = "1"
|
||||
|
||||
# 时间
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
# 跨平台路径
|
||||
dirs = "5"
|
||||
|
||||
# MD5 (联系人表名 Msg_<md5>)
|
||||
md5 = "0.7"
|
||||
|
||||
# 正则表达式
|
||||
regex = "1"
|
||||
roxmltree = "0.20"
|
||||
|
||||
# IPC Windows named pipe(Unix 直接用 tokio::net::UnixListener)
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
interprocess = { version = "2", features = ["tokio"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows = { version = "0.58", features = [
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_Diagnostics_ToolHelp",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Foundation",
|
||||
"Win32_System_Memory",
|
||||
] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
strip = true
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "3c257b4d-cb10-4f2f-805f-9c6f8899a3eb",
|
||||
"runtime": "bash",
|
||||
"purpose": "Search for S03-PLAN.md across project",
|
||||
"script_chars": 116,
|
||||
"started_at": "2026-05-13T06:21:52.251Z",
|
||||
"finished_at": "2026-05-13T06:22:00.307Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 8056,
|
||||
"stdout_bytes": 196,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\3c257b4d-cb10-4f2f-805f-9c6f8899a3eb.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\3c257b4d-cb10-4f2f-805f-9c6f8899a3eb.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
./.gsd/milestones/M001/slices/S03/S03-PLAN.md
|
||||
./.gsd/milestones/M001/slices/S03/S03-PLAN.md
|
||||
./.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md
|
||||
./.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "42ff4777-311e-454a-9214-d94324c9a8bc",
|
||||
"runtime": "node",
|
||||
"purpose": "complete S04 tasks T01 and T02 in DB",
|
||||
"script_chars": 642,
|
||||
"started_at": "2026-05-13T07:42:52.320Z",
|
||||
"finished_at": "2026-05-13T07:42:52.382Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 62,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 929,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\42ff4777-311e-454a-9214-d94324c9a8bc.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\42ff4777-311e-454a-9214-d94324c9a8bc.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
node:internal/modules/cjs/loader:1423
|
||||
throw err;
|
||||
^
|
||||
|
||||
Error: Cannot find module 'better-sqlite3'
|
||||
Require stack:
|
||||
- C:\Users\david\Work\wx-cli\.gsd\worktrees\M001\[eval]
|
||||
at Module._resolveFilename (node:internal/modules/cjs/loader:1420:15)
|
||||
at defaultResolveImpl (node:internal/modules/cjs/loader:1058:19)
|
||||
at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1063:22)
|
||||
at Module._load (node:internal/modules/cjs/loader:1226:37)
|
||||
at TracingChannel.traceSync (node:diagnostics_channel:328:14)
|
||||
at wrapModuleLoad (node:internal/modules/cjs/loader:244:24)
|
||||
at Module.require (node:internal/modules/cjs/loader:1503:12)
|
||||
at require (node:internal/modules/helpers:152:16)
|
||||
at [eval]:1:18
|
||||
at runScriptInThisContext (node:internal/vm:219:10) {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
requireStack: [ 'C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\[eval]' ]
|
||||
}
|
||||
|
||||
Node.js v24.11.0
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "437fc922-2f8c-49ad-8bfa-787e7722704c",
|
||||
"runtime": "bash",
|
||||
"purpose": "Cargo check native",
|
||||
"script_chars": 26,
|
||||
"started_at": "2026-05-13T06:49:30.233Z",
|
||||
"finished_at": "2026-05-13T06:49:33.116Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 2883,
|
||||
"stdout_bytes": 265,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\437fc922-2f8c-49ad-8bfa-787e7722704c.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\437fc922-2f8c-49ad-8bfa-787e7722704c.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
|
||||
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: `wx-cli` (bin "wx") generated 1 warning (run `cargo fix --bin "wx" -p wx-cli` to apply 1 suggestion)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.56s
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "4d05e008-44d0-4e6e-8f10-d02f90e1265c",
|
||||
"runtime": "python",
|
||||
"purpose": "complete S04 tasks in real GSD DB",
|
||||
"script_chars": 671,
|
||||
"started_at": "2026-05-13T07:43:27.532Z",
|
||||
"finished_at": "2026-05-13T07:43:27.744Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 212,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 367,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\4d05e008-44d0-4e6e-8f10-d02f90e1265c.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\4d05e008-44d0-4e6e-8f10-d02f90e1265c.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Traceback (most recent call last):
|
||||
File "<string>", line 7, in <module>
|
||||
cur.execute("SELECT task_id, status FROM tasks WHERE milestone_id = 'M001' AND slice_id = 'S04' ORDER BY task_id")
|
||||
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
sqlite3.OperationalError: no such column: task_id
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "525fbf54-b472-4505-bf33-96e7aee351c8",
|
||||
"runtime": "bash",
|
||||
"purpose": "S04 cargo check verification",
|
||||
"script_chars": 80,
|
||||
"started_at": "2026-05-13T06:40:35.710Z",
|
||||
"finished_at": "2026-05-13T06:40:45.658Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 9948,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 151,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\525fbf54-b472-4505-bf33-96e7aee351c8.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\525fbf54-b472-4505-bf33-96e7aee351c8.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: C:/Users/david/Work/wx-cli/.gsd/worktrees/M001: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "559a734a-164d-4111-a1a9-3b1122cfea02",
|
||||
"runtime": "bash",
|
||||
"purpose": "Find existing tests and verify structure",
|
||||
"script_chars": 261,
|
||||
"started_at": "2026-05-13T06:18:41.973Z",
|
||||
"finished_at": "2026-05-13T06:18:47.960Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 5987,
|
||||
"stdout_bytes": 3046,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\559a734a-164d-4111-a1a9-3b1122cfea02.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\559a734a-164d-4111-a1a9-3b1122cfea02.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
=== TESTS ===
|
||||
src/daemon/query.rs:2025: #[test]
|
||||
src/daemon/query.rs:2036: #[test]
|
||||
src/daemon/query.rs:2043: #[test]
|
||||
src/daemon/query.rs:2051: #[test]
|
||||
src/daemon/query.rs:2059: #[test]
|
||||
src/daemon/query.rs:2066: #[test]
|
||||
src/daemon/query.rs:2076: #[test]
|
||||
src/daemon/query.rs:2087: #[test]
|
||||
src/daemon/query.rs:2097: #[test]
|
||||
src/daemon/query.rs:2107: #[test]
|
||||
src/daemon/query.rs:2115: #[test]
|
||||
src/daemon/query.rs:2122: #[test]
|
||||
src/daemon/query.rs:2133: #[test]
|
||||
src/daemon/query.rs:2183: #[test]
|
||||
src/daemon/query.rs:2238: #[test]
|
||||
src/daemon/query.rs:2271: #[test]
|
||||
src/daemon/query.rs:2296: #[test]
|
||||
src/daemon/query.rs:2314: #[test]
|
||||
src/scanner/macos.rs:321: #[test]
|
||||
src/scanner/macos.rs:328: #[test]
|
||||
src/scanner/macos.rs:335: #[test]
|
||||
src/scanner/macos.rs:347: #[test]
|
||||
src/scanner/macos.rs:360: #[test]
|
||||
src/scanner/macos.rs:372: #[test]
|
||||
src/scanner/macos.rs:383: #[test]
|
||||
src/scanner/macos.rs:396: #[test]
|
||||
src/scanner/macos.rs:411: #[test]
|
||||
src/scanner/macos.rs:424: #[test]
|
||||
src/scanner/macos.rs:433: #[test]
|
||||
src/scanner/macos.rs:440: #[test]
|
||||
=== HELP ===
|
||||
sessions 列出最近会话
|
||||
history 查看聊天记录
|
||||
search 搜索消息
|
||||
contacts 查看联系人
|
||||
export 导出聊天记录到文件
|
||||
unread 显示有未读消息的会话
|
||||
members 查看群成员
|
||||
new-messages 获取自上次检查以来的新消息
|
||||
stats 聊天统计分析
|
||||
favorites 查看微信收藏内容
|
||||
sns-notifications 朋友圈互动通知:别人对我的朋友圈点赞/评论 + 我评过的帖子下的跟帖
|
||||
sns-feed 朋友圈时间线:按时间/作者筛选本地缓存的朋友圈
|
||||
sns-search 朋友圈全文搜索:匹配正文关键词
|
||||
daemon 管理 wx-daemon
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
--tcp <TCP> 通过 TCP 连接 daemon(如 127.0.0.1:9876)
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
=== DAEMON HELP ===
|
||||
warning: unused config key `net.timeout` in `/mnt/c/Users/david/.cargo/config.toml`
|
||||
warning: unused config key `http.low-speed-timeout` in `/mnt/c/Users/david/.cargo/config.toml`
|
||||
warning: unused import: `bail`
|
||||
--> src/scanner/linux.rs:6:14
|
||||
|
|
||||
6 | use anyhow::{bail, Context, Result};
|
||||
| ^^^^
|
||||
|
|
||||
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: `wx-cli` (bin "wx") generated 1 warning (run `cargo fix --bin "wx" -p wx-cli` to apply 1 suggestion)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.66s
|
||||
Running `target/debug/wx daemon --help`
|
||||
管理 wx-daemon
|
||||
|
||||
Usage: wx daemon <COMMAND>
|
||||
|
||||
Commands:
|
||||
status 查看 daemon 运行状态
|
||||
stop 停止 daemon
|
||||
logs 查看 daemon 日志
|
||||
start 启动 daemon
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-h, --help Print help
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "63ae12c6-b02a-4a08-8c32-4a95f9c18277",
|
||||
"runtime": "bash",
|
||||
"purpose": "Cross-platform cargo check for M001",
|
||||
"script_chars": 91,
|
||||
"started_at": "2026-05-13T06:49:07.532Z",
|
||||
"finished_at": "2026-05-13T06:49:16.843Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 9311,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 131,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\63ae12c6-b02a-4a08-8c32-4a95f9c18277.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\63ae12c6-b02a-4a08-8c32-4a95f9c18277.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: /c/Users/david/Work/wx-cli: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "6cccd1a7-3213-4b38-8485-360363fda36d",
|
||||
"runtime": "bash",
|
||||
"purpose": "Verify code changes for M001",
|
||||
"script_chars": 105,
|
||||
"started_at": "2026-05-13T06:54:57.512Z",
|
||||
"finished_at": "2026-05-13T06:55:05.803Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 8291,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 151,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\6cccd1a7-3213-4b38-8485-360363fda36d.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\6cccd1a7-3213-4b38-8485-360363fda36d.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: /c/Users/david/Work/wx-cli/.gsd/worktrees/M001: No such file or directory
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "75341ebb-ee4a-475f-b5be-53d0b3ab4378",
|
||||
"runtime": "bash",
|
||||
"purpose": "Cross-compile check Windows MSVC",
|
||||
"script_chars": 58,
|
||||
"started_at": "2026-05-13T06:49:43.870Z",
|
||||
"finished_at": "2026-05-13T06:49:57.396Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 13526,
|
||||
"stdout_bytes": 101,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\75341ebb-ee4a-475f-b5be-53d0b3ab4378.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\75341ebb-ee4a-475f-b5be-53d0b3ab4378.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
|
||||
error occurred in cc-rs: failed to find tool "lib.exe": No such file or directory (os error 2)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "77841434-4f83-4fc3-91fb-deb947c85254",
|
||||
"runtime": "bash",
|
||||
"purpose": "cargo check native",
|
||||
"script_chars": 26,
|
||||
"started_at": "2026-05-13T07:35:23.203Z",
|
||||
"finished_at": "2026-05-13T07:35:26.124Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 2921,
|
||||
"stdout_bytes": 265,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\77841434-4f83-4fc3-91fb-deb947c85254.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\77841434-4f83-4fc3-91fb-deb947c85254.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
|
||||
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: `wx-cli` (bin "wx") generated 1 warning (run `cargo fix --bin "wx" -p wx-cli` to apply 1 suggestion)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.68s
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "78fe28ad-d3c6-4749-b693-592c4626e094",
|
||||
"runtime": "bash",
|
||||
"purpose": "cargo test",
|
||||
"script_chars": 85,
|
||||
"started_at": "2026-05-13T07:35:29.565Z",
|
||||
"finished_at": "2026-05-13T07:35:50.015Z",
|
||||
"exit_code": 0,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 20450,
|
||||
"stdout_bytes": 280,
|
||||
"stderr_bytes": 54,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\78fe28ad-d3c6-4749-b693-592c4626e094.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\78fe28ad-d3c6-4749-b693-592c4626e094.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
running 38 tests
|
||||
test cli::transport::integration_tests::test_send_tcp_round_trip ... FAILED
|
||||
test cli::transport::tcp_integration_tests::test_tcp_daemon_ping_round_trip ... FAILED
|
||||
test result: FAILED. 35 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 17.71s
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "7c923504-de4d-4a8a-88b8-dd41896a0ed8",
|
||||
"runtime": "bash",
|
||||
"purpose": "S02 verification: cargo check, Windows check, cargo test",
|
||||
"script_chars": 249,
|
||||
"started_at": "2026-05-13T06:11:55.699Z",
|
||||
"finished_at": "2026-05-13T06:11:55.880Z",
|
||||
"exit_code": 1,
|
||||
"signal": null,
|
||||
"timed_out": false,
|
||||
"duration_ms": 181,
|
||||
"stdout_bytes": 0,
|
||||
"stderr_bytes": 151,
|
||||
"stdout_truncated": false,
|
||||
"stderr_truncated": false,
|
||||
"stdout_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\7c923504-de4d-4a8a-88b8-dd41896a0ed8.stdout",
|
||||
"stderr_path": "C:\\Users\\david\\Work\\wx-cli\\.gsd\\worktrees\\M001\\.gsd\\exec\\7c923504-de4d-4a8a-88b8-dd41896a0ed8.stderr"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wsl: Failed to mount E:\, see dmesg for more details.
|
||||
/bin/bash: line 1: cd: C:/Users/david/Work/wx-cli/.gsd/worktrees/M001: No such file or directory
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue