@sandgarden/miranda 0.1.82 → 0.1.86

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="9f7f592e18a1"
48
- RELEASE_TAG="collector-9f7f592e18a1"
47
+ BUILD_VERSION="dfe686cb61ce"
48
+ RELEASE_TAG="collector-dfe686cb61ce"
49
49
  RELEASE_REPO="sandgardenhq/plugins"
50
50
  ASSET_PREFIX="miranda-collector"
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"
51
+ CHECKSUM_DARWIN_ARM64="58b322fa26b3f2b7d2d6796d7f041b03916c78bc3fe34298157d812524697adb"
52
+ CHECKSUM_DARWIN_X64="2de39f78f59bf4fe2482e75ccd182d30e2881400a1d3d662bcb376e54a24e1af"
53
+ CHECKSUM_LINUX_X64="ee4f23586c6a96b86c3a1bcc98b37568c8de3e459cd1c1616096cbe3d8c30d37"
54
+ CHECKSUM_LINUX_ARM64="aa93bc71849dd295817d907f20865bdda1560145b46fbcc850b6b67293bc1a62"
55
+ CHECKSUM_WINDOWS_X64="e4024913af817202bc83e07fb3527ce6fb8ad75527c593e64c49118c11fa63ba"
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.82",
3
+ "version": "0.1.86",
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
 
@@ -44,7 +48,7 @@ they are consenting to.
44
48
  - `model_request`: the token counts already reported today
45
49
  - `tool_call`: tool name, argument names, repo-relative file path, and a shell command's first word only, plus the names of any wrappers a hook added to it before it ran (such as `rtk`)
46
50
  - `tool_result`: error flag, size, exit code and test counts, never the output
47
- - `project_facts`: manifest and instruction file names, sizes and hashes
51
+ - `project_facts`: manifest and instruction file names, sizes and hashes, and the MCP server names the repo's agent config files declare
48
52
  - `skill_invoked`: skill name and whether it came from a plugin, the project, or the user
49
53
  - `subagent_spawned`: subagent type, model override and whether it ran in the background, never its prompt
50
54
  - `plan_mode`: entering or leaving plan mode, never the plan
@@ -52,6 +56,7 @@ they are consenting to.
52
56
  - `vcs_event`: commit, push, PR create or merge, or rebase, with PR and issue numbers only, never a branch, message or remote
53
57
  - `hook_fired`: hook name, the first word of the hook's own command (such as `rtk`), and whether it blocked, never its arguments or output
54
58
  - `mcp_tool_call`: MCP server and tool name, never arguments or results
59
+ - `machine_facts`: the MCP server names the session's agent has configured on the machine, and whether each is on, never their commands, URLs, headers or env
55
60
 
56
61
  ## The instruction-file section
57
62
 
@@ -121,7 +126,7 @@ commitment the team has made, not a suggestion.
121
126
  → the deprecated `GLORIA_HOME` → `$XDG_CONFIG_HOME/sandgarden` →
122
127
  `~/.config/sandgarden`). `daemon status` always exits 0, so "not
123
128
  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
129
+ step 7, not as the enrolment test — the `config.json` check above is the
125
130
  one that has to work on every machine.
126
131
 
127
132
  ### 2. Propose and ask permission — once
@@ -137,7 +142,9 @@ yes/no. Cover only the actions actually needed, e.g.:
137
142
  - enrol this machine for usage tracking, if it is not already, saying what
138
143
  the collector reports (see "What the collector reports").
139
144
 
140
- If everything is already current, say so and skip to step 6. If the user
145
+ If everything is already current, say so and skip to step 6.
146
+ Registering the repository is not part of this yes/no — step 6 does it
147
+ without asking. If the user
141
148
  declines the file edits, stop — do not partially apply.
142
149
 
143
150
  ### 3. Write the doc
@@ -272,15 +279,98 @@ this machine's local session stores whether or not any agent plugin fires, so
272
279
  no further wiring is needed. See `USING-MIRANDA.md`'s "Codex, OpenCode, and
273
280
  Cursor" section for per-agent notes.
274
281
 
