@sandgarden/miranda 0.1.78 → 0.1.83

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/collector/stub.sh CHANGED
@@ -44,15 +44,15 @@
44
44
  # now downloads the same release from "sandgardenhq/plugins" with the
45
45
  # "miranda-collector" prefix (#813). They stay placeholders rather than
46
46
  # literals so the release host can move without editing this file.
47
- BUILD_VERSION="ccf32d7de6c3"
48
- RELEASE_TAG="collector-ccf32d7de6c3"
47
+ BUILD_VERSION="9f7f592e18a1"
48
+ RELEASE_TAG="collector-9f7f592e18a1"
49
49
  RELEASE_REPO="sandgardenhq/plugins"
50
50
  ASSET_PREFIX="miranda-collector"
51
- CHECKSUM_DARWIN_ARM64="9176bcad18eb27dc31b2e9e78302955d9ca27b7d06aa19ec0a2135fed607fd23"
52
- CHECKSUM_DARWIN_X64="b6ee1af736b79b90dfc7bd3815560ff010f5c1c55c1aad61805b5753cbefe7d4"
53
- CHECKSUM_LINUX_X64="ea812c0b651a6476d09a5b1c55f6ebb264468c8853bf537bb4450396e3294734"
54
- CHECKSUM_LINUX_ARM64="ec5191d750305b6415c1e1cddb5f97027d56bf4da3628ec854c3a847ba991cf9"
55
- CHECKSUM_WINDOWS_X64="5e3ddff729a8d36d4a5a6b25917783d8be037650a51869c402eea4d32d1093a5"
51
+ CHECKSUM_DARWIN_ARM64="bea2b552aa21695580ce1f9a0718de064475260bdf830330b8047f0064c4e4b7"
52
+ CHECKSUM_DARWIN_X64="3fe706eb9d77306f33d6550d20b7bb39a343349f64ad2b7476554111f3eb0415"
53
+ CHECKSUM_LINUX_X64="a43d87711cae9c43462b1297d6780126cc792710ab056fed80959f43c5679724"
54
+ CHECKSUM_LINUX_ARM64="e4824ceb3d4c937ef364f110835aeba6a533a17c90f46e262fea7dbb044c0729"
55
+ CHECKSUM_WINDOWS_X64="e2d6b01fed9f350aeedab3a60840f07b7cbe4b596e0327687fa664339a99238c"
56
56
 
57
57
  # A download lock older than this is a downloader that died mid-run: take it
58
58
  # over (mirrors the collector's sweep-lock staleness cutoff).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandgarden/miranda",
3
- "version": "0.1.78",
3
+ "version": "0.1.83",
4
4
  "type": "module",
5
5
  "description": "Miranda OpenCode plugin — token-usage tracking skill + the gloria.dev MCP server's scoped /miranda tools.",
6
6
  "main": "index.js",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: setting-up-usage-tracking
