@lucasschirm/claude-session-sync 0.1.0 → 0.1.1

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.
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "claude-session-sync",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Sync Claude Code session data to S3-compatible storage.",
5
- "hooks": "hooks/hooks.json"
5
+ "author": {
6
+ "name": "lucasschirm"
7
+ }
6
8
  }
package/README.md ADDED
@@ -0,0 +1,354 @@
1
+ # @lucasschirm/claude-session-sync
2
+
3
+ A [Claude Code](https://code.claude.com/) plugin that synchronizes your session
4
+ data — transcripts, workspace configuration, and session telemetry — to
5
+ S3-compatible storage via the [`@lucasschirm/sal-sync`](../../sync) engine.
6
+
7
+ ## What it does
8
+
9
+ Every Claude Code session goes through a lifecycle: start, tool calls, context
10
+ compaction, subagent spawns, and stop. This plugin hooks into those lifecycle
11
+ events to capture and upload session artifacts so they can be analyzed later by
12
+ the [Agentic Sessions Dashboard](../../../) (or any consumer of the sync
13
+ engine's output).
14
+
15
+ ### Hooks
16
+
17
+ The plugin registers hooks for the following Claude Code lifecycle events
18
+ (defined in [`hooks/hooks.json`](hooks/hooks.json)):
19
+
20
+ | Event | What happens |
21
+ | -------------- | ----------------------------------------------------------------------------------------------------- |
22
+ | `SessionStart` | Records the session, spawns a detached transcript watcher that uploads incremental transcript deltas. |
23
+ | `PreCompact` | Flushes pending transcript deltas before context compaction. |
24
+ | `PostCompact` | Resumes capture after compaction. |
25
+ | `Stop` | Flushes a final delta when the turn ends. |
26
+ | `StopFailure` | Flushes a final delta when the turn ends due to an API error. |
27
+ | `SubagentStop` | Flushes subagent transcript deltas when a subagent finishes. |
28
+ | `SessionEnd` | Performs the final sync: flushes remaining deltas, uploads the session manifest, and shuts down. |
29
+
30
+ All hooks except `SessionEnd` run asynchronously (`"async": true`) so they
31
+ never block Claude. `SessionEnd` has a 60-second timeout to ensure the final
32
+ manifest is uploaded before the process exits.
33
+
34
+ ### What gets captured
35
+
36
+ The sync engine captures only the artifacts in its versioned
37
+ [allowlist](../../sync/src/allowlist.ts):
38
+
39
+ - **Session & subagent transcript JSONL files** — captured raw by default,
40
+ subject to size limits. Opt out with `SAL_CAPTURE_TRANSCRIPTS=false`.
41
+ - **Workspace configuration** — `CLAUDE.md`, `.mcp.json`,
42
+ `.claude/settings.json`, `.claude/settings.local.json`,
43
+ `.claude/agents/**`, `.claude/skills/**`, `.claude/rules/**`.
44
+ - **Global configuration** — `~/.claude/settings.json`, `~/.claude/CLAUDE.md`,
45
+ `~/.claude/agents/**`, `~/.claude.json`.
46
+ - **Session telemetry** — `sessionId`, `projectId`, `harness`,
47
+ `harnessVersion`, `model`, `startedAt`, `endedAt`, `durationMs`,
48
+ `endReason`.
49
+
50
+ Configuration artifacts are sanitized before upload: known sensitive fields
51
+ (`env`, `password`, `secret`, `token`, `apiKey`, `authorization`, etc.) are
52
+ redacted, and bearer tokens, credential-bearing URLs, and private-key blocks
53
+ are stripped. See the full [privacy policy](../../sync/POLICY.md).
54
+
55
+ ## Installation
56
+
57
+ The plugin is distributed through the `session-analyzer` marketplace, which is
58
+ hosted in this repository at
59
+ [`.claude-plugin/marketplace.json`](../../../.claude-plugin/marketplace.json).
60
+ Installation is a two-step process: first add the marketplace, then install
61
+ the plugin.
62
+
63
+ ### Step 1 — Add the marketplace
64
+
65
+ You can add the marketplace from GitHub, a git URL, or a local clone.
66
+
67
+ #### From GitHub (recommended)
68
+
69
+ Use the `owner/repo` shorthand:
70
+
71
+ ```bash
72
+ claude plugin marketplace add lucasschirm/session-analyzer
73
+ ```
74
+
75
+ Pin to a specific branch or tag with `@ref`:
76
+
77
+ ```bash
78
+ claude plugin marketplace add lucasschirm/session-analyzer@feature/claude-session-sync
79
+ ```
80
+
81
+ #### From a git URL
82
+
83
+ For non-GitHub hosts or explicit HTTPS cloning:
84
+
85
+ ```bash
86
+ claude plugin marketplace add https://github.com/lucasschirm/session-analyzer.git
87
+ ```
88
+
89
+ #### From a local clone (for development)
90
+
91
+ If you have this repo cloned locally:
92
+
93
+ ```bash
94
+ claude plugin marketplace add ./path/to/session-analyzer
95
+ ```
96
+
97
+ #### Marketplace scope
98
+
99
+ The `--scope` flag controls who sees the marketplace declaration:
100
+
101
+ | Scope | Setting file | Shared with team? |
102
+ | --------- | ------------------------------ | ----------------- |
103
+ | `user` | `~/.claude/settings.json` | No (personal) |
104
+ | `project` | `.claude/settings.json` | Yes (committed) |
105
+ | `local` | `.claude/settings.local.json` | No (gitignored) |
106
+
107
+ ```bash
108
+ # Share the marketplace with your team
109
+ claude plugin marketplace add lucasschirm/session-analyzer --scope project
110
+ ```
111
+
112
+ ### Step 2 — Install the plugin
113
+
114
+ Once the marketplace is added, install the plugin:
115
+
116
+ ```bash
117
+ claude plugin install claude-session-sync@session-analyzer
118
+ ```
119
+
120
+ Or from inside an interactive Claude Code session:
121
+
122
+ ```
123
+ /plugin install claude-session-sync@session-analyzer
124
+ ```
125
+
126
+ The install command opens a details view where you select an installation
127
+ scope (user, project, or local — same semantics as above). After installing,
128
+ run `/reload-plugins` if prompted.
129
+
130
+ ### From source (local development)
131
+
132
+ For local development, build the plugin bundle first, then add the marketplace
133
+ from your local clone:
134
+
135
+ ```bash
136
+ # Build the plugin bundle (esbuild single-file executables)
137
+ pnpm --filter @lucasschirm/claude-session-sync build
138
+
139
+ # Add the local marketplace and install
140
+ claude plugin marketplace add .
141
+ claude plugin install claude-session-sync@session-analyzer
142
+ ```
143
+
144
+ The build produces self-contained executables in `bin/` (no `node_modules`
145
+ required at runtime):
146
+
147
+ ```
148
+ bin/session-start # SessionStart hook entry point
149
+ bin/session-end # SessionEnd hook entry point
150
+ bin/hook # PreCompact/PostCompact/Stop/StopFailure/SubagentStop
151
+ bin/transcript-watcher # Detached watcher process spawned by session-start
152
+ ```
153
+
154
+ ### Updating
155
+
156
+ To pull the latest version from the marketplace:
157
+
158
+ ```bash
159
+ claude plugin marketplace update session-analyzer
160
+ claude plugin update claude-session-sync@session-analyzer
161
+ ```
162
+
163
+ Or inside an interactive session:
164
+
165
+ ```
166
+ /plugin marketplace update session-analyzer
167
+ /plugin update claude-session-sync@session-analyzer
168
+ ```
169
+
170
+ ### Uninstalling
171
+
172
+ ```bash
173
+ claude plugin uninstall claude-session-sync@session-analyzer
174
+ claude plugin marketplace remove session-analyzer
175
+ ```
176
+
177
+ ## Configuration
178
+
179
+ The sync engine is configured entirely through environment variables. Set them
180
+ in one of the Claude Code settings files (see below), or export them in your
181
+ shell before launching `claude`.
182
+
183
+ ### Required
184
+
185
+ | Variable | Description |
186
+ | -------------------- | ----------------------------------------------------- |
187
+ | `SAL_PROJECT_ID` | Unique identifier for the project (e.g. `my-app`). |
188
+ | `SAL_STORAGE_TYPE` | Storage backend. Currently only `s3` is supported. |
189
+ | `SAL_STORAGE_BUCKET` | S3 bucket name. |
190
+ | `SAL_STORAGE_REGION` | AWS region (e.g. `us-east-1`). |
191
+ | `SAL_STORAGE_ID` | AWS access key ID. |
192
+ | `SAL_STORAGE_SECRET` | AWS secret access key. |
193
+
194
+ ### Optional
195
+
196
+ | Variable | Default | Description |
197
+ | ------------------------------ | ----------- | ------------------------------------------------------------------ |
198
+ | `SAL_STORAGE_ENDPOINT` | _(none)_ | Custom S3-compatible endpoint (e.g. `http://localhost:4566` for LocalStack). |
199
+ | `SAL_STORAGE_SESSION_TOKEN` | _(none)_ | Temporary AWS session token (for STS credentials). |
200
+ | `SAL_SYNC_DISABLED` | `false` | Set to `true` to fully disable synchronization. |
201
+ | `SAL_CAPTURE_TRANSCRIPTS` | `true` | Set to `false` to skip transcript capture (config still syncs). |
202
+ | `SAL_SYNC_TIMEOUT` | `30000` | Per-upload timeout in milliseconds. |
203
+ | `SAL_SYNC_RETRIES` | `3` | Number of retry attempts on upload failure. |
204
+ | `SAL_SESSION_END_BUDGET_MS` | `120000` | Time budget for the final SessionEnd sync in milliseconds. |
205
+ | `SAL_HOOK_UPLOAD_TIMEOUT` | `10000` | Per-hook upload timeout in milliseconds. |
206
+ | `SAL_MAX_FILE_BYTES` | `10485760` | Max size per uploaded file (10 MB). |
207
+ | `SAL_MAX_TOTAL_BYTES` | `104857600` | Max total bytes per sync run (100 MB). |
208
+ | `SAL_MAX_FILES` | `1000` | Max files per sync run. |
209
+ | `SAL_MAX_TRANSCRIPT_BYTES` | `52428800` | Max transcript file size (50 MB). |
210
+ | `SAL_MAX_JSON_DEPTH` | `128` | Max JSON nesting depth for sanitization. |
211
+ | `SAL_MAX_JSONL_LINE_BYTES` | `1048576` | Max bytes per JSONL line (1 MB). |
212
+
213
+ ### Configuring via Claude Code settings
214
+
215
+ Claude Code reads environment variables from the `env` key in its settings
216
+ files. There are three relevant scopes:
217
+
218
+ | File | Scope | Commit to git? |
219
+ | ----------------------------- | ------------------------------ | -------------- |
220
+ | `~/.claude/settings.json` | You, in every project | No |
221
+ | `.claude/settings.json` | Everyone in the project | Yes |
222
+ | `.claude/settings.local.json` | You, in this project only | No (gitignored)|
223
+
224
+ #### Option A: User-wide (recommended for personal use)
225
+
226
+ Edit `~/.claude/settings.json`:
227
+
228
+ ```json
229
+ {
230
+ "env": {
231
+ "SAL_PROJECT_ID": "my-app",
232
+ "SAL_STORAGE_TYPE": "s3",
233
+ "SAL_STORAGE_BUCKET": "my-session-bucket",
234
+ "SAL_STORAGE_REGION": "us-east-1",
235
+ "SAL_STORAGE_ID": "AKIAIOSFODNN7EXAMPLE",
236
+ "SAL_STORAGE_SECRET": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
237
+ },
238
+ "enabledPlugins": {
239
+ "claude-session-sync@session-analyzer": true
240
+ }
241
+ }
242
+ ```
243
+
244
+ #### Option B: Project-local (per-project credentials)
245
+
246
+ Create `.claude/settings.local.json` in your project root (this file is
247
+ gitignored by default, so credentials stay local):
248
+
249
+ ```json
250
+ {
251
+ "env": {
252
+ "SAL_PROJECT_ID": "my-app",
253
+ "SAL_STORAGE_TYPE": "s3",
254
+ "SAL_STORAGE_BUCKET": "my-session-bucket",
255
+ "SAL_STORAGE_REGION": "us-east-1",
256
+ "SAL_STORAGE_ID": "AKIAIOSFODNN7EXAMPLE",
257
+ "SAL_STORAGE_SECRET": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
258
+ "SAL_STORAGE_ENDPOINT": "http://localhost:4566"
259
+ }
260
+ }
261
+ ```
262
+
263
+ > **Note:** `pluginConfigs` values are only read from user settings
264
+ > (`~/.claude/settings.json`), `--settings`, and managed settings — not from
265
+ > project or local settings files. However, the `env` key **is** read from all
266
+ > settings scopes, so environment variables in `.claude/settings.local.json`
267
+ > work correctly for plugin configuration.
268
+
269
+ #### Option C: Shell environment
270
+
271
+ Export the variables before launching Claude Code:
272
+
273
+ ```bash
274
+ export SAL_PROJECT_ID="my-app"
275
+ export SAL_STORAGE_TYPE="s3"
276
+ export SAL_STORAGE_BUCKET="my-session-bucket"
277
+ export SAL_STORAGE_REGION="us-east-1"
278
+ export SAL_STORAGE_ID="AKIAIOSFODNN7EXAMPLE"
279
+ export SAL_STORAGE_SECRET="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
280
+ claude
281
+ ```
282
+
283
+ ### Using LocalStack for local development
284
+
285
+ For local testing without a real AWS account, run
286
+ [LocalStack](https://localstack.dev/) and point the plugin at it:
287
+
288
+ ```json
289
+ {
290
+ "env": {
291
+ "SAL_PROJECT_ID": "local-dev",
292
+ "SAL_STORAGE_TYPE": "s3",
293
+ "SAL_STORAGE_BUCKET": "sal-sessions",
294
+ "SAL_STORAGE_REGION": "us-east-1",
295
+ "SAL_STORAGE_ENDPOINT": "http://localhost:4566",
296
+ "SAL_STORAGE_ID": "test",
297
+ "SAL_STORAGE_SECRET": "test"
298
+ }
299
+ }
300
+ ```
301
+
302
+ ## Opting out
303
+
304
+ | Goal | Setting |
305
+ | ----------------------------- | -------------------------------- |
306
+ | Disable transcript capture | `SAL_CAPTURE_TRANSCRIPTS=false` |
307
+ | Fully disable synchronization | `SAL_SYNC_DISABLED=true` |
308
+
309
+ When fully disabled, the engine performs no filesystem discovery beyond the
310
+ minimum required to determine that synchronization is disabled, and
311
+ `SessionStart` does not spawn the watcher.
312
+
313
+ ## Development
314
+
315
+ ```bash
316
+ # Build the plugin
317
+ pnpm --filter @lucasschirm/claude-session-sync build
318
+
319
+ # Run tests
320
+ pnpm --filter @lucasschirm/claude-session-sync test
321
+
322
+ # Typecheck
323
+ pnpm --filter @lucasschirm/claude-session-sync typecheck
324
+
325
+ # Lint
326
+ pnpm --filter @lucasschirm/claude-session-sync lint
327
+ ```
328
+
329
+ ### Package structure
330
+
331
+ ```
332
+ packages/plugins/claude-session-sync/
333
+ ├── .claude-plugin/
334
+ │ └── plugin.json # Plugin manifest
335
+ ├── hooks/
336
+ │ └── hooks.json # Lifecycle hook definitions
337
+ ├── src/
338
+ │ ├── claude.ts # Hook input parsing + Claude session mapping
339
+ │ ├── hook.ts # Generic hook entry (PreCompact/PostCompact/Stop/...)
340
+ │ ├── session-start.ts # SessionStart entry point
341
+ │ ├── session-end.ts # SessionEnd entry point
342
+ │ ├── transcript-watcher.ts # Detached watcher spawner
343
+ │ └── index.ts # Public API barrel
344
+ ├── bin/ # Built executables (esbuild single-file bundles)
345
+ ├── build.mjs # esbuild bundling script
346
+ ├── tests/
347
+ │ ├── unit/ # Unit tests
348
+ │ └── e2e/ # End-to-end plugin lifecycle tests
349
+ └── package.json
350
+ ```
351
+
352
+ ## License
353
+
354
+ ISC