openwolf-enhanced 1.26.0 → 1.28.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/CHANGELOG.md +306 -0
- package/dist/dashboard/assets/{AISuggestions-DZmzksSA.js → AISuggestions-C7WFvzLO.js} +1 -1
- package/dist/dashboard/assets/{ActivityLog-BJ0omuzu.js → ActivityLog-SsRbpBFt.js} +1 -1
- package/dist/dashboard/assets/{ActivityTimeline-BWhxretI.js → ActivityTimeline-BoV30nDY.js} +1 -1
- package/dist/dashboard/assets/{AnatomyBrowser-DNVp6-_r.js → AnatomyBrowser-DwzsHn4z.js} +1 -1
- package/dist/dashboard/assets/{BugLog-DMJTuU9p.js → BugLog-CPl4Q-JG.js} +1 -1
- package/dist/dashboard/assets/{CerebrumViewer-BwcGr6pu.js → CerebrumViewer-_f6fBsNF.js} +1 -1
- package/dist/dashboard/assets/{CronStatus-Dwf_M4-S.js → CronStatus-1iBEPJK5.js} +1 -1
- package/dist/dashboard/assets/{DesignQC-DzHkh94I.js → DesignQC-D4UU7lca.js} +1 -1
- package/dist/dashboard/assets/{LinkGraph-kqQD--Yj.js → LinkGraph-BWtI8Gh3.js} +1 -1
- package/dist/dashboard/assets/{MemoryViewer-BCn9Fr-w.js → MemoryViewer-BYRVG34g.js} +1 -1
- package/dist/dashboard/assets/{NativeMemory-DPMZaP5E.js → NativeMemory-Dphtrqjt.js} +1 -1
- package/dist/dashboard/assets/{ProjectOverview-PWENJiC4.js → ProjectOverview-CTYohvjD.js} +1 -1
- package/dist/dashboard/assets/{ProjectsAggregate-Baj44DVk.js → ProjectsAggregate-CMxNs35H.js} +1 -1
- package/dist/dashboard/assets/{StatusBadge-Db61D51H.js → StatusBadge-CjrFCDOI.js} +1 -1
- package/dist/dashboard/assets/{TokenUsage-UefDh9w4.js → TokenUsage-C5wJpMl8.js} +1 -1
- package/dist/dashboard/assets/index-BNi8lsJE.css +2 -0
- package/dist/dashboard/assets/{index-e2PfOI0b.js → index-C74qneS9.js} +5 -5
- package/dist/dashboard/index.html +2 -2
- package/dist/hooks/post-bash.js +10 -5
- package/dist/hooks/post-read.js +24 -26
- package/dist/hooks/post-write.js +135 -118
- package/dist/hooks/pre-read.js +42 -36
- package/dist/hooks/pre-write.js +3 -3
- package/dist/hooks/precompact.js +2 -2
- package/dist/hooks/session-start.js +15 -6
- package/dist/hooks/shared.js +221 -14
- package/dist/hooks/stop.js +33 -7
- package/dist/src/cli/cron-cmd.js +2 -2
- package/dist/src/cli/cron-cmd.js.map +1 -1
- package/dist/src/cli/daemon-cmd.js +49 -21
- package/dist/src/cli/daemon-cmd.js.map +1 -1
- package/dist/src/cli/doctor-cmd.js +2 -1
- package/dist/src/cli/doctor-cmd.js.map +1 -1
- package/dist/src/cli/export-cmd.js +8 -0
- package/dist/src/cli/export-cmd.js.map +1 -1
- package/dist/src/cli/init.js +34 -8
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/registry.js +68 -33
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/update.js +37 -6
- package/dist/src/cli/update.js.map +1 -1
- package/dist/src/daemon/cron-engine.js +70 -8
- package/dist/src/daemon/cron-engine.js.map +1 -1
- package/dist/src/daemon/file-watcher.js +4 -1
- package/dist/src/daemon/file-watcher.js.map +1 -1
- package/dist/src/daemon/llm-provider.js +9 -6
- package/dist/src/daemon/llm-provider.js.map +1 -1
- package/dist/src/daemon/wolf-daemon.js +69 -15
- package/dist/src/daemon/wolf-daemon.js.map +1 -1
- package/dist/src/designqc/designqc-capture.js +116 -6
- package/dist/src/designqc/designqc-capture.js.map +1 -1
- package/dist/src/designqc/designqc-engine.js +9 -3
- package/dist/src/designqc/designqc-engine.js.map +1 -1
- package/dist/src/hooks/post-bash.js +10 -5
- package/dist/src/hooks/post-bash.js.map +1 -1
- package/dist/src/hooks/post-read.js +24 -26
- package/dist/src/hooks/post-read.js.map +1 -1
- package/dist/src/hooks/post-write.js +135 -118
- package/dist/src/hooks/post-write.js.map +1 -1
- package/dist/src/hooks/pre-read.js +42 -36
- package/dist/src/hooks/pre-read.js.map +1 -1
- package/dist/src/hooks/pre-write.js +3 -3
- package/dist/src/hooks/pre-write.js.map +1 -1
- package/dist/src/hooks/precompact.js +2 -2
- package/dist/src/hooks/precompact.js.map +1 -1
- package/dist/src/hooks/session-start.js +15 -6
- package/dist/src/hooks/session-start.js.map +1 -1
- package/dist/src/hooks/shared.js +221 -14
- package/dist/src/hooks/shared.js.map +1 -1
- package/dist/src/hooks/stop.js +33 -7
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/scanner/anatomy-scanner.js +7 -3
- package/dist/src/scanner/anatomy-scanner.js.map +1 -1
- package/dist/src/utils/agent-hooks.js +50 -4
- package/dist/src/utils/agent-hooks.js.map +1 -1
- package/dist/src/utils/daemon-pid.js +56 -0
- package/dist/src/utils/daemon-pid.js.map +1 -0
- package/dist/src/utils/dashboard-auth.js +13 -1
- package/dist/src/utils/dashboard-auth.js.map +1 -1
- package/dist/src/utils/embeddings.js +9 -1
- package/dist/src/utils/embeddings.js.map +1 -1
- package/dist/src/utils/fs-safe.js +69 -11
- package/dist/src/utils/fs-safe.js.map +1 -1
- package/dist/src/utils/logger.js +21 -6
- package/dist/src/utils/logger.js.map +1 -1
- package/dist/src/utils/maintenance.js +100 -6
- package/dist/src/utils/maintenance.js.map +1 -1
- package/dist/src/utils/platform.js +39 -0
- package/dist/src/utils/platform.js.map +1 -1
- package/dist/src/utils/remote.js +2 -2
- package/dist/src/utils/remote.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/config.json +34 -9
- package/dist/dashboard/assets/index-CVfvTpSA.css +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,312 @@ This is a fork of [OpenWolf](https://github.com/cytostack/openwolf) by Cytostack
|
|
|
6
6
|
Pvt Ltd. Versions ≤ 1.0.4 refer to the upstream project; `1.1.0` is the first
|
|
7
7
|
release of this fork.
|
|
8
8
|
|
|
9
|
+
## [1.28.0] — 2026-08-31
|
|
10
|
+
|
|
11
|
+
Upstream OpenWolf published 2.5.1 on 2026-08-30, the same day as our 1.27.0, and independently
|
|
12
|
+
fixed two of the same classes: multi-writer state and project boundaries. Its sixteen findings were
|
|
13
|
+
checked one at a time against **this** fork rather than adopted from a changelog. Ten applied and
|
|
14
|
+
are fixed here. Six did not, and are listed at the end so nobody "fixes" something that was never
|
|
15
|
+
broken. No 2.x features were ported — this release is fixes only.
|
|
16
|
+
|
|
17
|
+
Minor rather than patch: the anatomy exclusion defaults change what gets indexed, `daemon stop`
|
|
18
|
+
refuses cases it used to act on, and hook state moves to one file per session.
|
|
19
|
+
|
|
20
|
+
### Fixed — the lock now actually locks
|
|
21
|
+
|
|
22
|
+
- 🔒 **`withLock` ran the callback anyway when it could not acquire the lock.** That defeats the
|
|
23
|
+
lock for every writer that respects it: the point is that exactly one process is inside the
|
|
24
|
+
critical section, and a participant who proceeds regardless makes the guarantee vacuous for
|
|
25
|
+
everyone else. Under contention this was not a rare fallback but the common path — contention is
|
|
26
|
+
precisely when the timeout fires. It now fails closed and says so; `tryWithLock` and
|
|
27
|
+
`withLockOr` give callers that must not throw (every hook) a reported skip instead of a silent
|
|
28
|
+
overwrite. This is the finding an external audit of 1.27.0 raised as "locking is largely
|
|
29
|
+
illusory"; 1.27.0 brought all the writers under the lock and left this half undone.
|
|
30
|
+
|
|
31
|
+
- ⚡ **Lock polling started at a flat 25 ms.** With seven hooks around one file a herd needs several
|
|
32
|
+
rounds to drain and each waiter burned 25 ms per attempt whether or not the lock had been free a
|
|
33
|
+
microsecond earlier. It starts at 2 ms and backs off, so the common case — a lock held for the
|
|
34
|
+
duration of one write — is picked up almost immediately.
|
|
35
|
+
|
|
36
|
+
- 🔒 **Three shared files still had no lock at all.** 1.27.0 covered `_session.json`; `buglog.json`,
|
|
37
|
+
`anatomy.md` and the machine-wide registry were still plain read-modify-write. For the buglog
|
|
38
|
+
that meant two edits in one turn computing the same next id from the same snapshot and the second
|
|
39
|
+
write erasing the first entry while reusing its number. For `anatomy.md`, `writeAtomic` prevents
|
|
40
|
+
a torn file but not a lost update: both hooks produce valid markdown and the second silently
|
|
41
|
+
drops the first one's entry, which surfaces much later as an anatomy miss for a file that was
|
|
42
|
+
indexed.
|
|
43
|
+
|
|
44
|
+
- 🔒 **`~/.openwolf/registry.json` was neither locked nor written atomically.** It is the one piece
|
|
45
|
+
of state every project on the machine shares, and `openwolf init` in several projects at once —
|
|
46
|
+
which is how a machine gets set up — had each process read the same snapshot and write its own
|
|
47
|
+
back. Measured here with 30 concurrent registrations: entries were lost on every run before the
|
|
48
|
+
fix, none after. The non-atomic write was its own bug: a reader arriving mid-write got a partial
|
|
49
|
+
file, and the catch in `readRegistry` turned that into "no projects registered".
|
|
50
|
+
|
|
51
|
+
### Fixed — one state file per session
|
|
52
|
+
|
|
53
|
+
- 👥 **Two agents in the same project shared one `_session.json`.** The second one's SessionStart
|
|
54
|
+
reset the first one's in-flight tracking, and from then on both wrote to the same file: reads
|
|
55
|
+
counted against the wrong session, and the ledger entry for the first ended with whatever the
|
|
56
|
+
second had accumulated. State is now keyed by the harness `session_id` that every hook payload
|
|
57
|
+
already carried; an agent that supplies none keeps the shared path exactly as before. Files are
|
|
58
|
+
garbage collected after seven days, since a finished session is already folded into the ledger.
|
|
59
|
+
The daemon's file watcher no longer broadcasts them either — per-session hook state was read and
|
|
60
|
+
pushed to every websocket client on every tool call, and consumed by nothing.
|
|
61
|
+
|
|
62
|
+
### Fixed — project boundaries
|
|
63
|
+
|
|
64
|
+
- 🔗 **A project reached through a symlink was silently dropped from tracking.** Containment was
|
|
65
|
+
lexical only. `/home/me/work` is a link to `/mnt/data/work`, the agent opens
|
|
66
|
+
`/mnt/data/work/src/a.ts`, the prefix does not match, and every read in that project goes
|
|
67
|
+
unrecorded with no error anywhere — the default situation for anything under `/tmp` on macOS.
|
|
68
|
+
A lexical miss now gets a second opinion from `realpath` on both sides, so the common path still
|
|
69
|
+
costs nothing.
|
|
70
|
+
|
|
71
|
+
### Fixed — `daemon stop` could kill an unrelated process
|
|
72
|
+
|
|
73
|
+
- 🎯 **Port occupancy was treated as ownership.** The last-resort stop killed whatever was listening
|
|
74
|
+
on the configured dashboard port. That port is a number in a committed config file, the daemon
|
|
75
|
+
may have been moved off it by `openwolf dashboard`, and on a developer machine it is just as
|
|
76
|
+
likely to be a dev server or another project's daemon — killed, and then reported as
|
|
77
|
+
"✓ Daemon stopped". The daemon now records its pid, project root and hostname after a successful
|
|
78
|
+
bind, and stop kills only a process that record vouches for: same host, same project, still
|
|
79
|
+
alive. Anything else on the port is named and left alone. `daemon restart` had the same bug and
|
|
80
|
+
the same fix.
|
|
81
|
+
|
|
82
|
+
### Fixed — smaller, still real
|
|
83
|
+
|
|
84
|
+
- 🔑 **An existing dashboard token kept whatever permissions it had.** 0600 was applied only to
|
|
85
|
+
tokens this code created, so one restored from a backup, or written before that check existed,
|
|
86
|
+
stayed readable by other local users. It is repaired in place and never rotated — this is the
|
|
87
|
+
token a live browser tab is holding, and rotating it would log the user out to fix a permission
|
|
88
|
+
bit.
|
|
89
|
+
|
|
90
|
+
- 🧾 **A malformed agent config was destroyed and the failure reported as success.** `readJSON`
|
|
91
|
+
hands back `{}` for an unparseable file, so a `settings.json` or `hooks.json` with one stray
|
|
92
|
+
comma was treated as empty: OpenWolf's entries were written over it, every hook the user had
|
|
93
|
+
configured themselves was gone, and deployment printed a checkmark. The file is now left
|
|
94
|
+
byte-identical and one actionable warning explains how to recover. `openwolf update` also stopped
|
|
95
|
+
claiming "Claude settings updated" in the case where it had not updated them.
|
|
96
|
+
|
|
97
|
+
- 📋 **An unknown cron task id reported success.** `runTask` logged a warning and resolved, so the
|
|
98
|
+
API answered `202 Accepted` and the CLI printed "triggered" for a task that does not exist — a
|
|
99
|
+
typo looked exactly like a task that ran. Existence is now checked before the 202; the API
|
|
100
|
+
answers 404 with the list of known ids, and the CLI exits nonzero.
|
|
101
|
+
|
|
102
|
+
- 🗂️ **The anatomy index filled with other people's code.** `.venv`, `site-packages`, `.gradle` and
|
|
103
|
+
`.DS_Store` were missing from the defaults, and the exclusions existed in *four* places that
|
|
104
|
+
disagreed: the config template, `init`'s inline fallback, and two copies inside the scanner. On a
|
|
105
|
+
mixed Python/JS project the indexed-file budget went to dependency source, so every anatomy
|
|
106
|
+
lookup for the project's own files missed. There is now one shared list; virtualenvs are detected
|
|
107
|
+
by `pyvenv.cfg` under any directory name, not by convention; and agent-config directories
|
|
108
|
+
(`.claude`, `.codex`, `.opencode`, `.gemini`, `.cursor`) are excluded, since steering the model
|
|
109
|
+
toward its own harness config is noise that ranks high precisely because those files are short
|
|
110
|
+
and keyword-dense. Existing projects pick the new entries up on `openwolf update` as a **union** —
|
|
111
|
+
a plain deep merge would have replaced the array, so either the new defaults or the user's own
|
|
112
|
+
additions would have been lost.
|
|
113
|
+
|
|
114
|
+
### Checked and not applicable
|
|
115
|
+
|
|
116
|
+
Recorded so these are not "fixed" later on the strength of an upstream changelog:
|
|
117
|
+
|
|
118
|
+
- **Read tracking escaping the root via a `startsWith` prefix** — already fixed here; the separator
|
|
119
|
+
has been required since the sibling-directory bug. Only the symlink half applied.
|
|
120
|
+
- **The Bash governor's deleted output log** and **benchmark arms on a moving HEAD** — 2.x features
|
|
121
|
+
this fork does not have.
|
|
122
|
+
- **Scan freshness advanced by a skipped write** — depends on the 2.4.0 `_scan-state.json`
|
|
123
|
+
mechanism, which this fork does not have.
|
|
124
|
+
- **The scanner reading every file twice** — this fork reads once in the scan loop.
|
|
125
|
+
- **A bare-array `buglog.json`** — `readBugLog` has normalised both shapes for some time, and the
|
|
126
|
+
dashboard gained shape normalisation plus an error boundary in 1.27.0.
|
|
127
|
+
- **`detectAgent` keying on `CLAUDE_PROJECT_DIR`, which is "never set"** — disproved empirically
|
|
128
|
+
here rather than argued: this project's ledger holds 110 sessions attributed to `claude` against
|
|
129
|
+
one `default`, today's included. The variable is absent from the Bash tool's environment but
|
|
130
|
+
present in the hook environment, which is likely how the upstream conclusion was reached.
|
|
131
|
+
|
|
132
|
+
### Tests
|
|
133
|
+
|
|
134
|
+
13 new tests in `test/upstream-parity.test.js`, 224 total, all green. The two load-bearing ones were
|
|
135
|
+
verified against the *unfixed* build first: the lock test fails without the fail-closed change, and
|
|
136
|
+
the registry test loses entries on five runs out of five with the lock removed and passes on five
|
|
137
|
+
out of five with it. The concurrency test spawns real processes, because a lost update between OS
|
|
138
|
+
processes cannot be reproduced by a single-threaded loop.
|
|
139
|
+
|
|
140
|
+
## [1.27.0] — 2026-08-30
|
|
141
|
+
|
|
142
|
+
A security and robustness pass. An external AI audit of 1.26.0 was checked claim by claim against
|
|
143
|
+
the code first: of its 24 findings, 15 held, 7 were weaker or wrong in their reasoning, and 2 were
|
|
144
|
+
simply wrong. Two more issues turned up during that check that the audit had missed — including the
|
|
145
|
+
one that actually mattered on the Design QC path. Everything below is a fix; nothing new was added
|
|
146
|
+
except the retention limit and the process helper that the fixes needed.
|
|
147
|
+
|
|
148
|
+
Minor rather than patch, because three changes are visible to existing installs: a new
|
|
149
|
+
`retention.proposals_keep` key, a changed pm2 start path on Windows, and remote embedding endpoints
|
|
150
|
+
now requiring `https`.
|
|
151
|
+
|
|
152
|
+
### Fixed — values from committed files were treated as trusted input
|
|
153
|
+
|
|
154
|
+
`.wolf/config.json` and `.wolf/cron-manifest.json` are committed by design; that is the point of a
|
|
155
|
+
shared brain. It also means that on a cloned repository, their contents are written by whoever wrote
|
|
156
|
+
the repository. Four places took them at face value.
|
|
157
|
+
|
|
158
|
+
- 🔒 **A cron task id became a file path.** `writeProposal()` built
|
|
159
|
+
`.wolf/proposals/${taskId}-${stamp}.md` straight from the manifest, so an `id` of
|
|
160
|
+
`../../../../etc/cron.d/openwolf` wrote outside `.wolf/`, with the daemon's privileges, on a
|
|
161
|
+
schedule. Ids are now reduced to a single path segment that cannot traverse, cannot be empty, and
|
|
162
|
+
cannot be a Windows device name.
|
|
163
|
+
|
|
164
|
+
- 🔒 **The `context_files` guard could be walked around with a symlink.** It compared resolved path
|
|
165
|
+
*strings*, which knows nothing about links: a repo carrying `docs/notes -> /etc/shadow` passed the
|
|
166
|
+
check and shipped the target to the LLM API — the exact exfiltration the guard was written to
|
|
167
|
+
stop. The real path is resolved and checked too, against the project root's own real path, so a
|
|
168
|
+
project reached through a link (`/root/x -> /mnt/x`, macOS `/tmp`) still works.
|
|
169
|
+
|
|
170
|
+
- 🔒 **`designqc.chrome_path` chose which executable was launched.** The configured value went to
|
|
171
|
+
puppeteer's `executablePath` if the file merely existed. It must now be *named* like a browser and
|
|
172
|
+
live outside the project; anything else is refused with an explanation and auto-detection runs
|
|
173
|
+
instead.
|
|
174
|
+
|
|
175
|
+
- 🔒 **`package.json` `homepage` chose what Design QC photographed.** `detectDeployedUrl()` also
|
|
176
|
+
reads `.env*` and `vercel.json`, all unvalidated — so `"homepage":
|
|
177
|
+
"http://169.254.169.254/latest/meta-data/"` made a plain `openwolf designqc` screenshot the cloud
|
|
178
|
+
instance's metadata into `.wolf/designqc-captures/`, a directory that gets committed and read back
|
|
179
|
+
by a model. Repo-derived URLs are now restricted to public http(s); a URL you pass yourself
|
|
180
|
+
(`--url`, or the token-gated daemon route) may still be loopback or LAN, but never `file:`,
|
|
181
|
+
`data:` or `chrome:`.
|
|
182
|
+
|
|
183
|
+
- 🔒 **The embeddings endpoint had no egress guard at all.** The chat path has had one since 1.15.1;
|
|
184
|
+
this one never did, although what leaves through it is the knowledge base itself — cerebrum,
|
|
185
|
+
memory, anatomy — plus the bearer token. No https requirement, no private/metadata-address check,
|
|
186
|
+
and default redirect handling, so a 307 replayed the whole POST body at whatever host the first
|
|
187
|
+
one named. It now uses the same `assertSafeBaseUrl` as the chat path, with `redirect: "error"`.
|
|
188
|
+
|
|
189
|
+
**Breaking for one setup:** a remote `recall.embeddings.base_url` over plain `http://` is now
|
|
190
|
+
refused. Loopback stays keyless and cleartext as before. Point it at `https://`, or at a local
|
|
191
|
+
model server.
|
|
192
|
+
|
|
193
|
+
### Fixed — data loss
|
|
194
|
+
|
|
195
|
+
- 💾 **`openwolf init` in an existing project reset `config.json`.** It sat in `ALWAYS_OVERWRITE`, so
|
|
196
|
+
a re-run wiped tuned retention limits, assigned daemon/dashboard ports, Design QC settings and —
|
|
197
|
+
worst — `openwolf.remote.base_url`/`project`, silently unlinking the project from its team
|
|
198
|
+
workspace. `openwolf update` had already learned to deep-merge it for exactly these reasons, and
|
|
199
|
+
said so in a comment. `init` now uses the same merge: your values win, new default keys are added.
|
|
200
|
+
|
|
201
|
+
- 💾 **Five of the seven writers of `_session.json` took no lock.** `post-read`, `post-write`,
|
|
202
|
+
`pre-read`, `stop` and `session-start` did read-modify-write around unrelated work, so a
|
|
203
|
+
PostToolUse hook finishing while PreToolUse was mid-cycle silently dropped one of the two updates.
|
|
204
|
+
Reads and writes feed the token ledger, so a lost update is a wrong number in a report nobody can
|
|
205
|
+
audit afterwards. A single `updateSession()` helper now re-reads under the lock and applies a
|
|
206
|
+
delta, and every writer goes through it.
|
|
207
|
+
|
|
208
|
+
- 💾 **The Stop hook's crash-safety comment was not true.** `session.booked` was *set* inside the
|
|
209
|
+
ledger lock but *persisted* about thirty lines later, outside it, past two `memory.md` appends and
|
|
210
|
+
a memory compaction. Anything ending the process in that window left the ledger credited and the
|
|
211
|
+
session unmarked, so the next Stop booked every delta again — the exact over-count the comment
|
|
212
|
+
said was impossible. It is written under the same lock now, one statement after the ledger.
|
|
213
|
+
|
|
214
|
+
- 💾 **A corrupt `.json` was overwritten instead of preserved.** `readJSON` fell back to defaults and
|
|
215
|
+
the caller's read-modify-write then replaced the file, so a damaged `token-ledger.json` took the
|
|
216
|
+
usage history with it and left one stderr line as the only trace. The file is moved aside as
|
|
217
|
+
`<name>.corrupt-<timestamp>` first.
|
|
218
|
+
|
|
219
|
+
### Fixed — Windows
|
|
220
|
+
|
|
221
|
+
- 🪟 **The "never track files outside the project" guard did not hold across drives.**
|
|
222
|
+
`path.relative("C:\\proj", "F:\\x")` cannot express a route between two drives and returns
|
|
223
|
+
`F:\x` — no leading `..`, so the guard passed it and the absolute foreign path leaked into
|
|
224
|
+
`anatomy.md` and `memory.md` (upstream #56), on the one platform nobody had tested it on. An
|
|
225
|
+
absolute or drive-relative result is now recognised as "outside". The `..` test is also anchored
|
|
226
|
+
to a whole segment, so a file genuinely named `..config` in the project root stops counting as
|
|
227
|
+
external.
|
|
228
|
+
|
|
229
|
+
- 🪟 **pm2 could not be started at all.** Since the fix for CVE-2024-27980 (Node 18.20.2 / 20.12.2 /
|
|
230
|
+
21.7.3), Node refuses to spawn a `.cmd` without `shell: true` and throws `EINVAL`. Both pm2 call
|
|
231
|
+
sites wrapped that in a bare `catch`, so Windows users were told "pm2 found but daemon start
|
|
232
|
+
failed" — a message that reads like a pm2 problem and is not one. `shell: true` is *not* the fix,
|
|
233
|
+
since it joins the arguments back into a parseable string; calls now go through `cmd.exe /d /s /c`
|
|
234
|
+
with `windowsVerbatimArguments` and quoting we control. A path containing `%` (which cannot be
|
|
235
|
+
escaped on a command line) is refused loudly rather than launched wrongly.
|
|
236
|
+
|
|
237
|
+
- 🪟 **The Design QC dev server survived every run.** `proc.kill()` signals only the direct child,
|
|
238
|
+
which is a shell, and on Windows a signal to `cmd.exe` does not propagate — so the dev server kept
|
|
239
|
+
holding its port and the next run screenshotted the stale build. The process tree is killed via
|
|
240
|
+
`taskkill /T` on Windows and via the process group on POSIX.
|
|
241
|
+
|
|
242
|
+
### Fixed — daemon
|
|
243
|
+
|
|
244
|
+
- 🔧 **The logger never followed a project switch.** It was built once at boot, so after
|
|
245
|
+
`/api/switch` project B's cron runs, task failures and LLM errors kept appending to project A's
|
|
246
|
+
`daemon.log`, under A's log level — and `openwolf daemon logs` in B showed nothing at all, which
|
|
247
|
+
reads like a daemon that stopped working.
|
|
248
|
+
|
|
249
|
+
- 🔧 **The heartbeat kept the boot project's interval**, and `engine_status` was written as
|
|
250
|
+
`"running"` regardless of the new project's `cron.enabled`, so a project with cron switched off
|
|
251
|
+
showed a live engine and a ticking heartbeat with no scheduler behind it. It now reports
|
|
252
|
+
`disabled`, and the timer is re-armed at the new project's cadence.
|
|
253
|
+
|
|
254
|
+
- 🔧 **`daemon.log` and `proposals/` grew without bound.** Both limits existed in `config.json` and
|
|
255
|
+
were only ever enforced by `openwolf doctor`, a command you have to remember to type — while the
|
|
256
|
+
daemon is the process that writes both and runs for months. It now applies them to itself on each
|
|
257
|
+
heartbeat. `proposals/` had no limit at all before; the new `retention.proposals_keep` (default 20)
|
|
258
|
+
gives it one, added to existing configs by the deep merge.
|
|
259
|
+
|
|
260
|
+
### Fixed — dashboard
|
|
261
|
+
|
|
262
|
+
- 🖥️ **One malformed `.wolf` file blanked the whole dashboard.** Not through `JSON.parse` — every one
|
|
263
|
+
of those was already guarded — but through shape: a file that parses fine but is `{}` or `[]` gave
|
|
264
|
+
`undefined` where a panel indexed an array, and with no error boundary anywhere, React unmounted
|
|
265
|
+
the entire tree. Shapes are normalised once at ingest, and a `PanelBoundary` now contains a render
|
|
266
|
+
error to the panel that caused it.
|
|
267
|
+
|
|
268
|
+
- 🖥️ **A 401 rendered as an empty project.** `refresh()` ignored `r.ok` and fed
|
|
269
|
+
`{"error":"unauthorized"}` to the file processor, which found no known keys and left the initial
|
|
270
|
+
empty state on screen — indistinguishable from a project that had done nothing.
|
|
271
|
+
|
|
272
|
+
- 🖥️ **The retry button opened a second WebSocket** without closing the first, so every broadcast
|
|
273
|
+
arrived twice, and each further retry added another copy.
|
|
274
|
+
|
|
275
|
+
### Fixed — smaller things
|
|
276
|
+
|
|
277
|
+
- 📊 **CSV export could carry a live formula.** Spreadsheets execute a cell starting with `=`, `+`,
|
|
278
|
+
`-` or `@`, and the values come from `buglog.json` and the token ledger, which an agent writes
|
|
279
|
+
from whatever it read in the repo. Such values are now prefixed with an apostrophe.
|
|
280
|
+
|
|
281
|
+
- 🧩 **`?` in a `.gitignore`/`.wolfignore` pattern was neither escaped nor translated**, so it
|
|
282
|
+
survived into the compiled regex as a quantifier and made the preceding character optional:
|
|
283
|
+
`build?/*.js` matched `buil/x.js` and missed `build2/x.js`. It now means exactly one character, in
|
|
284
|
+
both copies of the matcher.
|
|
285
|
+
|
|
286
|
+
- 🧩 **An anatomy entry matched on a bare suffix**, with no path-segment boundary, so
|
|
287
|
+
`/tmp/other-src/api/client.ts` "matched" an entry for `src/api/client.ts` — printing another
|
|
288
|
+
file's description and booking an anatomy hit for a file `anatomy.md` had never seen.
|
|
289
|
+
|
|
290
|
+
- 🧩 **A newline bypassed the openwolf self-invocation filter** in the Bash hook. Newlines separate
|
|
291
|
+
commands exactly like `;` does and were missing from the split, so a multi-line block — the normal
|
|
292
|
+
shape of an agent's shell call — whose second line ran `openwolf push` was captured anyway.
|
|
293
|
+
|
|
294
|
+
- 🧩 **`openwolf restore ../../something` resolved outside `backups/`** and copied whatever it found
|
|
295
|
+
there over the project's knowledge base. A backup name must now be a single entry under
|
|
296
|
+
`backups/`.
|
|
297
|
+
|
|
298
|
+
### Notes on the audit
|
|
299
|
+
|
|
300
|
+
Recorded here because the corrections matter as much as the fixes. The report's `pm2 --cwd`
|
|
301
|
+
"cmd.exe metacharacter injection" does not exist — those calls use `execFileSync` with an argument
|
|
302
|
+
array, so no shell is involved; the real defect there was the `EINVAL` above. "`backups/` accumulate
|
|
303
|
+
forever" is wrong: `pruneBackups` runs in `update` and `doctor`. The dashboard finding had the right
|
|
304
|
+
conclusion with the wrong cause. And the finding filed as LOW — the cron task id — was the most
|
|
305
|
+
serious one in the report, while the Design QC SSRF filed as MEDIUM sits behind the dashboard token
|
|
306
|
+
and is largely self-directed; the repo-controlled path it missed is the one that was worth fixing.
|
|
307
|
+
|
|
308
|
+
### Tests
|
|
309
|
+
|
|
310
|
+
15 new tests in `test/hardening.test.js`, each pinned so that reverting a fix turns it red for the
|
|
311
|
+
same reason the bug was reported. 211 total, all green. They found two mistakes in these fixes
|
|
312
|
+
before release: a slug that came out unreadable, and a browser-path check that failed on Linux for
|
|
313
|
+
Windows-style paths because POSIX `path.basename()` does not treat `\` as a separator.
|
|
314
|
+
|
|
9
315
|
## [1.26.0] — 2026-08-29
|
|
10
316
|
|
|
11
317
|
### Added
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";import{i as r}from"./utils-BqE_aDxV.js";var i=t(e(),1),a=n(),o=new Set(`ts.tsx.js.jsx.mjs.cjs.py.rs.go.java.rb.php.cs.cpp.cc.c.h.hpp.swift.kt.vue.svelte.json.md.mdx.yml.yaml.toml.css.scss.html.sh.sql.prisma.graphql`.split(`.`)),s=/([A-Za-z0-9_.\-/]+\.[A-Za-z][A-Za-z0-9]{0,7})/g;function c(e,t){if(!t)return e;let n=[],r=0,i;for(s.lastIndex=0;(i=s.exec(e))!==null;){let s=i[1],c=s.slice(s.lastIndexOf(`.`)+1).toLowerCase();(s.includes(`/`)||o.has(c))&&(i.index>r&&n.push(e.slice(r,i.index)),n.push((0,a.jsx)(`button`,{onClick:()=>t(s),className:`font-mono underline decoration-dotted underline-offset-2`,style:{color:`var(--accent)`},title:`Jump to ${s} in Anatomy`,children:s},`${i.index}-${s}`)),r=i.index+s.length)}return r<e.length&&n.push(e.slice(r)),n.length?n:e}var l=[{key:`achievements`,title:`Achievements`,icon:`🏆`,color:`#059669`},{key:`improvements`,title:`Improvements`,icon:`✨`,color:`#3b82f6`},{key:`next_tasks`,title:`Next Tasks`,icon:`📋`,color:`#d97706`},{key:`risks`,title:`Risks & Tech Debt`,icon:`🛡`,color:`#dc2626`}],u=`Analyze this project and write a JSON file to .wolf/suggestions.json with this exact structure:
|
|
2
2
|
{
|
|
3
3
|
"generated_at": "<ISO timestamp>",
|
|
4
4
|
"achievements": ["..."],
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";var r=t(e(),1),i=n();function a(e){return e.split(`
|
|
2
2
|
`).filter(e=>e.trim().length>0).map(e=>{let t=/ → error$/.test(e),n=e.replace(/ → error$/,``),r=n.match(/^(\d{1,2}:\d{2})\s+(.*)$/);return r?{time:r[1],cmd:r[2],failed:t}:{time:``,cmd:n,failed:t}}).reverse()}function o({label:e,value:t,accent:n}){return(0,i.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:e}),(0,i.jsx)(`p`,{className:`text-2xl font-bold mt-1`,style:{color:n?`var(--danger)`:`var(--text-primary)`},children:t})]})}function s({data:e}){let[t,n]=(0,r.useState)(``),[s,c]=(0,r.useState)(!1),l=(0,r.useMemo)(()=>a(e.activityLog||``),[e.activityLog]),u=l.filter(e=>e.failed).length,d=l.filter(e=>(!s||e.failed)&&(!t||e.cmd.toLowerCase().includes(t.toLowerCase())));if(l.length===0)return(0,i.jsxs)(`div`,{className:`rounded-xl p-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsx)(`h3`,{className:`font-medium mb-2`,style:{color:`var(--text-secondary)`},children:`No shell activity captured`}),(0,i.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:[`Passive Bash capture is `,(0,i.jsx)(`strong`,{children:`opt-in`}),`. Enable it in `,(0,i.jsx)(`code`,{className:`px-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`.wolf/config.json`}),` — set `,(0,i.jsx)(`code`,{className:`px-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`openwolf.capture.enabled = true`}),` — and notable commands (commits, installs, tests, builds) plus any failures land in `,(0,i.jsx)(`code`,{children:`.wolf/activity.log`}),`, redacted, and feed the next session's resume digest.`]})]});let f={color:`var(--text-secondary)`,padding:`0.5rem 0.75rem`,borderTop:`1px solid var(--border)`},p={color:`var(--text-muted)`,fontWeight:500,textAlign:`left`,padding:`0.5rem 0.75rem`};return(0,i.jsxs)(`div`,{children:[(0,i.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-3 gap-4 mb-4`,children:[(0,i.jsx)(o,{label:`Captured commands`,value:String(l.length)}),(0,i.jsx)(o,{label:`Failures`,value:String(u),accent:u>0}),(0,i.jsx)(o,{label:`Showing`,value:String(d.length)})]}),(0,i.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 mb-3`,children:[(0,i.jsx)(`input`,{type:`text`,placeholder:`Filter commands…`,value:t,onChange:e=>n(e.target.value),className:`rounded-lg px-3 py-2 text-sm flex-1 min-w-[200px] focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,i.jsx)(`button`,{onClick:()=>c(e=>!e),className:`px-3 py-2 text-xs rounded-lg transition-colors`,style:{background:s?`var(--danger-subtle)`:`var(--bg-surface)`,border:`1px solid var(--border)`,color:s?`var(--danger)`:`var(--text-muted)`},children:s?`Showing failures only`:`Failures only`})]}),(0,i.jsx)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,i.jsx)(`div`,{className:`overflow-x-auto`,style:{maxHeight:520},children:(0,i.jsxs)(`table`,{className:`w-full text-sm`,style:{borderCollapse:`collapse`},children:[(0,i.jsx)(`thead`,{children:(0,i.jsxs)(`tr`,{children:[(0,i.jsx)(`th`,{style:{...p,width:64},children:`Time`}),(0,i.jsxs)(`th`,{style:p,children:[`Command (`,d.length,`)`]})]})}),(0,i.jsx)(`tbody`,{children:d.map((e,t)=>(0,i.jsxs)(`tr`,{style:{background:e.failed?`var(--danger-subtle)`:`transparent`},children:[(0,i.jsx)(`td`,{style:{...f,color:`var(--text-faint)`,whiteSpace:`nowrap`},children:e.time||`—`}),(0,i.jsxs)(`td`,{style:{...f,color:e.failed?`var(--danger)`:`var(--text-primary)`},className:`font-mono`,children:[e.cmd,e.failed&&(0,i.jsx)(`span`,{className:`text-xs ml-2`,style:{color:`var(--danger)`},children:`error`})]})]},t))})]})})}),(0,i.jsxs)(`p`,{className:`text-xs mt-3`,style:{color:`var(--text-faint)`},children:[`Secrets are redacted before capture; the newest commands feed the resume digest. Read-only view of `,(0,i.jsx)(`code`,{children:`.wolf/activity.log`}),`.`]})]})}export{s as ActivityLog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";var r=t(e(),1),i=n();function a({data:e}){let{memory:t}=e,[n,a]=(0,r.useState)(`all`),[o,s]=(0,r.useState)(``),[c,l]=(0,r.useState)(!0),u=(0,r.useMemo)(()=>{let e=t;if(n===`today`){let t=new Date().toISOString().slice(0,10);e=e.filter(e=>e.date===t)}else if(n===`week`){let t=new Date(Date.now()-7*864e5).toISOString().slice(0,10);e=e.filter(e=>e.date>=t)}if(o){let t=o.toLowerCase();e=e.map(e=>({...e,entries:e.entries.filter(e=>e.action.toLowerCase().includes(t)||e.files.toLowerCase().includes(t))})).filter(e=>e.entries.length>0)}return e},[t,n,o]);return(0,i.jsxs)(`div`,{children:[(0,i.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 mb-4`,children:[(0,i.jsx)(`div`,{className:`flex gap-1 rounded-lg p-1`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[`all`,`today`,`week`].map(e=>(0,i.jsx)(`button`,{onClick:()=>a(e),className:`px-3 py-1 text-xs rounded-md transition-colors`,style:{background:n===e?`var(--bg-surface-hover)`:`transparent`,color:n===e?`var(--text-primary)`:`var(--text-muted)`},children:e===`all`?`All`:e===`today`?`Today`:`This Week`},e))}),(0,i.jsx)(`input`,{type:`text`,placeholder:`Search actions...`,value:o,onChange:e=>s(e.target.value),className:`rounded-lg px-3 py-1.5 text-sm flex-1 min-w-[200px] focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,i.jsx)(`button`,{onClick:()=>l(!c),className:`px-3 py-1.5 text-xs rounded-lg`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-muted)`},children:c?`Flat view`:`Group by session`})]}),u.length===0?(0,i.jsx)(`div`,{className:`text-center py-12`,style:{color:`var(--text-muted)`},children:`No activity found.`}):c?u.map((e,t)=>(0,i.jsxs)(`div`,{className:`mb-4`,children:[(0,i.jsxs)(`div`,{className:`text-sm font-medium mb-2`,style:{color:`var(--text-muted)`},children:[e.date,` `,e.time,` — `,e.entries.length,` actions`]}),(0,i.jsx)(`div`,{className:`rounded-xl`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:e.entries.map((t,n)=>(0,i.jsxs)(`div`,{className:`flex items-center gap-4 px-4 py-3`,style:{borderBottom:n<e.entries.length-1?`1px solid var(--border)`:`none`},children:[(0,i.jsx)(`span`,{className:`text-xs font-mono w-12 shrink-0`,style:{color:`var(--text-faint)`},children:t.time}),(0,i.jsx)(`span`,{className:`w-2 h-2 rounded-full shrink-0 ${t.action.includes(`Created`)?`bg-emerald-500`:t.action.includes(`Edited`)?`bg-blue-500`:``}`,style:{background:!t.action.includes(`Created`)&&!t.action.includes(`Edited`)?`var(--text-faint)`:void 0}}),(0,i.jsx)(`span`,{className:`text-sm flex-1`,style:{color:`var(--text-secondary)`},children:t.action}),(0,i.jsx)(`span`,{className:`text-xs font-mono`,style:{color:`var(--text-faint)`},children:t.tokens})]},n))})]},t)):(0,i.jsx)(`div`,{className:`rounded-xl`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:u.flatMap(e=>e.entries.map((t,n)=>(0,i.jsxs)(`div`,{className:`flex items-center gap-4 px-4 py-3`,style:{borderBottom:`1px solid var(--border)`},children:[(0,i.jsx)(`span`,{className:`text-xs font-mono w-20 shrink-0`,style:{color:`var(--text-faint)`},children:e.date}),(0,i.jsx)(`span`,{className:`text-xs font-mono w-12 shrink-0`,style:{color:`var(--text-faint)`},children:t.time}),(0,i.jsx)(`span`,{className:`text-sm flex-1`,style:{color:`var(--text-secondary)`},children:t.action}),(0,i.jsx)(`span`,{className:`text-xs font-mono`,style:{color:`var(--text-faint)`},children:t.tokens})]},`${e.date}-${n}`)))})]})}export{a as ActivityTimeline};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";import{r,t as i}from"./utils-BqE_aDxV.js";var a=t(e(),1),o=n();function s({tokens:e,className:t}){return(0,o.jsxs)(`span`,{className:i(`font-mono text-xs`,e<200?`text-emerald-400`:e<1e3?`text-amber-400`:`text-red-400`,t),children:[`~`,r(e),` tok`]})}function c(e){let t={name:`.`,path:`.`,children:[],files:[]},n=new Map;n.set(`./`,t);for(let r of e){let e=r.section;if(!n.has(e)){let r=e.replace(/\/$/,``).split(`/`),i=t,a=``;for(let e of r){a=a?`${a}/${e}`:e;let t=`${a}/`;if(!n.has(t)){let r={name:e,path:t,children:[],files:[]};i.children.push(r),n.set(t,r)}i=n.get(t)}}n.get(e).files.push({file:r.file,description:r.description,tokens:r.tokens})}return t}function l({node:e,search:t,depth:n=0}){let[r,i]=(0,a.useState)(n<2),c=t.toLowerCase(),f=e.files.filter(e=>!t||e.file.toLowerCase().includes(c)||e.description.toLowerCase().includes(c)),p=e.children.some(e=>d(e,c));return t&&f.length===0&&!p?null:(0,o.jsxs)(`div`,{className:`ml-3`,children:[e.name!==`.`&&(0,o.jsxs)(`button`,{onClick:()=>i(!r),className:`flex items-center gap-1.5 py-1 text-sm transition-colors`,style:{color:`var(--text-secondary)`},children:[(0,o.jsx)(`span`,{className:`w-4 text-center`,style:{color:`var(--text-faint)`},children:r?`▼`:`▶`}),(0,o.jsx)(`span`,{className:`text-amber-400`,children:`📁`}),(0,o.jsxs)(`span`,{children:[e.name,`/`]}),(0,o.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[u(e),` files`]})]}),(r||e.name===`.`)&&(0,o.jsxs)(`div`,{className:e.name===`.`?``:`ml-4`,children:[f.sort((e,t)=>e.file.localeCompare(t.file)).map(e=>(0,o.jsxs)(`div`,{className:`flex items-center gap-2 py-1 pl-5`,children:[(0,o.jsx)(`span`,{style:{color:`var(--text-faint)`},children:`📄`}),(0,o.jsx)(`span`,{className:`text-sm font-mono`,style:{color:`var(--text-primary)`},children:e.file}),e.description&&(0,o.jsxs)(`span`,{className:`text-xs truncate max-w-xs`,style:{color:`var(--text-faint)`},children:[`— `,e.description]}),(0,o.jsx)(s,{tokens:e.tokens,className:`ml-auto shrink-0`})]},e.file)),e.children.sort((e,t)=>e.name.localeCompare(t.name)).map(e=>(0,o.jsx)(l,{node:e,search:t,depth:n+1},e.path))]})]})}function u(e){return e.files.length+e.children.reduce((e,t)=>e+u(t),0)}function d(e,t){return e.files.some(e=>e.file.toLowerCase().includes(t)||e.description.toLowerCase().includes(t))?!0:e.children.some(e=>d(e,t))}function f({data:e,initialFile:t}){let{anatomy:n}=e,[r,i]=(0,a.useState)(t??``),[s,u]=(0,a.useState)(!1);(0,a.useEffect)(()=>{t&&i(t)},[t]);let d=(0,a.useMemo)(()=>c(n.entries),[n.entries]),f=(0,a.useMemo)(()=>{let e=n.entries.map(e=>e.tokens);return{total:n.entries.length,avg:e.length>0?Math.round(e.reduce((e,t)=>e+t,0)/e.length):0,largest:e.length>0?Math.max(...e):0}},[n.entries]);return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 mb-4`,children:[(0,o.jsx)(`input`,{type:`text`,placeholder:`Search files...`,value:r,onChange:e=>i(e.target.value),className:`flex-1 min-w-[200px] rounded-lg px-3 py-2 text-sm focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,o.jsx)(`button`,{onClick:()=>u(!s),className:`px-3 py-2 text-xs rounded-lg`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-muted)`},children:s?`Sort: Size`:`Sort: A-Z`})]}),(0,o.jsxs)(`div`,{className:`flex gap-4 mb-4 text-sm`,style:{color:`var(--text-muted)`},children:[(0,o.jsxs)(`span`,{children:[f.total,` files tracked`]}),(0,o.jsxs)(`span`,{children:[`Avg: `,f.avg,` tok/file`]}),(0,o.jsxs)(`span`,{children:[`Largest: `,f.largest,` tok`]})]}),(0,o.jsx)(`div`,{className:`rounded-xl p-4`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:n.entries.length===0?(0,o.jsxs)(`div`,{className:`text-center py-12`,style:{color:`var(--text-muted)`},children:[(0,o.jsx)(`p`,{className:`text-2xl mb-2`,children:`📂`}),(0,o.jsxs)(`p`,{children:[`No anatomy data. Run `,(0,o.jsx)(`code`,{style:{color:`var(--text-secondary)`},children:`openwolf scan`}),` to index your project.`]})]}):(0,o.jsx)(l,{node:d,search:r})})]})}export{f as AnatomyBrowser};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";var r=t(e(),1),i=n();function a({data:e}){let{buglog:t}=e,[n,a]=(0,r.useState)(``),[o,s]=(0,r.useState)(null),c=n?t.bugs.filter(e=>e.error_message.toLowerCase().includes(n.toLowerCase())||e.root_cause.toLowerCase().includes(n.toLowerCase())||e.fix.toLowerCase().includes(n.toLowerCase())||e.tags.some(e=>e.toLowerCase().includes(n.toLowerCase()))):t.bugs;if(t.bugs.length===0)return(0,i.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-16 text-center`,children:[(0,i.jsx)(`div`,{className:`text-4xl mb-3`,children:`🐛`}),(0,i.jsx)(`h3`,{className:`font-medium mb-1`,style:{color:`var(--text-secondary)`},children:`No bugs logged yet`}),(0,i.jsx)(`p`,{className:`text-sm max-w-sm`,style:{color:`var(--text-muted)`},children:`When you encounter and fix bugs, they'll appear here for future reference.`})]});let l=t.bugs.flatMap(e=>e.tags),u=new Map;for(let e of l)u.set(e,(u.get(e)||0)+1);let d=[...u.entries()].sort((e,t)=>t[1]-e[1]).slice(0,5);return(0,i.jsxs)(`div`,{children:[(0,i.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4 mb-4`,children:[(0,i.jsx)(`input`,{type:`text`,placeholder:`Search bugs...`,value:n,onChange:e=>a(e.target.value),className:`flex-1 min-w-[200px] rounded-lg px-3 py-2 text-sm focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,i.jsxs)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:[t.bugs.length,` bugs logged`]})]}),d.length>0&&(0,i.jsx)(`div`,{className:`flex flex-wrap gap-2 mb-4`,children:d.map(([e,t])=>(0,i.jsxs)(`button`,{onClick:()=>a(e),className:`px-2 py-1 text-xs rounded-full`,style:{background:`var(--bg-surface-hover)`,border:`1px solid var(--border-subtle)`,color:`var(--text-muted)`},children:[e,` (`,t,`)`]},e))}),(0,i.jsx)(`div`,{className:`space-y-3`,children:c.map(e=>{let t=o===e.id;return(0,i.jsxs)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsxs)(`button`,{onClick:()=>s(t?null:e.id),className:`w-full flex items-start gap-3 px-5 py-3 transition-colors text-left`,onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsx)(`span`,{className:`text-sm mt-0.5`,style:{color:`var(--text-faint)`},children:t?`▼`:`▶`}),(0,i.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,i.jsx)(`p`,{className:`text-sm truncate`,style:{color:`var(--text-primary)`},children:e.error_message}),(0,i.jsxs)(`div`,{className:`flex items-center gap-3 mt-1`,children:[(0,i.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:e.file}),(0,i.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:e.timestamp?.slice(0,10)})]})]}),e.occurrences>1&&(0,i.jsxs)(`span`,{className:`shrink-0 px-2 py-0.5 rounded-full text-xs`,style:{background:`var(--warning-subtle)`,color:`var(--warning)`},children:[`Seen `,e.occurrences,`x`]})]}),t&&(0,i.jsxs)(`div`,{className:`px-5 py-4 space-y-3`,style:{borderTop:`1px solid var(--border)`},children:[(0,i.jsxs)(`div`,{children:[(0,i.jsx)(`p`,{className:`text-xs uppercase mb-1`,style:{color:`var(--text-faint)`},children:`Error Message`}),(0,i.jsx)(`pre`,{className:`text-sm rounded-lg p-3 overflow-x-auto font-mono`,style:{color:`var(--danger)`,background:`var(--danger-subtle)`},children:e.error_message})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(`p`,{className:`text-xs uppercase mb-1`,style:{color:`var(--text-faint)`},children:`Root Cause`}),(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-secondary)`},children:e.root_cause})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(`p`,{className:`text-xs uppercase mb-1`,style:{color:`var(--text-faint)`},children:`Fix`}),(0,i.jsx)(`pre`,{className:`text-sm rounded-lg p-3 overflow-x-auto font-mono`,style:{color:`var(--accent)`,background:`var(--accent-subtle)`},children:e.fix})]}),(0,i.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.tags.map(e=>(0,i.jsx)(`span`,{className:`px-2 py-0.5 text-xs rounded-full`,style:{background:`var(--bg-surface-hover)`,border:`1px solid var(--border-subtle)`,color:`var(--text-muted)`},children:e},e))})]})]},e.id)})})]})}export{a as BugLog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";var r=t(e(),1),i=n();function a({data:e}){let{cerebrum:t}=e,[n,a]=(0,r.useState)(``),[o,s]=(0,r.useState)({preferences:!0,learnings:!0,doNotRepeat:!0,decisions:!1}),c=e=>s(t=>({...t,[e]:!t[e]})),l=e=>!n||e.toLowerCase().includes(n.toLowerCase());return(0,i.jsxs)(`div`,{children:[(0,i.jsx)(`div`,{className:`flex items-center justify-between mb-4`,children:(0,i.jsxs)(`div`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:[`Last updated: `,t.lastUpdated||`—`,` ·`,t.preferences.length+t.learnings.length+t.doNotRepeat.length+t.decisions.length,` entries`]})}),(0,i.jsx)(`input`,{type:`text`,placeholder:`Search cerebrum...`,value:n,onChange:e=>a(e.target.value),className:`w-full rounded-lg px-3 py-2 text-sm mb-4 focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,i.jsxs)(`div`,{className:`rounded-xl mb-4 overflow-hidden`,style:{background:`var(--danger-subtle)`,border:`1px solid rgba(220, 38, 38, 0.2)`},children:[(0,i.jsxs)(`button`,{onClick:()=>c(`doNotRepeat`),className:`w-full flex items-center justify-between px-5 py-3 transition-colors`,onMouseEnter:e=>e.currentTarget.style.background=`rgba(220, 38, 38, 0.08)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsx)(`span`,{style:{color:`var(--danger)`},children:`⊘`}),(0,i.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--danger)`},children:`Do-Not-Repeat`}),(0,i.jsx)(`span`,{className:`text-xs px-2 py-0.5 rounded-full`,style:{background:`rgba(220, 38, 38, 0.1)`,color:`var(--danger)`},children:t.doNotRepeat.length})]}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:o.doNotRepeat?`▼`:`▶`})]}),o.doNotRepeat&&(0,i.jsxs)(`div`,{className:`px-5 pb-4 space-y-2`,children:[t.doNotRepeat.filter(e=>l(e.text)).map((e,t)=>(0,i.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`rgba(220, 38, 38, 0.05)`,border:`1px solid rgba(220, 38, 38, 0.1)`},children:[e.date&&(0,i.jsxs)(`span`,{className:`text-xs font-mono mr-2`,style:{color:`rgba(220, 38, 38, 0.6)`},children:[`[`,e.date,`]`]}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-secondary)`},children:e.text})]},t)),t.doNotRepeat.length===0&&(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`No entries yet.`})]})]}),(0,i.jsxs)(`div`,{className:`rounded-xl mb-4 overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsxs)(`button`,{onClick:()=>c(`preferences`),className:`w-full flex items-center justify-between px-5 py-3 transition-colors`,onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsx)(`span`,{className:`text-blue-400`,children:`◈`}),(0,i.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`User Preferences`}),(0,i.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:t.preferences.length})]}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:o.preferences?`▼`:`▶`})]}),o.preferences&&(0,i.jsxs)(`div`,{className:`px-5 pb-4`,children:[t.preferences.filter(l).map((e,t)=>(0,i.jsxs)(`div`,{className:`flex items-start gap-2 py-1.5`,children:[(0,i.jsx)(`span`,{className:`mt-1`,style:{color:`var(--text-faint)`},children:`•`}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-secondary)`},children:e})]},t)),t.preferences.length===0&&(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`No preferences recorded yet.`})]})]}),(0,i.jsxs)(`div`,{className:`rounded-xl mb-4 overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsxs)(`button`,{onClick:()=>c(`learnings`),className:`w-full flex items-center justify-between px-5 py-3 transition-colors`,onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsx)(`span`,{style:{color:`var(--accent)`},children:`◎`}),(0,i.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Key Learnings`}),(0,i.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:t.learnings.length})]}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:o.learnings?`▼`:`▶`})]}),o.learnings&&(0,i.jsxs)(`div`,{className:`px-5 pb-4 space-y-2`,children:[t.learnings.filter(l).map((e,t)=>(0,i.jsx)(`div`,{className:`rounded-lg p-3 text-sm`,style:{background:`var(--bg-surface-hover)`,color:`var(--text-secondary)`},children:e},t)),t.learnings.length===0&&(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`No learnings recorded yet.`})]})]}),(0,i.jsxs)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsxs)(`button`,{onClick:()=>c(`decisions`),className:`w-full flex items-center justify-between px-5 py-3 transition-colors`,onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsx)(`span`,{className:`text-amber-400`,children:`⚖`}),(0,i.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Decision Log`}),(0,i.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:t.decisions.length})]}),(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:o.decisions?`▼`:`▶`})]}),o.decisions&&(0,i.jsxs)(`div`,{className:`px-5 pb-4 space-y-2`,children:[t.decisions.filter(l).map((e,t)=>(0,i.jsx)(`div`,{className:`rounded-lg p-3 text-sm`,style:{background:`var(--bg-surface-hover)`,color:`var(--text-secondary)`},children:e},t)),t.decisions.length===0&&(0,i.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`No decisions logged yet.`})]})]})]})}export{a as CerebrumViewer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n,t as r}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n,t as r}from"./index-C74qneS9.js";import{i,n as a}from"./utils-BqE_aDxV.js";import{t as o}from"./StatusBadge-CjrFCDOI.js";var s=t(e(),1),c=n();function l({data:e}){let{cronManifest:t,cronState:n,client:l}=e,[u,d]=(0,s.useState)(!0),[f,p]=(0,s.useState)(!1),[m,h]=(0,s.useState)({}),g=e=>n.dead_letter_queue.some(t=>t.task_id===e)?`failed`:n.execution_log.filter(t=>t.task_id===e).sort((e,t)=>t.timestamp.localeCompare(e.timestamp))[0]?.status||`ok`,_=e=>{let t=n.execution_log.filter(t=>t.task_id===e).sort((e,t)=>t.timestamp.localeCompare(e.timestamp))[0];return t?i(t.timestamp):`never`},v=e=>{h(t=>({...t,[e]:`running`})),r(`/api/cron/run/${encodeURIComponent(e)}`,{method:`POST`}).then(t=>{h(n=>({...n,[e]:t.ok?`ok`:`error`})),setTimeout(()=>h(t=>{let n={...t};return delete n[e],n}),3e3)}).catch(()=>{h(t=>({...t,[e]:`error`})),setTimeout(()=>h(t=>{let n={...t};return delete n[e],n}),3e3)})},y=e=>{l?.send({type:`retry_dead_letter`,task_id:e})};return(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`div`,{className:`rounded-xl overflow-hidden mb-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,c.jsxs)(`table`,{className:`w-full`,children:[(0,c.jsx)(`thead`,{children:(0,c.jsxs)(`tr`,{style:{borderBottom:`1px solid var(--border)`},children:[(0,c.jsx)(`th`,{className:`text-left px-4 py-3 text-xs font-medium uppercase`,style:{color:`var(--text-faint)`},children:`Status`}),(0,c.jsx)(`th`,{className:`text-left px-4 py-3 text-xs font-medium uppercase`,style:{color:`var(--text-faint)`},children:`Task`}),(0,c.jsx)(`th`,{className:`text-left px-4 py-3 text-xs font-medium uppercase hidden md:table-cell`,style:{color:`var(--text-faint)`},children:`Schedule`}),(0,c.jsx)(`th`,{className:`text-left px-4 py-3 text-xs font-medium uppercase hidden md:table-cell`,style:{color:`var(--text-faint)`},children:`Last Run`}),(0,c.jsx)(`th`,{className:`text-right px-4 py-3 text-xs font-medium uppercase`,style:{color:`var(--text-faint)`},children:`Actions`})]})}),(0,c.jsx)(`tbody`,{children:t.tasks.map(e=>(0,c.jsxs)(`tr`,{className:`transition-colors`,style:{borderBottom:`1px solid var(--border)`},onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,c.jsx)(`td`,{className:`px-4 py-3`,children:(0,c.jsx)(o,{status:e.enabled?g(e.id):`disabled`})}),(0,c.jsxs)(`td`,{className:`px-4 py-3`,children:[(0,c.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-primary)`},children:e.name}),(0,c.jsx)(`p`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:e.description})]}),(0,c.jsx)(`td`,{className:`px-4 py-3 hidden md:table-cell text-sm`,style:{color:`var(--text-muted)`},children:a(e.schedule)}),(0,c.jsx)(`td`,{className:`px-4 py-3 hidden md:table-cell text-sm`,style:{color:`var(--text-faint)`},children:_(e.id)}),(0,c.jsx)(`td`,{className:`px-4 py-3 text-right`,children:(()=>{let t=m[e.id];return(0,c.jsx)(`button`,{onClick:()=>v(e.id),disabled:t===`running`,className:`px-3 py-1 text-xs rounded-md transition-colors`,style:{background:`var(--bg-surface-hover)`,border:`1px solid var(--border-subtle)`,color:t===`ok`?`var(--accent)`:t===`error`?`var(--danger)`:`var(--text-secondary)`,opacity:t===`running`?.6:1},children:t===`running`?`Running…`:t===`ok`?`Triggered ✓`:t===`error`?`Failed ✗`:`Run Now`})})()})]},e.id))})]})}),(0,c.jsxs)(`div`,{className:`rounded-xl p-5 mb-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,c.jsxs)(`button`,{onClick:()=>d(!u),className:`flex items-center gap-2 w-full text-left`,children:[(0,c.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:u?`▼`:`▶`}),(0,c.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Dead Letter Queue`}),(0,c.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[`(`,n.dead_letter_queue.length,`)`]})]}),u&&(n.dead_letter_queue.length===0?(0,c.jsx)(`div`,{className:`text-center py-6 text-sm mt-2`,style:{color:`var(--text-muted)`},children:`No dead letters — all systems healthy`}):(0,c.jsx)(`div`,{className:`space-y-3 mt-3`,children:n.dead_letter_queue.map((e,t)=>(0,c.jsx)(`div`,{className:`rounded-lg p-4`,style:{background:`var(--danger-subtle)`,border:`1px solid rgba(220, 38, 38, 0.2)`},children:(0,c.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`p`,{className:`text-sm font-medium`,style:{color:`var(--danger)`},children:e.task_id}),(0,c.jsx)(`p`,{className:`text-xs mt-1`,style:{color:`var(--text-muted)`},children:e.error}),(0,c.jsxs)(`p`,{className:`text-xs mt-1`,style:{color:`var(--text-faint)`},children:[i(e.timestamp),` · `,e.attempts,` attempts`]})]}),(0,c.jsx)(`button`,{onClick:()=>y(e.task_id),className:`px-3 py-1 text-xs rounded-md`,style:{background:`var(--bg-surface-hover)`,border:`1px solid var(--border-subtle)`,color:`var(--text-secondary)`},children:`Retry`})]})},t))}))]}),(0,c.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,c.jsxs)(`button`,{onClick:()=>p(!f),className:`flex items-center gap-2 w-full text-left`,children:[(0,c.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:f?`▼`:`▶`}),(0,c.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Execution History`})]}),f&&(0,c.jsxs)(`div`,{className:`mt-3`,children:[n.execution_log.slice(-30).reverse().map((e,t)=>(0,c.jsxs)(`div`,{className:`flex items-center gap-4 py-2`,style:{borderBottom:`1px solid var(--border)`},children:[(0,c.jsx)(`span`,{className:`text-xs font-mono`,style:{color:`var(--text-faint)`},children:e.timestamp?.slice(11,16)}),(0,c.jsx)(`span`,{className:`text-sm flex-1`,style:{color:`var(--text-secondary)`},children:e.task_id}),(0,c.jsxs)(`span`,{className:`text-xs font-mono`,style:{color:`var(--text-faint)`},children:[e.duration_ms,`ms`]}),(0,c.jsx)(o,{status:e.status})]},t)),n.execution_log.length===0&&(0,c.jsx)(`p`,{className:`text-sm py-4 text-center`,style:{color:`var(--text-muted)`},children:`No executions yet.`})]})]})]})}export{l as CronStatus};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,n,r,t as i}from"./index-
|
|
1
|
+
import{a as e,c as t,n,r,t as i}from"./index-C74qneS9.js";var a=t(e(),1),o=r(),s=e=>n(`/api/designqc/capture/${encodeURIComponent(e)}`);function c({data:e}){let{designqcReport:t,project:n}=e,[r,c]=(0,a.useState)(`idle`),[l,u]=(0,a.useState)(null),[d,f]=(0,a.useState)(null),p=t&&t.captures&&t.captures.length>0;return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`rounded-xl px-4 py-3 mb-6 flex items-start gap-3`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`span`,{style:{color:`var(--text-faint)`,marginTop:1},children:`ℹ`}),(0,o.jsxs)(`div`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:[`Works with `,(0,o.jsx)(`span`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`any accessible URL`}),` — local or deployed. The URL is auto-detected from `,(0,o.jsx)(`code`,{className:`px-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`package.json`}),` homepage, env files, or a running dev server.`,n?.root&&(0,o.jsxs)(`span`,{children:[` Scanning `,(0,o.jsx)(`code`,{className:`px-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:n.root}),`.`]})]})]}),(0,o.jsxs)(`div`,{className:`rounded-xl p-5 mb-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsxs)(`div`,{className:`flex items-center justify-between mb-3`,children:[(0,o.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Capture Screenshots`}),(0,o.jsx)(`button`,{onClick:()=>{c(`running`),u(null),i(`/api/designqc/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:`{}`}).then(async e=>{if(!e.ok){let t=await e.json().catch(()=>({error:e.statusText}));throw Error(t.error||e.statusText)}c(`idle`)}).catch(e=>{c(`error`),u(e.message)})},disabled:r===`running`,className:`px-4 py-1.5 text-sm rounded-lg transition-colors`,style:{background:r===`error`?`var(--danger-subtle)`:`var(--accent-subtle)`,border:`1px solid ${r===`error`?`rgba(220,38,38,0.3)`:`var(--accent)`}`,color:r===`error`?`var(--danger)`:`var(--accent)`,opacity:r===`running`?.6:1},children:r===`running`?`Capturing…`:r===`error`?`Retry Capture`:`Run Capture`})]}),r===`running`&&(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Auto-detecting URL, launching browser, capturing screenshots… this takes ~15–30s.`}),r===`error`&&l&&(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--danger)`},children:l}),r===`idle`&&(0,o.jsxs)(`div`,{className:`space-y-1.5 text-sm`,style:{color:`var(--text-muted)`},children:[(0,o.jsxs)(`p`,{children:[`Detects your URL automatically from `,(0,o.jsx)(`code`,{className:`px-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`package.json`}),`, env files, or a running dev server.`]}),(0,o.jsxs)(`p`,{children:[`After capture, ask Claude: `,(0,o.jsx)(`span`,{className:`italic`,children:`"Read .wolf/designqc-captures/ and evaluate the design"`})]})]})]}),(0,o.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`h3`,{className:`font-medium mb-3`,style:{color:`var(--text-secondary)`},children:`Last Capture`}),p?(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`flex gap-4 text-sm mb-4`,children:[(0,o.jsxs)(`span`,{style:{color:`var(--text-faint)`},children:[`Captured: `,t.captured_at||`—`]}),(0,o.jsxs)(`span`,{style:{color:`var(--text-faint)`},children:[`Size: `,t.total_size_kb||0,`KB`]}),(0,o.jsxs)(`span`,{style:{color:`var(--text-faint)`},children:[`Est. tokens: ~`,t.estimated_tokens||0]})]}),(0,o.jsx)(`div`,{className:`grid grid-cols-2 md:grid-cols-3 gap-4`,children:t.captures.map((e,t)=>(0,o.jsxs)(`button`,{onClick:()=>f(e.file),className:`text-left rounded-lg overflow-hidden transition-transform hover:-translate-y-0.5`,style:{background:`var(--bg-base)`,border:`1px solid var(--border)`},title:`Klicken zum Vergrößern`,children:[(0,o.jsx)(`img`,{src:s(e.file),alt:`${e.viewport} · ${e.route}`,loading:`lazy`,className:`w-full block`,style:{maxHeight:200,objectFit:`cover`,objectPosition:`top`,background:`var(--bg-surface)`}}),(0,o.jsxs)(`div`,{className:`px-3 py-2`,children:[(0,o.jsx)(`div`,{className:`text-sm truncate`,style:{color:`var(--text-primary)`},children:e.file}),(0,o.jsxs)(`div`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[e.viewport,` · `,e.route]})]})]},t))})]}):(0,o.jsx)(`div`,{className:`text-center py-8`,children:(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`No screenshots captured yet.`})})]}),d&&(0,o.jsxs)(`div`,{onClick:()=>f(null),className:`fixed inset-0 z-50 flex items-center justify-center p-6`,style:{background:`rgba(0,0,0,0.8)`},children:[(0,o.jsx)(`div`,{className:`relative max-w-6xl max-h-[90vh] overflow-auto rounded-lg`,onClick:e=>e.stopPropagation(),children:(0,o.jsx)(`img`,{src:s(d),alt:d,className:`block`,style:{maxWidth:`100%`}})}),(0,o.jsx)(`button`,{onClick:()=>f(null),className:`absolute top-4 right-4 w-9 h-9 rounded-full flex items-center justify-center text-lg`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`},"aria-label":`Schließen`,children:`✕`})]})]})}export{c as DesignQC};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n,t as r}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n,t as r}from"./index-C74qneS9.js";var i=t(e(),1),a=n();function o(e,t,n,r){let i=new Map(e.map((e,t)=>[e.key,t])),a=e.length,o=new Float64Array(a),s=new Float64Array(a);for(let e=0;e<a;e++){let t=e*2.399963%(Math.PI*2),i=Math.sqrt((e+.5)/a)*Math.min(n,r)*.42;o[e]=n/2+Math.cos(t)*i,s[e]=r/2+Math.sin(t)*i}let c=t.map(e=>[i.get(e.from),i.get(e.to)]).filter(e=>e[0]!==void 0&&e[1]!==void 0);for(let e=0;e<220;e++){let t=1-e/220;for(let e=0;e<a;e++)for(let n=e+1;n<a;n++){let r=o[e]-o[n],i=s[e]-s[n],a=r*r+i*i;if(a<1&&(a=1,r=e-n||1,i=1),a>9e4)continue;let c=420/a*t,l=Math.sqrt(a);o[e]+=r/l*c,s[e]+=i/l*c,o[n]-=r/l*c,s[n]-=i/l*c}for(let[e,n]of c){let r=o[n]-o[e],i=s[n]-s[e],a=Math.max(1,Math.hypot(r,i)),c=(a-72)*.02*t;o[e]+=r/a*c,s[e]+=i/a*c,o[n]-=r/a*c,s[n]-=i/a*c}for(let e=0;e<a;e++)o[e]=Math.max(14,Math.min(n-14,o[e])),s[e]=Math.max(14,Math.min(r-14,s[e]))}return{x:o,y:s,idx:i}}function s(){let[e,t]=(0,i.useState)(null),[n,s]=(0,i.useState)(null),c=(0,i.useRef)(null);(0,i.useEffect)(()=>{r(`/api/link-graph`).then(e=>e.json()).then(t).catch(()=>t({available:!1,error:`not reachable`}))},[]);let l=(0,i.useMemo)(()=>(e?.nodes??[]).filter(e=>e.in+e.out>0),[e]),u=(0,i.useMemo)(()=>[...l].sort((e,t)=>t.in+t.out-(e.in+e.out)).slice(0,90),[l]),d=(0,i.useMemo)(()=>new Set(u.map(e=>e.key)),[u]),f=(0,i.useMemo)(()=>(e?.edges??[]).filter(e=>d.has(e.from)&&d.has(e.to)),[e,d]),p=(e?.nodes?.length??0)-l.length;if((0,i.useEffect)(()=>{let t=c.current;if(!t||!e?.available||u.length===0)return;let r=t.width,i=t.height,{x:a,y:s,idx:l}=o(u,f,r,i),d=t.getContext(`2d`);if(!d)return;d.clearRect(0,0,r,i),d.strokeStyle=`rgba(148,163,184,0.22)`,d.lineWidth=1;for(let e of f){let t=l.get(e.from),n=l.get(e.to);t===void 0||n===void 0||(d.beginPath(),d.moveTo(a[t],s[t]),d.lineTo(a[n],s[n]),d.stroke())}let p=Math.max(1,...u.map(e=>e.in));u.forEach((e,t)=>{let r=3+Math.sqrt(e.in/p)*9;d.beginPath(),d.arc(a[t],s[t],r,0,Math.PI*2),d.fillStyle=e.key===n?`#fbbf24`:e.in>0?`#34d399`:`#64748b`,d.fill()}),d.fillStyle=`rgba(226,232,240,0.85)`,d.font=`11px ui-monospace, monospace`,[...u].sort((e,t)=>t.in-e.in).slice(0,8).forEach(e=>{let t=l.get(e.key);d.fillText(e.title.replace(/\.md$/,``).slice(0,26),a[t]+10,s[t]+4)})},[e,u,f,n]),!e)return(0,a.jsx)(`div`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Loading…`});if(!e.available)return(0,a.jsxs)(`div`,{className:`rounded-xl p-5 text-sm`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-muted)`},children:[`No link graph available`,e.error?` — ${e.error}`:``,`.`]});let m=[...e.nodes??[]].sort((e,t)=>t.in-e.in).filter(e=>e.in>0).slice(0,12);return(0,a.jsxs)(`div`,{className:`grid gap-6 lg:grid-cols-[1.4fr_1fr]`,children:[(0,a.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,a.jsxs)(`div`,{className:`mb-3 flex items-baseline justify-between`,children:[(0,a.jsx)(`h3`,{className:`font-medium`,style:{color:`var(--text-secondary)`},children:`Link graph`}),(0,a.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[u.length,` of `,l.length,` linked shown · `,p,` isolated · `,e.edges?.length??0,` links`]})]}),(0,a.jsx)(`canvas`,{ref:c,width:760,height:460,className:`w-full rounded-lg`,style:{background:`var(--bg-base)`,border:`1px solid var(--border)`}}),(0,a.jsxs)(`p`,{className:`mt-3 text-xs`,style:{color:`var(--text-faint)`},children:[`The `,90,` best-connected notes; dot size follows how often a note is referenced. Drawing all `,l.length,` produced a hairball, so the rest is counted rather than drawn —`,e.stats?.blocks.toLocaleString(`en-US`),` blocks sit behind these `,e.stats?.files,` files.`]})]}),(0,a.jsxs)(`div`,{className:`flex flex-col gap-6`,children:[(0,a.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,a.jsx)(`h3`,{className:`mb-3 font-medium`,style:{color:`var(--text-secondary)`},children:`Most referenced`}),m.length===0?(0,a.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Nothing links to anything yet.`}):(0,a.jsx)(`ul`,{className:`flex flex-col gap-1.5 text-sm`,children:m.map(e=>(0,a.jsx)(`li`,{children:(0,a.jsxs)(`button`,{onClick:()=>s(e.key===n?null:e.key),className:`flex w-full items-center gap-2 rounded px-1.5 py-1 text-left hover:bg-white/5`,style:{color:e.key===n?`var(--accent)`:`var(--text-primary)`},children:[(0,a.jsx)(`span`,{className:`font-mono text-xs tabular-nums`,style:{color:`var(--text-faint)`},children:String(e.in).padStart(2,` `)}),(0,a.jsx)(`span`,{className:`truncate`,children:e.title.replace(/\.md$/,``)})]})},e.key))})]}),(0,a.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,a.jsxs)(`h3`,{className:`mb-1 font-medium`,style:{color:`var(--text-secondary)`},children:[`Dead references `,e.dangling?.length?`(${e.dangling.length})`:``]}),(0,a.jsx)(`p`,{className:`mb-3 text-xs`,style:{color:`var(--text-faint)`},children:`A link whose target does not exist. Named rather than swallowed — each one is a note that was meant to be written, or a link that was mistyped.`}),(e.dangling?.length??0)===0?(0,a.jsx)(`p`,{className:`text-sm`,style:{color:`var(--accent)`},children:`None. Every reference resolves.`}):(0,a.jsx)(`ul`,{className:`flex flex-col gap-2 text-sm`,children:e.dangling.slice(0,12).map((e,t)=>(0,a.jsxs)(`li`,{className:`leading-snug`,children:[(0,a.jsx)(`code`,{className:`text-xs`,style:{color:`#f87171`},children:e.target}),(0,a.jsxs)(`div`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[`from `,e.fromSrc.replace(/^native\//,``)]})]},t))})]})]})]})}export{s as LinkGraph};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n}from"./index-
|
|
1
|
+
import{a as e,c as t,r as n}from"./index-C74qneS9.js";var r=t(e(),1),i=n();function a({data:e}){let{memory:t}=e,[n,a]=(0,r.useState)(0),[o,s]=(0,r.useState)(``),c=o?t.filter(e=>e.entries.some(e=>e.action.toLowerCase().includes(o.toLowerCase())||e.files.toLowerCase().includes(o.toLowerCase()))):t;return(0,i.jsxs)(`div`,{children:[(0,i.jsx)(`div`,{className:`flex items-center gap-3 mb-4`,children:(0,i.jsx)(`input`,{type:`text`,placeholder:`Search memory...`,value:o,onChange:e=>s(e.target.value),className:`flex-1 rounded-lg px-3 py-2 text-sm focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}})}),c.length===0?(0,i.jsx)(`div`,{className:`text-center py-12`,style:{color:`var(--text-muted)`},children:`No sessions found.`}):(0,i.jsx)(`div`,{className:`space-y-3`,children:c.map((e,t)=>{let r=n===t,o=e.entries.reduce((e,t)=>e+(parseInt(t.tokens.replace(/[^0-9]/g,``))||0),0);return(0,i.jsxs)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,i.jsxs)(`button`,{onClick:()=>a(r?-1:t),className:`w-full flex items-center justify-between px-5 py-3 transition-colors`,onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,i.jsx)(`span`,{className:`text-sm`,style:{color:`var(--text-faint)`},children:r?`▼`:`▶`}),(0,i.jsxs)(`span`,{className:`text-sm font-medium`,style:{color:`var(--text-primary)`},children:[e.date,` `,e.time]}),(0,i.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:[e.entries.length,` actions`]})]}),o>0&&(0,i.jsxs)(`span`,{className:`text-xs font-mono`,style:{color:`var(--text-faint)`},children:[`~`,o,` tok`]})]}),r&&e.entries.length>0&&(0,i.jsx)(`div`,{style:{borderTop:`1px solid var(--border)`},children:(0,i.jsxs)(`table`,{className:`w-full`,children:[(0,i.jsx)(`thead`,{children:(0,i.jsxs)(`tr`,{className:`text-xs uppercase`,style:{color:`var(--text-faint)`},children:[(0,i.jsx)(`th`,{className:`text-left px-4 py-2 w-16`,children:`Time`}),(0,i.jsx)(`th`,{className:`text-left px-4 py-2`,children:`Action`}),(0,i.jsx)(`th`,{className:`text-left px-4 py-2 hidden md:table-cell`,children:`Files`}),(0,i.jsx)(`th`,{className:`text-left px-4 py-2 hidden md:table-cell`,children:`Outcome`}),(0,i.jsx)(`th`,{className:`text-right px-4 py-2 w-20`,children:`Tokens`})]})}),(0,i.jsx)(`tbody`,{children:e.entries.map((e,t)=>(0,i.jsxs)(`tr`,{style:{borderBottom:`1px solid var(--border)`},onMouseEnter:e=>e.currentTarget.style.background=`var(--bg-surface-hover)`,onMouseLeave:e=>e.currentTarget.style.background=`transparent`,children:[(0,i.jsx)(`td`,{className:`px-4 py-2 text-xs font-mono`,style:{color:`var(--text-faint)`},children:e.time}),(0,i.jsx)(`td`,{className:`px-4 py-2 text-sm`,style:{color:`var(--text-secondary)`},children:e.action}),(0,i.jsx)(`td`,{className:`px-4 py-2 text-sm hidden md:table-cell`,style:{color:`var(--text-muted)`},children:e.files}),(0,i.jsx)(`td`,{className:`px-4 py-2 text-sm hidden md:table-cell`,style:{color:`var(--text-muted)`},children:e.outcome}),(0,i.jsx)(`td`,{className:`px-4 py-2 text-xs font-mono text-right`,style:{color:`var(--text-faint)`},children:e.tokens})]},t))})]})})]},t)})})]})}export{a as MemoryViewer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,r as n,t as r}from"./index-e2PfOI0b.js";import{i}from"./utils-BqE_aDxV.js";var a=t(e(),1),o=n();function s(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function c({label:e,value:t,accent:n}){return(0,o.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:e}),(0,o.jsx)(`p`,{className:`text-2xl font-bold mt-1`,style:{color:n?`var(--accent)`:`var(--text-primary)`},children:t})]})}var l=2160*60*60*1e3;function u({scope:e,setScope:t}){return(0,o.jsx)(`div`,{className:`inline-flex rounded-lg mb-4 p-0.5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[{id:`project`,label:`This project`},{id:`all`,label:`All projects`}].map(n=>(0,o.jsx)(`button`,{onClick:()=>t(n.id),className:`text-sm px-3 py-1.5 rounded-md transition-colors`,style:{background:e===n.id?`var(--accent)`:`transparent`,color:e===n.id?`#fff`:`var(--text-muted)`},children:n.label},n.id))})}function d({data:e}){let[t,n]=(0,a.useState)(`project`);return(0,o.jsxs)(`div`,{children:[(0,o.jsx)(u,{scope:t,setScope:n}),t===`project`?(0,o.jsx)(f,{data:e}):(0,o.jsx)(p,{data:e})]})}function f(e){let[t,n]=(0,a.useState)(null),[u,d]=(0,a.useState)(null),[f,p]=(0,a.useState)(``),[m,h]=(0,a.useState)(null),[g,_]=(0,a.useState)(!1);(0,a.useEffect)(()=>{let e=!1;return r(`/api/native-memory`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e||n(t)}).catch(t=>{e||d(String(t?.message||t))}),()=>{e=!0}},[]);let v=e=>{_(!0),h({name:e,content:``}),r(`/api/native-memory/file?name=${encodeURIComponent(e)}`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>h({name:e,content:t.content??``})).catch(()=>h({name:e,content:`(could not load file)`})).finally(()=>_(!1))};if(u)return(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--danger)`},children:[`Could not load native memory: `,u]});if(!t)return(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Loading…`});if(!t.available)return(0,o.jsxs)(`div`,{className:`rounded-xl p-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`h3`,{className:`font-medium mb-2`,style:{color:`var(--text-secondary)`},children:`No native memory found`}),(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:[`Claude Code's native Auto Memory isn't present for this project (expected at`,(0,o.jsx)(`code`,{className:`px-1 mx-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`~/.claude/projects/<project>/memory/`}),`). It appears once Auto Memory has written notes. OpenWolf falls back to its own `,(0,o.jsx)(`code`,{children:`.wolf/`}),` memory.`]})]});let y=t.health,b=Date.now(),x=(t.files??[]).filter(e=>!f||e.name.toLowerCase().includes(f.toLowerCase())),S={color:`var(--text-secondary)`,padding:`0.5rem 0.75rem`,borderTop:`1px solid var(--border)`},C={color:`var(--text-muted)`,fontWeight:500,textAlign:`left`,padding:`0.5rem 0.75rem`};return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4 mb-4`,children:[(0,o.jsx)(c,{label:`Topic files`,value:String(y.topicFiles)}),(0,o.jsx)(c,{label:`In index`,value:`${y.indexedCount}`,accent:!0}),(0,o.jsx)(c,{label:`Not indexed`,value:String(y.orphanCount)}),(0,o.jsx)(c,{label:`Footprint`,value:s(y.footprintBytes)})]}),(y.indexCutoffExceeded||y.orphanCount>0||y.deadLinks.length>0)&&(0,o.jsxs)(`div`,{className:`rounded-xl px-4 py-3 mb-4 text-sm space-y-1`,style:{background:`var(--danger-subtle)`,border:`1px solid rgba(220,38,38,0.3)`,color:`var(--text-secondary)`},children:[y.indexCutoffExceeded&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[`MEMORY.md is `,y.indexLines,` lines`]}),` — only the first 200 load at session start; the rest is invisible until trimmed.`]}),y.orphanCount>0&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[y.orphanCount,` topic files aren't in the index`]}),` → they never surface on resume. They're still searchable via `,(0,o.jsx)(`code`,{children:`openwolf recall`}),` and below.`]}),y.deadLinks.length>0&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[y.deadLinks.length,` dead index link(s)`]}),`: `,y.deadLinks.slice(0,5).join(`, `),y.deadLinks.length>5?`…`:``]})]}),(0,o.jsx)(`input`,{type:`text`,placeholder:`Filter topic files…`,value:f,onChange:e=>p(e.target.value),className:`w-full mb-3 rounded-lg px-3 py-2 text-sm focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,o.jsx)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,o.jsx)(`div`,{className:`overflow-x-auto`,style:{maxHeight:460},children:(0,o.jsxs)(`table`,{className:`w-full text-sm`,style:{borderCollapse:`collapse`},children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{children:[(0,o.jsxs)(`th`,{style:C,children:[`Topic file (`,x.length,`)`]}),(0,o.jsx)(`th`,{style:C,children:`Index`}),(0,o.jsx)(`th`,{style:{...C,textAlign:`right`},children:`Size`}),(0,o.jsx)(`th`,{style:C,children:`Modified`})]})}),(0,o.jsx)(`tbody`,{children:x.map(e=>{let t=b-new Date(e.mtime).getTime()>l;return(0,o.jsxs)(`tr`,{style:{cursor:`pointer`},onClick:()=>v(e.name),children:[(0,o.jsx)(`td`,{style:{...S,color:`var(--text-primary)`},className:`font-mono`,children:e.name}),(0,o.jsx)(`td`,{style:S,children:e.indexed?(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--accent-subtle)`,color:`var(--accent)`},children:`indexed`}):(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--bg-base)`,color:`var(--text-faint)`},children:`orphan`})}),(0,o.jsx)(`td`,{style:{...S,textAlign:`right`},children:s(e.bytes)}),(0,o.jsxs)(`td`,{style:{...S,color:t?`var(--text-faint)`:`var(--text-muted)`},children:[i(e.mtime),t?` · stale`:``]})]},e.name)})})]})})}),m&&(0,o.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,style:{background:`rgba(0,0,0,0.5)`},onClick:()=>h(null),children:(0,o.jsxs)(`div`,{className:`rounded-xl w-full max-w-3xl max-h-[80vh] flex flex-col`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},onClick:e=>e.stopPropagation(),children:[(0,o.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2`,style:{borderBottom:`1px solid var(--border)`},children:[(0,o.jsx)(`span`,{className:`font-mono text-sm`,style:{color:`var(--text-primary)`},children:m.name}),(0,o.jsx)(`button`,{onClick:()=>h(null),className:`text-sm px-2 py-1 rounded`,style:{color:`var(--text-muted)`},children:`✕`})]}),(0,o.jsx)(`pre`,{className:`text-xs px-4 py-3 overflow-auto whitespace-pre-wrap`,style:{color:`var(--text-secondary)`},children:g?`Loading…`:m.content})]})}),(0,o.jsx)(`p`,{className:`text-xs mt-3`,style:{color:`var(--text-faint)`},children:`Read-only view of Claude Code's native Auto Memory. OpenWolf never writes here — Claude's own Auto Dream owns consolidation.`})]})}function p({data:e}){let[t,n]=(0,a.useState)(null),[i,l]=(0,a.useState)(null),u=e.project.root;(0,a.useEffect)(()=>{let e=!1;return r(`/api/native-memory/aggregate`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e||n(t.projects||[])}).catch(t=>{e||l(String(t?.message||t))}),()=>{e=!0}},[]);let d=e=>{r(`/api/switch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({root:e})}).then(e=>{e.ok&&location.reload()})};if(i)return(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--danger)`},children:[`Could not load projects: `,i]});if(!t)return(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Loading projects…`});let f=t.filter(e=>e.available&&e.health),p=[...t].sort((e,t)=>e.available===t.available?(t.health?.topicFiles??0)-(e.health?.topicFiles??0):e.available?-1:1),m=f.reduce((e,t)=>({topics:e.topics+t.health.topicFiles,orphans:e.orphans+t.health.orphanCount,footprint:e.footprint+t.health.footprintBytes}),{topics:0,orphans:0,footprint:0}),h={color:`var(--text-muted)`,fontWeight:500,textAlign:`left`,padding:`0.5rem 0.75rem`},g={color:`var(--text-secondary)`,padding:`0.5rem 0.75rem`,borderTop:`1px solid var(--border)`};return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4 mb-6`,children:[(0,o.jsx)(c,{label:`With native memory`,value:`${f.length}/${t.length}`}),(0,o.jsx)(c,{label:`Total topic files`,value:String(m.topics),accent:!0}),(0,o.jsx)(c,{label:`Total orphaned`,value:String(m.orphans)}),(0,o.jsx)(c,{label:`Total footprint`,value:s(m.footprint)})]}),(0,o.jsx)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,o.jsx)(`div`,{className:`overflow-x-auto`,children:(0,o.jsxs)(`table`,{className:`w-full text-sm`,style:{borderCollapse:`collapse`},children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{children:[(0,o.jsx)(`th`,{style:h,children:`Project`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Topic files`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Indexed`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Orphaned`}),(0,o.jsx)(`th`,{style:h,children:`MEMORY.md`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Footprint`}),(0,o.jsx)(`th`,{style:h})]})}),(0,o.jsx)(`tbody`,{children:p.map(e=>{let t=u&&e.root===u,n=e.health;return(0,o.jsxs)(`tr`,{style:{background:t?`var(--bg-surface-hover)`:`transparent`},children:[(0,o.jsxs)(`td`,{style:g,children:[(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{style:{color:`var(--text-primary)`,fontWeight:500},children:e.name}),t&&(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--accent)`,color:`#fff`},children:`current`}),!e.available&&(0,o.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:`no native memory`})]}),(0,o.jsx)(`div`,{className:`text-xs truncate`,style:{color:`var(--text-faint)`,maxWidth:320},title:e.root,children:e.root})]}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:n?`var(--text-primary)`:`var(--text-faint)`},children:n?n.topicFiles:`—`}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:`var(--accent)`},children:n?n.indexedCount:`—`}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:n&&n.orphanCount>0?`var(--text-primary)`:`var(--text-faint)`},children:n?n.orphanCount:`—`}),(0,o.jsxs)(`td`,{style:g,children:[n?n.indexCutoffExceeded?(0,o.jsxs)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--danger-subtle)`,color:`var(--danger)`},title:`Only the first 200 lines load at session start`,children:[n.indexLines,` lines · over cutoff`]}):(0,o.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-muted)`},children:[n.indexLines,` lines`]}):(0,o.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:`—`}),n&&n.deadLinks.length>0&&(0,o.jsxs)(`span`,{className:`text-xs ml-2`,style:{color:`var(--danger)`},title:n.deadLinks.slice(0,8).join(`, `),children:[n.deadLinks.length,` dead`]})]}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:`var(--text-muted)`},children:n?s(n.footprintBytes):`—`}),(0,o.jsx)(`td`,{style:g,children:!t&&e.available&&(0,o.jsx)(`button`,{onClick:()=>d(e.root),className:`text-xs px-2 py-1 rounded-md transition-colors`,style:{background:`var(--bg-base)`,border:`1px solid var(--border)`,color:`var(--text-secondary)`},children:`Open`})})]},e.root)})})]})})}),(0,o.jsx)(`p`,{className:`text-xs mt-3`,style:{color:`var(--text-faint)`},children:`Native Auto Memory health across all registered OpenWolf projects. "Open" switches the daemon to that project — then "This project" browses its files. Read-only.`})]})}export{d as NativeMemory};
|
|
1
|
+
import{a as e,c as t,r as n,t as r}from"./index-C74qneS9.js";import{i}from"./utils-BqE_aDxV.js";var a=t(e(),1),o=n();function s(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function c({label:e,value:t,accent:n}){return(0,o.jsxs)(`div`,{className:`rounded-xl p-5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:e}),(0,o.jsx)(`p`,{className:`text-2xl font-bold mt-1`,style:{color:n?`var(--accent)`:`var(--text-primary)`},children:t})]})}var l=2160*60*60*1e3;function u({scope:e,setScope:t}){return(0,o.jsx)(`div`,{className:`inline-flex rounded-lg mb-4 p-0.5`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[{id:`project`,label:`This project`},{id:`all`,label:`All projects`}].map(n=>(0,o.jsx)(`button`,{onClick:()=>t(n.id),className:`text-sm px-3 py-1.5 rounded-md transition-colors`,style:{background:e===n.id?`var(--accent)`:`transparent`,color:e===n.id?`#fff`:`var(--text-muted)`},children:n.label},n.id))})}function d({data:e}){let[t,n]=(0,a.useState)(`project`);return(0,o.jsxs)(`div`,{children:[(0,o.jsx)(u,{scope:t,setScope:n}),t===`project`?(0,o.jsx)(f,{data:e}):(0,o.jsx)(p,{data:e})]})}function f(e){let[t,n]=(0,a.useState)(null),[u,d]=(0,a.useState)(null),[f,p]=(0,a.useState)(``),[m,h]=(0,a.useState)(null),[g,_]=(0,a.useState)(!1);(0,a.useEffect)(()=>{let e=!1;return r(`/api/native-memory`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e||n(t)}).catch(t=>{e||d(String(t?.message||t))}),()=>{e=!0}},[]);let v=e=>{_(!0),h({name:e,content:``}),r(`/api/native-memory/file?name=${encodeURIComponent(e)}`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>h({name:e,content:t.content??``})).catch(()=>h({name:e,content:`(could not load file)`})).finally(()=>_(!1))};if(u)return(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--danger)`},children:[`Could not load native memory: `,u]});if(!t)return(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Loading…`});if(!t.available)return(0,o.jsxs)(`div`,{className:`rounded-xl p-6`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:[(0,o.jsx)(`h3`,{className:`font-medium mb-2`,style:{color:`var(--text-secondary)`},children:`No native memory found`}),(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:[`Claude Code's native Auto Memory isn't present for this project (expected at`,(0,o.jsx)(`code`,{className:`px-1 mx-1 rounded text-xs`,style:{background:`var(--bg-base)`},children:`~/.claude/projects/<project>/memory/`}),`). It appears once Auto Memory has written notes. OpenWolf falls back to its own `,(0,o.jsx)(`code`,{children:`.wolf/`}),` memory.`]})]});let y=t.health,b=Date.now(),x=(t.files??[]).filter(e=>!f||e.name.toLowerCase().includes(f.toLowerCase())),S={color:`var(--text-secondary)`,padding:`0.5rem 0.75rem`,borderTop:`1px solid var(--border)`},C={color:`var(--text-muted)`,fontWeight:500,textAlign:`left`,padding:`0.5rem 0.75rem`};return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4 mb-4`,children:[(0,o.jsx)(c,{label:`Topic files`,value:String(y.topicFiles)}),(0,o.jsx)(c,{label:`In index`,value:`${y.indexedCount}`,accent:!0}),(0,o.jsx)(c,{label:`Not indexed`,value:String(y.orphanCount)}),(0,o.jsx)(c,{label:`Footprint`,value:s(y.footprintBytes)})]}),(y.indexCutoffExceeded||y.orphanCount>0||y.deadLinks.length>0)&&(0,o.jsxs)(`div`,{className:`rounded-xl px-4 py-3 mb-4 text-sm space-y-1`,style:{background:`var(--danger-subtle)`,border:`1px solid rgba(220,38,38,0.3)`,color:`var(--text-secondary)`},children:[y.indexCutoffExceeded&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[`MEMORY.md is `,y.indexLines,` lines`]}),` — only the first 200 load at session start; the rest is invisible until trimmed.`]}),y.orphanCount>0&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[y.orphanCount,` topic files aren't in the index`]}),` → they never surface on resume. They're still searchable via `,(0,o.jsx)(`code`,{children:`openwolf recall`}),` and below.`]}),y.deadLinks.length>0&&(0,o.jsxs)(`div`,{children:[`⚠ `,(0,o.jsxs)(`strong`,{children:[y.deadLinks.length,` dead index link(s)`]}),`: `,y.deadLinks.slice(0,5).join(`, `),y.deadLinks.length>5?`…`:``]})]}),(0,o.jsx)(`input`,{type:`text`,placeholder:`Filter topic files…`,value:f,onChange:e=>p(e.target.value),className:`w-full mb-3 rounded-lg px-3 py-2 text-sm focus:outline-none`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`,color:`var(--text-primary)`}}),(0,o.jsx)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,o.jsx)(`div`,{className:`overflow-x-auto`,style:{maxHeight:460},children:(0,o.jsxs)(`table`,{className:`w-full text-sm`,style:{borderCollapse:`collapse`},children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{children:[(0,o.jsxs)(`th`,{style:C,children:[`Topic file (`,x.length,`)`]}),(0,o.jsx)(`th`,{style:C,children:`Index`}),(0,o.jsx)(`th`,{style:{...C,textAlign:`right`},children:`Size`}),(0,o.jsx)(`th`,{style:C,children:`Modified`})]})}),(0,o.jsx)(`tbody`,{children:x.map(e=>{let t=b-new Date(e.mtime).getTime()>l;return(0,o.jsxs)(`tr`,{style:{cursor:`pointer`},onClick:()=>v(e.name),children:[(0,o.jsx)(`td`,{style:{...S,color:`var(--text-primary)`},className:`font-mono`,children:e.name}),(0,o.jsx)(`td`,{style:S,children:e.indexed?(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--accent-subtle)`,color:`var(--accent)`},children:`indexed`}):(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--bg-base)`,color:`var(--text-faint)`},children:`orphan`})}),(0,o.jsx)(`td`,{style:{...S,textAlign:`right`},children:s(e.bytes)}),(0,o.jsxs)(`td`,{style:{...S,color:t?`var(--text-faint)`:`var(--text-muted)`},children:[i(e.mtime),t?` · stale`:``]})]},e.name)})})]})})}),m&&(0,o.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,style:{background:`rgba(0,0,0,0.5)`},onClick:()=>h(null),children:(0,o.jsxs)(`div`,{className:`rounded-xl w-full max-w-3xl max-h-[80vh] flex flex-col`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},onClick:e=>e.stopPropagation(),children:[(0,o.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2`,style:{borderBottom:`1px solid var(--border)`},children:[(0,o.jsx)(`span`,{className:`font-mono text-sm`,style:{color:`var(--text-primary)`},children:m.name}),(0,o.jsx)(`button`,{onClick:()=>h(null),className:`text-sm px-2 py-1 rounded`,style:{color:`var(--text-muted)`},children:`✕`})]}),(0,o.jsx)(`pre`,{className:`text-xs px-4 py-3 overflow-auto whitespace-pre-wrap`,style:{color:`var(--text-secondary)`},children:g?`Loading…`:m.content})]})}),(0,o.jsx)(`p`,{className:`text-xs mt-3`,style:{color:`var(--text-faint)`},children:`Read-only view of Claude Code's native Auto Memory. OpenWolf never writes here — Claude's own Auto Dream owns consolidation.`})]})}function p({data:e}){let[t,n]=(0,a.useState)(null),[i,l]=(0,a.useState)(null),u=e.project.root;(0,a.useEffect)(()=>{let e=!1;return r(`/api/native-memory/aggregate`).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e||n(t.projects||[])}).catch(t=>{e||l(String(t?.message||t))}),()=>{e=!0}},[]);let d=e=>{r(`/api/switch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({root:e})}).then(e=>{e.ok&&location.reload()})};if(i)return(0,o.jsxs)(`p`,{className:`text-sm`,style:{color:`var(--danger)`},children:[`Could not load projects: `,i]});if(!t)return(0,o.jsx)(`p`,{className:`text-sm`,style:{color:`var(--text-muted)`},children:`Loading projects…`});let f=t.filter(e=>e.available&&e.health),p=[...t].sort((e,t)=>e.available===t.available?(t.health?.topicFiles??0)-(e.health?.topicFiles??0):e.available?-1:1),m=f.reduce((e,t)=>({topics:e.topics+t.health.topicFiles,orphans:e.orphans+t.health.orphanCount,footprint:e.footprint+t.health.footprintBytes}),{topics:0,orphans:0,footprint:0}),h={color:`var(--text-muted)`,fontWeight:500,textAlign:`left`,padding:`0.5rem 0.75rem`},g={color:`var(--text-secondary)`,padding:`0.5rem 0.75rem`,borderTop:`1px solid var(--border)`};return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4 mb-6`,children:[(0,o.jsx)(c,{label:`With native memory`,value:`${f.length}/${t.length}`}),(0,o.jsx)(c,{label:`Total topic files`,value:String(m.topics),accent:!0}),(0,o.jsx)(c,{label:`Total orphaned`,value:String(m.orphans)}),(0,o.jsx)(c,{label:`Total footprint`,value:s(m.footprint)})]}),(0,o.jsx)(`div`,{className:`rounded-xl overflow-hidden`,style:{background:`var(--bg-surface)`,border:`1px solid var(--border)`},children:(0,o.jsx)(`div`,{className:`overflow-x-auto`,children:(0,o.jsxs)(`table`,{className:`w-full text-sm`,style:{borderCollapse:`collapse`},children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{children:[(0,o.jsx)(`th`,{style:h,children:`Project`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Topic files`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Indexed`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Orphaned`}),(0,o.jsx)(`th`,{style:h,children:`MEMORY.md`}),(0,o.jsx)(`th`,{style:{...h,textAlign:`right`},children:`Footprint`}),(0,o.jsx)(`th`,{style:h})]})}),(0,o.jsx)(`tbody`,{children:p.map(e=>{let t=u&&e.root===u,n=e.health;return(0,o.jsxs)(`tr`,{style:{background:t?`var(--bg-surface-hover)`:`transparent`},children:[(0,o.jsxs)(`td`,{style:g,children:[(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{style:{color:`var(--text-primary)`,fontWeight:500},children:e.name}),t&&(0,o.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--accent)`,color:`#fff`},children:`current`}),!e.available&&(0,o.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:`no native memory`})]}),(0,o.jsx)(`div`,{className:`text-xs truncate`,style:{color:`var(--text-faint)`,maxWidth:320},title:e.root,children:e.root})]}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:n?`var(--text-primary)`:`var(--text-faint)`},children:n?n.topicFiles:`—`}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:`var(--accent)`},children:n?n.indexedCount:`—`}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:n&&n.orphanCount>0?`var(--text-primary)`:`var(--text-faint)`},children:n?n.orphanCount:`—`}),(0,o.jsxs)(`td`,{style:g,children:[n?n.indexCutoffExceeded?(0,o.jsxs)(`span`,{className:`text-xs px-1.5 py-0.5 rounded`,style:{background:`var(--danger-subtle)`,color:`var(--danger)`},title:`Only the first 200 lines load at session start`,children:[n.indexLines,` lines · over cutoff`]}):(0,o.jsxs)(`span`,{className:`text-xs`,style:{color:`var(--text-muted)`},children:[n.indexLines,` lines`]}):(0,o.jsx)(`span`,{className:`text-xs`,style:{color:`var(--text-faint)`},children:`—`}),n&&n.deadLinks.length>0&&(0,o.jsxs)(`span`,{className:`text-xs ml-2`,style:{color:`var(--danger)`},title:n.deadLinks.slice(0,8).join(`, `),children:[n.deadLinks.length,` dead`]})]}),(0,o.jsx)(`td`,{style:{...g,textAlign:`right`,color:`var(--text-muted)`},children:n?s(n.footprintBytes):`—`}),(0,o.jsx)(`td`,{style:g,children:!t&&e.available&&(0,o.jsx)(`button`,{onClick:()=>d(e.root),className:`text-xs px-2 py-1 rounded-md transition-colors`,style:{background:`var(--bg-base)`,border:`1px solid var(--border)`,color:`var(--text-secondary)`},children:`Open`})})]},e.root)})})]})})}),(0,o.jsx)(`p`,{className:`text-xs mt-3`,style:{color:`var(--text-faint)`},children:`Native Auto Memory health across all registered OpenWolf projects. "Open" switches the daemon to that project — then "This project" browses its files. Read-only.`})]})}export{d as NativeMemory};
|