@mulmoclaude/core 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -26,8 +26,10 @@ user opens it at `/collections/<slug>`). **Do not use the `mc-` prefix.**
|
|
|
26
26
|
> mimic other collections in the workspace. The whole point is a reproducible
|
|
27
27
|
> billing suite. (If the user wants a *custom* collection instead, that's a
|
|
28
28
|
> different task — use `config/helps/collection-skills.md`.) Existing records
|
|
29
|
-
> under `data/clients/items` / `data/worklog/items`
|
|
30
|
-
>
|
|
29
|
+
> under `data/clients/items` / `data/worklog/items` will render as-is **only
|
|
30
|
+
> when `worklog.clientId` values are already slugs AND a matching client
|
|
31
|
+
> record exists for each of them**. If either invariant is violated, the
|
|
32
|
+
> `ref` link breaks — the reconcile step below (§3) fixes both.
|
|
31
33
|
|
|
32
34
|
## Slug contract (do not change these)
|
|
33
35
|
|
|
@@ -206,10 +208,76 @@ If the user gives a clear "log N hours for X today", just write it. Use
|
|
|
206
208
|
|
|
207
209
|
---
|
|
208
210
|
|
|
211
|
+
## 3. Reconcile pre-existing worklog data (MANDATORY before "Done")
|
|
212
|
+
|
|
213
|
+
Both skills are now authored. Before telling the user setup is complete,
|
|
214
|
+
audit any records that were already on disk under `data/worklog/items/` —
|
|
215
|
+
they may have been written before the `clients` collection existed, so
|
|
216
|
+
`clientId` values can be either display names (`"Singularity Society"`) or
|
|
217
|
+
missing-slug references. Both break the `ref` link at render time.
|
|
218
|
+
|
|
219
|
+
Run this reconcile every time — even when the setup looks fine — because
|
|
220
|
+
"looks fine" from the LLM side (schemas written, files present) is
|
|
221
|
+
distinct from "the ref actually resolves" (clientId is a valid slug AND
|
|
222
|
+
`data/clients/items/<slug>.json` exists).
|
|
223
|
+
|
|
224
|
+
**Steps** (idempotent; safe to re-run):
|
|
225
|
+
|
|
226
|
+
1. **Inventory the existing worklog.** List `data/worklog/items/`. Read
|
|
227
|
+
every record and collect the distinct `clientId` values seen.
|
|
228
|
+
*Skip this step only when the directory does not exist at all.*
|
|
229
|
+
2. **For each distinct `clientId` value**, classify it:
|
|
230
|
+
- **valid slug + matching client file exists** → no action.
|
|
231
|
+
- **valid slug but no matching `data/clients/items/<slug>.json`** →
|
|
232
|
+
create a stub client record: `id: <slug>`, `name` derived by
|
|
233
|
+
title-casing the slug (`acme-corp` → "Acme Corp"), other fields blank
|
|
234
|
+
so the user can fill them in later.
|
|
235
|
+
- **not a valid slug** (contains uppercase, spaces, `&`, `.`, etc.) →
|
|
236
|
+
(a) generate the slug (lowercase, spaces → `-`, drop punctuation,
|
|
237
|
+
collapse repeat hyphens, strip leading/trailing hyphens); (b)
|
|
238
|
+
**validate the generated slug against the `clients.id` contract**
|
|
239
|
+
(see § 1 record shape: `[a-z0-9-]`, 1–48 chars): if it is empty
|
|
240
|
+
(punctuation-only or all-whitespace input like `"!!!"`), or longer
|
|
241
|
+
than 48 chars, **stop and ask the user** for a valid slug rather
|
|
242
|
+
than writing an invalid filename. If it is >48 chars but has
|
|
243
|
+
meaningful prefix content, propose truncation at 48 (dropping any
|
|
244
|
+
trailing hyphen) and confirm with the user before proceeding; (c)
|
|
245
|
+
**check for slug collisions BEFORE writing anything**: if
|
|
246
|
+
`data/clients/items/<slug>.json` already exists AND its `name`
|
|
247
|
+
field does not match the display value being reconciled, stop and
|
|
248
|
+
disambiguate — either append a numeric suffix (`acme-corp-2`)
|
|
249
|
+
after confirming the new client is genuinely distinct, or ask the
|
|
250
|
+
user which client the worklog entries belong to. Do **not**
|
|
251
|
+
silently overwrite an existing client. Also stop when two
|
|
252
|
+
different display values in the current inventory slugify to the
|
|
253
|
+
same slug (e.g. `"ACME Corp"` and `"Acme Corp."`); ask the user
|
|
254
|
+
whether they're the same client (merge to one slug) or distinct
|
|
255
|
+
(assign each a suffixed slug); (d) create
|
|
256
|
+
`data/clients/items/<slug>.json` with `id: <slug>`, `name:
|
|
257
|
+
<original display value>`, other fields blank; (e) rewrite the raw
|
|
258
|
+
display value inside every affected `data/worklog/items/*.json`
|
|
259
|
+
to the new slug in the `clientId` field (preserve every other
|
|
260
|
+
field untouched).
|
|
261
|
+
3. **Report** what changed: how many client records were created and how
|
|
262
|
+
many worklog `clientId` values were rewritten. Do not summarise the
|
|
263
|
+
raw records — point at `/collections/clients` and `/collections/worklog`.
|
|
264
|
+
|
|
265
|
+
If the worklog directory did not exist yet (fresh setup, no pre-existing
|
|
266
|
+
data), this step is a no-op and you can proceed straight to "Done".
|
|
267
|
+
|
|
268
|
+
**Don't skip this step because the LLM output says "existing records will
|
|
269
|
+
render as-is."** That claim only holds when both invariants (slug format
|
|
270
|
+
+ matching client file) are already true; the reconcile confirms them.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
209
274
|
## Done
|
|
210
275
|
|
|
211
276
|
Tell the user the two collections are ready at `/collections/clients` and
|
|
212
277
|
`/collections/worklog`. The bridge mirrors the files and re-scans, so they appear
|
|
213
|
-
without a restart. If
|
|
214
|
-
|
|
215
|
-
|
|
278
|
+
without a restart. If the reconcile in §3 created client stubs or rewrote
|
|
279
|
+
`clientId` values, mention the counts so the user knows to fill in the
|
|
280
|
+
stubs' contact info. If invoicing is the goal, point them at the next
|
|
281
|
+
step: run *"Set up invoicing for my business"* (the
|
|
282
|
+
`config/helps/billing-invoice.md` recipe, which references these
|
|
283
|
+
`clients` and pulls hours from this `worklog`).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mulmoclaude/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Shared server-side core for MulmoClaude and MulmoTerminal — the always-shipped-together subsystems consolidated behind subpath exports so the two hosts can't drift. Server-only except the browser-safe ./whisper/client, ./workspace-setup/slug, ./translation/client and ./remote-view entries. All host specifics are injected.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
},
|
|
150
150
|
"dependencies": {
|
|
151
151
|
"fast-xml-parser": "^5.9.3",
|
|
152
|
-
"js-yaml": "^5.2.
|
|
152
|
+
"js-yaml": "^5.2.1",
|
|
153
153
|
"zod": "^4.4.3"
|
|
154
154
|
},
|
|
155
155
|
"peerDependencies": {
|
|
@@ -160,9 +160,9 @@
|
|
|
160
160
|
"@receptron/task-scheduler": "*",
|
|
161
161
|
"@types/node": "^26.1.0",
|
|
162
162
|
"gui-chat-protocol": "^0.4.0",
|
|
163
|
-
"tsx": "^4.22.
|
|
163
|
+
"tsx": "^4.22.5",
|
|
164
164
|
"typescript": "^6.0.3",
|
|
165
|
-
"vite": "^8.1.
|
|
165
|
+
"vite": "^8.1.3",
|
|
166
166
|
"vite-plugin-dts": "^5.0.3"
|
|
167
167
|
},
|
|
168
168
|
"license": "MIT"
|