@sumicom/quicksave 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +31 -93
- package/dist/ai/asyncQueue.d.ts.map +1 -1
- package/dist/ai/asyncQueue.js +2 -0
- package/dist/ai/asyncQueue.js.map +1 -1
- package/dist/ai/attachmentStaging.d.ts +71 -0
- package/dist/ai/attachmentStaging.d.ts.map +1 -0
- package/dist/ai/attachmentStaging.js +243 -0
- package/dist/ai/attachmentStaging.js.map +1 -0
- package/dist/ai/attachmentStore.d.ts +40 -0
- package/dist/ai/attachmentStore.d.ts.map +1 -0
- package/dist/ai/attachmentStore.js +173 -0
- package/dist/ai/attachmentStore.js.map +1 -0
- package/dist/ai/cardBuilder.d.ts +6 -6
- package/dist/ai/cardBuilder.d.ts.map +1 -1
- package/dist/ai/cardBuilder.js +164 -16
- package/dist/ai/cardBuilder.js.map +1 -1
- package/dist/ai/claudeCliProvider.d.ts +34 -15
- package/dist/ai/claudeCliProvider.d.ts.map +1 -1
- package/dist/ai/claudeCliProvider.js +108 -64
- package/dist/ai/claudeCliProvider.js.map +1 -1
- package/dist/ai/claudeCodeProvider.d.ts.map +1 -1
- package/dist/ai/claudeCodeProvider.js +2 -0
- package/dist/ai/claudeCodeProvider.js.map +1 -1
- package/dist/ai/claudeSdkProvider.d.ts +6 -3
- package/dist/ai/claudeSdkProvider.d.ts.map +1 -1
- package/dist/ai/claudeSdkProvider.js +97 -29
- package/dist/ai/claudeSdkProvider.js.map +1 -1
- package/dist/ai/codexAppServer/approvalMapping.d.ts.map +1 -1
- package/dist/ai/codexAppServer/approvalMapping.js.map +1 -1
- package/dist/ai/codexAppServer/cardAdapter.d.ts +0 -3
- package/dist/ai/codexAppServer/cardAdapter.d.ts.map +1 -1
- package/dist/ai/codexAppServer/cardAdapter.js +40 -5
- package/dist/ai/codexAppServer/cardAdapter.js.map +1 -1
- package/dist/ai/codexAppServer/index.d.ts.map +1 -1
- package/dist/ai/codexAppServer/index.js +2 -0
- package/dist/ai/codexAppServer/index.js.map +1 -1
- package/dist/ai/codexAppServer/overrideStore.d.ts.map +1 -1
- package/dist/ai/codexAppServer/overrideStore.js.map +1 -1
- package/dist/ai/codexAppServer/permissionMapping.d.ts.map +1 -1
- package/dist/ai/codexAppServer/permissionMapping.js.map +1 -1
- package/dist/ai/codexAppServer/processManager.d.ts.map +1 -1
- package/dist/ai/codexAppServer/processManager.js +2 -0
- package/dist/ai/codexAppServer/processManager.js.map +1 -1
- package/dist/ai/codexAppServer/provider.d.ts.map +1 -1
- package/dist/ai/codexAppServer/provider.js +9 -24
- package/dist/ai/codexAppServer/provider.js.map +1 -1
- package/dist/ai/codexAppServer/rpcClient.d.ts.map +1 -1
- package/dist/ai/codexAppServer/rpcClient.js.map +1 -1
- package/dist/ai/codexAppServer/schema/index.d.ts.map +1 -1
- package/dist/ai/codexAppServer/schema/index.js +2 -0
- package/dist/ai/codexAppServer/schema/index.js.map +1 -1
- package/dist/ai/codexAppServer/stdioTransport.d.ts.map +1 -1
- package/dist/ai/codexAppServer/stdioTransport.js.map +1 -1
- package/dist/ai/codexAppServer/tokenAccounting.d.ts.map +1 -1
- package/dist/ai/codexAppServer/tokenAccounting.js.map +1 -1
- package/dist/ai/codexAppServer/version.d.ts.map +1 -1
- package/dist/ai/codexAppServer/version.js +2 -0
- package/dist/ai/codexAppServer/version.js.map +1 -1
- package/dist/ai/codexLogin.d.ts.map +1 -1
- package/dist/ai/codexLogin.js +2 -0
- package/dist/ai/codexLogin.js.map +1 -1
- package/dist/ai/codexMcpProvider.d.ts.map +1 -1
- package/dist/ai/codexMcpProvider.js +7 -10
- package/dist/ai/codexMcpProvider.js.map +1 -1
- package/dist/ai/commitSummary.d.ts.map +1 -1
- package/dist/ai/commitSummary.js +2 -0
- package/dist/ai/commitSummary.js.map +1 -1
- package/dist/ai/commitSummaryCli.d.ts.map +1 -1
- package/dist/ai/commitSummaryCli.js +2 -0
- package/dist/ai/commitSummaryCli.js.map +1 -1
- package/dist/ai/commitSummaryStore.d.ts.map +1 -1
- package/dist/ai/commitSummaryStore.js +2 -0
- package/dist/ai/commitSummaryStore.js.map +1 -1
- package/dist/ai/contentBlocks.d.ts +9 -0
- package/dist/ai/contentBlocks.d.ts.map +1 -0
- package/dist/ai/contentBlocks.js +86 -0
- package/dist/ai/contentBlocks.js.map +1 -0
- package/dist/ai/debugLogger.d.ts.map +1 -1
- package/dist/ai/debugLogger.js +2 -0
- package/dist/ai/debugLogger.js.map +1 -1
- package/dist/ai/enrichEntry.d.ts.map +1 -1
- package/dist/ai/enrichEntry.js.map +1 -1
- package/dist/ai/pdfMeta.d.ts +8 -0
- package/dist/ai/pdfMeta.d.ts.map +1 -0
- package/dist/ai/pdfMeta.js +51 -0
- package/dist/ai/pdfMeta.js.map +1 -0
- package/dist/ai/provider.d.ts +21 -8
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js.map +1 -1
- package/dist/ai/sandboxMcp.d.ts.map +1 -1
- package/dist/ai/sandboxMcp.js +2 -0
- package/dist/ai/sandboxMcp.js.map +1 -1
- package/dist/ai/sandboxMcpStdio.d.ts.map +1 -1
- package/dist/ai/sandboxMcpStdio.js +2 -0
- package/dist/ai/sandboxMcpStdio.js.map +1 -1
- package/dist/ai/sessionManager.d.ts +19 -7
- package/dist/ai/sessionManager.d.ts.map +1 -1
- package/dist/ai/sessionManager.js +81 -23
- package/dist/ai/sessionManager.js.map +1 -1
- package/dist/ai/sessionRegistry.d.ts.map +1 -1
- package/dist/ai/sessionRegistry.js +2 -0
- package/dist/ai/sessionRegistry.js.map +1 -1
- package/dist/ai/sessionStore.d.ts.map +1 -1
- package/dist/ai/sessionStore.js +2 -0
- package/dist/ai/sessionStore.js.map +1 -1
- package/dist/ai/systemPrompt.d.ts.map +1 -1
- package/dist/ai/systemPrompt.js +3 -0
- package/dist/ai/systemPrompt.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/connection/connection.d.ts.map +1 -1
- package/dist/connection/connection.js +2 -0
- package/dist/connection/connection.js.map +1 -1
- package/dist/connection/e2eHarness.d.ts +1 -1
- package/dist/connection/e2eHarness.d.ts.map +1 -1
- package/dist/connection/e2eHarness.js +26 -8
- package/dist/connection/e2eHarness.js.map +1 -1
- package/dist/connection/fakeRelay.d.ts.map +1 -1
- package/dist/connection/fakeRelay.js +2 -0
- package/dist/connection/fakeRelay.js.map +1 -1
- package/dist/connection/pubsub.d.ts.map +1 -1
- package/dist/connection/pubsub.js +2 -0
- package/dist/connection/pubsub.js.map +1 -1
- package/dist/connection/relay.d.ts.map +1 -1
- package/dist/connection/relay.js +2 -0
- package/dist/connection/relay.js.map +1 -1
- package/dist/files/fileBrowser.d.ts.map +1 -1
- package/dist/files/fileBrowser.js +44 -2
- package/dist/files/fileBrowser.js.map +1 -1
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +2 -0
- package/dist/git/operations.js.map +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts.map +1 -1
- package/dist/handlers/legacyBusAdapter.js +13 -1
- package/dist/handlers/legacyBusAdapter.js.map +1 -1
- package/dist/handlers/messageHandler.d.ts +23 -0
- package/dist/handlers/messageHandler.d.ts.map +1 -1
- package/dist/handlers/messageHandler.js +226 -14
- package/dist/handlers/messageHandler.js.map +1 -1
- package/dist/index.js +42 -2
- package/dist/index.js.map +1 -1
- package/dist/messageBus/busServerTransport.d.ts.map +1 -1
- package/dist/messageBus/busServerTransport.js +2 -0
- package/dist/messageBus/busServerTransport.js.map +1 -1
- package/dist/service/debugHttpServer.d.ts.map +1 -1
- package/dist/service/debugHttpServer.js +2 -0
- package/dist/service/debugHttpServer.js.map +1 -1
- package/dist/service/ensureDaemon.d.ts.map +1 -1
- package/dist/service/ensureDaemon.js +27 -2
- package/dist/service/ensureDaemon.js.map +1 -1
- package/dist/service/index.d.ts.map +1 -1
- package/dist/service/index.js +2 -0
- package/dist/service/index.js.map +1 -1
- package/dist/service/ipcClient.d.ts.map +1 -1
- package/dist/service/ipcClient.js +3 -1
- package/dist/service/ipcClient.js.map +1 -1
- package/dist/service/ipcServer.d.ts.map +1 -1
- package/dist/service/ipcServer.js +2 -0
- package/dist/service/ipcServer.js.map +1 -1
- package/dist/service/pushClient.d.ts.map +1 -1
- package/dist/service/pushClient.js +2 -0
- package/dist/service/pushClient.js.map +1 -1
- package/dist/service/run.d.ts.map +1 -1
- package/dist/service/run.js +14 -1
- package/dist/service/run.js.map +1 -1
- package/dist/service/singleton.d.ts +1 -0
- package/dist/service/singleton.d.ts.map +1 -1
- package/dist/service/singleton.js +5 -0
- package/dist/service/singleton.js.map +1 -1
- package/dist/service/stateStore.d.ts.map +1 -1
- package/dist/service/stateStore.js +2 -0
- package/dist/service/stateStore.js.map +1 -1
- package/dist/service/systemdUnit.d.ts +149 -0
- package/dist/service/systemdUnit.d.ts.map +1 -0
- package/dist/service/systemdUnit.js +322 -0
- package/dist/service/systemdUnit.js.map +1 -0
- package/dist/service/types.d.ts +6 -0
- package/dist/service/types.d.ts.map +1 -1
- package/dist/service/types.js +3 -1
- package/dist/service/types.js.map +1 -1
- package/dist/storage/eventStore.d.ts.map +1 -1
- package/dist/storage/eventStore.js +2 -0
- package/dist/storage/eventStore.js.map +1 -1
- package/dist/terminal/terminalManager.d.ts.map +1 -1
- package/dist/terminal/terminalManager.js +2 -0
- package/dist/terminal/terminalManager.js.map +1 -1
- package/dist/tombstoneCheck.d.ts.map +1 -1
- package/dist/tombstoneCheck.js +2 -0
- package/dist/tombstoneCheck.js.map +1 -1
- package/package.json +3 -3
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 King Young Technology and contributors
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,114 +1,52 @@
|
|
|
1
1
|
# @sumicom/quicksave — desktop agent
|
|
2
2
|
|
|
3
|
-
Background daemon that runs on your development machine and connects
|
|
4
|
-
Quicksave PWA (phone or browser) to
|
|
5
|
-
|
|
6
|
-
server never sees plaintext.
|
|
3
|
+
Background daemon that runs on your development machine and connects
|
|
4
|
+
your Quicksave PWA (phone or browser) to your coding-agent CLI sessions
|
|
5
|
+
and the local git working tree. All communication is end-to-end
|
|
6
|
+
encrypted; the relay server never sees plaintext.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Prerequisites
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Usage
|
|
10
|
+
Quicksave drives a coding-agent CLI on your `$PATH`. Install one (or
|
|
11
|
+
both) and sign in first:
|
|
15
12
|
|
|
16
13
|
```bash
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# or point at an explicit repo:
|
|
21
|
-
quicksave --repo /path/to/repo
|
|
14
|
+
# Claude Code (Anthropic) — https://code.claude.com/docs/en/setup
|
|
15
|
+
curl -fsSL https://claude.ai/install.sh | bash
|
|
16
|
+
claude # follow login prompts
|
|
22
17
|
|
|
23
|
-
#
|
|
24
|
-
|
|
18
|
+
# Codex (OpenAI) — https://github.com/openai/codex#readme
|
|
19
|
+
npm install -g @openai/codex
|
|
20
|
+
codex # follow login prompts
|
|
25
21
|
```
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
[Quicksave PWA](https://quicksave.dev) to connect.
|
|
29
|
-
|
|
30
|
-
The CLI auto-launches a background daemon (`quicksave service run`) and
|
|
31
|
-
then exits. The daemon keeps running; future `quicksave` invocations just
|
|
32
|
-
attach to it to add repos or re-read pairing info.
|
|
33
|
-
|
|
34
|
-
## Subcommands
|
|
35
|
-
|
|
36
|
-
| Command | Purpose |
|
|
37
|
-
| -------------------------------- | ------------------------------------------------------------ |
|
|
38
|
-
| `quicksave` | Start / ensure daemon; print pairing URL + QR |
|
|
39
|
-
| `quicksave rotate-keys` | Generate a new keypair (invalidates paired PWAs) |
|
|
40
|
-
| `quicksave service start` | Start daemon in the background |
|
|
41
|
-
| `quicksave service stop` | Stop the running daemon |
|
|
42
|
-
| `quicksave service status` | Live status (pid, peers, active sessions, managed repos) |
|
|
43
|
-
| `quicksave service info` | Static status from `service.json` (no IPC) |
|
|
44
|
-
| `quicksave service run` | Run daemon in foreground (not normally invoked directly) |
|
|
45
|
-
|
|
46
|
-
### Debug commands
|
|
23
|
+
You also need Node.js 20+ and `git`.
|
|
47
24
|
|
|
48
|
-
|
|
25
|
+
## Install
|
|
49
26
|
|
|
50
27
|
```bash
|
|
51
|
-
|
|
52
|
-
QUICKSAVE_DEBUG=1 quicksave service sessions # list all Claude sessions
|
|
53
|
-
QUICKSAVE_DEBUG=1 quicksave service cards <id> # card history for a session
|
|
54
|
-
QUICKSAVE_DEBUG=1 quicksave service resolve <id> # force-resolve stuck permission
|
|
28
|
+
npm install -g @sumicom/quicksave
|
|
55
29
|
```
|
|
56
30
|
|
|
57
|
-
##
|
|
58
|
-
|
|
59
|
-
- Maintains the WebSocket connection to the relay, does NaCl handshake with
|
|
60
|
-
each paired PWA, and decrypts/dispatches every message.
|
|
61
|
-
- Executes git operations against managed repos (`status`, `diff`, stage,
|
|
62
|
-
unstage, commit, branch, log, `.gitignore` edits, etc.).
|
|
63
|
-
- Manages Claude Code CLI sessions: spawns `claude` with stream-json I/O,
|
|
64
|
-
parses the output into `Card` events, handles `control_request`
|
|
65
|
-
permission prompts, forwards them to the PWA for approval, and streams
|
|
66
|
-
card updates back.
|
|
67
|
-
- Generates commit messages either via Anthropic API (user-supplied key)
|
|
68
|
-
or via an agentic `claude -p` loop that uses the user's local Claude
|
|
69
|
-
subscription.
|
|
70
|
-
- Hosts a pool of PTY-backed interactive shells (`src/terminal/terminalManager.ts`,
|
|
71
|
-
via `node-pty`) that the PWA can drive remotely. Each terminal keeps a
|
|
72
|
-
bounded scrollback buffer so a reconnecting PWA can redraw the current
|
|
73
|
-
screen without the shell having to repaint.
|
|
74
|
-
- Serves an IPC (Unix socket) JSON-RPC API for the CLI to query state and
|
|
75
|
-
issue debug commands.
|
|
76
|
-
- Triggers Web Push notifications through the relay when a permission
|
|
77
|
-
prompt arrives and no PWA peer is currently subscribed.
|
|
78
|
-
|
|
79
|
-
## Architecture
|
|
80
|
-
|
|
81
|
-
See [`docs/references/quicksave-architecture.md`](../../docs/references/quicksave-architecture.md)
|
|
82
|
-
for the full design — session lifecycle, MessageBus wiring, permission
|
|
83
|
-
flow, commit-summary pipeline, IPC protocol.
|
|
84
|
-
|
|
85
|
-
## Data location
|
|
86
|
-
|
|
87
|
-
| Path | Contents |
|
|
88
|
-
| ------------------------------- | ------------------------------------------------- |
|
|
89
|
-
| `~/.quicksave/config.json` | Agent ID, NaCl keypairs, managed repo list |
|
|
90
|
-
| `~/.quicksave/run/service.json` | Live daemon state (pid, socket path, heartbeat) |
|
|
91
|
-
| `~/.quicksave/run/*.sock` | IPC socket |
|
|
92
|
-
| `~/.quicksave/sessions/` | Per-session JSONL history (Claude Code CLI) |
|
|
93
|
-
|
|
94
|
-
## Development
|
|
31
|
+
## Quick start
|
|
95
32
|
|
|
96
33
|
```bash
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
pnpm --filter @sumicom/quicksave test # vitest
|
|
100
|
-
pnpm --filter @sumicom/quicksave build # tsc
|
|
34
|
+
cd /path/to/your/repo
|
|
35
|
+
quicksave
|
|
101
36
|
```
|
|
102
37
|
|
|
103
|
-
|
|
38
|
+
On first run this prints a pairing URL and QR code. Scan it from the
|
|
39
|
+
[Quicksave PWA](https://quicksave.dev) to connect.
|
|
104
40
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
# when called from inside a
|
|
109
|
-
# daemon-spawned Claude CLI
|
|
110
|
-
```
|
|
41
|
+
The CLI auto-launches a background daemon (`quicksave service run`) and
|
|
42
|
+
then exits. The daemon keeps running; future `quicksave` invocations
|
|
43
|
+
just attach to it to add repos or re-read pairing info.
|
|
111
44
|
|
|
112
|
-
##
|
|
45
|
+
## More
|
|
113
46
|
|
|
114
|
-
|
|
47
|
+
- **CLI subcommands, debug commands, data layout** —
|
|
48
|
+
[`docs/references/agent-cli.md`](../../docs/references/agent-cli.md)
|
|
49
|
+
- **Architecture (sessions, MessageBus, permissions, IPC)** —
|
|
50
|
+
[`docs/references/quicksave-architecture.en.md`](../../docs/references/quicksave-architecture.en.md)
|
|
51
|
+
- **Local development** —
|
|
52
|
+
[`docs/development.md`](../../docs/development.md)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asyncQueue.d.ts","sourceRoot":"","sources":["../../src/ai/asyncQueue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"asyncQueue.d.ts","sourceRoot":"","sources":["../../src/ai/asyncQueue.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,IAAI,CAAS;IAErB,8EAA8E;IAC9E,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAWpB,iDAAiD;IACjD,GAAG,IAAI,IAAI;IASX,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CAe3C"}
|
package/dist/ai/asyncQueue.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asyncQueue.js","sourceRoot":"","sources":["../../src/ai/asyncQueue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACb,KAAK,GAAQ,EAAE,CAAC;IAChB,OAAO,GAAgD,IAAI,CAAC;IAC5D,IAAI,GAAG,KAAK,CAAC;IAErB,8EAA8E;IAC9E,IAAI,CAAC,KAAQ;QACX,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,GAAG;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,EAAE,KAAK,EAAE,SAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,GAA+B,EAAE;gBACrC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACtE,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,OAAO,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,EAAE;oBAChD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;gBACzB,CAAC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"asyncQueue.js","sourceRoot":"","sources":["../../src/ai/asyncQueue.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,+BAA+B;AAC/B;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACb,KAAK,GAAQ,EAAE,CAAC;IAChB,OAAO,GAAgD,IAAI,CAAC;IAC5D,IAAI,GAAG,KAAK,CAAC;IAErB,8EAA8E;IAC9E,IAAI,CAAC,KAAQ;QACX,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,GAAG;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,EAAE,KAAK,EAAE,SAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,GAA+B,EAAE;gBACrC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACtE,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,OAAO,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,EAAE;oBAChD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;gBACzB,CAAC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Attachment, type AttachmentUploadRequestPayload, type AttachmentUploadResponsePayload } from '@sumicom/quicksave-shared';
|
|
2
|
+
export interface AttachmentNotFoundError extends Error {
|
|
3
|
+
code: 'attachment_not_found';
|
|
4
|
+
attachmentId: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AttachmentNotReadyError extends Error {
|
|
7
|
+
code: 'attachment_not_ready';
|
|
8
|
+
attachmentId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AttachmentTooLargeError extends Error {
|
|
11
|
+
code: 'attachment_too_large';
|
|
12
|
+
attachmentId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AttachmentTooManyPagesError extends Error {
|
|
15
|
+
code: 'attachment_too_many_pages';
|
|
16
|
+
attachmentId: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AttachmentBadRequestError extends Error {
|
|
19
|
+
code: 'attachment_bad_request';
|
|
20
|
+
attachmentId: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AttachmentPeerQuotaError extends Error {
|
|
23
|
+
code: 'attachment_peer_quota';
|
|
24
|
+
}
|
|
25
|
+
export interface AttachmentStagingOptions {
|
|
26
|
+
/** Override TTL — primarily for tests. */
|
|
27
|
+
ttlMs?: number;
|
|
28
|
+
/** Override per-peer cap — primarily for tests. */
|
|
29
|
+
perPeerMaxBytes?: number;
|
|
30
|
+
/** Custom clock — primarily for tests. */
|
|
31
|
+
now?: () => number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* In-memory staging map keyed by `(peerAddress, attachmentId)`. One instance
|
|
35
|
+
* per agent process; the messageHandler injects the peer address on every
|
|
36
|
+
* request.
|
|
37
|
+
*/
|
|
38
|
+
export declare class AttachmentStaging {
|
|
39
|
+
private readonly byPeer;
|
|
40
|
+
private readonly perPeerBytes;
|
|
41
|
+
private readonly ttlMs;
|
|
42
|
+
private readonly perPeerMaxBytes;
|
|
43
|
+
private readonly now;
|
|
44
|
+
constructor(opts?: AttachmentStagingOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Apply one upload chunk. Returns the running progress + ready flag.
|
|
47
|
+
* Throws a tagged Error (`code` field) for validation failures so the
|
|
48
|
+
* messageHandler can map them to bus error responses.
|
|
49
|
+
*/
|
|
50
|
+
acceptChunk(peerAddress: string, payload: AttachmentUploadRequestPayload): AttachmentUploadResponsePayload;
|
|
51
|
+
/**
|
|
52
|
+
* Atomically remove and return the requested attachments. Throws on the
|
|
53
|
+
* first missing or not-ready id (with that id in the error). On error,
|
|
54
|
+
* **no** attachments are consumed — callers can retry safely.
|
|
55
|
+
*/
|
|
56
|
+
consume(peerAddress: string, attachmentIds: readonly string[]): Attachment[];
|
|
57
|
+
/** Drop a staged attachment if present. Returns true if anything was removed. */
|
|
58
|
+
cancel(peerAddress: string, attachmentId: string): boolean;
|
|
59
|
+
/** Drop every staging record for a peer (called on disconnect). */
|
|
60
|
+
removePeer(peerAddress: string): void;
|
|
61
|
+
/** Sweep expired entries. Safe to call from a periodic timer. */
|
|
62
|
+
gc(): void;
|
|
63
|
+
/** Test/diagnostic: count of staged records for a peer. */
|
|
64
|
+
size(peerAddress: string): number;
|
|
65
|
+
/** Test/diagnostic: bytes currently held for a peer. */
|
|
66
|
+
bytesFor(peerAddress: string): number;
|
|
67
|
+
private validateMeta;
|
|
68
|
+
private isReady;
|
|
69
|
+
private dropEntry;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=attachmentStaging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachmentStaging.d.ts","sourceRoot":"","sources":["../../src/ai/attachmentStaging.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,UAAU,EAEf,KAAK,8BAA8B,EACnC,KAAK,+BAA+B,EACrC,MAAM,2BAA2B,CAAC;AAqBnC,MAAM,WAAW,uBAAwB,SAAQ,KAAK;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,uBAAwB,SAAQ,KAAK;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,uBAAwB,SAAQ,KAAK;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,2BAA4B,SAAQ,KAAK;IACxD,IAAI,EAAE,2BAA2B,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,yBAA0B,SAAQ,KAAK;IACtD,IAAI,EAAE,wBAAwB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,wBAAyB,SAAQ,KAAK;IACrD,IAAI,EAAE,uBAAuB,CAAC;CAC/B;AAqBD,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoD;IAC3E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,IAAI,GAAE,wBAA6B;IAM/C;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,8BAA8B,GAAG,+BAA+B;IA2G1G;;;;OAIG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,EAAE;IA6B5E,iFAAiF;IACjF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAI1D,mEAAmE;IACnE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKrC,iEAAiE;IACjE,EAAE,IAAI,IAAI;IAeV,2DAA2D;IAC3D,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIjC,wDAAwD;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAMrC,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,SAAS;CAiBlB"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 King Young Technology
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Attachment staging — buffers chunked uploads from a peer until they are
|
|
5
|
+
// consumed by a `claude:start` / `claude:resume` whose payload references
|
|
6
|
+
// the attachment ids. Buffers live in memory; the GC loop drops idle records
|
|
7
|
+
// after `ATTACHMENT_STAGING_TTL_MS`.
|
|
8
|
+
// ============================================================================
|
|
9
|
+
import { ATTACHMENT_LIMITS, ATTACHMENT_STAGING_TTL_MS, PDF_MAX_PAGES, PER_PEER_STAGING_MAX_BYTES, } from '@sumicom/quicksave-shared';
|
|
10
|
+
import { countPdfPages } from './pdfMeta.js';
|
|
11
|
+
function makeError(code, message, extra = {}) {
|
|
12
|
+
const err = new Error(message);
|
|
13
|
+
err.code = code;
|
|
14
|
+
Object.assign(err, extra);
|
|
15
|
+
return err;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* In-memory staging map keyed by `(peerAddress, attachmentId)`. One instance
|
|
19
|
+
* per agent process; the messageHandler injects the peer address on every
|
|
20
|
+
* request.
|
|
21
|
+
*/
|
|
22
|
+
export class AttachmentStaging {
|
|
23
|
+
byPeer = new Map();
|
|
24
|
+
perPeerBytes = new Map();
|
|
25
|
+
ttlMs;
|
|
26
|
+
perPeerMaxBytes;
|
|
27
|
+
now;
|
|
28
|
+
constructor(opts = {}) {
|
|
29
|
+
this.ttlMs = opts.ttlMs ?? ATTACHMENT_STAGING_TTL_MS;
|
|
30
|
+
this.perPeerMaxBytes = opts.perPeerMaxBytes ?? PER_PEER_STAGING_MAX_BYTES;
|
|
31
|
+
this.now = opts.now ?? (() => Date.now());
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Apply one upload chunk. Returns the running progress + ready flag.
|
|
35
|
+
* Throws a tagged Error (`code` field) for validation failures so the
|
|
36
|
+
* messageHandler can map them to bus error responses.
|
|
37
|
+
*/
|
|
38
|
+
acceptChunk(peerAddress, payload) {
|
|
39
|
+
const { attachmentId, chunkIndex, chunk, meta } = payload;
|
|
40
|
+
if (!attachmentId || typeof attachmentId !== 'string') {
|
|
41
|
+
throw makeError('attachment_bad_request', 'attachmentId required', { attachmentId: String(attachmentId) });
|
|
42
|
+
}
|
|
43
|
+
if (typeof chunkIndex !== 'number' || chunkIndex < 0 || !Number.isInteger(chunkIndex)) {
|
|
44
|
+
throw makeError('attachment_bad_request', 'chunkIndex must be a non-negative integer', { attachmentId });
|
|
45
|
+
}
|
|
46
|
+
if (typeof chunk !== 'string') {
|
|
47
|
+
throw makeError('attachment_bad_request', 'chunk must be base64 string', { attachmentId });
|
|
48
|
+
}
|
|
49
|
+
const peerMap = this.byPeer.get(peerAddress) ?? new Map();
|
|
50
|
+
let staged = peerMap.get(attachmentId);
|
|
51
|
+
if (!staged) {
|
|
52
|
+
// First time we see this id — meta is required.
|
|
53
|
+
if (!meta) {
|
|
54
|
+
throw makeError('attachment_bad_request', 'meta required on first chunk', { attachmentId });
|
|
55
|
+
}
|
|
56
|
+
this.validateMeta(attachmentId, meta);
|
|
57
|
+
staged = {
|
|
58
|
+
attachmentId,
|
|
59
|
+
kind: meta.kind,
|
|
60
|
+
mimeType: meta.mimeType,
|
|
61
|
+
name: meta.name,
|
|
62
|
+
size: meta.size,
|
|
63
|
+
totalChunks: meta.totalChunks,
|
|
64
|
+
chunks: new Array(meta.totalChunks),
|
|
65
|
+
receivedBytes: 0,
|
|
66
|
+
receivedCount: 0,
|
|
67
|
+
lastTouchedAt: this.now(),
|
|
68
|
+
};
|
|
69
|
+
peerMap.set(attachmentId, staged);
|
|
70
|
+
this.byPeer.set(peerAddress, peerMap);
|
|
71
|
+
}
|
|
72
|
+
else if (meta) {
|
|
73
|
+
// Subsequent chunks may include meta but must be consistent.
|
|
74
|
+
if (meta.kind !== staged.kind
|
|
75
|
+
|| meta.mimeType !== staged.mimeType
|
|
76
|
+
|| meta.name !== staged.name
|
|
77
|
+
|| meta.size !== staged.size
|
|
78
|
+
|| meta.totalChunks !== staged.totalChunks) {
|
|
79
|
+
throw makeError('attachment_bad_request', 'meta mismatch for existing attachment', { attachmentId });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (chunkIndex >= staged.totalChunks) {
|
|
83
|
+
throw makeError('attachment_bad_request', `chunkIndex ${chunkIndex} >= totalChunks ${staged.totalChunks}`, { attachmentId });
|
|
84
|
+
}
|
|
85
|
+
if (staged.chunks[chunkIndex] !== undefined) {
|
|
86
|
+
// Idempotent re-send: if the bytes match, no-op; otherwise reject.
|
|
87
|
+
const existing = staged.chunks[chunkIndex];
|
|
88
|
+
const incoming = Buffer.from(chunk, 'base64');
|
|
89
|
+
if (existing.equals(incoming)) {
|
|
90
|
+
staged.lastTouchedAt = this.now();
|
|
91
|
+
return { attachmentId, receivedBytes: staged.receivedBytes, ready: this.isReady(staged) };
|
|
92
|
+
}
|
|
93
|
+
throw makeError('attachment_bad_request', `chunk ${chunkIndex} already received with different bytes`, { attachmentId });
|
|
94
|
+
}
|
|
95
|
+
const buf = Buffer.from(chunk, 'base64');
|
|
96
|
+
const nextRunningBytes = staged.receivedBytes + buf.length;
|
|
97
|
+
if (nextRunningBytes > staged.size) {
|
|
98
|
+
throw makeError('attachment_too_large', `running bytes exceeds declared size`, { attachmentId });
|
|
99
|
+
}
|
|
100
|
+
const peerTotal = this.perPeerBytes.get(peerAddress) ?? 0;
|
|
101
|
+
if (peerTotal + buf.length > this.perPeerMaxBytes) {
|
|
102
|
+
throw makeError('attachment_peer_quota', 'per-peer staging quota exceeded');
|
|
103
|
+
}
|
|
104
|
+
staged.chunks[chunkIndex] = buf;
|
|
105
|
+
staged.receivedBytes = nextRunningBytes;
|
|
106
|
+
staged.receivedCount += 1;
|
|
107
|
+
staged.lastTouchedAt = this.now();
|
|
108
|
+
this.perPeerBytes.set(peerAddress, peerTotal + buf.length);
|
|
109
|
+
const ready = this.isReady(staged);
|
|
110
|
+
if (ready && staged.receivedBytes !== staged.size) {
|
|
111
|
+
// Strict: declared size must match received bytes when ready.
|
|
112
|
+
this.dropEntry(peerAddress, attachmentId);
|
|
113
|
+
throw makeError('attachment_bad_request', 'received bytes do not match declared size', { attachmentId });
|
|
114
|
+
}
|
|
115
|
+
// Page-count check on PDF completion. The Anthropic API rejects PDFs over
|
|
116
|
+
// PDF_MAX_PAGES and the SDK rewrites the rejection as a poison "PDF too
|
|
117
|
+
// large" assistant block — drop the entry now so the user sees a clean
|
|
118
|
+
// error instead of a stuck session. countPdfPages returns null/0 for
|
|
119
|
+
// PDFs where pages live in compressed object streams (rare); in that
|
|
120
|
+
// case we let it through and fall back to the recovery card path.
|
|
121
|
+
if (ready && staged.kind === 'pdf') {
|
|
122
|
+
const pages = countPdfPages(Buffer.concat(staged.chunks));
|
|
123
|
+
if (pages !== null && pages > PDF_MAX_PAGES) {
|
|
124
|
+
this.dropEntry(peerAddress, attachmentId);
|
|
125
|
+
throw makeError('attachment_too_many_pages', `PDF has ${pages} pages (max ${PDF_MAX_PAGES})`, { attachmentId });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { attachmentId, receivedBytes: staged.receivedBytes, ready };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Atomically remove and return the requested attachments. Throws on the
|
|
132
|
+
* first missing or not-ready id (with that id in the error). On error,
|
|
133
|
+
* **no** attachments are consumed — callers can retry safely.
|
|
134
|
+
*/
|
|
135
|
+
consume(peerAddress, attachmentIds) {
|
|
136
|
+
if (attachmentIds.length === 0)
|
|
137
|
+
return [];
|
|
138
|
+
const peerMap = this.byPeer.get(peerAddress);
|
|
139
|
+
if (!peerMap) {
|
|
140
|
+
throw makeError('attachment_not_found', `no staged attachments for peer`, { attachmentId: attachmentIds[0] });
|
|
141
|
+
}
|
|
142
|
+
// Validate all first, then remove.
|
|
143
|
+
for (const id of attachmentIds) {
|
|
144
|
+
const s = peerMap.get(id);
|
|
145
|
+
if (!s)
|
|
146
|
+
throw makeError('attachment_not_found', `attachment ${id} not staged`, { attachmentId: id });
|
|
147
|
+
if (!this.isReady(s))
|
|
148
|
+
throw makeError('attachment_not_ready', `attachment ${id} not ready`, { attachmentId: id });
|
|
149
|
+
}
|
|
150
|
+
const result = [];
|
|
151
|
+
for (const id of attachmentIds) {
|
|
152
|
+
const s = peerMap.get(id);
|
|
153
|
+
const data = Buffer.concat(s.chunks).toString('base64');
|
|
154
|
+
result.push({
|
|
155
|
+
id: s.attachmentId,
|
|
156
|
+
kind: s.kind,
|
|
157
|
+
mimeType: s.mimeType,
|
|
158
|
+
name: s.name,
|
|
159
|
+
size: s.size,
|
|
160
|
+
data,
|
|
161
|
+
});
|
|
162
|
+
this.dropEntry(peerAddress, id);
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
/** Drop a staged attachment if present. Returns true if anything was removed. */
|
|
167
|
+
cancel(peerAddress, attachmentId) {
|
|
168
|
+
return this.dropEntry(peerAddress, attachmentId);
|
|
169
|
+
}
|
|
170
|
+
/** Drop every staging record for a peer (called on disconnect). */
|
|
171
|
+
removePeer(peerAddress) {
|
|
172
|
+
this.byPeer.delete(peerAddress);
|
|
173
|
+
this.perPeerBytes.delete(peerAddress);
|
|
174
|
+
}
|
|
175
|
+
/** Sweep expired entries. Safe to call from a periodic timer. */
|
|
176
|
+
gc() {
|
|
177
|
+
const cutoff = this.now() - this.ttlMs;
|
|
178
|
+
for (const [peer, map] of this.byPeer) {
|
|
179
|
+
for (const [id, s] of map) {
|
|
180
|
+
if (s.lastTouchedAt <= cutoff) {
|
|
181
|
+
this.dropEntry(peer, id);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (map.size === 0) {
|
|
185
|
+
this.byPeer.delete(peer);
|
|
186
|
+
this.perPeerBytes.delete(peer);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Test/diagnostic: count of staged records for a peer. */
|
|
191
|
+
size(peerAddress) {
|
|
192
|
+
return this.byPeer.get(peerAddress)?.size ?? 0;
|
|
193
|
+
}
|
|
194
|
+
/** Test/diagnostic: bytes currently held for a peer. */
|
|
195
|
+
bytesFor(peerAddress) {
|
|
196
|
+
return this.perPeerBytes.get(peerAddress) ?? 0;
|
|
197
|
+
}
|
|
198
|
+
// ── Private ─────────────────────────────────────────────────────────────
|
|
199
|
+
validateMeta(attachmentId, meta) {
|
|
200
|
+
if (!meta.kind || !ATTACHMENT_LIMITS[meta.kind]) {
|
|
201
|
+
throw makeError('attachment_bad_request', `unknown kind`, { attachmentId });
|
|
202
|
+
}
|
|
203
|
+
if (typeof meta.size !== 'number' || meta.size <= 0 || !Number.isFinite(meta.size)) {
|
|
204
|
+
throw makeError('attachment_bad_request', 'invalid size', { attachmentId });
|
|
205
|
+
}
|
|
206
|
+
if (meta.size > ATTACHMENT_LIMITS[meta.kind].maxBytes) {
|
|
207
|
+
throw makeError('attachment_too_large', `${meta.kind} exceeds ${ATTACHMENT_LIMITS[meta.kind].maxBytes} bytes`, { attachmentId });
|
|
208
|
+
}
|
|
209
|
+
if (typeof meta.totalChunks !== 'number' || meta.totalChunks <= 0 || !Number.isInteger(meta.totalChunks)) {
|
|
210
|
+
throw makeError('attachment_bad_request', 'invalid totalChunks', { attachmentId });
|
|
211
|
+
}
|
|
212
|
+
if (typeof meta.mimeType !== 'string' || meta.mimeType.length === 0) {
|
|
213
|
+
throw makeError('attachment_bad_request', 'invalid mimeType', { attachmentId });
|
|
214
|
+
}
|
|
215
|
+
if (typeof meta.name !== 'string' || meta.name.length === 0) {
|
|
216
|
+
throw makeError('attachment_bad_request', 'invalid name', { attachmentId });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
isReady(s) {
|
|
220
|
+
return s.receivedCount === s.totalChunks;
|
|
221
|
+
}
|
|
222
|
+
dropEntry(peerAddress, attachmentId) {
|
|
223
|
+
const peerMap = this.byPeer.get(peerAddress);
|
|
224
|
+
if (!peerMap)
|
|
225
|
+
return false;
|
|
226
|
+
const s = peerMap.get(attachmentId);
|
|
227
|
+
if (!s)
|
|
228
|
+
return false;
|
|
229
|
+
peerMap.delete(attachmentId);
|
|
230
|
+
const remainingBytes = (this.perPeerBytes.get(peerAddress) ?? 0) - s.receivedBytes;
|
|
231
|
+
if (remainingBytes > 0) {
|
|
232
|
+
this.perPeerBytes.set(peerAddress, remainingBytes);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
this.perPeerBytes.delete(peerAddress);
|
|
236
|
+
}
|
|
237
|
+
if (peerMap.size === 0) {
|
|
238
|
+
this.byPeer.delete(peerAddress);
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=attachmentStaging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachmentStaging.js","sourceRoot":"","sources":["../../src/ai/attachmentStaging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Attachment, AttachmentMetadata } from '@sumicom/quicksave-shared';
|
|
2
|
+
export interface PersistedMeta {
|
|
3
|
+
id: string;
|
|
4
|
+
kind: AttachmentMetadata['kind'];
|
|
5
|
+
mimeType: string;
|
|
6
|
+
name: string;
|
|
7
|
+
size: number;
|
|
8
|
+
storedAt: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Persist a batch of resolved attachments under one session id. Idempotent
|
|
12
|
+
* per id — re-writing the same id overwrites both files.
|
|
13
|
+
*/
|
|
14
|
+
export declare function persistAttachments(sessionId: string, attachments: readonly Attachment[]): Promise<void>;
|
|
15
|
+
export interface TurnManifestEntry {
|
|
16
|
+
ids: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Read the per-session attachment turn manifest in send order. Returns an
|
|
20
|
+
* empty array if no manifest exists yet (e.g. a session whose attachments
|
|
21
|
+
* predate this code), letting callers fall back to fuzzy rebind.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readTurnManifest(sessionId: string): Promise<TurnManifestEntry[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Read one attachment's bytes back, returning the wire `Attachment` shape
|
|
26
|
+
* (metadata + base64 data). Returns `null` if the attachment isn't on disk
|
|
27
|
+
* — e.g. session was end-tasked, or the JSONL had an attachment we didn't
|
|
28
|
+
* persist (cold-start session before this code shipped).
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadAttachment(sessionId: string, attachmentId: string): Promise<Attachment | null>;
|
|
31
|
+
/** Drop every persisted attachment for one session (called on end-task). */
|
|
32
|
+
export declare function removeSessionAttachments(sessionId: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* List metadata for every attachment persisted under a session id. Mainly
|
|
35
|
+
* for diagnostics / tests.
|
|
36
|
+
*/
|
|
37
|
+
export declare function listSessionAttachments(sessionId: string): Promise<PersistedMeta[]>;
|
|
38
|
+
/** True if the meta+bin pair exist on disk — without reading the bytes. */
|
|
39
|
+
export declare function hasPersistedAttachment(sessionId: string, attachmentId: string): Promise<boolean>;
|
|
40
|
+
//# sourceMappingURL=attachmentStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachmentStore.d.ts","sourceRoot":"","sources":["../../src/ai/attachmentStore.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGhF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,SAAS,UAAU,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoBtF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyB5B;AAED,4EAA4E;AAC5E,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/E;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAkBxF;AAED,2EAA2E;AAC3E,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|