275
- ### 6. Report
282
+ ### 6. Register this repository as a project
283
+
284
+ Run this after step 5, whichever enrolment path ran — and also when steps 2–5
285
+ had nothing to do. Do it **without asking**: the developer is setting up
286
+ tracking for exactly this repository, and registering it is the only way its
287
+ spend stops landing in Unassigned. Use the `miranda` MCP tools only.
288
+
289
+ 1. **Read the remote.** At the repo root (`git rev-parse --show-toplevel`),
290
+ run:
291
+
292
+ ```sh
293
+ git remote get-url origin | sed -E 's#://[^/@]*@#://#'
294
+ ```
295
+
296
+ The `sed` drops any userinfo (`user:token@`) before the URL is printed: an
297
+ `https` remote can carry a credential, and it must never reach the
298
+ transcript, a tool argument or the report. Use `origin` and nothing else —
299
+ it is the only remote the collector reads. If this isn't a git repository,
300
+ or the command prints nothing on stdout (no `origin` remote — git's
301
+ `error: No such remote` goes to stderr), skip the rest of step 6 and say
302
+ why in the report (e.g. "this repository has no `origin` remote, so there
303
+ is no URL a project could match").
304
+
305
+ 2. **Normalize it** the way the server does, so the comparison means what
306
+ ingest means:
307
+ - scp-like SSH, `git@host:owner/repo.git` → `https://host/owner/repo`;
308
+ - `ssh://`, `git://` and `git+ssh://` URLs → `https://` on the same host
309
+ (port included) and path; `http://` and `https://` keep their scheme;
310
+ - drop any userinfo left, then a trailing `.git` (and any `/` after it),
311
+ then any trailing `/`.
312
+
313
+ Change nothing else — not even letter case.
314
+
315
+ 3. **Look for a match.** Call `list_projects`, normalize each project's
316
+ `repoUrl` the same way (older rows can carry a trailing `/` or `.git`), and
317
+ compare exactly, case-sensitive — ingest matches the same way, so a
318
+ case-only difference is not a match. If a project matches, name the
319
+ existing project — its name and slug (all of them, if more than one
320
+ matches) — say spend from this repository is already attributed to it, and
321
+ register nothing.
322
+
323
+ 4. **Register when nothing matches.** Call `register_project` with
324
+ `{ "project": { "slug": …, "name": …, "repoUrl": <normalized URL> } }`:
325
+ - `name` — the repository name: the last path segment of the normalized
326
+ URL (`https://github.com/sandgardenhq/gloria.dev` → `gloria.dev`);
327
+ - `slug` — that name lowercased, every run of characters outside `a-z0-9`
328
+ replaced by `-`, leading and trailing `-` trimmed (`gloria-dev`).
329
+
330
+ `register_project` **upserts by slug**: sending a slug some other project
331
+ already has overwrites that project's name and repository. So if
332
+ `list_projects` already has the slug — whatever its `repoUrl`, set or not —
333
+ or the slug came out empty, use `<owner>-<repo>` built the same way
334
+ (`sandgardenhq-gloria-dev`). `<owner>` is the path segment before the
335
+ repository name (for `https://gitlab.com/group/sub/repo`, `sub`). If that is
336
+ taken too, append a number to it — `<owner>-<repo>-2`, `-3`, … — until it
337
+ is free. Slugs can't be changed later, so never guess past this rule.
338
+
339
+ 5. **Report what happened** in step 7, from the result's `project` and
340
+ `backfill`:
341
+ - the `slug` it registered under (and the name, when it isn't the same as
342
+ the slug);
343
+ - `backfill.status` `"ran"` with `sessionCount` above 0 — that many earlier
344
+ sessions moved from Unassigned onto the project, worth `spendMicros` ÷
345
+ 1,000,000 dollars (round to cents), the earliest from `earliestSessionAt`
346
+ (Unix seconds; show it as a date). When `unpriced` is true, some of that
347
+ spend has no price yet, so the dollar figure is a lower bound — say so;
348
+ - `"ran"` with `sessionCount` 0 — there was no earlier Unassigned spend
349
+ from this repository to move;
350
+ - `"failed"` — the project is saved, but its earlier spend didn't move;
351
+ sessions from now on are attributed to it;
352
+ - `"skipped"` — nothing moved;
353
+ - in every case, spend from more than 80 days before today stays in
354
+ Unassigned.
355
+
356
+ If `list_projects` or `register_project` fails with a transient error (a
357
+ dropped connection, a timeout), retry it once. If it still fails, or the
358
+ `miranda` MCP server isn't connected, or the call returns an error — say so,
359
+ with the error, and carry on to the report. It doesn't undo the file edits or the enrolment.
360
+
361
+ ### 7. Report
276
362
 
277
363
  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`.
364
+ usage tracking configured or already present, the project registered or
365
+ matched — or why the step was skipped — with what step 6 moved) and suggest
366
+ committing the changes, e.g. `chore: wire miranda agent doc into instruction
367
+ files`.
280
368
 
281
369
  ## Idempotency rules
282
370
 
283
371
  - Re-running with identical content is a no-op; say "already current".
372
+ - Re-running in a repository that is already a project registers nothing:
373
+ step 6 finds the match and names it.
284
374
  - Marker blocks are always replaced in place, never duplicated. If a file
285
375
  somehow contains multiple marker blocks, replace the first and remove the
286
376
  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