skein-cli 0.1.0-alpha.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.
Files changed (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +180 -0
  3. package/bin/skein.mjs +7 -0
  4. package/dist/adapters/aider/conv-reader.d.ts +7 -0
  5. package/dist/adapters/aider/conv-reader.js +203 -0
  6. package/dist/adapters/aider/conv-reader.js.map +1 -0
  7. package/dist/adapters/aider/index.d.ts +2 -0
  8. package/dist/adapters/aider/index.js +123 -0
  9. package/dist/adapters/aider/index.js.map +1 -0
  10. package/dist/adapters/base.d.ts +71 -0
  11. package/dist/adapters/base.js +38 -0
  12. package/dist/adapters/base.js.map +1 -0
  13. package/dist/adapters/claude-code/conv-reader.d.ts +2 -0
  14. package/dist/adapters/claude-code/conv-reader.js +155 -0
  15. package/dist/adapters/claude-code/conv-reader.js.map +1 -0
  16. package/dist/adapters/claude-code/index.d.ts +3 -0
  17. package/dist/adapters/claude-code/index.js +517 -0
  18. package/dist/adapters/claude-code/index.js.map +1 -0
  19. package/dist/adapters/claude-desktop/index.d.ts +2 -0
  20. package/dist/adapters/claude-desktop/index.js +95 -0
  21. package/dist/adapters/claude-desktop/index.js.map +1 -0
  22. package/dist/adapters/codex/index.d.ts +2 -0
  23. package/dist/adapters/codex/index.js +472 -0
  24. package/dist/adapters/codex/index.js.map +1 -0
  25. package/dist/adapters/cursor/index.d.ts +2 -0
  26. package/dist/adapters/cursor/index.js +255 -0
  27. package/dist/adapters/cursor/index.js.map +1 -0
  28. package/dist/adapters/opencode/conv-reader.d.ts +3 -0
  29. package/dist/adapters/opencode/conv-reader.js +190 -0
  30. package/dist/adapters/opencode/conv-reader.js.map +1 -0
  31. package/dist/adapters/opencode/index.d.ts +2 -0
  32. package/dist/adapters/opencode/index.js +349 -0
  33. package/dist/adapters/opencode/index.js.map +1 -0
  34. package/dist/adapters/registry.d.ts +4 -0
  35. package/dist/adapters/registry.js +26 -0
  36. package/dist/adapters/registry.js.map +1 -0
  37. package/dist/cli.d.ts +3 -0
  38. package/dist/cli.js +54 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/commands/conv.d.ts +2 -0
  41. package/dist/commands/conv.js +261 -0
  42. package/dist/commands/conv.js.map +1 -0
  43. package/dist/commands/doctor.d.ts +2 -0
  44. package/dist/commands/doctor.js +85 -0
  45. package/dist/commands/doctor.js.map +1 -0
  46. package/dist/commands/init.d.ts +2 -0
  47. package/dist/commands/init.js +38 -0
  48. package/dist/commands/init.js.map +1 -0
  49. package/dist/commands/memory.d.ts +2 -0
  50. package/dist/commands/memory.js +197 -0
  51. package/dist/commands/memory.js.map +1 -0
  52. package/dist/commands/migrate.d.ts +2 -0
  53. package/dist/commands/migrate.js +102 -0
  54. package/dist/commands/migrate.js.map +1 -0
  55. package/dist/commands/profile.d.ts +2 -0
  56. package/dist/commands/profile.js +183 -0
  57. package/dist/commands/profile.js.map +1 -0
  58. package/dist/commands/redact.d.ts +2 -0
  59. package/dist/commands/redact.js +73 -0
  60. package/dist/commands/redact.js.map +1 -0
  61. package/dist/commands/trace.d.ts +2 -0
  62. package/dist/commands/trace.js +181 -0
  63. package/dist/commands/trace.js.map +1 -0
  64. package/dist/commands/view.d.ts +13 -0
  65. package/dist/commands/view.js +184 -0
  66. package/dist/commands/view.js.map +1 -0
  67. package/dist/commands/watch.d.ts +6 -0
  68. package/dist/commands/watch.js +61 -0
  69. package/dist/commands/watch.js.map +1 -0
  70. package/dist/commands/wrap.d.ts +2 -0
  71. package/dist/commands/wrap.js +131 -0
  72. package/dist/commands/wrap.js.map +1 -0
  73. package/dist/conv/chatgpt-import.d.ts +33 -0
  74. package/dist/conv/chatgpt-import.js +145 -0
  75. package/dist/conv/chatgpt-import.js.map +1 -0
  76. package/dist/conv/cursor.d.ts +12 -0
  77. package/dist/conv/cursor.js +55 -0
  78. package/dist/conv/cursor.js.map +1 -0
  79. package/dist/conv/export.d.ts +40 -0
  80. package/dist/conv/export.js +215 -0
  81. package/dist/conv/export.js.map +1 -0
  82. package/dist/conv/replay/aider.d.ts +24 -0
  83. package/dist/conv/replay/aider.js +56 -0
  84. package/dist/conv/replay/aider.js.map +1 -0
  85. package/dist/conv/replay/claude-code.d.ts +38 -0
  86. package/dist/conv/replay/claude-code.js +80 -0
  87. package/dist/conv/replay/claude-code.js.map +1 -0
  88. package/dist/conv/replay/context.d.ts +25 -0
  89. package/dist/conv/replay/context.js +63 -0
  90. package/dist/conv/replay/context.js.map +1 -0
  91. package/dist/conv/replay/index.d.ts +22 -0
  92. package/dist/conv/replay/index.js +84 -0
  93. package/dist/conv/replay/index.js.map +1 -0
  94. package/dist/conv/search.d.ts +67 -0
  95. package/dist/conv/search.js +379 -0
  96. package/dist/conv/search.js.map +1 -0
  97. package/dist/conv/sink.d.ts +26 -0
  98. package/dist/conv/sink.js +76 -0
  99. package/dist/conv/sink.js.map +1 -0
  100. package/dist/conv/sources/aider.d.ts +13 -0
  101. package/dist/conv/sources/aider.js +95 -0
  102. package/dist/conv/sources/aider.js.map +1 -0
  103. package/dist/conv/sources/claude-code.d.ts +13 -0
  104. package/dist/conv/sources/claude-code.js +189 -0
  105. package/dist/conv/sources/claude-code.js.map +1 -0
  106. package/dist/conv/sources/codex.d.ts +15 -0
  107. package/dist/conv/sources/codex.js +175 -0
  108. package/dist/conv/sources/codex.js.map +1 -0
  109. package/dist/conv/sources/opencode.d.ts +12 -0
  110. package/dist/conv/sources/opencode.js +92 -0
  111. package/dist/conv/sources/opencode.js.map +1 -0
  112. package/dist/conv/store.d.ts +10 -0
  113. package/dist/conv/store.js +75 -0
  114. package/dist/conv/store.js.map +1 -0
  115. package/dist/conv/title.d.ts +9 -0
  116. package/dist/conv/title.js +74 -0
  117. package/dist/conv/title.js.map +1 -0
  118. package/dist/conv/watcher.d.ts +28 -0
  119. package/dist/conv/watcher.js +75 -0
  120. package/dist/conv/watcher.js.map +1 -0
  121. package/dist/conv/zip.d.ts +11 -0
  122. package/dist/conv/zip.js +82 -0
  123. package/dist/conv/zip.js.map +1 -0
  124. package/dist/hf/client.d.ts +41 -0
  125. package/dist/hf/client.js +87 -0
  126. package/dist/hf/client.js.map +1 -0
  127. package/dist/index.d.ts +5 -0
  128. package/dist/index.js +6 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/ir/index.d.ts +24 -0
  131. package/dist/ir/index.js +23 -0
  132. package/dist/ir/index.js.map +1 -0
  133. package/dist/ir/profile.d.ts +55 -0
  134. package/dist/ir/profile.js +177 -0
  135. package/dist/ir/profile.js.map +1 -0
  136. package/dist/memory/index.d.ts +41 -0
  137. package/dist/memory/index.js +109 -0
  138. package/dist/memory/index.js.map +1 -0
  139. package/dist/memory/search.d.ts +24 -0
  140. package/dist/memory/search.js +114 -0
  141. package/dist/memory/search.js.map +1 -0
  142. package/dist/memory/sinks/claude-mem.d.ts +13 -0
  143. package/dist/memory/sinks/claude-mem.js +100 -0
  144. package/dist/memory/sinks/claude-mem.js.map +1 -0
  145. package/dist/memory/sinks/codex.d.ts +12 -0
  146. package/dist/memory/sinks/codex.js +82 -0
  147. package/dist/memory/sinks/codex.js.map +1 -0
  148. package/dist/memory/sinks/context.d.ts +21 -0
  149. package/dist/memory/sinks/context.js +42 -0
  150. package/dist/memory/sinks/context.js.map +1 -0
  151. package/dist/memory/sources/chatgpt.d.ts +22 -0
  152. package/dist/memory/sources/chatgpt.js +98 -0
  153. package/dist/memory/sources/chatgpt.js.map +1 -0
  154. package/dist/memory/sources/claude-mem.d.ts +8 -0
  155. package/dist/memory/sources/claude-mem.js +104 -0
  156. package/dist/memory/sources/claude-mem.js.map +1 -0
  157. package/dist/memory/sources/codex.d.ts +8 -0
  158. package/dist/memory/sources/codex.js +77 -0
  159. package/dist/memory/sources/codex.js.map +1 -0
  160. package/dist/memory/store.d.ts +19 -0
  161. package/dist/memory/store.js +82 -0
  162. package/dist/memory/store.js.map +1 -0
  163. package/dist/proxy/http.d.ts +21 -0
  164. package/dist/proxy/http.js +205 -0
  165. package/dist/proxy/http.js.map +1 -0
  166. package/dist/proxy/recorder.d.ts +35 -0
  167. package/dist/proxy/recorder.js +221 -0
  168. package/dist/proxy/recorder.js.map +1 -0
  169. package/dist/proxy/streaming.d.ts +33 -0
  170. package/dist/proxy/streaming.js +185 -0
  171. package/dist/proxy/streaming.js.map +1 -0
  172. package/dist/redactor/entropy.d.ts +29 -0
  173. package/dist/redactor/entropy.js +98 -0
  174. package/dist/redactor/entropy.js.map +1 -0
  175. package/dist/redactor/index.d.ts +52 -0
  176. package/dist/redactor/index.js +152 -0
  177. package/dist/redactor/index.js.map +1 -0
  178. package/dist/redactor/ner.d.ts +53 -0
  179. package/dist/redactor/ner.js +97 -0
  180. package/dist/redactor/ner.js.map +1 -0
  181. package/dist/redactor/pii-patterns.d.ts +22 -0
  182. package/dist/redactor/pii-patterns.js +187 -0
  183. package/dist/redactor/pii-patterns.js.map +1 -0
  184. package/dist/redactor/secret-patterns.d.ts +27 -0
  185. package/dist/redactor/secret-patterns.js +475 -0
  186. package/dist/redactor/secret-patterns.js.map +1 -0
  187. package/dist/schema/conv.d.ts +698 -0
  188. package/dist/schema/conv.js +85 -0
  189. package/dist/schema/conv.js.map +1 -0
  190. package/dist/schema/index.d.ts +2 -0
  191. package/dist/schema/index.js +3 -0
  192. package/dist/schema/index.js.map +1 -0
  193. package/dist/schema/manifest.d.ts +1531 -0
  194. package/dist/schema/manifest.js +179 -0
  195. package/dist/schema/manifest.js.map +1 -0
  196. package/dist/schema/memory.d.ts +107 -0
  197. package/dist/schema/memory.js +45 -0
  198. package/dist/schema/memory.js.map +1 -0
  199. package/dist/schema/trace.d.ts +164 -0
  200. package/dist/schema/trace.js +89 -0
  201. package/dist/schema/trace.js.map +1 -0
  202. package/dist/trace/consent.d.ts +30 -0
  203. package/dist/trace/consent.js +60 -0
  204. package/dist/trace/consent.js.map +1 -0
  205. package/dist/trace/extract.d.ts +22 -0
  206. package/dist/trace/extract.js +168 -0
  207. package/dist/trace/extract.js.map +1 -0
  208. package/dist/trace/ml-pii.d.ts +33 -0
  209. package/dist/trace/ml-pii.js +35 -0
  210. package/dist/trace/ml-pii.js.map +1 -0
  211. package/dist/trace/push.d.ts +59 -0
  212. package/dist/trace/push.js +141 -0
  213. package/dist/trace/push.js.map +1 -0
  214. package/dist/trace/serialize.d.ts +23 -0
  215. package/dist/trace/serialize.js +67 -0
  216. package/dist/trace/serialize.js.map +1 -0
  217. package/dist/ui/banner.d.ts +2 -0
  218. package/dist/ui/banner.js +17 -0
  219. package/dist/ui/banner.js.map +1 -0
  220. package/dist/ui/box.d.ts +4 -0
  221. package/dist/ui/box.js +38 -0
  222. package/dist/ui/box.js.map +1 -0
  223. package/dist/ui/index.d.ts +5 -0
  224. package/dist/ui/index.js +5 -0
  225. package/dist/ui/index.js.map +1 -0
  226. package/dist/ui/spinner.d.ts +10 -0
  227. package/dist/ui/spinner.js +44 -0
  228. package/dist/ui/spinner.js.map +1 -0
  229. package/dist/ui/table.d.ts +9 -0
  230. package/dist/ui/table.js +55 -0
  231. package/dist/ui/table.js.map +1 -0
  232. package/dist/util/frontmatter.d.ts +6 -0
  233. package/dist/util/frontmatter.js +20 -0
  234. package/dist/util/frontmatter.js.map +1 -0
  235. package/dist/util/fs.d.ts +5 -0
  236. package/dist/util/fs.js +41 -0
  237. package/dist/util/fs.js.map +1 -0
  238. package/dist/util/ids.d.ts +3 -0
  239. package/dist/util/ids.js +16 -0
  240. package/dist/util/ids.js.map +1 -0
  241. package/dist/util/log.d.ts +13 -0
  242. package/dist/util/log.js +33 -0
  243. package/dist/util/log.js.map +1 -0
  244. package/dist/util/paths.d.ts +18 -0
  245. package/dist/util/paths.js +36 -0
  246. package/dist/util/paths.js.map +1 -0
  247. package/dist/version.d.ts +5 -0
  248. package/dist/version.js +32 -0
  249. package/dist/version.js.map +1 -0
  250. package/package.json +86 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 François Chastel
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.
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ <div align="center">
2
+
3
+ # `skein`
4
+
5
+ ### Move your AI coding harness between tools — and capture, search, and protect every conversation along the way.
6
+
7
+ <br />
8
+
9
+ [![Tests](https://img.shields.io/badge/tests-135%20passing-brightgreen?style=flat-square)](https://github.com/FrancoisChastel/skein/actions)
10
+ [![Node](https://img.shields.io/badge/node-%E2%89%A522-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/)
11
+ [![TypeScript](https://img.shields.io/badge/typescript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
12
+ [![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
13
+ [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](CONTRIBUTING.md)
14
+
15
+ [**Quickstart**](#-quickstart) · [**Docs**](#-documentation) · [**Contributing**](CONTRIBUTING.md)
16
+
17
+ <br />
18
+
19
+ <a href="docs/media/skein-showcase.gif">
20
+ <img src="docs/media/skein-showcase.gif" alt="skein feature showcase: migrate harnesses, capture every conversation, search, redact secrets and PII, contribute redacted traces with real per-turn metrics, and unify memory" width="820" />
21
+ </a>
22
+
23
+ <sub>Every pillar, one take: migrate harnesses · capture every turn · search · redact · contribute <strong>redacted traces with real per-turn metrics</strong> · unify memory.</sub>
24
+
25
+ </div>
26
+
27
+ ---
28
+
29
+ ## What is skein?
30
+
31
+ You've spent months tuning your AI coding setup — subagents, slash commands, hooks, MCP servers, rules, memory. Switching harnesses or sharing that setup means copying files and losing nuance, while your conversations stay locked inside whichever tool created them.
32
+
33
+ **Skein treats your harness as a portable artifact.** One canonical Intermediate Representation, adapters that speak every major coding tool, a universal proxy that captures every LLM turn, a unified memory store, and a four-tier redactor that strips secrets and PII before anything leaves your machine.
34
+
35
+ ```bash
36
+ npx skein-cli migrate --from claude-code --to codex --dry-run
37
+ ```
38
+
39
+ That one command rewrites your entire Claude Code setup into Codex-native format — subagents become skills, `.mcp.json` becomes TOML, hooks travel intact, `CLAUDE.md` becomes `AGENTS.md` — and your past conversations stream into a searchable, replayable archive.
40
+
41
+ ---
42
+
43
+ ## ✨ What skein does
44
+
45
+ <table>
46
+ <tr>
47
+ <td width="50%" valign="top">
48
+
49
+ ### 🔁 Migrate your harness
50
+ One command moves skills, agents, commands, rules, MCP servers, hooks, permissions, and model config between **Claude Code · Codex CLI · OpenCode · Cursor · Aider · Claude Desktop**. Lossless where possible, honestly lossy where it isn't.
51
+
52
+ </td>
53
+ <td width="50%" valign="top">
54
+
55
+ ### 🎙 Capture any tool's conversations
56
+ `skein wrap <tool>` puts an HTTP proxy in front of any harness that talks to an LLM API — Anthropic, OpenAI Chat, OpenAI Responses, streaming SSE included. Works for tools we've never tested too.
57
+
58
+ </td>
59
+ </tr>
60
+ <tr>
61
+ <td width="50%" valign="top">
62
+
63
+ ### 🔎 Search across every session
64
+ SQLite FTS5 over every captured conversation — title, content, full-text, incremental indexing, tool/model/cost breakdowns. The first cross-tool transcript archive.
65
+
66
+ </td>
67
+ <td width="50%" valign="top">
68
+
69
+ ### 🛡️ Defend privacy by default
70
+ Four-tier redactor: 47 secret patterns + Shannon entropy + Luhn-validated PII regex + optional ML NER. Runs on every share. Never on by accident.
71
+
72
+ </td>
73
+ </tr>
74
+ <tr>
75
+ <td width="50%" valign="top">
76
+
77
+ ### 🤗 Share redacted traces
78
+ Contribute per-turn traces — provider, model, effort, **real metrics (tokens, latency, cost)**, tool-call structure, **and redacted prompt / output / tool-I/O** — to one community dataset. Opt-in, scrubbed before it leaves your machine, export to jsonl / json / csv.
79
+
80
+ </td>
81
+ <td width="50%" valign="top">
82
+
83
+ ### 🧠 Unify your memory store
84
+ Pull cross-session observations and saved facts from **claude-mem · Codex · ChatGPT exports** into one log, then migrate them into any other memory system. Native writers for claude-mem + Codex; cloud-only targets get a paste-ready brief.
85
+
86
+ </td>
87
+ </tr>
88
+ </table>
89
+
90
+ ---
91
+
92
+ ## 🚀 Quickstart
93
+
94
+ ```bash
95
+ npm install -g skein-cli # installs the `skein` command (Node ≥ 22, no native build step)
96
+ npx skein-cli doctor # or run without installing
97
+ ```
98
+
99
+ ```bash
100
+ skein doctor # what's installed + what can move where
101
+ skein migrate --from claude-code --to codex # move your whole harness (add --dry-run to preview)
102
+ skein wrap claude # capture every LLM turn behind a local proxy
103
+ skein conv search "auth middleware" # full-text search across every session
104
+ skein redact ./session.jsonl --ml # scrub secrets + PII from anything
105
+ skein memory capture --tool claude-mem # unify cross-tool memory, then import --to <tool>
106
+ skein trace export --format csv --out t.csv # export redacted traces (jsonl | json | csv)
107
+ ```
108
+
109
+ ### A concrete example, end-to-end
110
+
111
+ <div align="center">
112
+
113
+ <a href="docs/media/skein-live-migration.gif">
114
+ <img src="docs/media/skein-live-migration.gif" alt="skein migrating a Claude Code setup into Codex CLI, then unifying memory across both tools" width="760" />
115
+ </a>
116
+
117
+ <sub>On a real machine: profile snapshot → migrate into Codex → capture 4,737 claude-mem observations → replay into <code>~/.codex/memories_1.sqlite</code> → verify.</sub>
118
+
119
+ </div>
120
+
121
+ ---
122
+
123
+ ## 🔌 Supported tools
124
+
125
+ | | Migrate config | Capture conversations | Memory |
126
+ |---|:---:|:---:|:---:|
127
+ | **Claude Code** | ✅ | ✅ | ✅ |
128
+ | **Codex CLI** | ✅ | ✅ | ✅ |
129
+ | **OpenCode** | ✅ | ✅ | — |
130
+ | **Cursor** | ✅ | ✅ (via proxy) | — |
131
+ | **Aider** | ✅ | ✅ | — |
132
+ | **Claude Desktop** | ✅ (MCP) | — | — |
133
+ | **ChatGPT** | — | ✅ (export) | ✅ (export) |
134
+
135
+ Adding a tool is **one adapter file** — see [CONTRIBUTING.md](CONTRIBUTING.md).
136
+
137
+ ---
138
+
139
+ ## 📖 Documentation
140
+
141
+ | Guide | What's inside |
142
+ |---|---|
143
+ | [**Command reference**](docs/COMMANDS.md) | Every command and flag, plus the Conversations & Memory deep-dives |
144
+ | [**Architecture**](docs/ARCHITECTURE.md) | The hub-and-spoke IR, capture modes, conversation format |
145
+ | [**Community traces dataset**](docs/traces-dataset/PLAN.md) | What's published, redaction, consent, and the privacy posture |
146
+ | [**Cookbook**](docs/COOKBOOK.md) | Task-oriented recipes |
147
+ | [**FAQ**](docs/FAQ.md) | Common questions, the IR shape, why hub-and-spoke |
148
+ | [**Roadmap**](docs/ROADMAP.md) | Where skein is headed |
149
+
150
+ ---
151
+
152
+ ## 🛡️ Security & privacy
153
+
154
+ Skein is **local-first** — nothing leaves your machine without an explicit, consented action. The four-tier redactor (secrets regex → entropy → PII regex → optional ML NER) runs before any share, and is also a standalone command:
155
+
156
+ ```bash
157
+ echo 'sk-ant-… alice@example.com 4242 4242 4242 4242' | skein redact
158
+ ```
159
+
160
+ Found a vulnerability? Please report it privately — see [SECURITY.md](SECURITY.md).
161
+
162
+ ---
163
+
164
+ ## 🤝 Contributing
165
+
166
+ Issues and PRs welcome — adding a new tool is usually **one adapter file**. Start with [CONTRIBUTING.md](CONTRIBUTING.md), and be excellent to each other ([Code of Conduct](CODE_OF_CONDUCT.md)).
167
+
168
+ ## 📄 License
169
+
170
+ [MIT](LICENSE) — © 2026 François Chastel and contributors.
171
+
172
+ ---
173
+
174
+ <div align="center">
175
+
176
+ **[Quickstart](#-quickstart)** · **[Docs](#-documentation)** · **[Contributing](CONTRIBUTING.md)**
177
+
178
+ <sub>Made at the intersection of harness migration and conversation portability.</sub>
179
+
180
+ </div>
package/bin/skein.mjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/cli.js')
3
+ .then(m => m.run())
4
+ .catch(err => {
5
+ console.error(err)
6
+ process.exit(1)
7
+ })
@@ -0,0 +1,7 @@
1
+ import type { ConvReader, ReadContext } from '../base.js';
2
+ export interface AiderReaderContext extends ReadContext {
3
+ /** When set, restrict the scan to this project root (default: ctx.projectPath ?? ctx.homeDir). */
4
+ projectPath?: string;
5
+ }
6
+ export declare const aiderConvReader: ConvReader;
7
+ export declare function aiderHistoryPath(ctx: ReadContext): string | undefined;
@@ -0,0 +1,203 @@
1
+ import { createReadStream, promises as fs } from 'node:fs';
2
+ import { createInterface } from 'node:readline';
3
+ import { basename, join } from 'node:path';
4
+ import { CONV_SCHEMA } from '../../version.js';
5
+ /**
6
+ * Aider conv reader.
7
+ *
8
+ * Aider writes one markdown transcript per project at the repo root:
9
+ * `.aider.chat.history.md`. The file uses two reserved separators:
10
+ *
11
+ * - `# aider chat started at <ts>` — opens a new chat session
12
+ * - `####` heading — splits user prompts from assistant responses
13
+ * - `> ` — quoted user prompt within an interleaved turn
14
+ *
15
+ * One markdown file = one or more Skein sessions (split on the
16
+ * `# aider chat started` headers). Each session id is derived from the
17
+ * project basename + the chat-start timestamp so it is stable across
18
+ * re-reads.
19
+ */
20
+ const CHAT_START = /^#\s+aider chat started at (.+?)\s*$/i;
21
+ const HEADING_4 = /^####\s+(.+?)\s*$/;
22
+ const USER_LINE = /^>\s?(.*)$/;
23
+ export const aiderConvReader = {
24
+ async *listSessions(ctx) {
25
+ const path = aiderHistoryPath(ctx);
26
+ if (!path)
27
+ return;
28
+ for await (const session of readSessions(path)) {
29
+ yield aiderSessionToSummary(path, session);
30
+ }
31
+ },
32
+ async *readSession(id, ctx) {
33
+ const path = aiderHistoryPath(ctx);
34
+ if (!path)
35
+ return;
36
+ for await (const session of readSessions(path)) {
37
+ if (session.id !== id)
38
+ continue;
39
+ yield {
40
+ type: 'session.start',
41
+ id: session.id,
42
+ tool: 'aider',
43
+ project: parentOf(path),
44
+ title: session.title,
45
+ schema: CONV_SCHEMA,
46
+ ts: session.startedAt,
47
+ };
48
+ let seq = 0;
49
+ for (const turn of session.turns) {
50
+ seq += 1;
51
+ const content = [{ type: 'text', text: turn.text }];
52
+ yield {
53
+ type: 'message',
54
+ session: session.id,
55
+ seq,
56
+ role: turn.role,
57
+ content,
58
+ ts: session.startedAt,
59
+ };
60
+ }
61
+ yield { type: 'session.end', session: session.id, ts: session.startedAt };
62
+ return;
63
+ }
64
+ },
65
+ };
66
+ export function aiderHistoryPath(ctx) {
67
+ const projectPath = ctx.projectPath ?? process.cwd();
68
+ if (!projectPath)
69
+ return undefined;
70
+ return join(projectPath, '.aider.chat.history.md');
71
+ }
72
+ async function* readSessions(path) {
73
+ if (!(await pathExists(path)))
74
+ return;
75
+ let current;
76
+ let buffer = [];
77
+ let pendingRole = 'user';
78
+ // Tracks whether the previous non-blank line was a `> …` quoted user prompt.
79
+ // When the user block ends (next non-blank line is unquoted), we flush the
80
+ // user turn and start collecting an assistant turn.
81
+ let lastNonBlankWasUserQuote = false;
82
+ const flushTurn = () => {
83
+ if (!current)
84
+ return;
85
+ const text = buffer.join('\n').trim();
86
+ if (text.length === 0) {
87
+ buffer = [];
88
+ return;
89
+ }
90
+ current.turns.push({ role: pendingRole, text });
91
+ buffer = [];
92
+ };
93
+ for await (const line of readLines(path)) {
94
+ const startMatch = CHAT_START.exec(line);
95
+ if (startMatch) {
96
+ flushTurn();
97
+ if (current)
98
+ yield current;
99
+ const startedAt = parseChatTimestamp(startMatch[1] ?? '');
100
+ const title = `Aider chat ${startMatch[1] ?? ''}`.trim();
101
+ current = {
102
+ id: makeSessionId(path, startedAt),
103
+ startedAt,
104
+ title,
105
+ turns: [],
106
+ };
107
+ pendingRole = 'user';
108
+ lastNonBlankWasUserQuote = false;
109
+ continue;
110
+ }
111
+ if (!current) {
112
+ current = {
113
+ id: makeSessionId(path, new Date(0).toISOString()),
114
+ startedAt: new Date(0).toISOString(),
115
+ title: 'Aider chat (no start header)',
116
+ turns: [],
117
+ };
118
+ pendingRole = 'user';
119
+ lastNonBlankWasUserQuote = false;
120
+ }
121
+ const headingMatch = HEADING_4.exec(line);
122
+ if (headingMatch) {
123
+ flushTurn();
124
+ const heading = (headingMatch[1] ?? '').toLowerCase();
125
+ pendingRole = heading.startsWith('>') ? 'user' : 'assistant';
126
+ const stripped = (headingMatch[1] ?? '').replace(/^>\s?/, '').trim();
127
+ if (stripped.length > 0)
128
+ buffer.push(stripped);
129
+ lastNonBlankWasUserQuote = pendingRole === 'user';
130
+ continue;
131
+ }
132
+ const userMatch = USER_LINE.exec(line);
133
+ if (userMatch) {
134
+ if (pendingRole !== 'user' && buffer.length > 0)
135
+ flushTurn();
136
+ pendingRole = 'user';
137
+ buffer.push(userMatch[1] ?? '');
138
+ lastNonBlankWasUserQuote = true;
139
+ continue;
140
+ }
141
+ if (line.trim().length === 0) {
142
+ // Blank line — preserve role state but emit a paragraph break in the
143
+ // accumulating buffer so multi-paragraph turns stay readable.
144
+ if (buffer.length > 0)
145
+ buffer.push('');
146
+ continue;
147
+ }
148
+ if (lastNonBlankWasUserQuote && pendingRole === 'user') {
149
+ // Transition from quoted user prompt to assistant prose.
150
+ flushTurn();
151
+ pendingRole = 'assistant';
152
+ }
153
+ buffer.push(line);
154
+ lastNonBlankWasUserQuote = false;
155
+ }
156
+ flushTurn();
157
+ if (current)
158
+ yield current;
159
+ }
160
+ function aiderSessionToSummary(path, session) {
161
+ return {
162
+ id: session.id,
163
+ tool: 'aider',
164
+ project: parentOf(path),
165
+ title: session.title,
166
+ startedAt: session.startedAt,
167
+ messageCount: session.turns.length,
168
+ path,
169
+ };
170
+ }
171
+ function makeSessionId(path, startedAt) {
172
+ const project = basename(parentOf(path));
173
+ return `aider-${project}-${startedAt.replace(/[^0-9]/g, '').slice(0, 14) || 'unknown'}`;
174
+ }
175
+ function parentOf(path) {
176
+ const idx = path.lastIndexOf('/');
177
+ return idx > 0 ? path.slice(0, idx) : path;
178
+ }
179
+ function parseChatTimestamp(raw) {
180
+ // Aider writes "2026-06-14 10:00:00"; normalize to ISO 8601.
181
+ const trimmed = raw.trim();
182
+ const iso = trimmed.replace(' ', 'T');
183
+ const parsed = new Date(iso);
184
+ if (Number.isNaN(parsed.getTime()))
185
+ return new Date().toISOString();
186
+ return parsed.toISOString();
187
+ }
188
+ async function* readLines(path) {
189
+ const stream = createReadStream(path, { encoding: 'utf8' });
190
+ const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
191
+ for await (const line of rl)
192
+ yield line;
193
+ }
194
+ async function pathExists(path) {
195
+ try {
196
+ await fs.access(path);
197
+ return true;
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }
203
+ //# sourceMappingURL=conv-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conv-reader.js","sourceRoot":"","sources":["../../../src/adapters/aider/conv-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Adapter } from '../base.js';
2
+ export declare const aiderAdapter: Adapter;
@@ -0,0 +1,123 @@
1
+ import { join } from 'node:path';
2
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
3
+ import { emptyReport } from '../base.js';
4
+ import { exists, readTextOrUndefined, writeFileAtomic } from '../../util/fs.js';
5
+ const CAPS = {
6
+ identity: 'unsupported',
7
+ rules: 'translatable',
8
+ agents: 'unsupported',
9
+ commands: 'unsupported',
10
+ skills: 'unsupported',
11
+ mcp: 'unsupported',
12
+ hooks: 'unsupported',
13
+ permissions: 'translatable',
14
+ models: 'native',
15
+ conversations: 'translatable',
16
+ };
17
+ const reader = {
18
+ async readRules(ctx) {
19
+ const conf = await readConf(ctx);
20
+ const rules = [];
21
+ for (const path of conf?.read ?? []) {
22
+ const body = await readTextOrUndefined(ctx.projectPath ? join(ctx.projectPath, path) : join(ctx.homeDir, path));
23
+ if (body) {
24
+ rules.push({
25
+ id: `aider-read-${path}`,
26
+ scope: ctx.projectPath ? 'project' : 'global',
27
+ activation: 'always',
28
+ body: body.trim(),
29
+ });
30
+ }
31
+ }
32
+ return rules;
33
+ },
34
+ async readModels(ctx) {
35
+ const conf = await readConf(ctx);
36
+ if (!conf)
37
+ return undefined;
38
+ return {
39
+ ...(conf.model ? { defaultModel: conf.model } : {}),
40
+ ...(conf['weak-model'] ? { smallModel: conf['weak-model'] } : {}),
41
+ };
42
+ },
43
+ };
44
+ async function readConf(ctx) {
45
+ for (const candidate of [
46
+ ctx.projectPath ? join(ctx.projectPath, '.aider.conf.yml') : undefined,
47
+ join(ctx.homeDir, '.aider.conf.yml'),
48
+ ]) {
49
+ if (!candidate)
50
+ continue;
51
+ const raw = await readTextOrUndefined(candidate);
52
+ if (raw) {
53
+ try {
54
+ return parseYaml(raw);
55
+ }
56
+ catch {
57
+ continue;
58
+ }
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+ const writer = {
64
+ async writeRules(rules, ctx) {
65
+ const report = emptyReport();
66
+ if (rules.length === 0)
67
+ return report;
68
+ const path = ctx.projectPath
69
+ ? join(ctx.projectPath, 'CONVENTIONS.md')
70
+ : join(ctx.homeDir, 'CONVENTIONS.md');
71
+ const body = rules.map(r => r.body.trim()).join('\n\n---\n\n');
72
+ if (!ctx.dryRun)
73
+ await writeFileAtomic(path, body + '\n');
74
+ report.written.push(ctx.dryRun ? `(dry) ${path}` : path);
75
+ const confPath = ctx.projectPath
76
+ ? join(ctx.projectPath, '.aider.conf.yml')
77
+ : join(ctx.homeDir, '.aider.conf.yml');
78
+ const existing = await readTextOrUndefined(confPath);
79
+ const conf = (existing ? parseYamlOrUndefined(existing) : undefined) ?? {};
80
+ conf.read = [...new Set([...(conf.read ?? []), 'CONVENTIONS.md'])];
81
+ if (!ctx.dryRun)
82
+ await writeFileAtomic(confPath, stringifyYaml(conf));
83
+ report.written.push(ctx.dryRun ? `(dry) ${confPath}` : confPath);
84
+ return report;
85
+ },
86
+ async writeModels(models, ctx) {
87
+ const report = emptyReport();
88
+ const confPath = ctx.projectPath
89
+ ? join(ctx.projectPath, '.aider.conf.yml')
90
+ : join(ctx.homeDir, '.aider.conf.yml');
91
+ const existing = await readTextOrUndefined(confPath);
92
+ const conf = (existing ? parseYamlOrUndefined(existing) : undefined) ?? {};
93
+ if (models.defaultModel)
94
+ conf.model = models.defaultModel;
95
+ if (models.smallModel)
96
+ conf['weak-model'] = models.smallModel;
97
+ if (!ctx.dryRun)
98
+ await writeFileAtomic(confPath, stringifyYaml(conf));
99
+ report.written.push(ctx.dryRun ? `(dry) ${confPath}` : confPath);
100
+ return report;
101
+ },
102
+ };
103
+ function parseYamlOrUndefined(raw) {
104
+ try {
105
+ return parseYaml(raw);
106
+ }
107
+ catch {
108
+ return undefined;
109
+ }
110
+ }
111
+ export const aiderAdapter = {
112
+ id: 'aider',
113
+ name: 'Aider',
114
+ homepage: 'https://aider.chat',
115
+ capabilities: CAPS,
116
+ async detect(ctx) {
117
+ return ((await exists(join(ctx.homeDir, '.aider.conf.yml'))) ||
118
+ (ctx.projectPath ? exists(join(ctx.projectPath, '.aider.conf.yml')) : Promise.resolve(false)));
119
+ },
120
+ reader,
121
+ writer,
122
+ };
123
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/aider/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { Agent, Command, Hook, Identity, McpServer, ModelConfig, Permission, ProfileManifest, Rule, Skill } from '../schema/manifest.js';
2
+ import type { ConvEvent, ConvSessionSummary } from '../schema/conv.js';
3
+ export type CapabilityLevel = 'native' | 'translatable' | 'lossy' | 'unsupported';
4
+ export interface AdapterCapabilities {
5
+ identity: CapabilityLevel;
6
+ rules: CapabilityLevel;
7
+ agents: CapabilityLevel;
8
+ commands: CapabilityLevel;
9
+ skills: CapabilityLevel;
10
+ mcp: CapabilityLevel;
11
+ hooks: CapabilityLevel;
12
+ permissions: CapabilityLevel;
13
+ models: CapabilityLevel;
14
+ conversations: CapabilityLevel;
15
+ }
16
+ export interface ReadContext {
17
+ projectPath?: string;
18
+ homeDir: string;
19
+ }
20
+ export interface WriteContext {
21
+ projectPath?: string;
22
+ homeDir: string;
23
+ dryRun?: boolean;
24
+ }
25
+ export interface WriteReport {
26
+ written: string[];
27
+ skipped: {
28
+ item: string;
29
+ reason: string;
30
+ }[];
31
+ warnings: string[];
32
+ }
33
+ export declare function emptyReport(): WriteReport;
34
+ export declare function mergeReports(a: WriteReport, b: WriteReport): WriteReport;
35
+ export interface ProfileReader {
36
+ readIdentity?(ctx: ReadContext): Promise<Identity | undefined>;
37
+ readRules?(ctx: ReadContext): Promise<Rule[]>;
38
+ readAgents?(ctx: ReadContext): Promise<Agent[]>;
39
+ readCommands?(ctx: ReadContext): Promise<Command[]>;
40
+ readSkills?(ctx: ReadContext): Promise<Skill[]>;
41
+ readMcpServers?(ctx: ReadContext): Promise<McpServer[]>;
42
+ readHooks?(ctx: ReadContext): Promise<Hook[]>;
43
+ readPermissions?(ctx: ReadContext): Promise<Permission | undefined>;
44
+ readModels?(ctx: ReadContext): Promise<ModelConfig | undefined>;
45
+ }
46
+ export interface ProfileWriter {
47
+ writeIdentity?(identity: Identity, ctx: WriteContext): Promise<WriteReport>;
48
+ writeRules?(rules: Rule[], ctx: WriteContext): Promise<WriteReport>;
49
+ writeAgents?(agents: Agent[], ctx: WriteContext): Promise<WriteReport>;
50
+ writeCommands?(commands: Command[], ctx: WriteContext): Promise<WriteReport>;
51
+ writeSkills?(skills: Skill[], ctx: WriteContext): Promise<WriteReport>;
52
+ writeMcpServers?(servers: McpServer[], ctx: WriteContext): Promise<WriteReport>;
53
+ writeHooks?(hooks: Hook[], ctx: WriteContext): Promise<WriteReport>;
54
+ writePermissions?(perm: Permission, ctx: WriteContext): Promise<WriteReport>;
55
+ writeModels?(models: ModelConfig, ctx: WriteContext): Promise<WriteReport>;
56
+ }
57
+ export interface ConvReader {
58
+ listSessions(ctx: ReadContext): AsyncIterable<ConvSessionSummary>;
59
+ readSession(id: string, ctx: ReadContext): AsyncIterable<ConvEvent>;
60
+ }
61
+ export interface Adapter {
62
+ id: string;
63
+ name: string;
64
+ homepage?: string;
65
+ capabilities: AdapterCapabilities;
66
+ detect(ctx: ReadContext): Promise<boolean>;
67
+ reader?: ProfileReader;
68
+ writer?: ProfileWriter;
69
+ convReader?: ConvReader;
70
+ }
71
+ export declare function profileFromReader(reader: ProfileReader, sourceTool: string, ctx: ReadContext): Promise<ProfileManifest>;