@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 +1 -0
- package/dist/client.js +3 -0
- package/dist/commands/agent.js +68 -0
- package/package.json +1 -1
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
|
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -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.
|
|
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"
|