@mirasoth/soothe-client 0.5.4 → 0.5.7
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/{chunk-B5FIL7O4.js → chunk-56Z7SUGW.js} +11 -14
- package/dist/chunk-56Z7SUGW.js.map +1 -0
- package/dist/client-CUYIRMFW.js +7 -0
- package/dist/index.cjs +174 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -24
- package/dist/index.d.ts +44 -24
- package/dist/index.js +160 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-B5FIL7O4.js.map +0 -1
- package/dist/client-BOND6P6S.js +0 -7
- /package/dist/{client-BOND6P6S.js.map → client-CUYIRMFW.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
subscribeEnvelope,
|
|
85
85
|
unsubscribeEnvelope,
|
|
86
86
|
validateLoopInputIntentHint
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-56Z7SUGW.js";
|
|
88
88
|
|
|
89
89
|
// src/session.ts
|
|
90
90
|
async function bootstrapLoopSession(client, resumeLoopId, config, loopNew) {
|
|
@@ -270,6 +270,10 @@ var CommandClient = class {
|
|
|
270
270
|
async autopilotGetJob(jobId) {
|
|
271
271
|
return this.request("autopilot_get_job", { job_id: jobId });
|
|
272
272
|
}
|
|
273
|
+
/** Jobs → goals → loops snapshot for CLI top. */
|
|
274
|
+
async autopilotTop(includeTerminal = false) {
|
|
275
|
+
return this.request("autopilot_top", { include_terminal: includeTerminal });
|
|
276
|
+
}
|
|
273
277
|
async cronAdd(text, priority = 0) {
|
|
274
278
|
const params = { text };
|
|
275
279
|
if (priority > 0) params.priority = priority;
|
|
@@ -287,7 +291,7 @@ async function checkDaemonStatus(client, timeout) {
|
|
|
287
291
|
return client.requestResponse("daemon_status", {}, "daemon_status", timeout ?? 5e3);
|
|
288
292
|
}
|
|
289
293
|
async function isDaemonLive(wsURL, timeout) {
|
|
290
|
-
const { Client: Client2 } = await import("./client-
|
|
294
|
+
const { Client: Client2 } = await import("./client-CUYIRMFW.js");
|
|
291
295
|
const t = timeout ?? 5e3;
|
|
292
296
|
const client = new Client2(wsURL, defaultConfig());
|
|
293
297
|
try {
|
|
@@ -361,9 +365,6 @@ async function refreshAuthToken(client, refreshToken, timeout) {
|
|
|
361
365
|
timeout ?? 15e3
|
|
362
366
|
);
|
|
363
367
|
}
|
|
364
|
-
async function fetchLoopCards(client, loopID, timeout) {
|
|
365
|
-
return client.fetchLoopCards(loopID, timeout);
|
|
366
|
-
}
|
|
367
368
|
async function fetchLoopMessages(client, loopID, opts) {
|
|
368
369
|
return client.getLoopMessages(
|
|
369
370
|
loopID,
|
|
@@ -374,7 +375,7 @@ async function fetchLoopMessages(client, loopID, opts) {
|
|
|
374
375
|
);
|
|
375
376
|
}
|
|
376
377
|
async function connectedWebsocket(wsUrl, fn, timeoutMs = 3e4) {
|
|
377
|
-
const { Client: Client2 } = await import("./client-
|
|
378
|
+
const { Client: Client2 } = await import("./client-CUYIRMFW.js");
|
|
378
379
|
const client = new Client2(wsUrl, defaultConfig());
|
|
379
380
|
const deadline = Date.now() + timeoutMs;
|
|
380
381
|
try {
|
|
@@ -431,6 +432,59 @@ async function protocol1Rpc(wsUrl, method, params = null, opts = {}) {
|
|
|
431
432
|
}
|
|
432
433
|
}
|
|
433
434
|
|
|
435
|
+
// src/turn_boundary.ts
|
|
436
|
+
function formatTurnId(loopId, generation) {
|
|
437
|
+
const lid = String(loopId || "").trim();
|
|
438
|
+
const gen = Number(generation);
|
|
439
|
+
if (!lid || !Number.isFinite(gen) || gen <= 0) return "";
|
|
440
|
+
return `${lid}:${Math.trunc(gen)}`;
|
|
441
|
+
}
|
|
442
|
+
function parseTurnGeneration(turnId) {
|
|
443
|
+
const raw = String(turnId || "").trim();
|
|
444
|
+
if (!raw || !raw.includes(":")) return null;
|
|
445
|
+
const suffix = raw.split(":").pop() ?? "";
|
|
446
|
+
const gen = Number.parseInt(suffix, 10);
|
|
447
|
+
return Number.isFinite(gen) && gen > 0 ? gen : null;
|
|
448
|
+
}
|
|
449
|
+
function frameTurnId(frame) {
|
|
450
|
+
if (!frame || typeof frame !== "object") return null;
|
|
451
|
+
const tid = frame.turn_id;
|
|
452
|
+
if (typeof tid === "string" && tid.trim()) return tid.trim();
|
|
453
|
+
const data = frame.data;
|
|
454
|
+
if (data && typeof data === "object") {
|
|
455
|
+
const inner = data.turn_id;
|
|
456
|
+
if (typeof inner === "string" && inner.trim()) return inner.trim();
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
function frameSeq(frame) {
|
|
461
|
+
if (!frame || typeof frame !== "object") return null;
|
|
462
|
+
const raw = frame.seq;
|
|
463
|
+
if (typeof raw === "boolean") return null;
|
|
464
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0 && Number.isInteger(raw)) {
|
|
465
|
+
return raw;
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
function turnIdsMatch(expected, candidate) {
|
|
470
|
+
const exp = String(expected || "").trim();
|
|
471
|
+
const cand = String(candidate || "").trim();
|
|
472
|
+
return Boolean(exp) && Boolean(cand) && exp === cand;
|
|
473
|
+
}
|
|
474
|
+
function isTurnTerminalAllowed(opts) {
|
|
475
|
+
if (!opts.queryStarted || !opts.turnProgressSeen) return false;
|
|
476
|
+
return turnIdsMatch(opts.expectedTurnId, opts.frameTurnId);
|
|
477
|
+
}
|
|
478
|
+
function isIdleTerminalAllowed(opts) {
|
|
479
|
+
if (!opts.queryStarted || !String(opts.expectedTurnId || "").trim()) return false;
|
|
480
|
+
const cand = String(opts.frameTurnId || "").trim();
|
|
481
|
+
if (cand) {
|
|
482
|
+
if (!turnIdsMatch(opts.expectedTurnId, cand)) return false;
|
|
483
|
+
return Boolean(opts.turnProgressSeen || opts.cancellationSeen);
|
|
484
|
+
}
|
|
485
|
+
return Boolean(opts.cancellationSeen);
|
|
486
|
+
}
|
|
487
|
+
|
|
434
488
|
// src/appkit/broadcaster.ts
|
|
435
489
|
var SUBSCRIBER_QUEUE_CAP = 100;
|
|
436
490
|
var SSEBroadcaster = class {
|
|
@@ -1387,8 +1441,9 @@ var TURN_END_IDLE = "status.idle";
|
|
|
1387
1441
|
var TURN_END_STOPPED = "status.stopped";
|
|
1388
1442
|
var TurnLifecycleGate = class {
|
|
1389
1443
|
sawRunning = false;
|
|
1390
|
-
sawStreamPayload = false;
|
|
1391
1444
|
sawTurnProgress = false;
|
|
1445
|
+
expectedTurnId = null;
|
|
1446
|
+
cancellationSeen = false;
|
|
1392
1447
|
observe(msg) {
|
|
1393
1448
|
const frame = normalizeFrame(msg);
|
|
1394
1449
|
if (!frame) return;
|
|
@@ -1396,22 +1451,43 @@ var TurnLifecycleGate = class {
|
|
|
1396
1451
|
if (typ === "status") {
|
|
1397
1452
|
if (String(frame.state ?? "").trim().toLowerCase() === "running") {
|
|
1398
1453
|
this.sawRunning = true;
|
|
1454
|
+
const statusTurn = frameTurnId(frame);
|
|
1455
|
+
if (statusTurn) {
|
|
1456
|
+
const newGen = parseTurnGeneration(statusTurn);
|
|
1457
|
+
const oldGen = parseTurnGeneration(this.expectedTurnId);
|
|
1458
|
+
if (this.expectedTurnId === null || newGen !== null && (oldGen === null || newGen >= oldGen)) {
|
|
1459
|
+
if (this.expectedTurnId && statusTurn !== this.expectedTurnId) {
|
|
1460
|
+
this.sawTurnProgress = false;
|
|
1461
|
+
}
|
|
1462
|
+
this.expectedTurnId = statusTurn;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1399
1465
|
}
|
|
1400
1466
|
return;
|
|
1401
1467
|
}
|
|
1402
1468
|
if (typ === "event") {
|
|
1403
|
-
this.sawStreamPayload = true;
|
|
1404
1469
|
const mode = String(frame.mode ?? "");
|
|
1405
1470
|
if (isTurnProgressChunk(mode, frame.data)) {
|
|
1406
1471
|
this.sawTurnProgress = true;
|
|
1407
1472
|
}
|
|
1408
1473
|
}
|
|
1409
1474
|
}
|
|
1410
|
-
allowStreamEnd() {
|
|
1411
|
-
return
|
|
1475
|
+
allowStreamEnd(frameTurn) {
|
|
1476
|
+
return isTurnTerminalAllowed({
|
|
1477
|
+
expectedTurnId: this.expectedTurnId,
|
|
1478
|
+
frameTurnId: frameTurn,
|
|
1479
|
+
queryStarted: this.sawRunning,
|
|
1480
|
+
turnProgressSeen: this.sawTurnProgress
|
|
1481
|
+
});
|
|
1412
1482
|
}
|
|
1413
|
-
allowIdleComplete() {
|
|
1414
|
-
return
|
|
1483
|
+
allowIdleComplete(frameTurn) {
|
|
1484
|
+
return isIdleTerminalAllowed({
|
|
1485
|
+
expectedTurnId: this.expectedTurnId,
|
|
1486
|
+
frameTurnId: frameTurn,
|
|
1487
|
+
queryStarted: this.sawRunning,
|
|
1488
|
+
turnProgressSeen: this.sawTurnProgress,
|
|
1489
|
+
cancellationSeen: this.cancellationSeen
|
|
1490
|
+
});
|
|
1415
1491
|
}
|
|
1416
1492
|
};
|
|
1417
1493
|
var TurnBoundary = class {
|
|
@@ -1426,17 +1502,23 @@ var TurnBoundary = class {
|
|
|
1426
1502
|
const typ = String(frame.type ?? "");
|
|
1427
1503
|
if (typ === "status") {
|
|
1428
1504
|
const state = String(frame.state ?? "").trim().toLowerCase();
|
|
1505
|
+
const frameTurn = frameTurnId(frame);
|
|
1429
1506
|
if (state === "stopped" && this.gate.sawRunning) {
|
|
1507
|
+
if (this.gate.expectedTurnId && !turnIdsMatch(this.gate.expectedTurnId, frameTurn)) {
|
|
1508
|
+
return [false, ""];
|
|
1509
|
+
}
|
|
1430
1510
|
return this.mark(TURN_END_STOPPED);
|
|
1431
1511
|
}
|
|
1432
|
-
if (state === "idle" && this.gate.allowIdleComplete()) {
|
|
1512
|
+
if (state === "idle" && this.gate.allowIdleComplete(frameTurn)) {
|
|
1433
1513
|
return this.mark(TURN_END_IDLE);
|
|
1434
1514
|
}
|
|
1435
1515
|
return [false, ""];
|
|
1436
1516
|
}
|
|
1437
1517
|
if (typ === "event") {
|
|
1438
1518
|
const mode = String(frame.mode ?? "");
|
|
1439
|
-
|
|
1519
|
+
const data = frame.data;
|
|
1520
|
+
const dataTurn = frameTurnId(data) || frameTurnId(frame);
|
|
1521
|
+
if (mode === "custom" && isTurnEndCustomData(data) && this.gate.allowStreamEnd(dataTurn)) {
|
|
1440
1522
|
return this.mark(TURN_END_STREAM_END);
|
|
1441
1523
|
}
|
|
1442
1524
|
}
|
|
@@ -1462,20 +1544,26 @@ function normalizeFrame(msg) {
|
|
|
1462
1544
|
return inner;
|
|
1463
1545
|
}
|
|
1464
1546
|
if (inner && typeof inner === "object" && inner.mode) {
|
|
1465
|
-
|
|
1547
|
+
const out = {
|
|
1466
1548
|
type: "event",
|
|
1467
1549
|
mode: inner.mode,
|
|
1468
1550
|
data: inner.data,
|
|
1469
1551
|
namespace: inner.namespace ?? payload.namespace
|
|
1470
1552
|
};
|
|
1553
|
+
const tid = inner.turn_id ?? payload.turn_id ?? m.turn_id;
|
|
1554
|
+
if (tid) out.turn_id = tid;
|
|
1555
|
+
return out;
|
|
1471
1556
|
}
|
|
1472
1557
|
if (payload.mode) {
|
|
1473
|
-
|
|
1558
|
+
const out = {
|
|
1474
1559
|
type: "event",
|
|
1475
1560
|
mode: payload.mode,
|
|
1476
1561
|
data: payload.data,
|
|
1477
1562
|
namespace: payload.namespace
|
|
1478
1563
|
};
|
|
1564
|
+
const tid = payload.turn_id ?? m.turn_id;
|
|
1565
|
+
if (tid) out.turn_id = tid;
|
|
1566
|
+
return out;
|
|
1479
1567
|
}
|
|
1480
1568
|
return null;
|
|
1481
1569
|
}
|
|
@@ -2113,25 +2201,6 @@ var DaemonSession = class {
|
|
|
2113
2201
|
return this.rpcClient.listLoops(15e3);
|
|
2114
2202
|
});
|
|
2115
2203
|
}
|
|
2116
|
-
async fetchLoopCards(loopId) {
|
|
2117
|
-
const lid = String(loopId || "").trim();
|
|
2118
|
-
if (!lid) return { cards: [], seq: 0, contextTokens: 0, success: false };
|
|
2119
|
-
return this.withRpcLock(async () => {
|
|
2120
|
-
await this.ensureRpcConnected();
|
|
2121
|
-
try {
|
|
2122
|
-
const resp = await this.rpcClient.fetchLoopCards(lid, 3e4);
|
|
2123
|
-
const rawCards = resp.cards;
|
|
2124
|
-
return {
|
|
2125
|
-
cards: Array.isArray(rawCards) ? rawCards : [],
|
|
2126
|
-
seq: Number(resp.seq ?? 0),
|
|
2127
|
-
contextTokens: typeof resp.context_tokens === "number" && resp.context_tokens >= 0 ? resp.context_tokens : 0,
|
|
2128
|
-
success: true
|
|
2129
|
-
};
|
|
2130
|
-
} catch {
|
|
2131
|
-
return { cards: [], seq: 0, contextTokens: 0, success: false };
|
|
2132
|
-
}
|
|
2133
|
-
});
|
|
2134
|
-
}
|
|
2135
2204
|
async fetchLoopHistory(loopId) {
|
|
2136
2205
|
const lid = String(loopId || "").trim();
|
|
2137
2206
|
if (!lid) {
|
|
@@ -2183,7 +2252,7 @@ var DaemonSession = class {
|
|
|
2183
2252
|
this.lastTurnErrorMessage = null;
|
|
2184
2253
|
let queryStarted = false;
|
|
2185
2254
|
let expectedLoopId = this.loopId;
|
|
2186
|
-
let
|
|
2255
|
+
let expectedTurnId = null;
|
|
2187
2256
|
let turnProgressSeen = false;
|
|
2188
2257
|
this.streaming = true;
|
|
2189
2258
|
const absoluteDeadline = opts.maxWaitMs !== void 0 && opts.maxWaitMs > 0 ? Date.now() + opts.maxWaitMs : null;
|
|
@@ -2217,6 +2286,17 @@ var DaemonSession = class {
|
|
|
2217
2286
|
if (expectedLoopId && typeof eventLoopId === "string" && eventLoopId && eventLoopId !== expectedLoopId) {
|
|
2218
2287
|
continue;
|
|
2219
2288
|
}
|
|
2289
|
+
const evTurnId = frameTurnId(frame);
|
|
2290
|
+
const statusState = eventType === "status" ? String(frame.state ?? "") : "";
|
|
2291
|
+
const isRunningStatus = statusState === "running";
|
|
2292
|
+
const isTerminalStatus = statusState === "idle" || statusState === "stopped";
|
|
2293
|
+
if (expectedTurnId && (eventType === "event" || eventType === "status") && !isRunningStatus) {
|
|
2294
|
+
if (isTerminalStatus) {
|
|
2295
|
+
if (evTurnId && !turnIdsMatch(expectedTurnId, evTurnId)) continue;
|
|
2296
|
+
} else if (!turnIdsMatch(expectedTurnId, evTurnId)) {
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2220
2300
|
if (eventType === "error") {
|
|
2221
2301
|
const errObj = frame.error ?? {};
|
|
2222
2302
|
throw new Error(String(errObj.message || frame.message || "daemon error"));
|
|
@@ -2227,16 +2307,37 @@ var DaemonSession = class {
|
|
|
2227
2307
|
this.loopId = loopEv;
|
|
2228
2308
|
expectedLoopId = loopEv;
|
|
2229
2309
|
}
|
|
2230
|
-
|
|
2231
|
-
if (state === "running") {
|
|
2310
|
+
if (statusState === "running") {
|
|
2232
2311
|
queryStarted = true;
|
|
2233
|
-
|
|
2234
|
-
|
|
2312
|
+
const statusTurn = frameTurnId(frame);
|
|
2313
|
+
if (statusTurn) {
|
|
2314
|
+
const newGen = parseTurnGeneration(statusTurn);
|
|
2315
|
+
const oldGen = parseTurnGeneration(expectedTurnId);
|
|
2316
|
+
if (expectedTurnId === null || newGen !== null && (oldGen === null || newGen >= oldGen)) {
|
|
2317
|
+
if (expectedTurnId && statusTurn !== expectedTurnId) {
|
|
2318
|
+
turnProgressSeen = false;
|
|
2319
|
+
}
|
|
2320
|
+
expectedTurnId = statusTurn;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
} else if (queryStarted && statusState === "stopped") {
|
|
2324
|
+
const stopTurn = frameTurnId(frame);
|
|
2325
|
+
if (expectedTurnId && !turnIdsMatch(expectedTurnId, stopTurn)) continue;
|
|
2326
|
+
this.lastTurnEndState = statusState;
|
|
2235
2327
|
yield* this.drainStreamEventsAfterIdle(expectedLoopId);
|
|
2236
2328
|
break;
|
|
2237
|
-
} else if (queryStarted &&
|
|
2238
|
-
|
|
2239
|
-
|
|
2329
|
+
} else if (queryStarted && statusState === "idle") {
|
|
2330
|
+
const idleTurn = frameTurnId(frame);
|
|
2331
|
+
if (!isIdleTerminalAllowed({
|
|
2332
|
+
expectedTurnId,
|
|
2333
|
+
frameTurnId: idleTurn,
|
|
2334
|
+
queryStarted,
|
|
2335
|
+
turnProgressSeen,
|
|
2336
|
+
cancellationSeen: this.lastTurnCancellationSeen
|
|
2337
|
+
})) {
|
|
2338
|
+
continue;
|
|
2339
|
+
}
|
|
2340
|
+
this.lastTurnEndState = statusState;
|
|
2240
2341
|
yield* this.drainStreamEventsAfterIdle(expectedLoopId);
|
|
2241
2342
|
break;
|
|
2242
2343
|
}
|
|
@@ -2258,9 +2359,16 @@ var DaemonSession = class {
|
|
|
2258
2359
|
continue;
|
|
2259
2360
|
}
|
|
2260
2361
|
if (mode === "custom" && isTurnEndCustomData(data)) {
|
|
2261
|
-
|
|
2362
|
+
const dataTurn = frameTurnId(data) || evTurnId;
|
|
2363
|
+
if (!isTurnTerminalAllowed({
|
|
2364
|
+
expectedTurnId,
|
|
2365
|
+
frameTurnId: dataTurn,
|
|
2366
|
+
queryStarted,
|
|
2367
|
+
turnProgressSeen
|
|
2368
|
+
})) {
|
|
2369
|
+
continue;
|
|
2370
|
+
}
|
|
2262
2371
|
}
|
|
2263
|
-
streamPayloadSeen = true;
|
|
2264
2372
|
if (isTurnProgressChunk(mode, data)) turnProgressSeen = true;
|
|
2265
2373
|
yield [namespace, mode, data];
|
|
2266
2374
|
if (mode === "custom" && isTurnEndCustomData(data)) {
|
|
@@ -2456,19 +2564,23 @@ export {
|
|
|
2456
2564
|
extractSootheLoopID,
|
|
2457
2565
|
extractThinkingStep,
|
|
2458
2566
|
fetchConfigSection,
|
|
2459
|
-
fetchLoopCards,
|
|
2460
2567
|
fetchLoopHistory,
|
|
2461
2568
|
fetchLoopMessages,
|
|
2462
2569
|
fetchSkillsCatalog,
|
|
2570
|
+
formatTurnId,
|
|
2571
|
+
frameSeq,
|
|
2572
|
+
frameTurnId,
|
|
2463
2573
|
idleTimeoutForTurn,
|
|
2464
2574
|
inboundNeedsDeliveryAck,
|
|
2465
2575
|
inputMessageForLoop,
|
|
2466
2576
|
isCompletionEvent,
|
|
2467
2577
|
isDaemonLive,
|
|
2468
2578
|
isDaemonTurnEndEvent,
|
|
2579
|
+
isIdleTerminalAllowed,
|
|
2469
2580
|
isSubagentProgressEvent,
|
|
2470
2581
|
isTurnEndCustomData,
|
|
2471
2582
|
isTurnProgressChunk,
|
|
2583
|
+
isTurnTerminalAllowed,
|
|
2472
2584
|
isValidVerbosityLevel,
|
|
2473
2585
|
loadConfigFromEnv,
|
|
2474
2586
|
newLoopInputMessage,
|
|
@@ -2478,6 +2590,7 @@ export {
|
|
|
2478
2590
|
notificationEnvelope,
|
|
2479
2591
|
parseCardCustomPayload,
|
|
2480
2592
|
parseNamespace,
|
|
2593
|
+
parseTurnGeneration,
|
|
2481
2594
|
pingEnvelope,
|
|
2482
2595
|
pongEnvelope,
|
|
2483
2596
|
protocol1Rpc,
|
|
@@ -2488,6 +2601,7 @@ export {
|
|
|
2488
2601
|
shouldShow,
|
|
2489
2602
|
splitWirePayload,
|
|
2490
2603
|
subscribeEnvelope,
|
|
2604
|
+
turnIdsMatch,
|
|
2491
2605
|
unsubscribeEnvelope,
|
|
2492
2606
|
validateLoopInputIntentHint,
|
|
2493
2607
|
waitDaemonReady,
|