cyrenecode 0.1.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cyrene
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,260 @@
1
+ <p align="center">
2
+ <img src="assets/brand/cyrene-logo.svg" alt="Cyrene" width="420" />
3
+ </p>
4
+
5
+ # Cyrene
6
+
7
+ Terminal-first coding assistant built with Bun, React Ink, and a reviewable query loop.
8
+
9
+ ## Install
10
+
11
+ ### Global CLI
12
+
13
+ ```bash
14
+ npm install -g cyrenecode
15
+ ```
16
+
17
+ Or run it without a global install:
18
+
19
+ ```bash
20
+ npx cyrenecode
21
+ ```
22
+
23
+ ### From source
24
+
25
+ ```bash
26
+ bun install
27
+ ```
28
+
29
+ > The published npm package ships a prebuilt CLI bundle. If you are developing
30
+ > from source, install Bun first.
31
+
32
+ ## Run from source
33
+
34
+ ```bash
35
+ bun dev
36
+ ```
37
+
38
+ By default, the CLI runs with a local in-memory core transport, so you can test
39
+ the full query loop without any backend service.
40
+
41
+ ## Configure
42
+
43
+ Cyrene now uses a **global user config home** by default:
44
+
45
+ - Windows: `C:\Users\<you>\.cyrene`
46
+ - macOS / Linux: `~/.cyrene`
47
+
48
+ Project-local `.cyrene/` is still read for backward compatibility, but global
49
+ user scope is the primary home for model/provider metadata and session state.
50
+
51
+ ### HTTP credentials
52
+
53
+ You can still launch with explicit environment variables:
54
+
55
+ ```bash
56
+ CYRENE_BASE_URL=https://your-openai-compatible-host
57
+ CYRENE_API_KEY=your_api_key
58
+ CYRENE_MODEL=gpt-4o-mini
59
+ ```
60
+
61
+ When they are present, they remain the **highest-priority source** for that run.
62
+ Cyrene will report them as `process_env` via `/auth` and will not overwrite them
63
+ behind your back.
64
+
65
+ ### First-run login onboarding
66
+
67
+ If usable HTTP credentials are missing, Cyrene auto-opens a skippable login
68
+ wizard on the initial idle screen.
69
+
70
+ Wizard flow:
71
+
72
+ 1. provider base URL
73
+ 2. API key
74
+ 3. optional initial model
75
+ 4. confirmation + persistence target preview
76
+
77
+ Skip is always allowed. If you skip, Cyrene stays fully usable in `local-core`
78
+ mode and you can reconnect later with `/login`.
79
+
80
+ ### What gets persisted where
81
+
82
+ - **Secret only:** `CYRENE_API_KEY`
83
+ - Windows: user-level environment variable
84
+ - macOS/Linux zsh: managed block in `~/.zshrc`
85
+ - macOS/Linux bash: managed block in `~/.bashrc` or `~/.bash_profile`
86
+ - fish: managed file in `~/.config/fish/conf.d/`
87
+ - other POSIX shells: managed block in `~/.profile`
88
+ - **Non-secret provider/model metadata:** global user `.cyrene/model.yaml`
89
+
90
+ Successful `/login` persists the API key at user scope and also updates the
91
+ current CLI process so the transport can switch immediately without restart.
92
+ `/logout` removes only the Cyrene-managed persisted API key. It does **not**
93
+ delete sessions, summaries, or model/provider catalog files.
94
+
95
+ When credentials are missing or incomplete, Cyrene falls back to local-core
96
+ instead of blocking the app.
97
+
98
+ #### Shell-specific persistence behavior
99
+
100
+ - **zsh**: updates one managed block in `~/.zshrc`
101
+ - **bash**: uses `~/.bashrc`, otherwise `~/.bash_profile`, otherwise creates `~/.bashrc`
102
+ - **fish**: writes `~/.config/fish/conf.d/cyrene-auth.fish`
103
+ - **other POSIX shells**: updates one managed block in `~/.profile`
104
+
105
+ Repeated `/login` updates replace the existing Cyrene-managed entry instead of
106
+ duplicating it. `/logout` removes only the Cyrene-managed block or file and
107
+ does not touch unrelated shell configuration.
108
+
109
+ Current request shape:
110
+ ```json
111
+ {
112
+ "model": "gpt-4o-mini",
113
+ "stream": true,
114
+ "messages": [{ "role": "user", "content": "..." }]
115
+ }
116
+ ```
117
+
118
+ Model switch:
119
+ - `/model` opens model picker (Up/Down select, Left/Right page, Enter switch).
120
+ - `/model refresh` pulls model list immediately and overwrites `.cyrene/model.yaml`.
121
+ - `/model <name>` switches immediately only if model exists in `.cyrene/model.yaml`; otherwise it fails.
122
+ - `/login` opens the auth wizard on demand.
123
+ - `/logout` removes Cyrene-managed user-scoped API key persistence.
124
+ - `/auth` shows the current mode, credential source, and persistence target.
125
+
126
+ Model source priority:
127
+ 1. `.cyrene/model.yaml`
128
+ 2. If missing/invalid, fetch from `GET /v1/models`
129
+ 3. If fetch fails, model initialization fails (and refresh reports failure)
130
+
131
+ Prompt priority and customization:
132
+ - Priority is fixed as: `system prompt > .cyrene/.cyrene.md > pins`.
133
+ - User-facing config is centralized in `.cyrene/config.yaml`.
134
+ - `system_prompt` can be set in `.cyrene/config.yaml` (or env fallback: `CYRENE_SYSTEM_PROMPT=...`).
135
+ - `auto_summary_refresh` can be set in `.cyrene/config.yaml` to enable/disable the rolling reducer that updates `summary` + `pendingDigest` inside normal user turns. Default: `true`.
136
+ - `request_temperature` can be set in `.cyrene/config.yaml` to control the HTTP main-request sampling temperature. Default: `0.2`.
137
+ - Runtime system prompt commands:
138
+ - `/system` show current system prompt
139
+ - `/system <text>` set current runtime system prompt
140
+ - `/system reset` reset to default
141
+ - `.cyrene/.cyrene.md` is fully user-editable project policy.
142
+ - `/pin <note>` and `/pins` manage human-selected focus.
143
+ - `/unpin <index>` removes one pinned focus item (1-based index).
144
+
145
+ Session and context:
146
+ - Sessions are persisted under `.cyrene/session` as JSON files.
147
+ - `/help` shows the command reference.
148
+ - `/sessions` lists sessions by latest update time.
149
+ - `/resume <session_id>` restores a previous session.
150
+ - `/resume` opens keyboard picker (Left/Right page, Enter resume, Esc cancel).
151
+ - `/new` starts a fresh session.
152
+ - `/pin <note>` stores human-selected key context.
153
+ - `/pins` shows pinned key context.
154
+ - `/unpin <index>` removes a pinned key context item.
155
+ - `/state` shows reducer/session state diagnostics for the current runtime.
156
+ - `/auth` shows whether the runtime is using HTTP or local-core, plus where the
157
+ current credential came from.
158
+ - Pin count comes from `.cyrene/config.yaml` via `pin_max_count`.
159
+ - Older context is tracked through the rolling working-state pair: durable `summary` + lagging `pendingDigest`, while recent turns are kept for prompt context.
160
+
161
+ ## Rolling context architecture
162
+
163
+ Cyrene keeps long-running coding context in three layers instead of stuffing the
164
+ entire transcript back into every prompt:
165
+
166
+ 1. **`summary`** - a durable, compact working state used as the main context anchor
167
+ 2. **`pendingDigest`** - the most recent turn digest that has not been merged yet
168
+ 3. **memory index** - richer archived evidence that can be retrieved on demand
169
+
170
+ This keeps prompts smaller while still preserving continuity. The durable summary
171
+ is intentionally structured into sections such as:
172
+
173
+ - `OBJECTIVE`
174
+ - `CONFIRMED FACTS`
175
+ - `CONSTRAINTS`
176
+ - `COMPLETED`
177
+ - `REMAINING`
178
+ - `KNOWN PATHS`
179
+ - `RECENT FAILURES`
180
+ - `NEXT BEST ACTIONS`
181
+
182
+ ### High-level memory layout
183
+
184
+ ```mermaid
185
+ flowchart TD
186
+ U["User turn"] --> P["Prompt builder"]
187
+ S["Durable summary"] --> P
188
+ D["Pending digest<br/>(last turn, not yet merged)"] --> P
189
+ M["Memory index<br/>(retrieved evidence)"] --> P
190
+ P --> Q["Main model request"]
191
+ Q --> A["Visible assistant answer"]
192
+ Q --> H["Hidden reducer block<br/>&lt;cyrene_state_update&gt;..."]
193
+ H --> R["Reducer parser"]
194
+ R --> S
195
+ R --> D
196
+ M -. "search / retrieval guided by summary + digest" .-> P
197
+ ```
198
+
199
+ ### One turn -> summary progression
200
+
201
+ Cyrene does **not** make a second background summary request after the answer.
202
+ Instead, state updates piggyback on the same main response.
203
+
204
+ ```mermaid
205
+ sequenceDiagram
206
+ participant U as User
207
+ participant C as Cyrene UI
208
+ participant P as Prompt Builder
209
+ participant L as LLM
210
+ participant R as Reducer Parser
211
+ participant S as Session Store
212
+
213
+ U->>C: Send current request
214
+ C->>S: Load summary + pendingDigest + retrieved memory
215
+ S-->>C: Current session context
216
+ C->>P: Build main prompt
217
+ P->>L: One normal model request
218
+
219
+ L-->>C: Visible answer + hidden state tail
220
+ Note over L,C: <cyrene_state_update>{...}</cyrene_state_update>
221
+
222
+ C->>R: Strip visible answer, parse reducer payload
223
+ R-->>C: Parsed update
224
+ C->>S: Persist visible assistant message
225
+
226
+ alt First reducer-enabled turn
227
+ C->>S: Keep summary as-is
228
+ C->>S: Store new pendingDigest
229
+ else Later turn with valid reducer payload
230
+ C->>S: Merge old pendingDigest into summary
231
+ C->>S: Replace pendingDigest with current-turn digest
232
+ else Missing/invalid reducer tail
233
+ C->>R: Build local fallback digest
234
+ alt Prior pendingDigest exists
235
+ C->>S: Locally advance summary from prior pendingDigest
236
+ C->>S: Store fallback pendingDigest for current turn
237
+ else No prior pendingDigest
238
+ C->>S: Store fallback pendingDigest only
239
+ end
240
+ end
241
+ ```
242
+
243
+ ### Why this design exists
244
+
245
+ - avoids a hidden second model call after every answer
246
+ - keeps prompt growth bounded
247
+ - makes task progress explicit for the model
248
+ - lets archive retrieval stay detailed while the working state stays small
249
+
250
+ Use `/state` during a session to inspect reducer mode, `summary` length,
251
+ `pendingDigest` length, and the latest state-update diagnostic.
252
+
253
+ ## Security
254
+
255
+ See [SECURITY.md](SECURITY.md) for repository security boundaries, disclosure
256
+ guidelines, and hardening notes.
257
+
258
+ ## License
259
+
260
+ [MIT](LICENSE)
package/SECURITY.md ADDED
@@ -0,0 +1,117 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ This repository is under active development. Security fixes are expected to land
6
+ on the latest mainline code first.
7
+
8
+ | Version | Supported |
9
+ | --- | --- |
10
+ | latest `main` / current working tree | Yes |
11
+ | older snapshots / forks / local patches | Best effort only |
12
+
13
+ ## Reporting a vulnerability
14
+
15
+ If you believe you found a security issue, please **avoid public disclosure
16
+ first**.
17
+
18
+ Recommended process:
19
+
20
+ 1. Share the issue privately with the project maintainers through an existing
21
+ trusted channel.
22
+ 2. Include:
23
+ - affected commit / branch
24
+ - reproduction steps
25
+ - impact assessment
26
+ - whether the issue requires local access, workspace access, or network access
27
+ 3. Wait for a fix or mitigation plan before publishing details.
28
+
29
+ If this repository is hosted on a platform that supports private security
30
+ reporting, prefer that channel.
31
+
32
+ ## Security model
33
+
34
+ Cyrene is a local, terminal-first coding assistant. Its security posture relies
35
+ on a few core boundaries:
36
+
37
+ ### 1. Workspace boundary
38
+
39
+ - file tools are intended to stay inside the configured workspace root
40
+ - path-escape checks should reject reads/writes outside the workspace
41
+ - review-gated mutations should show the exact target path before approval
42
+
43
+ ### 2. Human review boundary
44
+
45
+ - destructive or higher-risk filesystem actions should require review
46
+ - shell and command execution should be reviewable unless explicitly classified
47
+ as low risk
48
+ - persistent shell sessions should preserve clear status output so users know
49
+ what is running
50
+
51
+ ### 3. Prompt/context boundary
52
+
53
+ - long-lived context is compacted into `summary` and `pendingDigest`
54
+ - archive memory is indexed and retrieved selectively instead of replaying
55
+ entire transcripts
56
+ - hidden reducer state should never be shown to users as visible transcript text
57
+
58
+ ### 4. Provider boundary
59
+
60
+ - HTTP transport sends prompts to an OpenAI-compatible API when configured
61
+ - `CYRENE_API_KEY` is intentionally excluded from transcript items, session
62
+ JSON, reducer state (`summary` / `pendingDigest`), and memory index storage
63
+ - Cyrene may persist `CYRENE_API_KEY` in **user-scoped environment/profile
64
+ storage** through the login flow:
65
+ - Windows user environment
66
+ - managed shell-profile blocks for zsh / bash / POSIX shells
67
+ - managed fish config file under `~/.config/fish/conf.d/`
68
+ - provider URL and model catalog metadata live in the global user `.cyrene`
69
+ directory and are treated as non-secret runtime metadata
70
+ - model/provider switching should be explicit and visible in the UI
71
+
72
+ ## Current hardening expectations
73
+
74
+ When changing code, please preserve or improve these properties:
75
+
76
+ - prevent duplicate request submission and duplicate completion handling
77
+ - avoid command/tool loops that cause accidental repeated execution
78
+ - keep approval flows one-shot and idempotent where possible
79
+ - do not allow hidden reducer metadata to leak into visible assistant output
80
+ - keep large-file and large-output handling bounded to protect terminal stability
81
+ - maintain test coverage for:
82
+ - workspace escape protection
83
+ - review-gated file mutations
84
+ - command/shell risk handling
85
+ - duplicate submit / duplicate finalize guards
86
+ - reducer fallback behavior
87
+
88
+ ## Out of scope / non-goals
89
+
90
+ Unless explicitly documented otherwise, this project does **not** currently
91
+ promise:
92
+
93
+ - sandboxing against a malicious local user with full machine access
94
+ - protection against a compromised upstream model or provider
95
+ - protection against unsafe custom plugins, local patches, or user-modified
96
+ prompts/policies
97
+ - backward security support for stale forks or heavily diverged branches
98
+
99
+ ## Secure deployment notes
100
+
101
+ If you run Cyrene outside local experimentation:
102
+
103
+ - keep API keys out of the repo and shell history
104
+ - review `.cyrene/` config and session files before sharing them
105
+ - remember that login persistence writes `CYRENE_API_KEY` to user-scoped shell
106
+ or environment storage, not to session JSON
107
+ - treat session logs as potentially sensitive prompt/output data
108
+ - prefer least-privilege execution contexts for shell access
109
+ - verify Docker / CI mounts so the workspace root is exactly what you intend
110
+ - rotate provider credentials if they were ever written to logs or transcripts
111
+
112
+ ## Disclosure philosophy
113
+
114
+ Please report vulnerabilities responsibly and give maintainers time to patch
115
+ before publishing exploit details. Public issues are welcome for general
116
+ hardening ideas, but not for live secrets, escape techniques, or reproducible
117
+ unpatched exploit chains.
@@ -0,0 +1,11 @@
1
+ <svg width="820" height="200" viewBox="0 0 820 200" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="cyreneLogoTitle cyreneLogoDesc">
2
+ <title id="cyreneLogoTitle">Cyrene Logo</title>
3
+ <desc id="cyreneLogoDesc">Cyrene wordmark paired with a geometric cyan C-shaped signal mark.</desc>
4
+ <g transform="translate(18 20)">
5
+ <path d="M108 44C95.8497 32.2032 77.5944 28.7658 61.9407 35.2795C46.287 41.7932 36 57.07 36 74.0252C36 90.9804 46.287 106.257 61.9407 112.771C77.5944 119.284 95.8497 115.847 108 104.05" stroke="#2FD7FF" stroke-width="18" stroke-linecap="round"/>
6
+ <path d="M77 63L98 80L77 97" stroke="#08131B" stroke-width="14" stroke-linecap="round" stroke-linejoin="round"/>
7
+ <path d="M77 63L98 80L77 97" stroke="#F3FCFF" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <circle cx="108" cy="80" r="8" fill="#2FD7FF" stroke="#08131B" stroke-width="4"/>
9
+ </g>
10
+ <text x="178" y="118" fill="#F4FCFF" stroke="#08131B" stroke-width="8" paint-order="stroke fill" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif" font-size="88" font-weight="800" letter-spacing="11">CYRENE</text>
11
+ </svg>
@@ -0,0 +1,8 @@
1
+ <svg width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="cyreneMarkTitle cyreneMarkDesc">
2
+ <title id="cyreneMarkTitle">Cyrene Mark</title>
3
+ <desc id="cyreneMarkDesc">A geometric cyan C-shape with a forward signal arrow and locator dot.</desc>
4
+ <path d="M108 44C95.8497 32.2032 77.5944 28.7658 61.9407 35.2795C46.287 41.7932 36 57.07 36 74.0252C36 90.9804 46.287 106.257 61.9407 112.771C77.5944 119.284 95.8497 115.847 108 104.05" stroke="#2FD7FF" stroke-width="18" stroke-linecap="round"/>
5
+ <path d="M77 63L98 80L77 97" stroke="#08131B" stroke-width="14" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <path d="M77 63L98 80L77 97" stroke="#F3FCFF" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
7
+ <circle cx="108" cy="80" r="8" fill="#2FD7FF" stroke="#08131B" stroke-width="4"/>
8
+ </svg>
package/bin/cyrene.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli.js";