@sporhq/spor 0.4.0 → 0.4.2
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/.claude-plugin/plugin.json +1 -1
- package/bin/spor.js +30 -18
- package/package.json +1 -1
- package/skills/brief/SKILL.md +15 -3
- package/skills/spor/SKILL.md +4 -0
|
@@ -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.4.
|
|
5
|
+
"version": "0.4.2",
|
|
6
6
|
"author": { "name": "losthammer" }
|
|
7
7
|
}
|
package/bin/spor.js
CHANGED
|
@@ -925,27 +925,39 @@ function claudePluginInfo() {
|
|
|
925
925
|
return p ? { version: p.version, scope: p.scope, enabled: p.enabled, installPath: p.installPath } : null;
|
|
926
926
|
}
|
|
927
927
|
|
|
928
|
-
// Best-effort: is a claude.ai Spor MCP connector bound on this box? A
|
|
929
|
-
// added in claude.ai surfaces in Claude Code as the mcp__…_Spor__*
|
|
930
|
-
// (art-cc-spor-connector-dual-host), i.e. a SECOND live write surface
|
|
931
|
-
// the local file graph.
|
|
932
|
-
//
|
|
933
|
-
//
|
|
934
|
-
//
|
|
935
|
-
//
|
|
936
|
-
//
|
|
937
|
-
//
|
|
938
|
-
//
|
|
939
|
-
//
|
|
928
|
+
// Best-effort: is a claude.ai Spor MCP connector CURRENTLY bound on this box? A
|
|
929
|
+
// connector added in claude.ai surfaces in Claude Code as the mcp__…_Spor__*
|
|
930
|
+
// tools (art-cc-spor-connector-dual-host), i.e. a SECOND live write surface
|
|
931
|
+
// alongside the local file graph. We read the LIVE set from `claude mcp list`
|
|
932
|
+
// (mirroring claudePluginInfo's spawn) and look for a Spor-named connector —
|
|
933
|
+
// matching the pre-rename "Substrate" name too. We deliberately do NOT key on
|
|
934
|
+
// ~/.claude.json's `claudeAiMcpEverConnected`: that array is a sticky historical
|
|
935
|
+
// "ever connected" list that never clears when a connector is disabled or
|
|
936
|
+
// removed, so it warned forever after the user unbound the connector
|
|
937
|
+
// (issue-spor-status-split-brain-warning-false-positive). FAIL-OPEN by contract:
|
|
938
|
+
// claude absent / nonzero exit / timeout / empty output all return false, so
|
|
939
|
+
// `spor status` never emits a false split-brain warning or hangs. The health
|
|
940
|
+
// status (Connected / Needs authentication / Failed) is ignored — any current
|
|
941
|
+
// binding is a configured second write surface. SPOR_FAKE_MCP_LIST injects
|
|
942
|
+
// canned `claude mcp list` output for tests.
|
|
940
943
|
function sporConnectorBound() {
|
|
941
944
|
try {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
945
|
+
let text = process.env.SPOR_FAKE_MCP_LIST;
|
|
946
|
+
if (text == null) {
|
|
947
|
+
const cmd = claudeCmd();
|
|
948
|
+
if (cmd === "claude" && !hasCmd("claude")) return false;
|
|
949
|
+
const r = spawnSync(cmd, ["mcp", "list"], { encoding: "utf8", timeout: 8000 });
|
|
950
|
+
if (r.status !== 0 || !r.stdout) return false;
|
|
951
|
+
text = r.stdout;
|
|
952
|
+
}
|
|
953
|
+
// Each connector is a line like "claude.ai Spor: <url> - <status>". Match the
|
|
954
|
+
// NAME segment (before the first colon) only, so a "spor" in a URL or status
|
|
955
|
+
// can't trip it; \b keeps "Spotify"/"Supabase" from matching "spor".
|
|
956
|
+
return text
|
|
957
|
+
.split("\n")
|
|
958
|
+
.some((line) => /\bspor\b|\bsubstrate\b/i.test(line.split(":")[0] || ""));
|
|
947
959
|
} catch {
|
|
948
|
-
return false; //
|
|
960
|
+
return false; // claude missing, spawn error, or unparseable => assume none
|
|
949
961
|
}
|
|
950
962
|
}
|
|
951
963
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sporhq/spor",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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",
|
package/skills/brief/SKILL.md
CHANGED
|
@@ -37,14 +37,26 @@ Steps:
|
|
|
37
37
|
**Local mode (personal graph) — `SPOR_SERVER` unset:** first resolve the
|
|
38
38
|
plugin root — `${CLAUDE_PLUGIN_ROOT}` is empty in the Bash tool, so read
|
|
39
39
|
the path the session-start hook cached
|
|
40
|
-
(issue-cc-skill-plugin-root-unsubstituted)
|
|
40
|
+
(issue-cc-skill-plugin-root-unsubstituted) — then resolve THIS repo's
|
|
41
|
+
project slug the same way a session does, so the compile is scoped to the
|
|
42
|
+
repo you're in instead of project-blind:
|
|
41
43
|
```bash
|
|
42
44
|
SPOR_ROOT="$(cat "${SPOR_HOME:-$HOME/.spor}/cache/plugin-root" 2>/dev/null \
|
|
43
45
|
|| cat "$HOME/.substrate/cache/plugin-root" 2>/dev/null)"
|
|
44
46
|
SPOR_ROOT="${SPOR_ROOT:-$CLAUDE_PLUGIN_ROOT}"
|
|
47
|
+
SLUG="$(node -e 'process.stdout.write(require("'"$SPOR_ROOT"'/scripts/engines/util.js").projectSlug(process.cwd()))' 2>/dev/null)"
|
|
45
48
|
```
|
|
46
|
-
- node id: `node "$SPOR_ROOT/lib/compile.js" --root <id> --skeleton`
|
|
47
|
-
- query: `node "$SPOR_ROOT/lib/compile.js" --query "<text>"`
|
|
49
|
+
- node id: `node "$SPOR_ROOT/lib/compile.js" --root <id> --skeleton ${SLUG:+--project "$SLUG"}`
|
|
50
|
+
- query: `node "$SPOR_ROOT/lib/compile.js" --query "<text>" ${SLUG:+--project "$SLUG"}`
|
|
51
|
+
|
|
52
|
+
**Always pass `--project "$SLUG"`.** Without it, `compile --root`/`--query`
|
|
53
|
+
run *project-blind* (`sessionProject == null`): the org-norm ride-along then
|
|
54
|
+
keeps every `always_on` norm and ignores `applies_to_repos`/`applies_to_tags`/
|
|
55
|
+
`applies_to_projects` scoping entirely — so an unscoped briefing shows norms a
|
|
56
|
+
real session in this repo would filter out (the `applies_to_*` selectors match
|
|
57
|
+
the SESSION repo, not the `--root` node's repo). `--project` makes the compile
|
|
58
|
+
match what session-start actually injects here.
|
|
59
|
+
|
|
48
60
|
(The compiler defaults to the global graph at `$SPOR_HOME/nodes`, falling
|
|
49
61
|
back to `~/.spor/nodes` — or a pre-existing `~/.substrate/nodes` when
|
|
50
62
|
`~/.spor` is absent.)
|
package/skills/spor/SKILL.md
CHANGED
|
@@ -100,6 +100,10 @@ mode dispatches to the server (mirroring `/spor:brief`). Much of this is what
|
|
|
100
100
|
the session hooks already inject for you automatically; pulling one on demand
|
|
101
101
|
with `spor brief`, `spor compile`, or `/spor:brief` is the same briefing.
|
|
102
102
|
Passing `--nodes <dir>` always targets that local checkout, even under a server.
|
|
103
|
+
In local mode, add `--project <repo-slug>` to scope to a repo: without it
|
|
104
|
+
`compile --root`/`--query` run *project-blind* and the `always_on` norm
|
|
105
|
+
ride-along ignores `applies_to_*` scoping (every norm rides along) — pass it to
|
|
106
|
+
match what a real session in that repo sees. `/spor:brief` does this for you.
|
|
103
107
|
|
|
104
108
|
**In Cowork (Anthropic's chat workspace) and Claude Code with the connector**
|
|
105
109
|
there is no shell and no ambient injection — reach the graph through the
|