@sporhq/spor 0.2.2 → 0.2.3

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.
@@ -2,6 +2,6 @@
2
2
  "name": "spor",
3
3
  "displayName": "Spor Context Compiler",
4
4
  "description": "Maintains a typed, versioned knowledge graph and compiles compact briefings from it: session-start injection, per-prompt relevance digests, capture at discovery, end-of-session distillation, decision queue.",
5
- "version": "0.2.2",
5
+ "version": "0.2.3",
6
6
  "author": { "name": "losthammer" }
7
7
  }
package/README.md CHANGED
@@ -64,10 +64,13 @@ For the per-host event mapping, fidelity notes, distiller backend, and the
64
64
  `AGENTS.md` fallback for hosts with no hook support, see
65
65
  [adapters/](adapters/).
66
66
 
67
- To start with a populated graph, point the bundled `spor-backfill` agent at
68
- your existing sources: it mines git history, design docs, and issue trackers
69
- into a first graph. Or skip that and just work distillation grows the graph one session
70
- at a time.
67
+ To start with a populated graph, ask your agent to run the bundled
68
+ `spor-backfill` agent against your existing sources in Claude Code:
69
+ *"use the spor-backfill subagent to bootstrap a Spor graph for this repo."*
70
+ It is a **subagent** (invoked through the Task tool, not a `/spor:` slash
71
+ command), so it runs in its own context, mining git history, design docs, and
72
+ issue trackers into a first graph. Or skip that and just work — distillation
73
+ grows the graph one session at a time.
71
74
 
72
75
  ## What your agent gets, and gives back
73
76
 
@@ -88,7 +91,9 @@ The loop runs without you having to drive it:
88
91
  You can also ask for any of this directly: an on-demand briefing for a task,
89
92
  a correction when a briefing was wrong, a capture of work you're deferring,
90
93
  and a ranked queue of what to do next. In Claude Code these surface as
91
- `/spor:brief`, `/spor:correct`, `/spor:defer`, and `/spor:next`.
94
+ `/spor:brief`, `/spor:correct`, `/spor:defer`, and `/spor:next`. (Graph
95
+ bootstrapping is separate: `spor-backfill` is a *subagent* you invoke by
96
+ asking your agent to use it — it does not appear in the `/spor:` slash menu.)
92
97
 
93
98
  Corrections are durable. When a briefing includes something stale or misses
94
99
  something it should have known, you record the correction once, and every
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sporhq/spor",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Spor — a shared memory substrate for teams and agents. Decisions, their reasons, and the traces they leave. Knowledge-graph context compiler: session-start briefings, per-prompt digests, capture at discovery, end-of-session distillation, decision queue.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Anthony Allen",
@@ -61,6 +61,25 @@ function nodeBody(raw) {
61
61
  return u.stripTrailingNewlines(u.byteHead(awkOut, 7000));
62
62
  }
63
63
 
64
+ // Durable repo-identity node text (issue-spor-onboard-no-repo-identity-node),
65
+ // mirroring the server's learnFingerprints registration so local and remote
66
+ // produce the same shape. Ungrouped by default — no grouped-under edge; the
67
+ // standing grouping suggester proposes the single home project.
68
+ function repoNodeMarkdown(slug, fp, today) {
69
+ return `---
70
+ id: repo-${slug}
71
+ type: repo
72
+ title: ${slug}
73
+ summary: Git-repo identity for '${slug}', auto-registered from its fingerprints when the repo first appeared in the local graph. Ungrouped — no home project yet; the grouping suggester proposes a grouped-under home.
74
+ slugs: [${slug}]
75
+ fingerprints: [${fp.join(", ")}]
76
+ date: ${today}
77
+ ---
78
+
79
+ Auto-registered repo identity for \`${slug}\` (issue-spor-onboard-no-repo-identity-node). Created on first sight so the repo is a first-class node: the anchor for rename-healing fingerprint matching and for a \`grouped-under\` home. It starts UNGROUPED by default — repo-scoped reads work on the slug, and the standing grouping suggester proposes its single home project for confirmation. Slug aliases and fingerprints accumulate here across renames and re-clones.
80
+ `;
81
+ }
82
+
64
83
  async function sessionStart(input) {
65
84
  const graph = u.graphHome();
66
85
  const nodes = path.join(graph, "nodes");
@@ -412,6 +431,26 @@ ${pbody}`;
412
431
  /* fail open */
413
432
  }
414
433
 
434
+ // Ensure this repo has a durable identity node once it actually has content
435
+ // in the graph (issue-spor-onboard-no-repo-identity-node). Mirrors the
436
+ // server's learnFingerprints in remote mode: a backfilled/distilled repo with
437
+ // no `type: repo` node yet gets one registered from its git fingerprints, so
438
+ // it is a first-class node — the anchor for a grouped-under home and for
439
+ // rename-healing. Gated on projCount>0 (real graph content), no owning repo
440
+ // node yet, and fingerprints present, so a session in some unrelated checkout
441
+ // never spawns an identity node. Ungrouped by default; the grouping suggester
442
+ // proposes the home. Pure side effect, written AFTER the briefing is built so
443
+ // it never alters this run's output; fail-open — never blocks session-start.
444
+ try {
445
+ const fp = cwd && fs.existsSync(cwd) ? u.repoFingerprints(cwd) : [];
446
+ const repoFile = path.join(nodes, `repo-${slug}.md`);
447
+ if (!owner && projCount > 0 && fp.length && /^[a-z0-9][a-z0-9-]*$/.test(slug) && !fs.existsSync(repoFile)) {
448
+ fs.writeFileSync(repoFile, repoNodeMarkdown(slug, fp, new Date().toISOString().slice(0, 10)));
449
+ }
450
+ } catch {
451
+ /* best effort — never block session-start */
452
+ }
453
+
415
454
  return envelope(ctx);
416
455
  }
417
456