@spfunctions/cli 1.1.7 → 1.1.8

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/dist/client.d.ts CHANGED
@@ -18,6 +18,7 @@ export declare class SFClient {
18
18
  injectSignal(id: string, type: string, content: string, source?: string): Promise<any>;
19
19
  evaluate(id: string): Promise<any>;
20
20
  getFeed(hours?: number, limit?: number): Promise<any>;
21
+ getChanges(id: string, since: string): Promise<any>;
21
22
  updateThesis(id: string, data: Record<string, unknown>): Promise<any>;
22
23
  publish(id: string, slug: string, description?: string): Promise<any>;
23
24
  unpublish(id: string): Promise<any>;
package/dist/client.js CHANGED
@@ -65,6 +65,9 @@ class SFClient {
65
65
  async getFeed(hours = 24, limit = 200) {
66
66
  return this.request('GET', `/api/feed?hours=${hours}&limit=${limit}`);
67
67
  }
68
+ async getChanges(id, since) {
69
+ return this.request('GET', `/api/thesis/${id}/changes?since=${encodeURIComponent(since)}`);
70
+ }
68
71
  async updateThesis(id, data) {
69
72
  return this.request('PATCH', `/api/thesis/${id}`, data);
70
73
  }
@@ -433,6 +433,13 @@ async function agentCommand(thesisId, opts) {
433
433
  let isProcessing = false;
434
434
  // Cache for positions (fetched by /pos or get_positions tool)
435
435
  let cachedPositions = null;
436
+ // ── Heartbeat polling state ───────────────────────────────────────────────
437
+ // Background poll delta endpoint every 60s.
438
+ // If confidence changed ≥ 3%, auto-trigger agent analysis.
439
+ // If agent is busy (isProcessing), queue and deliver after agent finishes.
440
+ let lastPollTimestamp = new Date().toISOString();
441
+ let pendingHeartbeatDelta = null; // queued delta when agent is busy
442
+ let heartbeatPollTimer = null;
436
443
  // ── Inline confirmation mechanism ─────────────────────────────────────────
437
444
  // Tools can call promptUser() during execution to ask the user a question.
438
445
  // This temporarily unlocks the editor, waits for input, then resumes.
@@ -1328,6 +1335,12 @@ ${ctx.lastEvaluation?.summary ? `Latest evaluation summary: ${ctx.lastEvaluation
1328
1335
  isProcessing = false;
1329
1336
  persistSession();
1330
1337
  flushRender();
1338
+ // Deliver queued heartbeat notification if any
1339
+ if (pendingHeartbeatDelta) {
1340
+ const delta = pendingHeartbeatDelta;
1341
+ pendingHeartbeatDelta = null;
1342
+ handleHeartbeatDelta(delta);
1343
+ }
1331
1344
  }
1332
1345
  if (event.type === 'tool_execution_start') {
1333
1346
  const toolLine = new MutableLine(C.zinc600(` \u26A1 ${event.toolName}...`));
@@ -1865,6 +1878,8 @@ Output a structured summary. Be concise but preserve every important detail —
1865
1878
  };
1866
1879
  // ── Ctrl+C handler ─────────────────────────────────────────────────────────
1867
1880
  function cleanup() {
1881
+ if (heartbeatPollTimer)
1882
+ clearInterval(heartbeatPollTimer);
1868
1883
  if (currentLoader)
1869
1884
  currentLoader.stop();
1870
1885
  persistSession();
@@ -1949,6 +1964,59 @@ Output a structured summary. Be concise but preserve every important detail —
1949
1964
  addSystemText(buildWelcomeDashboard(latestContext, initialPositions));
1950
1965
  addSystemText(' ' + sessionStatus);
1951
1966
  addSpacer();
1967
+ // ── Heartbeat delta handler ───────────────────────────────────────────────
1968
+ const HEARTBEAT_CONFIDENCE_THRESHOLD = 0.03; // 3%
1969
+ function handleHeartbeatDelta(delta) {
1970
+ const absDelta = Math.abs(delta.confidenceDelta || 0);
1971
+ const confPct = Math.round((delta.confidence || 0) * 100);
1972
+ const deltaPct = Math.round((delta.confidenceDelta || 0) * 100);
1973
+ const sign = deltaPct > 0 ? '+' : '';
1974
+ if (absDelta >= HEARTBEAT_CONFIDENCE_THRESHOLD) {
1975
+ // Big change → auto-trigger agent analysis
1976
+ const arrow = deltaPct > 0 ? '\u25B2' : '\u25BC';
1977
+ const color = deltaPct > 0 ? C.emerald : C.red;
1978
+ addSystemText(color(` ${arrow} Heartbeat: confidence ${sign}${deltaPct}% → ${confPct}%`));
1979
+ if (delta.latestSummary) {
1980
+ addSystemText(C.zinc400(` ${delta.latestSummary.slice(0, 100)}`));
1981
+ }
1982
+ addSpacer();
1983
+ // Update header
1984
+ headerBar.setFromContext({ ...latestContext, confidence: delta.confidence, lastEvaluation: { confidenceDelta: delta.confidenceDelta } }, initialPositions || undefined);
1985
+ tui.requestRender();
1986
+ // Auto-trigger agent
1987
+ isProcessing = true;
1988
+ const prompt = `[HEARTBEAT ALERT] Confidence just changed ${sign}${deltaPct}% to ${confPct}%. ${delta.evaluationCount} evaluation(s) since last check. Latest: "${(delta.latestSummary || '').slice(0, 150)}". Briefly analyze what happened and whether any action is needed. Be concise.`;
1989
+ agent.prompt(prompt).catch((err) => {
1990
+ addSystemText(C.red(`Error: ${err.message}`));
1991
+ isProcessing = false;
1992
+ });
1993
+ }
1994
+ else if (absDelta > 0) {
1995
+ // Small change → silent notification line only
1996
+ addSystemText(C.zinc600(` \u2500 heartbeat: ${confPct}% (${sign}${deltaPct}%) \u2014 ${delta.evaluationCount || 0} eval(s)`));
1997
+ tui.requestRender();
1998
+ }
1999
+ // absDelta === 0: truly nothing changed, stay silent
2000
+ }
2001
+ // ── Start heartbeat polling ───────────────────────────────────────────────
2002
+ heartbeatPollTimer = setInterval(async () => {
2003
+ try {
2004
+ const delta = await sfClient.getChanges(resolvedThesisId, lastPollTimestamp);
2005
+ lastPollTimestamp = new Date().toISOString();
2006
+ if (!delta.changed)
2007
+ return;
2008
+ if (isProcessing || pendingPrompt) {
2009
+ // Agent is busy — queue for delivery after agent_end
2010
+ pendingHeartbeatDelta = delta;
2011
+ }
2012
+ else {
2013
+ handleHeartbeatDelta(delta);
2014
+ }
2015
+ }
2016
+ catch {
2017
+ // Silent — don't spam errors from background polling
2018
+ }
2019
+ }, 60_000); // every 60 seconds
1952
2020
  // ── Start TUI ──────────────────────────────────────────────────────────────
1953
2021
  tui.start();
1954
2022
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfunctions/cli",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "Prediction market intelligence CLI. Causal thesis model, 24/7 Kalshi/Polymarket scan, live orderbook, edge detection. Interactive agent mode with tool calling.",
5
5
  "bin": {
6
6
  "sf": "./dist/index.js"