weishu
e5a8212f4a
feat(session): validate agents and browse workspace directories
2026-08-25 16:12:29 +08:00
weishu
3510a0f4f1
fix(ios): Linux compile + full package test round — fixtures green locally (A-CI-local)
...
ios/scripts/linux-test.sh stages HapiKit + shared/fixtures at repo depth
into a persistent tmp dir and runs swift test in swift:6.1-noble; the
manifest drops HapiUI (SwiftUI/swift-markdown/Highlightr) under
#if os(Linux). 458 tests green, including all 48 chat and 11 pagination
golden fixtures.
Fixes that fell out of the first real compile of the blind-written port:
- ChatTypes.CodexReview.wireValue + SummaryPatching legacy id fallback:
split expressions that exceeded the Swift 6 type-checker budget
- FileEndpointsTests: raw string containing "# terminated the literal
early (never compiled anywhere) — now ##-delimited
- SSEClient.backoffSleep: Task { try? ... } inferred Task<()?, Never>
- Darwin gates: Security/Keychain behind canImport(Security) (tests use
InMemoryCredentialStore via CredentialStoring), CryptoKit digest with
FNV-1a filename fallback, FoundationNetworking imports for URLSession
types, corelibs URLCache diskPath: initializer, get-only
waitsForConnectivity, delegate-based SSE transport where
URLSession.bytes(for:) does not exist
2026-08-18 11:51:57 +08:00
weishu
05d063cc33
feat(ios): composer attachments + dictation (A-M3f)
...
Attachments (Android B-M3f semantics ported verbatim):
- HapiClient/Attachments/AttachmentPolicy — pure plan matrix (>4 MB
recompressible image -> 2048 px JPEG q85 with .jpg rename, 50 MB hard
reject, 192 MB image read cap, 512 px q80 previewUrl data-URL thumbs,
data-URL parse/round-trip).
- HapiClient/Attachments/ComposerAttachments — upload-on-pick tray over an
AttachmentUploading seam (APIClient conforms): uploading/ready/failed
chips, retained payload for retry, remove -> best-effort delete,
mid-upload removal deletes the orphan on completion, consume() ->
AttachmentMetadata with JPEG data-URL previewUrl, discardAllDetached +
deinit orphan cleanup (Android onCleared analogue).
- ChatInteractor: tray ownership, unsettled chips refuse the send with a
notice, attachments-only sends post empty text, optimistic rows carry
the metadata, appendDictatedText/postNotice/discardAttachments.
- App: AttachmentPreparer (capped security-scoped reads, ImageIO
downscale/encode with EXIF transform, HEIC-undecodable fallback),
PhotosPicker multi (videos via FileRepresentation temp files),
UIImagePickerController camera capture, fileImporter; composer chip row
(thumb/spinner/tap-to-retry/remove) with attachment-aware send gating;
user bubbles upgrade chips to off-main-decoded previewUrl thumbnails
(web-sent attachments included).
Dictation (Android B-M3ce port):
- HapiProtocol/Models/VoiceApi — TranscriptionResponse,
TranscriptionProvidersResponse, TranscriptionProviderInfo.
- HapiClient/Endpoints/VoiceEndpoints — GET
/api/voice/transcription/providers + multipart POST
/api/voice/transcription (file/provider/mode/language, Android part
order) over MultipartFormData; DictationTranscribing conformance.
- HapiClient/Voice/DictationController — idle/starting/recording/
transcribing, transcribed/noProvider/error events, provider memoized
(first standard-capable entry), appendTranscript port.
- App: AVAudioRecorderDictation (m4a/AAC mono 44.1 kHz 96 kbps, session
activate/deactivate), mic button + recording chip (elapsed + cancel),
record-permission request via AVAudioApplication.
Info.plist gains NSMicrophoneUsageDescription; the camera string now
covers attachment capture (modern PhotosPicker needs no photo-library
permission). Tests: policy matrix, tray over the real client with exact
base64 upload bodies + gated in-flight scenarios, dictation controller
suite with fake recorder/transport, voice endpoint request shapes, and
the interactor attachment-send matrix transcribed from the Android VM
tests (wire bodies byte-for-byte).
2026-08-18 11:27:28 +08:00
weishu
fa91f06662
feat(ios): new session flow (A-M3c)
...
Port of the tested Android NEW SESSION reference (B-M3d) to iOS:
- HapiProtocol: NewSessionCatalogs (static claude models/efforts + codex
reasoning-effort fallback, exact Android data) in Catalog/; CodexModelSummary
+ CodexModelsResponse wire types (shared/src/apiTypes.ts).
- HapiClient: machineCodexModels endpoint (GET /api/machines/:id/codex-models,
rpc_target_missing surfaces as APIError); NewSession/NewSessionForm.swift —
typed Codable draft (tolerant decode) + NewSessionLogic: exact spawn body
per SpawnSessionRequestSchema (yolo incl. false for non-grok/non-codex-family,
permissionMode incl. 'default' for grok+codex-family, sessionType always,
trimmed-or-absent worktreeName, serviceTier only while fast tier visible,
collaborationMode only when plan, model only claude/codex), parent-path
derivation, suggestion filtering, recent-path LRU(8), worktree-name
validation, codex catalog helpers, draft sanitization.
- App: Features/NewSession (NewSessionModel @Observable orchestration —
machine preselect last-used, 250 ms debounced list-directory autocomplete
with per-parent cache, exists probe with worktree-blocking / simple
two-tap-create, codex catalog fetch + selection reconcile, UserDefaults
draft/prefs per hub; NewSessionView Form UI with per-flavor option matrix);
session-list "+" toolbar button on HomeView presents the sheet, success
dismisses and pushes the chat.
- Tests: spawn-body exactness (4 configs, canonical JSON), parent query,
suggestions, LRU, worktree validation, fast-tier detection, reasoning-effort
normalization, draft sanitize + tolerant decode; codex-models endpoint
request/error construction.
2026-08-18 10:03:05 +08:00
weishu
1f0ec6184d
feat(ios): HapiClient API transport + auth (A-M1b)
...
APIClient (final class, Sendable) with typed endpoints for the M2/M3 REST
surface behind an HTTPPerforming seam; actor AuthManager with single-flight
JWT refresh (POST /api/auth), proactive refresh 10 min before exp, terminal
authFailed state, and 401 -> refresh -> retry-once wiring per
docs/api/client-contract/auth.md; Keychain credential store (per-hub records
under run.hapi.companion) with CredentialStoring seam + in-memory double;
HubRegistry (ordered hubs + active hub in injectable UserDefaults, origin
normalization); payload-only JWT decoding; APIError {status, code, body}
parsing per errors.md; minimal multipart builder for M4c dictation; 256 MB
URLCache session for generated images.
Request/response wire models (SendMessageRequest, PermissionApproveRequest,
SpawnRequest/SpawnResponse, MessagesQuery, envelopes, RPC-wrapped shapes)
join HapiProtocol/Models mirroring shared/src/apiTypes.ts.
swift-testing coverage: JWT decode (padding/garbage/hostile exp), auth
single-flight (8 concurrent callers -> one exchange), 401 retry-once and
terminal paths, APIError body parsing, endpoint request construction
byte-checks (cursor queries, deliveryMode body, answers formats, explicit
null model reset) via a recording performer, hub URL normalization,
multipart bytes.
2026-08-17 15:20:03 +08:00