claude-opencode-sessions 0.1.0__tar.gz

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.
Files changed (34) hide show
  1. claude_opencode_sessions-0.1.0/.gitignore +12 -0
  2. claude_opencode_sessions-0.1.0/CHANGELOG.rst +24 -0
  3. claude_opencode_sessions-0.1.0/LICENSE +21 -0
  4. claude_opencode_sessions-0.1.0/PKG-INFO +287 -0
  5. claude_opencode_sessions-0.1.0/README.rst +258 -0
  6. claude_opencode_sessions-0.1.0/pyproject.toml +90 -0
  7. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/__init__.py +10 -0
  8. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/__main__.py +3 -0
  9. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/cli.py +196 -0
  10. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/cli_backend.py +140 -0
  11. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/errors.py +39 -0
  12. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/import_command.py +216 -0
  13. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/importer.py +414 -0
  14. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/locate.py +90 -0
  15. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/models.py +96 -0
  16. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/parse.py +224 -0
  17. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/py.typed +0 -0
  18. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/render.py +169 -0
  19. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/scope.py +160 -0
  20. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/service.py +149 -0
  21. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/sqlite_backend.py +249 -0
  22. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/__init__.py +0 -0
  23. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/conftest.py +314 -0
  24. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/fixtures/schema_1x.sql +76 -0
  25. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/fixtures/schema_2x.sql +37 -0
  26. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_cli.py +140 -0
  27. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_cli_backend.py +116 -0
  28. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_importer.py +504 -0
  29. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_launcher.py +47 -0
  30. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_locate.py +62 -0
  31. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_parse.py +120 -0
  32. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_render.py +107 -0
  33. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_scope.py +121 -0
  34. claude_opencode_sessions-0.1.0/src/claude_opencode_sessions/tests/test_sqlite_backend.py +157 -0
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ .coverage
8
+ htmlcov/
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+ .DS_Store
@@ -0,0 +1,24 @@
1
+ =========
2
+ Changelog
3
+ =========
4
+ All notable changes to this project are documented here. Versions apply to
5
+ both the PyPI package ``claude-opencode-sessions`` and the Claude Code plugin
6
+ ``opencode-sessions``.
7
+
8
+ 0.1.0
9
+ =====
10
+ 2026-09-30
11
+
12
+ - First release.
13
+ - ``import``, ``list`` and ``doctor`` commands (``claude-opencode-sessions``).
14
+ - Reads opencode's SQLite database directly, read-only: opencode 1.x
15
+ (>= 1.2, ``session``/``message``/``part``) and 2.x
16
+ (``session_v2``/``session_message``), with ``opencode session list`` /
17
+ ``opencode export`` as a fallback.
18
+ - Scoping mirrors Claude Code's ``/resume``: current worktree by default,
19
+ ``--worktrees``, ``--all``.
20
+ - Claude Code plugin ``opencode-sessions`` with ``/opencode-sessions:import``.
21
+ It imports the repository's opencode sessions as Claude Code conversations,
22
+ so they open with ``/resume``. It runs in a ``UserPromptExpansion`` hook
23
+ without a model call, and never creates duplicates (content-addressed
24
+ session ids, plus ``(1)``, ``(2)``… suffixes for changed sessions).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artur Barseghyan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.5
2
+ Name: claude-opencode-sessions
3
+ Version: 0.1.0
4
+ Summary: Import your opencode sessions for the current repository into Claude Code, so they open with /resume.
5
+ Project-URL: Homepage, https://github.com/barseghyanartur/claude-plugin-opencode-sessions
6
+ Project-URL: Repository, https://github.com/barseghyanartur/claude-plugin-opencode-sessions
7
+ Project-URL: Issues, https://github.com/barseghyanartur/claude-plugin-opencode-sessions/issues
8
+ Project-URL: Changelog, https://github.com/barseghyanartur/claude-plugin-opencode-sessions/blob/main/CHANGELOG.rst
9
+ Author-email: Artur Barseghyan <artur.barseghyan@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,claude,claude-code,llm,opencode,plugin,sessions
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Software Development
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/x-rst
29
+
30
+ ========================
31
+ claude-opencode-sessions
32
+ ========================
33
+ Bring your `opencode <https://opencode.ai>`_ sessions into **Claude Code**.
34
+
35
+ In Claude Code, run ``/opencode-sessions:import``. Your opencode sessions for
36
+ the current repository become regular Claude Code conversations, titled
37
+ ``[opencode] …``. Then use ``/resume`` (or ``claude --resume``) to browse
38
+ them, and press Enter to continue one.
39
+
40
+ - **No model call, no tokens.** The import runs in a Claude Code hook and
41
+ prints its report directly. Tokens are only spent once you resume a session
42
+ and start typing, just like any other conversation.
43
+ - **No duplicates, ever.** A session whose content hasn't changed since its
44
+ last import is skipped. A session that changed gets a new copy with the
45
+ next suffix: ``Title``, ``Title (1)``, ``Title (2)``…. Existing files are
46
+ never overwritten.
47
+ - **Only this repository.** Scoping works like ``/resume``: the current git
48
+ worktree by default, or ``--worktrees`` for all worktrees of the repo.
49
+ - Reads opencode's SQLite database **read-only**: opencode 1.2+ (1.x and 2.x
50
+ layouts), with ``opencode export`` as a fallback.
51
+ - Python 3.10+, standard library only. No network access.
52
+ - The same package also works as a command-line tool:
53
+ ``claude-opencode-sessions`` runs ``import`` and ``list`` in the terminal.
54
+
55
+ .. contents:: Table of contents
56
+ :depth: 2
57
+ :local:
58
+
59
+ Install
60
+ =======
61
+ As a Claude Code plugin
62
+ -----------------------
63
+ .. code-block:: sh
64
+
65
+ claude plugin marketplace add barseghyanartur/claude-plugin-opencode-sessions
66
+ claude plugin install opencode-sessions@barseghyanartur
67
+
68
+ Or inside a Claude Code session:
69
+
70
+ .. code-block:: text
71
+
72
+ /plugin marketplace add barseghyanartur/claude-plugin-opencode-sessions
73
+ /plugin install opencode-sessions@barseghyanartur
74
+
75
+ Update later with ``claude plugin update opencode-sessions@barseghyanartur``,
76
+ or turn on auto-update for the marketplace under **Marketplaces** in
77
+ ``/plugin``.
78
+
79
+ The plugin runs the code bundled in the plugin itself, so it does not need
80
+ the PyPI package. It needs a Python >= 3.10 on ``PATH`` (``python3``,
81
+ ``python3.1x``) or `uv <https://docs.astral.sh/uv/>`_. Note that
82
+ ``/usr/bin/python3`` on macOS is 3.9. ``brew install python`` or
83
+ ``uv python install 3.12`` fixes that, or set ``OCS_PYTHON=/path/to/python``.
84
+
85
+ As a command-line tool
86
+ ----------------------
87
+ .. code-block:: sh
88
+
89
+ uv tool install claude-opencode-sessions # or: pipx install claude-opencode-sessions
90
+ uvx claude-opencode-sessions list # one-off run without installing
91
+
92
+ Usage in Claude Code
93
+ ====================
94
+ .. code-block:: text
95
+
96
+ /opencode-sessions:import # sessions of the current worktree
97
+ /opencode-sessions:import --worktrees # every worktree of the repository
98
+ /opencode-sessions:import --dry-run # show what would happen
99
+ /opencode-sessions:import --with-tool-output # include (truncated) tool output
100
+ /resume # pick an "[opencode] …" session
101
+
102
+ Example report:
103
+
104
+ .. code-block:: text
105
+
106
+ opencode → Claude Code import · git worktree /Users/me/repos/brrn
107
+ into ~/.claude/projects/-Users-me-repos-brrn
108
+
109
+ imported [opencode] Fixing stalled make armdict-fetch-hy build (1)
110
+ unchanged [opencode] HTTP Request/Response Log Analysis for brrn.ru …
111
+
112
+ 1 imported, 1 unchanged · skipped: 1 sub-agent
113
+ Open them with /resume — titles start with "[opencode]".
114
+
115
+ What an imported conversation contains
116
+ --------------------------------------
117
+ - One transcript per opencode session, in Claude Code's own session folder
118
+ for this project (``~/.claude/projects/<project>/<uuid>.jsonl``).
119
+ - User messages and assistant replies as text. Each tool call becomes one
120
+ line (``→ bash: `pytest -x```), and its output is left out unless you pass
121
+ ``--with-tool-output``. Reasoning, synthetic and sub-agent content are left
122
+ out.
123
+ - A first line saying which opencode session it came from. Claude reads this
124
+ when you resume, so it knows the context.
125
+
126
+ How duplicates are prevented
127
+ ----------------------------
128
+ The Claude session id is ``uuid5(opencode session id + hash of the converted
129
+ content)``. Importing unchanged content maps to a file that already exists,
130
+ so it is skipped. The first line of each imported file records the opencode
131
+ session id, content hash and suffix, so changed content gets the next free
132
+ suffix (the highest existing one + 1). New files are written under a
133
+ temporary name and hard-linked into place, which can't overwrite an existing
134
+ file. Continuing an imported conversation in Claude doesn't count as a
135
+ change: only the opencode side is compared.
136
+
137
+ Claude Code's transcript format is internal and may change between Claude
138
+ Code versions. The importer writes only a minimal, stable subset of it.
139
+
140
+ Command line
141
+ ============
142
+ The same package works in the terminal:
143
+
144
+ .. code-block:: sh
145
+
146
+ claude-opencode-sessions import --dry-run # same as /opencode-sessions:import
147
+ claude-opencode-sessions import --worktrees
148
+ claude-opencode-sessions list # sessions in scope, newest first
149
+ claude-opencode-sessions list --all --format json
150
+ claude-opencode-sessions doctor # environment + database report
151
+
152
+ Hidden by default: archived sessions (``--include-archived``) and sub-agent
153
+ sessions (``--include-subagents``).
154
+
155
+ Scoping
156
+ -------
157
+ .. list-table::
158
+ :header-rows: 1
159
+ :widths: 12 20 50 18
160
+
161
+ * - Mode
162
+ - Flag
163
+ - Sessions whose directory is…
164
+ - ``/resume`` equivalent
165
+ * - worktree
166
+ - *(default)*
167
+ - inside the current git worktree (its top-level directory or below).
168
+ Outside git: the current directory or below
169
+ - default view
170
+ * - repo
171
+ - ``--worktrees``
172
+ - inside any worktree of the repository, plus sessions of the same
173
+ opencode project whose worktree was deleted
174
+ - ``Ctrl+W``
175
+ * - all
176
+ - ``--all`` (``list`` only)
177
+ - anywhere
178
+ - ``Ctrl+A``
179
+
180
+ Configuration
181
+ -------------
182
+ .. list-table::
183
+ :header-rows: 1
184
+ :widths: 30 70
185
+
186
+ * - Variable
187
+ - Purpose
188
+ * - ``OPENCODE_SESSIONS_DB``
189
+ - Path to ``opencode.db``. Default:
190
+ ``$XDG_DATA_HOME/opencode/opencode.db``, then
191
+ ``~/.local/share/opencode/opencode.db``, then ``opencode db path``
192
+ * - ``OCS_PYTHON``
193
+ - Interpreter for the plugin launcher (``scripts/opencode-sessions``)
194
+
195
+ Every command also accepts ``--db PATH`` and ``--backend auto|sqlite|cli``.
196
+
197
+ How it works
198
+ ============
199
+ - **sqlite** (default): opens ``opencode.db`` with ``mode=ro``. On 2.x it
200
+ reads ``session_v2`` + ``session_message``. On 1.x it reads ``session`` +
201
+ ``message`` + ``part``. When both exist in the same file, sessions are
202
+ merged by id (2.x wins), and messages fall back to the 1.x tables per
203
+ session.
204
+ - **cli** (fallback): used when the database is missing, locked or not
205
+ recognised, or when more than 20% of a session's messages can't be parsed.
206
+ It runs ``opencode session list --format json`` and
207
+ ``opencode export <id>``.
208
+
209
+ See `docs/design.md <docs/design.md>`_ for the design and
210
+ `docs/schema-notes.md <docs/schema-notes.md>`_ for the tables and fields
211
+ that are read.
212
+
213
+ Development
214
+ ===========
215
+ .. code-block:: sh
216
+
217
+ make install # uv sync (creates .venv with dev tools)
218
+ make test # pytest (tests live in src/claude_opencode_sessions/tests)
219
+ make check # ruff + mypy --strict + pytest + manifest validation
220
+ make run ARGS="list --all"
221
+ make dev # claude --plugin-dir . (live plugin; /reload-plugins after edits)
222
+ make install-local / make uninstall-local
223
+
224
+ Publishing
225
+ ==========
226
+ One version number covers both the PyPI package and the plugin. It lives in
227
+ ``pyproject.toml`` (managed with ``uv version``), and ``make bump`` copies it
228
+ into ``.claude-plugin/plugin.json``.
229
+
230
+ How each channel works
231
+ ----------------------
232
+ - **Claude Code plugin:** there is no registry upload. This repository *is*
233
+ the marketplace (``.claude-plugin/marketplace.json``), so pushing to
234
+ ``main`` publishes. Users only receive an update when the ``version`` in
235
+ ``plugin.json`` changes, so every release must bump it.
236
+ - **PyPI:** ``claude-opencode-sessions`` is uploaded with ``twine``, using
237
+ the credentials in ``~/.pypirc``, so you don't type them each time.
238
+ - **Anthropic community marketplace (optional):** a reviewed listing in
239
+ ``anthropics/claude-plugins-community``, pinned to a commit. Submit through
240
+ the form that ``make submit`` prints the details for.
241
+
242
+ One-time setup
243
+ --------------
244
+ Put API tokens for PyPI and TestPyPI in ``~/.pypirc`` (``chmod 600``):
245
+
246
+ .. code-block:: ini
247
+
248
+ [distutils]
249
+ index-servers =
250
+ pypi
251
+ testpypi
252
+
253
+ [pypi]
254
+ username = __token__
255
+ password = pypi-...
256
+
257
+ [testpypi]
258
+ repository = https://test.pypi.org/legacy/
259
+ username = __token__
260
+ password = pypi-...
261
+
262
+ Release checklist
263
+ -----------------
264
+ .. code-block:: sh
265
+
266
+ make bump BUMP=minor # or BUMP=patch|major, or VERSION=0.2.0
267
+ $EDITOR CHANGELOG.rst # add the release notes
268
+ git commit -am "Release $(uv version --short)"
269
+ make test-release # check, build, twine check, upload to TestPyPI
270
+ make release # the same, upload to PyPI
271
+ make tag # tag vX.Y.Z and push (plugin users get the update)
272
+
273
+ For the community marketplace, run ``make submit`` after the release and
274
+ file the form.
275
+
276
+ Troubleshooting
277
+ ===============
278
+ If ``/opencode-sessions:import`` makes Claude answer instead of printing a
279
+ report, the hook didn't run. Check the Python requirement above and run
280
+ ``claude-opencode-sessions doctor``, or
281
+ ``sh ~/.claude/plugins/…/scripts/opencode-sessions doctor``. It shows the
282
+ Python in use, the database path, the detected layout, row counts and the
283
+ scope roots for the current directory.
284
+
285
+ License
286
+ =======
287
+ MIT
@@ -0,0 +1,258 @@
1
+ ========================
2
+ claude-opencode-sessions
3
+ ========================
4
+ Bring your `opencode <https://opencode.ai>`_ sessions into **Claude Code**.
5
+
6
+ In Claude Code, run ``/opencode-sessions:import``. Your opencode sessions for
7
+ the current repository become regular Claude Code conversations, titled
8
+ ``[opencode] …``. Then use ``/resume`` (or ``claude --resume``) to browse
9
+ them, and press Enter to continue one.
10
+
11
+ - **No model call, no tokens.** The import runs in a Claude Code hook and
12
+ prints its report directly. Tokens are only spent once you resume a session
13
+ and start typing, just like any other conversation.
14
+ - **No duplicates, ever.** A session whose content hasn't changed since its
15
+ last import is skipped. A session that changed gets a new copy with the
16
+ next suffix: ``Title``, ``Title (1)``, ``Title (2)``…. Existing files are
17
+ never overwritten.
18
+ - **Only this repository.** Scoping works like ``/resume``: the current git
19
+ worktree by default, or ``--worktrees`` for all worktrees of the repo.
20
+ - Reads opencode's SQLite database **read-only**: opencode 1.2+ (1.x and 2.x
21
+ layouts), with ``opencode export`` as a fallback.
22
+ - Python 3.10+, standard library only. No network access.
23
+ - The same package also works as a command-line tool:
24
+ ``claude-opencode-sessions`` runs ``import`` and ``list`` in the terminal.
25
+
26
+ .. contents:: Table of contents
27
+ :depth: 2
28
+ :local:
29
+
30
+ Install
31
+ =======
32
+ As a Claude Code plugin
33
+ -----------------------
34
+ .. code-block:: sh
35
+
36
+ claude plugin marketplace add barseghyanartur/claude-plugin-opencode-sessions
37
+ claude plugin install opencode-sessions@barseghyanartur
38
+
39
+ Or inside a Claude Code session:
40
+
41
+ .. code-block:: text
42
+
43
+ /plugin marketplace add barseghyanartur/claude-plugin-opencode-sessions
44
+ /plugin install opencode-sessions@barseghyanartur
45
+
46
+ Update later with ``claude plugin update opencode-sessions@barseghyanartur``,
47
+ or turn on auto-update for the marketplace under **Marketplaces** in
48
+ ``/plugin``.
49
+
50
+ The plugin runs the code bundled in the plugin itself, so it does not need
51
+ the PyPI package. It needs a Python >= 3.10 on ``PATH`` (``python3``,
52
+ ``python3.1x``) or `uv <https://docs.astral.sh/uv/>`_. Note that
53
+ ``/usr/bin/python3`` on macOS is 3.9. ``brew install python`` or
54
+ ``uv python install 3.12`` fixes that, or set ``OCS_PYTHON=/path/to/python``.
55
+
56
+ As a command-line tool
57
+ ----------------------
58
+ .. code-block:: sh
59
+
60
+ uv tool install claude-opencode-sessions # or: pipx install claude-opencode-sessions
61
+ uvx claude-opencode-sessions list # one-off run without installing
62
+
63
+ Usage in Claude Code
64
+ ====================
65
+ .. code-block:: text
66
+
67
+ /opencode-sessions:import # sessions of the current worktree
68
+ /opencode-sessions:import --worktrees # every worktree of the repository
69
+ /opencode-sessions:import --dry-run # show what would happen
70
+ /opencode-sessions:import --with-tool-output # include (truncated) tool output
71
+ /resume # pick an "[opencode] …" session
72
+
73
+ Example report:
74
+
75
+ .. code-block:: text
76
+
77
+ opencode → Claude Code import · git worktree /Users/me/repos/brrn
78
+ into ~/.claude/projects/-Users-me-repos-brrn
79
+
80
+ imported [opencode] Fixing stalled make armdict-fetch-hy build (1)
81
+ unchanged [opencode] HTTP Request/Response Log Analysis for brrn.ru …
82
+
83
+ 1 imported, 1 unchanged · skipped: 1 sub-agent
84
+ Open them with /resume — titles start with "[opencode]".
85
+
86
+ What an imported conversation contains
87
+ --------------------------------------
88
+ - One transcript per opencode session, in Claude Code's own session folder
89
+ for this project (``~/.claude/projects/<project>/<uuid>.jsonl``).
90
+ - User messages and assistant replies as text. Each tool call becomes one
91
+ line (``→ bash: `pytest -x```), and its output is left out unless you pass
92
+ ``--with-tool-output``. Reasoning, synthetic and sub-agent content are left
93
+ out.
94
+ - A first line saying which opencode session it came from. Claude reads this
95
+ when you resume, so it knows the context.
96
+
97
+ How duplicates are prevented
98
+ ----------------------------
99
+ The Claude session id is ``uuid5(opencode session id + hash of the converted
100
+ content)``. Importing unchanged content maps to a file that already exists,
101
+ so it is skipped. The first line of each imported file records the opencode
102
+ session id, content hash and suffix, so changed content gets the next free
103
+ suffix (the highest existing one + 1). New files are written under a
104
+ temporary name and hard-linked into place, which can't overwrite an existing
105
+ file. Continuing an imported conversation in Claude doesn't count as a
106
+ change: only the opencode side is compared.
107
+
108
+ Claude Code's transcript format is internal and may change between Claude
109
+ Code versions. The importer writes only a minimal, stable subset of it.
110
+
111
+ Command line
112
+ ============
113
+ The same package works in the terminal:
114
+
115
+ .. code-block:: sh
116
+
117
+ claude-opencode-sessions import --dry-run # same as /opencode-sessions:import
118
+ claude-opencode-sessions import --worktrees
119
+ claude-opencode-sessions list # sessions in scope, newest first
120
+ claude-opencode-sessions list --all --format json
121
+ claude-opencode-sessions doctor # environment + database report
122
+
123
+ Hidden by default: archived sessions (``--include-archived``) and sub-agent
124
+ sessions (``--include-subagents``).
125
+
126
+ Scoping
127
+ -------
128
+ .. list-table::
129
+ :header-rows: 1
130
+ :widths: 12 20 50 18
131
+
132
+ * - Mode
133
+ - Flag
134
+ - Sessions whose directory is…
135
+ - ``/resume`` equivalent
136
+ * - worktree
137
+ - *(default)*
138
+ - inside the current git worktree (its top-level directory or below).
139
+ Outside git: the current directory or below
140
+ - default view
141
+ * - repo
142
+ - ``--worktrees``
143
+ - inside any worktree of the repository, plus sessions of the same
144
+ opencode project whose worktree was deleted
145
+ - ``Ctrl+W``
146
+ * - all
147
+ - ``--all`` (``list`` only)
148
+ - anywhere
149
+ - ``Ctrl+A``
150
+
151
+ Configuration
152
+ -------------
153
+ .. list-table::
154
+ :header-rows: 1
155
+ :widths: 30 70
156
+
157
+ * - Variable
158
+ - Purpose
159
+ * - ``OPENCODE_SESSIONS_DB``
160
+ - Path to ``opencode.db``. Default:
161
+ ``$XDG_DATA_HOME/opencode/opencode.db``, then
162
+ ``~/.local/share/opencode/opencode.db``, then ``opencode db path``
163
+ * - ``OCS_PYTHON``
164
+ - Interpreter for the plugin launcher (``scripts/opencode-sessions``)
165
+
166
+ Every command also accepts ``--db PATH`` and ``--backend auto|sqlite|cli``.
167
+
168
+ How it works
169
+ ============
170
+ - **sqlite** (default): opens ``opencode.db`` with ``mode=ro``. On 2.x it
171
+ reads ``session_v2`` + ``session_message``. On 1.x it reads ``session`` +
172
+ ``message`` + ``part``. When both exist in the same file, sessions are
173
+ merged by id (2.x wins), and messages fall back to the 1.x tables per
174
+ session.
175
+ - **cli** (fallback): used when the database is missing, locked or not
176
+ recognised, or when more than 20% of a session's messages can't be parsed.
177
+ It runs ``opencode session list --format json`` and
178
+ ``opencode export <id>``.
179
+
180
+ See `docs/design.md <docs/design.md>`_ for the design and
181
+ `docs/schema-notes.md <docs/schema-notes.md>`_ for the tables and fields
182
+ that are read.
183
+
184
+ Development
185
+ ===========
186
+ .. code-block:: sh
187
+
188
+ make install # uv sync (creates .venv with dev tools)
189
+ make test # pytest (tests live in src/claude_opencode_sessions/tests)
190
+ make check # ruff + mypy --strict + pytest + manifest validation
191
+ make run ARGS="list --all"
192
+ make dev # claude --plugin-dir . (live plugin; /reload-plugins after edits)
193
+ make install-local / make uninstall-local
194
+
195
+ Publishing
196
+ ==========
197
+ One version number covers both the PyPI package and the plugin. It lives in
198
+ ``pyproject.toml`` (managed with ``uv version``), and ``make bump`` copies it
199
+ into ``.claude-plugin/plugin.json``.
200
+
201
+ How each channel works
202
+ ----------------------
203
+ - **Claude Code plugin:** there is no registry upload. This repository *is*
204
+ the marketplace (``.claude-plugin/marketplace.json``), so pushing to
205
+ ``main`` publishes. Users only receive an update when the ``version`` in
206
+ ``plugin.json`` changes, so every release must bump it.
207
+ - **PyPI:** ``claude-opencode-sessions`` is uploaded with ``twine``, using
208
+ the credentials in ``~/.pypirc``, so you don't type them each time.
209
+ - **Anthropic community marketplace (optional):** a reviewed listing in
210
+ ``anthropics/claude-plugins-community``, pinned to a commit. Submit through
211
+ the form that ``make submit`` prints the details for.
212
+
213
+ One-time setup
214
+ --------------
215
+ Put API tokens for PyPI and TestPyPI in ``~/.pypirc`` (``chmod 600``):
216
+
217
+ .. code-block:: ini
218
+
219
+ [distutils]
220
+ index-servers =
221
+ pypi
222
+ testpypi
223
+
224
+ [pypi]
225
+ username = __token__
226
+ password = pypi-...
227
+
228
+ [testpypi]
229
+ repository = https://test.pypi.org/legacy/
230
+ username = __token__
231
+ password = pypi-...
232
+
233
+ Release checklist
234
+ -----------------
235
+ .. code-block:: sh
236
+
237
+ make bump BUMP=minor # or BUMP=patch|major, or VERSION=0.2.0
238
+ $EDITOR CHANGELOG.rst # add the release notes
239
+ git commit -am "Release $(uv version --short)"
240
+ make test-release # check, build, twine check, upload to TestPyPI
241
+ make release # the same, upload to PyPI
242
+ make tag # tag vX.Y.Z and push (plugin users get the update)
243
+
244
+ For the community marketplace, run ``make submit`` after the release and
245
+ file the form.
246
+
247
+ Troubleshooting
248
+ ===============
249
+ If ``/opencode-sessions:import`` makes Claude answer instead of printing a
250
+ report, the hook didn't run. Check the Python requirement above and run
251
+ ``claude-opencode-sessions doctor``, or
252
+ ``sh ~/.claude/plugins/…/scripts/opencode-sessions doctor``. It shows the
253
+ Python in use, the database path, the detected layout, row counts and the
254
+ scope roots for the current directory.
255
+
256
+ License
257
+ =======
258
+ MIT
@@ -0,0 +1,90 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "claude-opencode-sessions"
7
+ version = "0.1.0"
8
+ description = "Import your opencode sessions for the current repository into Claude Code, so they open with /resume."
9
+ readme = "README.rst"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Artur Barseghyan", email = "artur.barseghyan@gmail.com" }]
14
+ keywords = ["opencode", "claude", "claude-code", "plugin", "sessions", "llm", "agents"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Software Development",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = []
32
+
33
+ [project.scripts]
34
+ claude-opencode-sessions = "claude_opencode_sessions.cli:main"
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/barseghyanartur/claude-plugin-opencode-sessions"
38
+ Repository = "https://github.com/barseghyanartur/claude-plugin-opencode-sessions"
39
+ Issues = "https://github.com/barseghyanartur/claude-plugin-opencode-sessions/issues"
40
+ Changelog = "https://github.com/barseghyanartur/claude-plugin-opencode-sessions/blob/main/CHANGELOG.rst"
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pytest>=8",
45
+ "pytest-cov>=5",
46
+ "ruff>=0.6",
47
+ "mypy>=1.11",
48
+ "twine>=6",
49
+ ]
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/claude_opencode_sessions"]
53
+
54
+ [tool.hatch.build.targets.sdist]
55
+ include = [
56
+ "src/claude_opencode_sessions",
57
+ "README.rst",
58
+ "CHANGELOG.rst",
59
+ "LICENSE",
60
+ ]
61
+
62
+ [tool.pytest.ini_options]
63
+ testpaths = ["src/claude_opencode_sessions/tests"]
64
+ addopts = "-ra"
65
+
66
+ [tool.coverage.run]
67
+ source = ["claude_opencode_sessions"]
68
+ omit = ["*/tests/*"]
69
+
70
+ [tool.coverage.report]
71
+ show_missing = true
72
+ skip_covered = true
73
+
74
+ [tool.ruff]
75
+ line-length = 88
76
+ target-version = "py310"
77
+ src = ["src"]
78
+
79
+ [tool.ruff.lint]
80
+ select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF", "C4"]
81
+ ignore = ["SIM300", "RUF001"]
82
+
83
+ [tool.ruff.lint.per-file-ignores]
84
+ "src/claude_opencode_sessions/tests/*" = ["E501"]
85
+
86
+ [tool.mypy]
87
+ python_version = "3.10"
88
+ strict = true
89
+ files = ["src/claude_opencode_sessions"]
90
+ exclude = ["src/claude_opencode_sessions/tests/"]