@sporhq/spor 0.5.0 → 0.5.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.
@@ -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.5.0",
5
+ "version": "0.5.1",
6
6
  "author": { "name": "losthammer" }
7
7
  }
package/bin/spor.js CHANGED
@@ -450,6 +450,27 @@ async function cmdCompile(cfg, verb, args) {
450
450
  return passthrough("compile.js", compileArgs);
451
451
  }
452
452
 
453
+ // Compile a node's remote briefing the way the /spor:brief skill does: the raw
454
+ // node (GET /v1/nodes/<id>) plus a title/summary-seeded /v1/digest for its
455
+ // neighborhood, concatenated. Shared by compileRemote (brief / compile --root)
456
+ // and compileBriefing (dispatch) so the two can't drift — dispatch used to
457
+ // embed only the bare node, a thinner standing context than an interactive
458
+ // brief (issue-spor-dispatch-briefing-omits-neighborhood). Returns
459
+ // {transport,error} | {ok:false,status} | {ok:true,status,text}; the
460
+ // neighborhood is fail-soft (a failed/empty digest just yields the raw node).
461
+ async function remoteNodeBriefing(cfg, { root, project }) {
462
+ const r = await remote.get(cfg, `/v1/nodes/${encodeURIComponent(root)}`, { timeoutMs: 8000 });
463
+ if (r.transport) return { transport: true, error: r.error, text: "" };
464
+ if (!r.ok) return { ok: false, status: r.status, text: "" };
465
+ const raw = (r.json && r.json.raw) || r.text || "";
466
+ // Seed the neighborhood digest from the node's own title/summary (the REST
467
+ // /v1/digest is query-mode only — root compile is not exposed over REST).
468
+ const seed = (r.json && (r.json.title || r.json.summary)) || fmField(raw, "title") || fmField(raw, "summary") || root;
469
+ const d = await remote.post(cfg, "/v1/digest", project ? { query: seed, project } : { query: seed }, { timeoutMs: 8000 });
470
+ const neighborhood = d.ok && d.json && d.json.found !== false ? d.json.text || "" : "";
471
+ return { ok: true, status: r.status, text: neighborhood ? `${raw}\n\n${neighborhood}` : raw };
472
+ }
473
+
453
474
  // The remote arm of compile/brief. Mirrors the /spor:brief skill's remote
454
475
  // resolution: a node id -> the raw node plus a title/summary-seeded /v1/digest
455
476
  // for its neighborhood; free text -> POST /v1/digest. --skeleton has no server
@@ -475,27 +496,20 @@ async function compileRemote(cfg, args) {
475
496
 
476
497
  let text = "";
477
498
  if (root) {
478
- const r = await remote.get(cfg, `/v1/nodes/${encodeURIComponent(root)}`, { timeoutMs: 8000 });
479
- if (r.transport) {
480
- err(`offline — could not reach server (${r.error})`);
499
+ const b = await remoteNodeBriefing(cfg, { root, project });
500
+ if (b.transport) {
501
+ err(`offline — could not reach server (${b.error})`);
481
502
  return 1;
482
503
  }
483
- if (r.status === 404) {
504
+ if (b.status === 404) {
484
505
  err(`no such node: ${root}`);
485
506
  return 1;
486
507
  }
487
- if (!r.ok) {
488
- err(`error ${r.status}`);
508
+ if (!b.ok) {
509
+ err(`error ${b.status}`);
489
510
  return 1;
490
511
  }
491
- const raw = (r.json && r.json.raw) || r.text || "";
492
- // Seed the neighborhood digest from the node's own title/summary, exactly as
493
- // the /spor:brief skill does (the REST /v1/digest is query-mode only — root
494
- // compile is not exposed over REST, only via the query_graph MCP tool).
495
- const seed = (r.json && (r.json.title || r.json.summary)) || fmField(raw, "title") || fmField(raw, "summary") || root;
496
- const d = await remote.post(cfg, "/v1/digest", project ? { query: seed, project } : { query: seed }, { timeoutMs: 8000 });
497
- const neighborhood = d.ok && d.json && d.json.found !== false ? d.json.text || "" : "";
498
- text = neighborhood ? `${raw}\n\n${neighborhood}` : raw;
512
+ text = b.text;
499
513
  } else {
500
514
  const body = { query };
501
515
  if (project) body.project = project;
@@ -1535,8 +1549,11 @@ async function resolveNode(cfg, id) {
1535
1549
  async function compileBriefing(cfg, { nodeId, query, full, project }) {
1536
1550
  if (cfg.mode() === "remote") {
1537
1551
  if (nodeId) {
1538
- const r = await remote.get(cfg, `/v1/nodes/${encodeURIComponent(nodeId)}`, { timeoutMs: 8000 });
1539
- return r.ok && r.json ? r.json.raw || r.text || "" : "";
1552
+ // Same raw-node + seeded-neighborhood resolution as `spor brief <id>`, so
1553
+ // a dispatched agent's standing context matches an interactive brief
1554
+ // rather than the bare node (issue-spor-dispatch-briefing-omits-neighborhood).
1555
+ const b = await remoteNodeBriefing(cfg, { root: nodeId, project });
1556
+ return b.ok ? b.text : "";
1540
1557
  }
1541
1558
  const r = await remote.post(cfg, "/v1/digest", project ? { query, project } : { query });
1542
1559
  return r.ok && r.json && r.json.found !== false ? r.json.text || "" : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sporhq/spor",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
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",