3
- description: Use when installing the Miranda plugin into a repo ("set up token tracking", "enable usage tracking", "install miranda"), when a repo is missing .miranda/USING-MIRANDA.md or the miranda section in CLAUDE.md/AGENTS.md, or after a Miranda plugin update to refresh a stale doc — copies the canonical USING-MIRANDA.md agent doc into the repo, wires an evergreen Miranda section into the agent instruction files (with the user's permission), and enrols this machine for usage collection. Idempotent; safe to re-run.
3
+ description: Use when installing the Miranda plugin into a repo ("set up token tracking", "enable usage tracking", "install miranda"), when a repo is missing .miranda/USING-MIRANDA.md or the miranda section in CLAUDE.md/AGENTS.md, or after a Miranda plugin update to refresh a stale doc — copies the canonical USING-MIRANDA.md agent doc into the repo, wires an evergreen Miranda section into the agent instruction files (with the user's permission), enrols this machine for usage collection, and registers the current repository as a Miranda project if it isn't one. Idempotent; safe to re-run.
4
4
  ---
5
5
 
6
6
  # Setting Up Usage Tracking
@@ -20,10 +20,14 @@ gets collected. Two files carry that:
20
20
  releases; only the doc does.
21
21
 
22
22
  Then, once those are wired, enrol this machine so the collector daemon the
23
- Miranda plugin installs actually starts reporting usage.
23
+ Miranda plugin installs actually starts reporting usage, and make sure this
24
+ repository is a Miranda project — the collector attributes a session to a
25
+ project only when the session's `origin` remote matches one, so an
26
+ unregistered repository's spend all lands in **Unassigned**.
24
27
 
25
28
  Never modify the user's files without showing them exactly what will change
26
- and getting a yes first.
29
+ and getting a yes first. Registering the repository writes no file, and is
30
+ done without asking (step 6).
27
31
 
28
32
  ## What the collector reports
29
33
 
@@ -121,7 +125,7 @@ commitment the team has made, not a suggestion.
121
125
  → the deprecated `GLORIA_HOME` → `$XDG_CONFIG_HOME/sandgarden` →
122
126
  `~/.config/sandgarden`). `daemon status` always exits 0, so "not
123
127
  enrolled" is not an error. Treat this as extra detail for the report in
124
- step 6, not as the enrolment test — the `config.json` check above is the
128
+ step 7, not as the enrolment test — the `config.json` check above is the
125
129
  one that has to work on every machine.
126
130
 
127
131
  ### 2. Propose and ask permission — once
@@ -137,7 +141,9 @@ yes/no. Cover only the actions actually needed, e.g.:
137
141
  - enrol this machine for usage tracking, if it is not already, saying what
138
142
  the collector reports (see "What the collector reports").
139
143
 
140
- If everything is already current, say so and skip to step 6. If the user
144
+ If everything is already current, say so and skip to step 6.
145
+ Registering the repository is not part of this yes/no — step 6 does it
146
+ without asking. If the user
141
147
  declines the file edits, stop — do not partially apply.
142
148
 
143
149
  ### 3. Write the doc
@@ -272,15 +278,98 @@ this machine's local session stores whether or not any agent plugin fires, so
272
278
  no further wiring is needed. See `USING-MIRANDA.md`'s "Codex, OpenCode, and
273
279
  Cursor" section for per-agent notes.
274
280
 
275
- ### 6. Report
281
+ ### 6. Register this repository as a project
282
+
283
+ Run this after step 5, whichever enrolment path ran — and also when steps 2–5
284
+ had nothing to do. Do it **without asking**: the developer is setting up
285
+ tracking for exactly this repository, and registering it is the only way its
286
+ spend stops landing in Unassigned. Use the `miranda` MCP tools only.
287
+
288
+ 1. **Read the remote.** At the repo root (`git rev-parse --show-toplevel`),
289
+ run:
290
+
291
+ ```sh
292
+ git remote get-url origin | sed -E 's#://[^/@]*@#://#'
293
+ ```
294
+
295
+ The `sed` drops any userinfo (`user:token@`) before the URL is printed: an
296
+ `https` remote can carry a credential, and it must never reach the
297
+ transcript, a tool argument or the report. Use `origin` and nothing else —
298
+ it is the only remote the collector reads. If this isn't a git repository,
299
+ or the command prints nothing on stdout (no `origin` remote — git's
300
+ `error: No such remote` goes to stderr), skip the rest of step 6 and say
301
+ why in the report (e.g. "this repository has no `origin` remote, so there
302
+ is no URL a project could match").
303
+
304
+ 2. **Normalize it** the way the server does, so the comparison means what
305
+ ingest means:
306
+ - scp-like SSH, `git@host:owner/repo.git` → `https://host/owner/repo`;
307
+ - `ssh://`, `git://` and `git+ssh://` URLs → `https://` on the same host
308
+ (port included) and path; `http://` and `https://` keep their scheme;
309
+ - drop any userinfo left, then a trailing `.git` (and any `/` after it),
310
+ then any trailing `/`.
311
+
312
+ Change nothing else — not even letter case.
313
+
314
+ 3. **Look for a match.** Call `list_projects`, normalize each project's
315
+ `repoUrl` the same way (older rows can carry a trailing `/` or `.git`), and
316
+ compare exactly, case-sensitive — ingest matches the same way, so a
317
+ case-only difference is not a match. If a project matches, name the
318
+ existing project — its name and slug (all of them, if more than one
319
+ matches) — say spend from this repository is already attributed to it, and
320
+ register nothing.
321
+
322
+ 4. **Register when nothing matches.** Call `register_project` with
323
+ `{ "project": { "slug": …, "name": …, "repoUrl": <normalized URL> } }`:
324
+ - `name` — the repository name: the last path segment of the normalized
325
+ URL (`https://github.com/sandgardenhq/gloria.dev` → `gloria.dev`);
326
+ - `slug` — that name lowercased, every run of characters outside `a-z0-9`
327
+ replaced by `-`, leading and trailing `-` trimmed (`gloria-dev`).
328
+
329
+ `register_project` **upserts by slug**: sending a slug some other project
330
+ already has overwrites that project's name and repository. So if
331
+ `list_projects` already has the slug — whatever its `repoUrl`, set or not —
332
+ or the slug came out empty, use `<owner>-<repo>` built the same way
333
+ (`sandgardenhq-gloria-dev`). `<owner>` is the path segment before the
334
+ repository name (for `https://gitlab.com/group/sub/repo`, `sub`). If that is
335
+ taken too, append a number to it — `<owner>-<repo>-2`, `-3`, … — until it
336
+ is free. Slugs can't be changed later, so never guess past this rule.
337
+
338
+ 5. **Report what happened** in step 7, from the result's `project` and
339
+ `backfill`:
340
+ - the `slug` it registered under (and the name, when it isn't the same as
341
+ the slug);
342
+ - `backfill.status` `"ran"` with `sessionCount` above 0 — that many earlier
343
+ sessions moved from Unassigned onto the project, worth `spendMicros` ÷
344
+ 1,000,000 dollars (round to cents), the earliest from `earliestSessionAt`
345
+ (Unix seconds; show it as a date). When `unpriced` is true, some of that
346
+ spend has no price yet, so the dollar figure is a lower bound — say so;
347
+ - `"ran"` with `sessionCount` 0 — there was no earlier Unassigned spend
348
+ from this repository to move;
349
+ - `"failed"` — the project is saved, but its earlier spend didn't move;
350
+ sessions from now on are attributed to it;
351
+ - `"skipped"` — nothing moved;
352
+ - in every case, spend from more than 80 days before today stays in
353
+ Unassigned.
354
+
355
+ If `list_projects` or `register_project` fails with a transient error (a
356
+ dropped connection, a timeout), retry it once. If it still fails, or the
357
+ `miranda` MCP server isn't connected, or the call returns an error — say so,
358
+ with the error, and carry on to the report. It doesn't undo the file edits or the enrolment.
359
+
360
+ ### 7. Report
276
361
 
277
362
  Summarize what changed (files created/updated, section inserted where,
278
- usage tracking configured or already present) and suggest committing the
279
- changes, e.g. `chore: wire miranda agent doc into instruction files`.
363
+ usage tracking configured or already present, the project registered or
364
+ matched — or why the step was skipped — with what step 6 moved) and suggest
365
+ committing the changes, e.g. `chore: wire miranda agent doc into instruction
366
+ files`.
280
367
 
281
368
  ## Idempotency rules
282
369
 
283
370
  - Re-running with identical content is a no-op; say "already current".
371
+ - Re-running in a repository that is already a project registers nothing:
372
+ step 6 finds the match and names it.
284
373
  - Marker blocks are always replaced in place, never duplicated. If a file
285
374
  somehow contains multiple marker blocks, replace the first and remove the
286
375
  rest, and mention it.
@@ -13,7 +13,8 @@ Miranda is available two ways, and both apply to you:
13
13
  `get_my_effectiveness`, `get_my_workflow`, `get_my_tracking_status`,
14
14
  `assign_my_session_work_item`, the managers-only `get_team_effectiveness`,
15
15
  plus the shared
16
- `get_info`/`register_project`/`put_project_github_info` — the same rows the
16
+ `get_info`/`list_projects`/`register_project`/`put_project_github_info` —
17
+ the same rows the
17
18
  `gloria` server exposes, since Miranda and gloria share one database).
18
19
  - **The usage-collector hooks** installed with the Miranda plugin (Claude
19
20
  Code, Codex, OpenCode) — they run automatically once the collector's
@@ -120,6 +121,28 @@ flight. The collector's `gloria-usage session` subcommand will answer that
120
121
  locally, with no round-trip, once it ships; until then, say the current
121
122
  session's cost isn't available yet rather than estimating it.
122
123
 
124
+ ## When this repository isn't a project
125
+
126
+ Miranda attributes a session to a project only when the session's `origin`
127
+ remote matches a registered project's `repoUrl`; everything else lands in
128
+ **Unassigned**, where no per-project or per-issue figure can see it. So when a
129
+ Miranda tool result shows this repository isn't a project — `list_projects`
130
+ has no project whose `repoUrl` matches this repository's `origin`, or
131
+ `get_my_tracking_status` or `get_my_spend` puts this repository's sessions in
132
+ Unassigned — register it, **without asking**. Registering is part of tracking
133
+ this repository, which the team has already adopted.
134
+
135
+ Follow the `setting-up-usage-tracking` skill's "Register this repository as a
136
+ project" step: read `origin` with
137
+ `git remote get-url origin | sed -E 's#://[^/@]*@#://#'` (the `sed` keeps a
138
+ token embedded in the remote out of the transcript), normalize it (SSH forms
139
+ to `https://`, no userinfo, no `.git` or trailing `/`), compare it against
140
+ every project's `repoUrl` normalized the same way, and when nothing matches, call `register_project` with the repository's name
141
+ and a slug no existing project has. Then tell the user the slug and what the
142
+ result's `backfill` moved out of Unassigned (sessions, dollars, earliest
143
+ session). Spend older than 80 days stays in Unassigned. No `origin` remote
144
+ means nothing to match — say so and move on.
145
+
123
146
  ## Setting up usage tracking
124
147
 
125
148
  The Miranda plugin ships hooks (Claude Code, Codex, OpenCode) that transmit
@@ -138,8 +161,13 @@ Reads need `inventory:read` (any member); writes need `inventory:write`.
138
161
 
139
162
  - `get_info` — org id/name/slug. Cheap; call it first when you need org
140
163
  context or to check the `miranda` MCP server is reachable.
164
+ - `list_projects` — every project in the org, with its `repoUrl`. How you
165
+ tell whether this repository is a project yet.
141
166
  - `register_project`, `put_project_github_info` — register this repo as a
142
- gloria.dev/Miranda project (the same rows either server writes).
167
+ gloria.dev/Miranda project (the same rows either server writes). Upserts by
168
+ slug, so never send a slug another project already has. When it gives a
169
+ project a `repoUrl`, its `backfill` reports the repository's earlier
170
+ Unassigned spend that moved onto it.
143
171
  - `tag_session_work_item` — declare the GitHub issue this session is working
144
172
  on (bare issue number, `gh:482`, or a full issue URL). Session-local — it
145
173
  writes only to this session's own transcript, never the database — the