@wrongstack/core 0.269.0 → 0.272.0
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/{agent-bridge-PcHQl_UQ.d.ts → agent-bridge-jVSZiygR.d.ts} +1 -1
- package/dist/{agent-subagent-runner-SHJW7t8q.d.ts → agent-subagent-runner-DOLIwBRo.d.ts} +7 -7
- package/dist/{brain-BYcK__Ym.d.ts → brain-CdbbJWi3.d.ts} +71 -1
- package/dist/{compactor-C2RKEBtC.d.ts → compactor-72ug-ZRB.d.ts} +1 -1
- package/dist/{config-C_ae2k86.d.ts → config-D2DGoGSQ.d.ts} +29 -2
- package/dist/{context-Dp87Bcaq.d.ts → context-Dw55zZ_Q.d.ts} +110 -1
- package/dist/coordination/index.d.ts +121 -17
- package/dist/coordination/index.js +738 -74
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +25 -25
- package/dist/defaults/index.js +599 -86
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +23 -18
- package/dist/execution/index.js +136 -41
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +36 -6
- package/dist/execution/prompt-enhancer.js +35 -9
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/{global-mailbox-Bvrz1P3f.d.ts → global-mailbox-CQj_C9Dp.d.ts} +139 -3
- package/dist/{goal-preamble-CA_4yiGQ.d.ts → goal-preamble-ZXDjjR1y.d.ts} +9 -9
- package/dist/{goal-store-DhuJoUNG.d.ts → goal-store-CcJBd-g1.d.ts} +1 -1
- package/dist/hq/index.d.ts +93 -6
- package/dist/hq/index.js +619 -49
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-whDfTANu.d.ts → index-2Lhk5v0o.d.ts} +2 -2
- package/dist/{index-CZQ6Pwbs.d.ts → index-BL7BAx0p.d.ts} +8 -8
- package/dist/{index-W4VJCzHa.d.ts → index-Qo4kTzgw.d.ts} +5 -5
- package/dist/index.d.ts +96 -56
- package/dist/index.js +1941 -352
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +5 -3
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-DJdZiRcv.d.ts → mcp-servers-DS-YUXvF.d.ts} +3 -3
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +28 -5
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-C3a-2-Yd.d.ts → models-registry-DP6pGHet.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-CJSpTe5O.d.ts → multi-agent-coordinator-BvbdNQ14.d.ts} +1 -1
- package/dist/{null-fleet-bus-QVshIsDx.d.ts → null-fleet-bus-BxTfXBKo.d.ts} +6 -6
- package/dist/observability/index.d.ts +2 -2
- package/dist/{parallel-eternal-engine-D9y5Pkcc.d.ts → parallel-eternal-engine-Cf-GTegR.d.ts} +9 -9
- package/dist/{path-resolver-CnQ8SIfh.d.ts → path-resolver-DztfnFcv.d.ts} +3 -3
- package/dist/{permission-CvYQNUqZ.d.ts → permission-CC7XFYWG.d.ts} +1 -1
- package/dist/{permission-policy-D5Ss8j4B.d.ts → permission-policy-cYR4RJmw.d.ts} +2 -2
- package/dist/{pipeline-l_zzFRh3.d.ts → pipeline-sNIkhXeB.d.ts} +2 -2
- package/dist/{plan-templates-NtPgyeJA.d.ts → plan-templates-DYiKFmEb.d.ts} +11 -5
- package/dist/{provider-model-resolve-d5poT5y0.d.ts → provider-model-resolve-dYAbTs_i.d.ts} +3 -3
- package/dist/{provider-runner-gkctlQV_.d.ts → provider-runner-Dw8x0F7u.d.ts} +3 -3
- package/dist/{retry-policy-CtFhfwa8.d.ts → retry-policy-BV7nzeAd.d.ts} +1 -1
- package/dist/sdd/index.d.ts +8 -8
- package/dist/sdd/index.js +2 -0
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-BLsVmTIK.d.ts → secret-vault-eMBKfheR.d.ts} +9 -1
- package/dist/security/index.d.ts +5 -5
- package/dist/security/index.js +137 -10
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-CXl2_y9W.d.ts → selector-C4ORTOid.d.ts} +1 -1
- package/dist/{session-event-bridge-Ccud20CC.d.ts → session-event-bridge-CeNpUL9w.d.ts} +1 -1
- package/dist/{session-reader-ZeXQmsmE.d.ts → session-reader-BepLSnGL.d.ts} +1 -1
- package/dist/storage/index.d.ts +45 -13
- package/dist/storage/index.js +374 -113
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +9 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +19 -19
- package/dist/types/index.js +202 -41
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +17 -4
- package/dist/utils/index.js +48 -9
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/hq/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
|
2
2
|
import * as syncFs from 'fs';
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
import { hostname } from 'os';
|
|
5
|
-
import * as
|
|
5
|
+
import * as path2 from 'path';
|
|
6
6
|
import { basename } from 'path';
|
|
7
7
|
import * as fsp from 'fs/promises';
|
|
8
8
|
|
|
@@ -105,7 +105,13 @@ function parseHqFrame(raw) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
var KNOWN_HQ_EVENT_PAYLOAD_TYPES = /* @__PURE__ */ new Set([
|
|
108
|
+
var KNOWN_HQ_EVENT_PAYLOAD_TYPES = /* @__PURE__ */ new Set([
|
|
109
|
+
"mailbox.snapshot",
|
|
110
|
+
"mailbox.event",
|
|
111
|
+
"session.snapshot",
|
|
112
|
+
"session.transcript",
|
|
113
|
+
"session.ended"
|
|
114
|
+
]);
|
|
109
115
|
function isHqMailboxMessageSummary(x) {
|
|
110
116
|
if (typeof x !== "object" || x === null) return false;
|
|
111
117
|
const v = x;
|
|
@@ -152,6 +158,52 @@ function isHqMailboxEventPayload(x) {
|
|
|
152
158
|
if (v.agent !== void 0 && !isHqMailboxAgentSummary(v.agent)) return false;
|
|
153
159
|
return true;
|
|
154
160
|
}
|
|
161
|
+
var HQ_SESSION_AGENT_STATUSES = /* @__PURE__ */ new Set([
|
|
162
|
+
"idle",
|
|
163
|
+
"running",
|
|
164
|
+
"streaming",
|
|
165
|
+
"waiting_user",
|
|
166
|
+
"error"
|
|
167
|
+
]);
|
|
168
|
+
function isHqSessionAgentSummary(x) {
|
|
169
|
+
if (typeof x !== "object" || x === null) return false;
|
|
170
|
+
const v = x;
|
|
171
|
+
return typeof v.id === "string" && typeof v.name === "string" && typeof v.status === "string" && HQ_SESSION_AGENT_STATUSES.has(v.status) && typeof v.iterations === "number" && typeof v.toolCalls === "number" && typeof v.lastActivityAt === "string";
|
|
172
|
+
}
|
|
173
|
+
var HQ_SESSION_STATUSES = /* @__PURE__ */ new Set(["active", "idle", "closing", "stale"]);
|
|
174
|
+
function isHqSessionSnapshotPayload(x) {
|
|
175
|
+
if (typeof x !== "object" || x === null) return false;
|
|
176
|
+
const v = x;
|
|
177
|
+
if (typeof v.sessionId !== "string" || typeof v.clientKind !== "string" || typeof v.machineId !== "string" || typeof v.projectId !== "string" || typeof v.projectName !== "string" || typeof v.projectRoot !== "string" || typeof v.status !== "string" || !HQ_SESSION_STATUSES.has(v.status) || typeof v.startedAt !== "string" || typeof v.lastActivityAt !== "string" || typeof v.agentCount !== "number" || !Array.isArray(v.agents)) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
for (const agent of v.agents) {
|
|
181
|
+
if (!isHqSessionAgentSummary(agent)) return false;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
var HQ_TRANSCRIPT_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "error"]);
|
|
186
|
+
function isHqTranscriptEntry(x) {
|
|
187
|
+
if (typeof x !== "object" || x === null) return false;
|
|
188
|
+
const v = x;
|
|
189
|
+
return typeof v.ts === "string" && typeof v.role === "string" && HQ_TRANSCRIPT_ROLES.has(v.role) && typeof v.text === "string";
|
|
190
|
+
}
|
|
191
|
+
function isHqTranscriptAppendPayload(x) {
|
|
192
|
+
if (typeof x !== "object" || x === null) return false;
|
|
193
|
+
const v = x;
|
|
194
|
+
if (typeof v.sessionId !== "string" || typeof v.fromSeq !== "number" || !Array.isArray(v.entries)) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
for (const entry of v.entries) {
|
|
198
|
+
if (!isHqTranscriptEntry(entry)) return false;
|
|
199
|
+
}
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
function isHqSessionEndedPayload(x) {
|
|
203
|
+
if (typeof x !== "object" || x === null) return false;
|
|
204
|
+
const v = x;
|
|
205
|
+
return typeof v.sessionId === "string" && typeof v.endedAt === "string";
|
|
206
|
+
}
|
|
155
207
|
function parseHqEventPayload(eventType, payload) {
|
|
156
208
|
if (!KNOWN_HQ_EVENT_PAYLOAD_TYPES.has(eventType)) {
|
|
157
209
|
return { ok: true, payload };
|
|
@@ -161,6 +213,12 @@ function parseHqEventPayload(eventType, payload) {
|
|
|
161
213
|
return isHqMailboxSnapshotPayload(payload) ? { ok: true, payload } : { ok: false, reason: "malformed-payload" };
|
|
162
214
|
case "mailbox.event":
|
|
163
215
|
return isHqMailboxEventPayload(payload) ? { ok: true, payload } : { ok: false, reason: "malformed-payload" };
|
|
216
|
+
case "session.snapshot":
|
|
217
|
+
return isHqSessionSnapshotPayload(payload) ? { ok: true, payload } : { ok: false, reason: "malformed-payload" };
|
|
218
|
+
case "session.transcript":
|
|
219
|
+
return isHqTranscriptAppendPayload(payload) ? { ok: true, payload } : { ok: false, reason: "malformed-payload" };
|
|
220
|
+
case "session.ended":
|
|
221
|
+
return isHqSessionEndedPayload(payload) ? { ok: true, payload } : { ok: false, reason: "malformed-payload" };
|
|
164
222
|
default: {
|
|
165
223
|
const _exhaustive = eventType;
|
|
166
224
|
return _exhaustive;
|
|
@@ -554,7 +612,7 @@ function taskSummary(message) {
|
|
|
554
612
|
return Object.keys(task).length > 0 ? task : void 0;
|
|
555
613
|
}
|
|
556
614
|
function mapMailboxMessageToHqSummary(message, options = {}) {
|
|
557
|
-
const previewLength = options.previewLength ??
|
|
615
|
+
const previewLength = options.previewLength ?? 500;
|
|
558
616
|
const bodyPreview = previewText(message.body, previewLength, options.redactionPolicy);
|
|
559
617
|
const outcomePreview = previewText(message.outcome, previewLength, options.redactionPolicy);
|
|
560
618
|
const task = taskSummary(message);
|
|
@@ -642,8 +700,8 @@ function createMailboxEventPayload(input) {
|
|
|
642
700
|
var OPEN_STATE = 1;
|
|
643
701
|
var DEFAULT_RECONNECT_BASE_MS = 1e3;
|
|
644
702
|
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
645
|
-
var DEFAULT_MAX_QUEUED_MESSAGES =
|
|
646
|
-
var DEFAULT_COMMAND_POLL_INTERVAL_MS =
|
|
703
|
+
var DEFAULT_MAX_QUEUED_MESSAGES = 2e3;
|
|
704
|
+
var DEFAULT_COMMAND_POLL_INTERVAL_MS = 2e3;
|
|
647
705
|
var DEFAULT_COMMAND_POLL_LIMIT = 25;
|
|
648
706
|
function defaultSocketFactory(url) {
|
|
649
707
|
const WebSocketCtor = globalThis.WebSocket;
|
|
@@ -797,6 +855,41 @@ var HqPublisher = class {
|
|
|
797
855
|
...input.timestamp !== void 0 ? { timestamp: input.timestamp } : {}
|
|
798
856
|
});
|
|
799
857
|
}
|
|
858
|
+
/** The client identity this publisher announced (clientId, kind, machineId, …). */
|
|
859
|
+
get identity() {
|
|
860
|
+
return this.options.client;
|
|
861
|
+
}
|
|
862
|
+
/** The project identity this publisher is bound to. */
|
|
863
|
+
get project() {
|
|
864
|
+
return this.options.project;
|
|
865
|
+
}
|
|
866
|
+
/** Publish a live session/terminal snapshot (state + agents). */
|
|
867
|
+
publishSessionSnapshot(payload, opts) {
|
|
868
|
+
return this.publishEvent({
|
|
869
|
+
type: "session.snapshot",
|
|
870
|
+
payload,
|
|
871
|
+
sessionId: payload.sessionId,
|
|
872
|
+
...opts?.timestamp !== void 0 ? { timestamp: opts.timestamp } : {}
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
/** Publish an incremental batch of transcript turns for a session. */
|
|
876
|
+
publishTranscriptAppend(payload, opts) {
|
|
877
|
+
return this.publishEvent({
|
|
878
|
+
type: "session.transcript",
|
|
879
|
+
payload,
|
|
880
|
+
sessionId: payload.sessionId,
|
|
881
|
+
...opts?.timestamp !== void 0 ? { timestamp: opts.timestamp } : {}
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
/** Mark a session/terminal as ended. */
|
|
885
|
+
publishSessionEnded(payload, opts) {
|
|
886
|
+
return this.publishEvent({
|
|
887
|
+
type: "session.ended",
|
|
888
|
+
payload,
|
|
889
|
+
sessionId: payload.sessionId,
|
|
890
|
+
...opts?.timestamp !== void 0 ? { timestamp: opts.timestamp } : {}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
800
893
|
pollCommands() {
|
|
801
894
|
this.sendFrame({
|
|
802
895
|
type: "client.command_poll",
|
|
@@ -914,9 +1007,9 @@ var HqPublisher = class {
|
|
|
914
1007
|
}
|
|
915
1008
|
};
|
|
916
1009
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
917
|
-
const dir =
|
|
1010
|
+
const dir = path2.dirname(targetPath);
|
|
918
1011
|
await fsp.mkdir(dir, { recursive: true });
|
|
919
|
-
const tmp =
|
|
1012
|
+
const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
920
1013
|
try {
|
|
921
1014
|
if (typeof content === "string") {
|
|
922
1015
|
await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
@@ -934,8 +1027,8 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
934
1027
|
}
|
|
935
1028
|
let mode;
|
|
936
1029
|
try {
|
|
937
|
-
const
|
|
938
|
-
mode =
|
|
1030
|
+
const stat4 = await fsp.stat(targetPath);
|
|
1031
|
+
mode = stat4.mode & 511;
|
|
939
1032
|
} catch {
|
|
940
1033
|
mode = opts.mode;
|
|
941
1034
|
}
|
|
@@ -952,9 +1045,9 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
952
1045
|
}
|
|
953
1046
|
}
|
|
954
1047
|
async function withFileLock(targetPath, fn, opts = {}) {
|
|
955
|
-
const dir =
|
|
1048
|
+
const dir = path2.dirname(targetPath);
|
|
956
1049
|
await fsp.mkdir(dir, { recursive: true });
|
|
957
|
-
const lockPath =
|
|
1050
|
+
const lockPath = path2.join(dir, `.${path2.basename(targetPath)}.lock`);
|
|
958
1051
|
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
959
1052
|
const staleMs = opts.staleMs ?? 3e4;
|
|
960
1053
|
const started = Date.now();
|
|
@@ -972,8 +1065,8 @@ async function withFileLock(targetPath, fn, opts = {}) {
|
|
|
972
1065
|
}
|
|
973
1066
|
if (code !== "EEXIST") throw err;
|
|
974
1067
|
try {
|
|
975
|
-
const
|
|
976
|
-
if (Date.now() -
|
|
1068
|
+
const stat4 = await fsp.stat(lockPath);
|
|
1069
|
+
if (Date.now() - stat4.mtimeMs > staleMs) {
|
|
977
1070
|
await fsp.unlink(lockPath);
|
|
978
1071
|
continue;
|
|
979
1072
|
}
|
|
@@ -1022,10 +1115,62 @@ async function renameWithRetry(from, to) {
|
|
|
1022
1115
|
}
|
|
1023
1116
|
throw lastErr;
|
|
1024
1117
|
}
|
|
1118
|
+
function projectHash(absRoot) {
|
|
1119
|
+
return createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 12);
|
|
1120
|
+
}
|
|
1121
|
+
function projectSlug(absRoot) {
|
|
1122
|
+
const base = slugify(path2.basename(absRoot));
|
|
1123
|
+
const hash = createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 6);
|
|
1124
|
+
return `${base}-${hash}`;
|
|
1125
|
+
}
|
|
1126
|
+
function slugify(name) {
|
|
1127
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
|
|
1128
|
+
}
|
|
1025
1129
|
function wstackGlobalRoot() {
|
|
1026
1130
|
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
1027
|
-
if (fromEnv && fromEnv.trim().length > 0) return
|
|
1028
|
-
return
|
|
1131
|
+
if (fromEnv && fromEnv.trim().length > 0) return path2.resolve(fromEnv);
|
|
1132
|
+
return path2.join(os.homedir(), ".wrongstack");
|
|
1133
|
+
}
|
|
1134
|
+
function resolveWstackPaths(opts) {
|
|
1135
|
+
const globalRoot = opts.globalRoot ?? (opts.userHome ? path2.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
1136
|
+
const hash = projectHash(opts.projectRoot);
|
|
1137
|
+
const slug = projectSlug(opts.projectRoot);
|
|
1138
|
+
const projectDir = path2.join(globalRoot, "projects", slug);
|
|
1139
|
+
return {
|
|
1140
|
+
globalRoot,
|
|
1141
|
+
configDir: globalRoot,
|
|
1142
|
+
globalConfig: path2.join(globalRoot, "config.json"),
|
|
1143
|
+
secretsKey: path2.join(globalRoot, ".key"),
|
|
1144
|
+
globalMemory: path2.join(globalRoot, "memory.md"),
|
|
1145
|
+
globalSkills: path2.join(globalRoot, "skills"),
|
|
1146
|
+
globalPrompts: path2.join(globalRoot, "prompts"),
|
|
1147
|
+
cacheDir: path2.join(globalRoot, "cache"),
|
|
1148
|
+
modelsCache: path2.join(globalRoot, "cache", "models.dev.json"),
|
|
1149
|
+
modelsOverlayCache: path2.join(globalRoot, "cache", "models-overlay.json"),
|
|
1150
|
+
historyFile: path2.join(globalRoot, "history"),
|
|
1151
|
+
logFile: path2.join(globalRoot, "logs", "wrongstack.log"),
|
|
1152
|
+
projectDir,
|
|
1153
|
+
projectCodebaseIndex: path2.join(projectDir, "codebase-index"),
|
|
1154
|
+
projectMemory: path2.join(projectDir, "memory.md"),
|
|
1155
|
+
projectSessions: path2.join(projectDir, "sessions"),
|
|
1156
|
+
projectTrust: path2.join(projectDir, "trust.json"),
|
|
1157
|
+
projectMeta: path2.join(projectDir, "meta.json"),
|
|
1158
|
+
projectLocalConfig: path2.join(projectDir, "config.local.json"),
|
|
1159
|
+
inProjectConfig: path2.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
1160
|
+
inProjectAgentsFile: path2.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
1161
|
+
inProjectSkills: path2.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
1162
|
+
inProjectWorktrees: path2.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
1163
|
+
projectHash: hash,
|
|
1164
|
+
projectSlug: slug,
|
|
1165
|
+
projectGoal: path2.join(projectDir, "goal.json"),
|
|
1166
|
+
projectSpecs: path2.join(projectDir, "specs"),
|
|
1167
|
+
projectTaskGraphs: path2.join(projectDir, "task-graphs"),
|
|
1168
|
+
projectSddSession: path2.join(projectDir, "sdd-session.json"),
|
|
1169
|
+
projectPlan: path2.join(projectDir, "plan.json"),
|
|
1170
|
+
projectAutophase: path2.join(projectDir, "autophase"),
|
|
1171
|
+
syncConfig: path2.join(globalRoot, "sync.json"),
|
|
1172
|
+
projectStatus: (projectHash2) => path2.join(globalRoot, "projects", projectHash2, "status.json")
|
|
1173
|
+
};
|
|
1029
1174
|
}
|
|
1030
1175
|
|
|
1031
1176
|
// src/coordination/mailbox-types.ts
|
|
@@ -1093,14 +1238,14 @@ var GlobalMailbox = class {
|
|
|
1093
1238
|
* @param hqPublisher — optional HQ publisher for cross-project telemetry
|
|
1094
1239
|
*/
|
|
1095
1240
|
constructor(projectDir, events, hqPublisher) {
|
|
1096
|
-
this.messagePath =
|
|
1097
|
-
this.registryPath =
|
|
1098
|
-
this.clientRegistryPath =
|
|
1241
|
+
this.messagePath = path2.join(projectDir, MAILBOX_FILE);
|
|
1242
|
+
this.registryPath = path2.join(projectDir, "_mailbox.registry.json");
|
|
1243
|
+
this.clientRegistryPath = path2.join(projectDir, CLIENT_REGISTRY_FILE);
|
|
1099
1244
|
this._events = events;
|
|
1100
1245
|
this._hqPublisher = hqPublisher;
|
|
1101
1246
|
}
|
|
1102
1247
|
get hqMailboxId() {
|
|
1103
|
-
return `${
|
|
1248
|
+
return `${path2.basename(path2.dirname(this.messagePath))}:mailbox`;
|
|
1104
1249
|
}
|
|
1105
1250
|
publishHqMailboxEvent(input) {
|
|
1106
1251
|
try {
|
|
@@ -1133,7 +1278,7 @@ var GlobalMailbox = class {
|
|
|
1133
1278
|
taskContext: input.taskContext
|
|
1134
1279
|
};
|
|
1135
1280
|
const line = JSON.stringify(msg) + LINE_SEPARATOR;
|
|
1136
|
-
await fsp.mkdir(
|
|
1281
|
+
await fsp.mkdir(path2.dirname(this.messagePath), { recursive: true });
|
|
1137
1282
|
await withFileLock(this.messagePath, async () => {
|
|
1138
1283
|
await fsp.appendFile(this.messagePath, line, "utf8");
|
|
1139
1284
|
this._pushToCache(msg);
|
|
@@ -1472,30 +1617,69 @@ var GlobalMailbox = class {
|
|
|
1472
1617
|
async _readMessages() {
|
|
1473
1618
|
try {
|
|
1474
1619
|
const raw = await fsp.readFile(this.messagePath, "utf8");
|
|
1475
|
-
|
|
1476
|
-
const messages = [];
|
|
1477
|
-
for (const line of lines) {
|
|
1478
|
-
try {
|
|
1479
|
-
const parsed = JSON.parse(line);
|
|
1480
|
-
if (!parsed["readBy"]) {
|
|
1481
|
-
const readBy = {};
|
|
1482
|
-
if (parsed["read"] && parsed["readAt"]) {
|
|
1483
|
-
readBy[parsed["to"]] = parsed["readAt"];
|
|
1484
|
-
}
|
|
1485
|
-
parsed["readBy"] = readBy;
|
|
1486
|
-
delete parsed["read"];
|
|
1487
|
-
delete parsed["readAt"];
|
|
1488
|
-
}
|
|
1489
|
-
messages.push(parsed);
|
|
1490
|
-
} catch {
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
return messages;
|
|
1620
|
+
return this._parseLines(raw);
|
|
1494
1621
|
} catch (err) {
|
|
1495
1622
|
if (err.code === "ENOENT") return [];
|
|
1496
1623
|
throw err;
|
|
1497
1624
|
}
|
|
1498
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Read only newly-appended bytes from the file and append them to the
|
|
1628
|
+
* in-memory cache. This avoids re-reading and re-parsing the entire file
|
|
1629
|
+
* when another process appended messages since our last read.
|
|
1630
|
+
*
|
|
1631
|
+
* Only safe when the file grew in size (messages are append-only). When
|
|
1632
|
+
* the file was rewritten (ack/purge changed existing content), callers
|
|
1633
|
+
* must fall back to {@link _readMessages}.
|
|
1634
|
+
*
|
|
1635
|
+
* @returns The (now up-to-date) message cache.
|
|
1636
|
+
*/
|
|
1637
|
+
async _readNewMessagesOnly(fd, oldSize, newSize) {
|
|
1638
|
+
const tailLen = newSize - oldSize;
|
|
1639
|
+
const buf = Buffer.alloc(tailLen);
|
|
1640
|
+
await fd.read(buf, 0, tailLen, oldSize);
|
|
1641
|
+
const tail = buf.toString("utf8");
|
|
1642
|
+
for (const line of tail.split(LINE_SEPARATOR)) {
|
|
1643
|
+
if (!line.trim()) continue;
|
|
1644
|
+
try {
|
|
1645
|
+
const parsed = JSON.parse(line);
|
|
1646
|
+
if (!parsed["readBy"]) {
|
|
1647
|
+
const readBy = {};
|
|
1648
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
1649
|
+
readBy[parsed["to"]] = parsed["readAt"];
|
|
1650
|
+
}
|
|
1651
|
+
parsed["readBy"] = readBy;
|
|
1652
|
+
delete parsed["read"];
|
|
1653
|
+
delete parsed["readAt"];
|
|
1654
|
+
}
|
|
1655
|
+
this._messageCache.push(parsed);
|
|
1656
|
+
} catch {
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return this._messageCache;
|
|
1660
|
+
}
|
|
1661
|
+
/** Parse a JSONL string into MailboxMessage[], including migration. */
|
|
1662
|
+
_parseLines(raw) {
|
|
1663
|
+
const lines = raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);
|
|
1664
|
+
const messages = [];
|
|
1665
|
+
for (const line of lines) {
|
|
1666
|
+
try {
|
|
1667
|
+
const parsed = JSON.parse(line);
|
|
1668
|
+
if (!parsed["readBy"]) {
|
|
1669
|
+
const readBy = {};
|
|
1670
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
1671
|
+
readBy[parsed["to"]] = parsed["readAt"];
|
|
1672
|
+
}
|
|
1673
|
+
parsed["readBy"] = readBy;
|
|
1674
|
+
delete parsed["read"];
|
|
1675
|
+
delete parsed["readAt"];
|
|
1676
|
+
}
|
|
1677
|
+
messages.push(parsed);
|
|
1678
|
+
} catch {
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return messages;
|
|
1682
|
+
}
|
|
1499
1683
|
/**
|
|
1500
1684
|
* Read messages, then adopt the result as the in-memory cache. Use this
|
|
1501
1685
|
* from writers that just took the file lock — the read reflects the
|
|
@@ -1515,6 +1699,10 @@ var GlobalMailbox = class {
|
|
|
1515
1699
|
* stat matches the cached mtime+size we return the cached array — no
|
|
1516
1700
|
* file read and no JSON.parse — collapsing the per-iteration query
|
|
1517
1701
|
* cost on the mailbox-loop hot path.
|
|
1702
|
+
*
|
|
1703
|
+
* When the file only grew (new messages appended by another process),
|
|
1704
|
+
* we read and parse just the tail bytes instead of the entire file.
|
|
1705
|
+
* This avoids re-parsing the full 10K-message history on every check.
|
|
1518
1706
|
*/
|
|
1519
1707
|
async _readMessagesCached() {
|
|
1520
1708
|
try {
|
|
@@ -1522,6 +1710,17 @@ var GlobalMailbox = class {
|
|
|
1522
1710
|
if (this._messageCache !== null && this._messageCacheMtime === st.mtimeMs && this._messageCacheSize === st.size) {
|
|
1523
1711
|
return this._messageCache;
|
|
1524
1712
|
}
|
|
1713
|
+
if (this._messageCache !== null && this._messageCacheSize >= 0 && st.size > this._messageCacheSize) {
|
|
1714
|
+
const fd = await fsp.open(this.messagePath, "r");
|
|
1715
|
+
try {
|
|
1716
|
+
const updated = await this._readNewMessagesOnly(fd, this._messageCacheSize, st.size);
|
|
1717
|
+
this._messageCacheMtime = st.mtimeMs;
|
|
1718
|
+
this._messageCacheSize = st.size;
|
|
1719
|
+
return updated;
|
|
1720
|
+
} finally {
|
|
1721
|
+
await fd.close();
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1525
1724
|
const all = await this._readMessages();
|
|
1526
1725
|
this._setMessageCache(all, st.mtimeMs, st.size);
|
|
1527
1726
|
return all;
|
|
@@ -1574,7 +1773,7 @@ var GlobalMailbox = class {
|
|
|
1574
1773
|
this._messageCache.push(msg);
|
|
1575
1774
|
}
|
|
1576
1775
|
async _ensureRegistry() {
|
|
1577
|
-
await fsp.mkdir(
|
|
1776
|
+
await fsp.mkdir(path2.dirname(this.registryPath), { recursive: true });
|
|
1578
1777
|
}
|
|
1579
1778
|
async _readRegistry(opts) {
|
|
1580
1779
|
if (!opts?.fresh && this._registryCache && Date.now() - this._registryCacheAt < REGISTRY_CACHE_TTL_MS) {
|
|
@@ -1619,7 +1818,7 @@ var GlobalMailbox = class {
|
|
|
1619
1818
|
}
|
|
1620
1819
|
// ── Client registry internals ───────────────────────────────────────────
|
|
1621
1820
|
async _ensureClientRegistry() {
|
|
1622
|
-
await fsp.mkdir(
|
|
1821
|
+
await fsp.mkdir(path2.dirname(this.clientRegistryPath), { recursive: true });
|
|
1623
1822
|
}
|
|
1624
1823
|
async _readClientRegistry(opts) {
|
|
1625
1824
|
if (!opts?.fresh && this._clientRegistryCache && Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS) {
|
|
@@ -1665,12 +1864,12 @@ var GlobalMailbox = class {
|
|
|
1665
1864
|
};
|
|
1666
1865
|
var HQ_AUTH_FILE_VERSION = 1;
|
|
1667
1866
|
function defaultHqDataDir() {
|
|
1668
|
-
return
|
|
1867
|
+
return path2.join(wstackGlobalRoot(), "hq");
|
|
1669
1868
|
}
|
|
1670
1869
|
function resolveHqDataDir(override, env = process.env) {
|
|
1671
1870
|
const raw = override ?? env["WRONGSTACK_HQ_DATA_DIR"]?.trim();
|
|
1672
1871
|
if (!raw) return defaultHqDataDir();
|
|
1673
|
-
return
|
|
1872
|
+
return path2.isAbsolute(raw) ? path2.resolve(raw) : path2.resolve(process.cwd(), raw);
|
|
1674
1873
|
}
|
|
1675
1874
|
function emptyHqAuthFile() {
|
|
1676
1875
|
return {
|
|
@@ -1679,10 +1878,10 @@ function emptyHqAuthFile() {
|
|
|
1679
1878
|
};
|
|
1680
1879
|
}
|
|
1681
1880
|
function hqAuthFilePath(dataDir) {
|
|
1682
|
-
return
|
|
1881
|
+
return path2.join(dataDir, "auth.json");
|
|
1683
1882
|
}
|
|
1684
1883
|
function hqRuntimeFilePath(dataDir) {
|
|
1685
|
-
return
|
|
1884
|
+
return path2.join(dataDir, "runtime.json");
|
|
1686
1885
|
}
|
|
1687
1886
|
async function writeHqRuntimeFile(dataDir, file) {
|
|
1688
1887
|
const payload = {
|
|
@@ -1794,7 +1993,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
1794
1993
|
let closed = false;
|
|
1795
1994
|
let watcher;
|
|
1796
1995
|
try {
|
|
1797
|
-
watcher = syncFs.watch(
|
|
1996
|
+
watcher = syncFs.watch(path2.dirname(file), { recursive: false });
|
|
1798
1997
|
} catch (err) {
|
|
1799
1998
|
opts.warn?.(`HQ auth watcher could not start: ${err.message}`);
|
|
1800
1999
|
return { close: () => {
|
|
@@ -1818,7 +2017,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
1818
2017
|
watcher.on("change", (eventType, filename) => {
|
|
1819
2018
|
const name = typeof filename === "string" ? filename : "";
|
|
1820
2019
|
if (eventType === "rename" || eventType === "change") {
|
|
1821
|
-
if (!name || name === "auth.json" || name ===
|
|
2020
|
+
if (!name || name === "auth.json" || name === path2.basename(file)) {
|
|
1822
2021
|
trigger();
|
|
1823
2022
|
}
|
|
1824
2023
|
}
|
|
@@ -1883,7 +2082,7 @@ function resolveHqConfig(options = {}) {
|
|
|
1883
2082
|
};
|
|
1884
2083
|
}
|
|
1885
2084
|
function stableMachineId() {
|
|
1886
|
-
return createHash("sha256").update(
|
|
2085
|
+
return createHash("sha256").update(hostname()).digest("hex").slice(0, 12);
|
|
1887
2086
|
}
|
|
1888
2087
|
function deriveProjectId(projectRoot) {
|
|
1889
2088
|
return createHash("sha256").update(projectRoot).digest("hex").slice(0, 12);
|
|
@@ -1926,6 +2125,377 @@ function createGlobalMailbox(options) {
|
|
|
1926
2125
|
return new GlobalMailbox(options.projectDir, options.events, options.hqPublisher);
|
|
1927
2126
|
}
|
|
1928
2127
|
|
|
1929
|
-
|
|
2128
|
+
// src/hq/agent-bridge.ts
|
|
2129
|
+
function startAgentMonitorEventBridge(opts) {
|
|
2130
|
+
const { events, clientId, projectId, publish } = opts;
|
|
2131
|
+
const seq = { current: 0 };
|
|
2132
|
+
function nextSeq() {
|
|
2133
|
+
seq.current += 1;
|
|
2134
|
+
return seq.current;
|
|
2135
|
+
}
|
|
2136
|
+
function buildEnvelope(type, payload) {
|
|
2137
|
+
return createHqEventEnvelope({
|
|
2138
|
+
id: `${Date.now().toString(36)}-${nextSeq()}`,
|
|
2139
|
+
type,
|
|
2140
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2141
|
+
clientId,
|
|
2142
|
+
projectId,
|
|
2143
|
+
seq: nextSeq(),
|
|
2144
|
+
payload
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
const offMessage = events.on("agent.timeline.message", (payload) => {
|
|
2148
|
+
if (!publish) return;
|
|
2149
|
+
const msgPayload = {
|
|
2150
|
+
subagentId: payload.subagentId,
|
|
2151
|
+
agentName: payload.agentName,
|
|
2152
|
+
content: payload.content,
|
|
2153
|
+
kind: payload.kind,
|
|
2154
|
+
iteration: payload.iteration,
|
|
2155
|
+
ts: payload.ts
|
|
2156
|
+
};
|
|
2157
|
+
if (payload.toolName !== void 0) msgPayload.toolName = payload.toolName;
|
|
2158
|
+
if (payload.costUsd !== void 0) msgPayload.costUsd = payload.costUsd;
|
|
2159
|
+
publish(buildEnvelope("agent.message", msgPayload));
|
|
2160
|
+
});
|
|
2161
|
+
const offStatus = events.on("agent.status_changed", (payload) => {
|
|
2162
|
+
if (!publish) return;
|
|
2163
|
+
const statusPayload = {
|
|
2164
|
+
subagentId: payload.subagentId,
|
|
2165
|
+
agentName: payload.agentName,
|
|
2166
|
+
status: payload.status,
|
|
2167
|
+
ts: payload.ts
|
|
2168
|
+
};
|
|
2169
|
+
if (payload.summary !== void 0) statusPayload.summary = payload.summary;
|
|
2170
|
+
if (payload.task !== void 0) statusPayload.task = payload.task;
|
|
2171
|
+
publish(buildEnvelope("agent.status", statusPayload));
|
|
2172
|
+
});
|
|
2173
|
+
return () => {
|
|
2174
|
+
offMessage();
|
|
2175
|
+
offStatus();
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
// src/hq/transcript-mapper.ts
|
|
2180
|
+
function blocksToText(content) {
|
|
2181
|
+
if (typeof content === "string") return content;
|
|
2182
|
+
if (Array.isArray(content)) {
|
|
2183
|
+
return content.filter(
|
|
2184
|
+
(b) => !!b && typeof b === "object" && b.type === "text" && typeof b.text === "string"
|
|
2185
|
+
).map((b) => b.text).join("\n");
|
|
2186
|
+
}
|
|
2187
|
+
return "";
|
|
2188
|
+
}
|
|
2189
|
+
function asString(v) {
|
|
2190
|
+
if (typeof v === "string") return v;
|
|
2191
|
+
try {
|
|
2192
|
+
return JSON.stringify(v, null, 2);
|
|
2193
|
+
} catch {
|
|
2194
|
+
return String(v);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
function argsEntry(ts, name, input, id) {
|
|
2198
|
+
return {
|
|
2199
|
+
ts,
|
|
2200
|
+
role: "tool",
|
|
2201
|
+
tool: String(name ?? "tool"),
|
|
2202
|
+
toolInput: input !== void 0 && input !== null ? asString(input) : "{}",
|
|
2203
|
+
text: "",
|
|
2204
|
+
...typeof id === "string" ? { toolUseId: id } : {}
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
function mapSessionEventToEntries(ev) {
|
|
2208
|
+
const ts = typeof ev["ts"] === "string" ? ev["ts"] : "";
|
|
2209
|
+
const make = (role, text, extra) => ({
|
|
2210
|
+
ts,
|
|
2211
|
+
role,
|
|
2212
|
+
text,
|
|
2213
|
+
...extra
|
|
2214
|
+
});
|
|
2215
|
+
switch (ev["type"]) {
|
|
2216
|
+
case "user_input": {
|
|
2217
|
+
const t = blocksToText(ev["content"]);
|
|
2218
|
+
return t.trim() ? [make("user", t)] : [];
|
|
2219
|
+
}
|
|
2220
|
+
case "llm_response": {
|
|
2221
|
+
const out = [];
|
|
2222
|
+
const t = blocksToText(ev["content"]);
|
|
2223
|
+
if (t.trim()) out.push(make("assistant", t));
|
|
2224
|
+
const content = ev["content"];
|
|
2225
|
+
if (Array.isArray(content)) {
|
|
2226
|
+
for (const b of content) {
|
|
2227
|
+
if (b && typeof b === "object" && b.type === "tool_use") {
|
|
2228
|
+
const block = b;
|
|
2229
|
+
out.push(argsEntry(ts, block.name, block.input, block.id));
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return out;
|
|
2234
|
+
}
|
|
2235
|
+
case "tool_use":
|
|
2236
|
+
return [argsEntry(ts, ev["name"], ev["input"], ev["id"])];
|
|
2237
|
+
case "tool_call_start":
|
|
2238
|
+
return [argsEntry(ts, ev["name"], ev["input"] ?? ev["args"], ev["id"])];
|
|
2239
|
+
case "tool_result": {
|
|
2240
|
+
const isError = ev["isError"] === true;
|
|
2241
|
+
const content = ev["content"] ?? ev["output"];
|
|
2242
|
+
const outStr = content !== void 0 && content !== null ? asString(content) : "";
|
|
2243
|
+
return [
|
|
2244
|
+
make(isError ? "error" : "tool", outStr, {
|
|
2245
|
+
tool: "\u21B3 result",
|
|
2246
|
+
...isError ? { isError: true } : {},
|
|
2247
|
+
...typeof ev["id"] === "string" ? { toolUseId: ev["id"] } : {}
|
|
2248
|
+
})
|
|
2249
|
+
];
|
|
2250
|
+
}
|
|
2251
|
+
case "tool_call_end": {
|
|
2252
|
+
const isError = ev["isError"] === true;
|
|
2253
|
+
const content = ev["output"] ?? ev["content"];
|
|
2254
|
+
const outStr = content !== void 0 && content !== null ? asString(content) : "";
|
|
2255
|
+
if (!outStr.trim() && !isError && typeof ev["durationMs"] !== "number") return [];
|
|
2256
|
+
return [
|
|
2257
|
+
make(isError ? "error" : "tool", outStr, {
|
|
2258
|
+
tool: typeof ev["name"] === "string" ? String(ev["name"]) : "\u21B3 result",
|
|
2259
|
+
...typeof ev["durationMs"] === "number" ? { durationMs: ev["durationMs"] } : {},
|
|
2260
|
+
...isError ? { isError: true } : {},
|
|
2261
|
+
...typeof ev["id"] === "string" ? { toolUseId: ev["id"] } : {}
|
|
2262
|
+
})
|
|
2263
|
+
];
|
|
2264
|
+
}
|
|
2265
|
+
case "error":
|
|
2266
|
+
case "provider_error":
|
|
2267
|
+
return [make("error", String(ev["message"] ?? "error"))];
|
|
2268
|
+
case "agent_spawned":
|
|
2269
|
+
return [make("system", `spawned ${String(ev["role"] ?? "agent")}`)];
|
|
2270
|
+
case "task_completed":
|
|
2271
|
+
return [make("system", `task done: ${String(ev["title"] ?? "")}`)];
|
|
2272
|
+
case "task_failed":
|
|
2273
|
+
return [make("system", `task failed: ${String(ev["title"] ?? "")}`)];
|
|
2274
|
+
default:
|
|
2275
|
+
return [];
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
function isResultEntry(e) {
|
|
2279
|
+
return (e.role === "tool" || e.role === "error") && e.toolUseId !== void 0 && e.toolInput === void 0;
|
|
2280
|
+
}
|
|
2281
|
+
function mergeToolResults(flat) {
|
|
2282
|
+
const out = [];
|
|
2283
|
+
const argsById = /* @__PURE__ */ new Map();
|
|
2284
|
+
for (const src of flat) {
|
|
2285
|
+
const e = { ...src };
|
|
2286
|
+
if (isResultEntry(e) && e.toolUseId !== void 0) {
|
|
2287
|
+
const tgt = argsById.get(e.toolUseId);
|
|
2288
|
+
if (tgt) {
|
|
2289
|
+
tgt.text = e.text || "";
|
|
2290
|
+
if (e.durationMs !== void 0) tgt.durationMs = e.durationMs;
|
|
2291
|
+
if (e.isError) {
|
|
2292
|
+
tgt.role = "error";
|
|
2293
|
+
tgt.isError = true;
|
|
2294
|
+
}
|
|
2295
|
+
continue;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
out.push(e);
|
|
2299
|
+
if (e.role === "tool" && e.toolUseId !== void 0 && e.toolInput !== void 0) {
|
|
2300
|
+
argsById.set(e.toolUseId, e);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
return out;
|
|
2304
|
+
}
|
|
2305
|
+
function buildTranscriptFromEvents(events) {
|
|
2306
|
+
const flat = [];
|
|
2307
|
+
for (const ev of events) {
|
|
2308
|
+
for (const e of mapSessionEventToEntries(ev)) flat.push(e);
|
|
2309
|
+
}
|
|
2310
|
+
return mergeToolResults(flat);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
// src/hq/session-bridge.ts
|
|
2314
|
+
var VALID_AGENT_STATUS = /* @__PURE__ */ new Set([
|
|
2315
|
+
"idle",
|
|
2316
|
+
"running",
|
|
2317
|
+
"streaming",
|
|
2318
|
+
"waiting_user",
|
|
2319
|
+
"error"
|
|
2320
|
+
]);
|
|
2321
|
+
function toAgentSummary(a) {
|
|
2322
|
+
const status = VALID_AGENT_STATUS.has(a.status) ? a.status : "idle";
|
|
2323
|
+
return {
|
|
2324
|
+
id: a.id,
|
|
2325
|
+
name: a.name,
|
|
2326
|
+
status,
|
|
2327
|
+
iterations: a.iterations,
|
|
2328
|
+
toolCalls: a.toolCalls,
|
|
2329
|
+
lastActivityAt: a.lastActivityAt,
|
|
2330
|
+
...a.currentTool !== void 0 ? { currentTool: a.currentTool } : {},
|
|
2331
|
+
...a.costUsd !== void 0 ? { costUsd: a.costUsd } : {},
|
|
2332
|
+
...a.tokensIn !== void 0 ? { tokensIn: a.tokensIn } : {},
|
|
2333
|
+
...a.tokensOut !== void 0 ? { tokensOut: a.tokensOut } : {},
|
|
2334
|
+
...a.ctxPct !== void 0 ? { ctxPct: a.ctxPct } : {},
|
|
2335
|
+
...a.model !== void 0 ? { model: a.model } : {},
|
|
2336
|
+
...a.partialText !== void 0 ? { partialText: a.partialText } : {}
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
function deriveSessionStatus(agents) {
|
|
2340
|
+
return agents.some(
|
|
2341
|
+
(a) => a.status === "running" || a.status === "streaming" || a.status === "waiting_user"
|
|
2342
|
+
) ? "active" : "idle";
|
|
2343
|
+
}
|
|
2344
|
+
function startSessionTelemetryBridge(opts) {
|
|
2345
|
+
const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
2346
|
+
const publisher = opts.publisher;
|
|
2347
|
+
const identity = publisher.identity;
|
|
2348
|
+
const project = publisher.project;
|
|
2349
|
+
const startedAt = opts.startedAt ?? now();
|
|
2350
|
+
const wpaths = resolveWstackPaths({
|
|
2351
|
+
projectRoot: opts.projectRoot,
|
|
2352
|
+
...opts.globalRoot !== void 0 ? { globalRoot: opts.globalRoot } : {}
|
|
2353
|
+
});
|
|
2354
|
+
const sessionFile = path2.join(wpaths.projectSessions, `${opts.sessionId}.jsonl`);
|
|
2355
|
+
let agents = [];
|
|
2356
|
+
let lastActivityAt = startedAt;
|
|
2357
|
+
let lastSnapshotHash = "";
|
|
2358
|
+
let disposed = false;
|
|
2359
|
+
function buildSnapshot() {
|
|
2360
|
+
return {
|
|
2361
|
+
sessionId: opts.sessionId,
|
|
2362
|
+
clientKind: identity.kind,
|
|
2363
|
+
machineId: identity.machineId,
|
|
2364
|
+
projectId: project.projectId,
|
|
2365
|
+
projectName: opts.projectName ?? project.projectName,
|
|
2366
|
+
projectRoot: opts.projectRoot,
|
|
2367
|
+
status: deriveSessionStatus(agents),
|
|
2368
|
+
startedAt,
|
|
2369
|
+
lastActivityAt,
|
|
2370
|
+
agentCount: agents.length,
|
|
2371
|
+
agents,
|
|
2372
|
+
...identity.hostname !== void 0 ? { hostname: identity.hostname } : {},
|
|
2373
|
+
...identity.pid !== void 0 ? { pid: identity.pid } : {},
|
|
2374
|
+
...opts.gitBranch !== void 0 ? { gitBranch: opts.gitBranch } : {}
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
function publishSnapshot(force = false) {
|
|
2378
|
+
if (disposed) return;
|
|
2379
|
+
const snap = buildSnapshot();
|
|
2380
|
+
const hash = JSON.stringify({ ...snap, lastActivityAt: "" });
|
|
2381
|
+
if (!force && hash === lastSnapshotHash) return;
|
|
2382
|
+
lastSnapshotHash = hash;
|
|
2383
|
+
try {
|
|
2384
|
+
publisher.publishSessionSnapshot(snap);
|
|
2385
|
+
} catch {
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
const offAgents = opts.events?.on("session.agents_updated", (payload) => {
|
|
2389
|
+
agents = payload.agents.map(toAgentSummary);
|
|
2390
|
+
lastActivityAt = now();
|
|
2391
|
+
publishSnapshot();
|
|
2392
|
+
});
|
|
2393
|
+
publishSnapshot(true);
|
|
2394
|
+
let offset = 0;
|
|
2395
|
+
let partial = "";
|
|
2396
|
+
let seqEmitted = 0;
|
|
2397
|
+
let tailing = false;
|
|
2398
|
+
let watcher = null;
|
|
2399
|
+
let watchPending = false;
|
|
2400
|
+
function setupWatcher() {
|
|
2401
|
+
if (disposed || watcher) return;
|
|
2402
|
+
try {
|
|
2403
|
+
const nextWatcher = syncFs.watch(sessionFile, () => {
|
|
2404
|
+
if (watchPending || disposed) return;
|
|
2405
|
+
watchPending = true;
|
|
2406
|
+
setTimeout(() => {
|
|
2407
|
+
watchPending = false;
|
|
2408
|
+
void tail();
|
|
2409
|
+
}, 25);
|
|
2410
|
+
});
|
|
2411
|
+
nextWatcher.on("error", () => {
|
|
2412
|
+
try {
|
|
2413
|
+
nextWatcher.close();
|
|
2414
|
+
} catch {
|
|
2415
|
+
}
|
|
2416
|
+
if (watcher === nextWatcher) watcher = null;
|
|
2417
|
+
});
|
|
2418
|
+
watcher = nextWatcher;
|
|
2419
|
+
} catch {
|
|
2420
|
+
watcher = null;
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
async function tail() {
|
|
2424
|
+
if (disposed || tailing) return;
|
|
2425
|
+
tailing = true;
|
|
2426
|
+
try {
|
|
2427
|
+
const stat4 = await fsp.stat(sessionFile).catch(() => null);
|
|
2428
|
+
if (disposed) return;
|
|
2429
|
+
if (!stat4) return;
|
|
2430
|
+
setupWatcher();
|
|
2431
|
+
if (stat4.size <= offset) return;
|
|
2432
|
+
const fd = await fsp.open(sessionFile, "r");
|
|
2433
|
+
try {
|
|
2434
|
+
if (disposed) return;
|
|
2435
|
+
const len = stat4.size - offset;
|
|
2436
|
+
const buf = Buffer.allocUnsafe(len);
|
|
2437
|
+
await fd.read(buf, 0, len, offset);
|
|
2438
|
+
offset = stat4.size;
|
|
2439
|
+
partial += buf.toString("utf8");
|
|
2440
|
+
const lines = partial.split("\n");
|
|
2441
|
+
partial = lines.pop() ?? "";
|
|
2442
|
+
const entries = [];
|
|
2443
|
+
for (const line of lines) {
|
|
2444
|
+
const trimmed = line.trim();
|
|
2445
|
+
if (!trimmed) continue;
|
|
2446
|
+
let obj;
|
|
2447
|
+
try {
|
|
2448
|
+
obj = JSON.parse(trimmed);
|
|
2449
|
+
} catch {
|
|
2450
|
+
continue;
|
|
2451
|
+
}
|
|
2452
|
+
for (const entry of mapSessionEventToEntries(obj)) entries.push(entry);
|
|
2453
|
+
}
|
|
2454
|
+
if (entries.length > 0) {
|
|
2455
|
+
try {
|
|
2456
|
+
publisher.publishTranscriptAppend({
|
|
2457
|
+
sessionId: opts.sessionId,
|
|
2458
|
+
fromSeq: seqEmitted,
|
|
2459
|
+
entries
|
|
2460
|
+
});
|
|
2461
|
+
} catch {
|
|
2462
|
+
}
|
|
2463
|
+
seqEmitted += entries.length;
|
|
2464
|
+
lastActivityAt = now();
|
|
2465
|
+
}
|
|
2466
|
+
} finally {
|
|
2467
|
+
await fd.close();
|
|
2468
|
+
}
|
|
2469
|
+
} catch {
|
|
2470
|
+
} finally {
|
|
2471
|
+
tailing = false;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
const snapshotTimer = setInterval(() => publishSnapshot(true), opts.snapshotIntervalMs ?? 2500);
|
|
2475
|
+
const tailTimer = setInterval(() => void tail(), opts.transcriptIntervalMs ?? 500);
|
|
2476
|
+
snapshotTimer.unref?.();
|
|
2477
|
+
tailTimer.unref?.();
|
|
2478
|
+
void tail();
|
|
2479
|
+
return () => {
|
|
2480
|
+
if (disposed) return;
|
|
2481
|
+
disposed = true;
|
|
2482
|
+
offAgents?.();
|
|
2483
|
+
if (watcher) {
|
|
2484
|
+
try {
|
|
2485
|
+
watcher.close();
|
|
2486
|
+
} catch {
|
|
2487
|
+
}
|
|
2488
|
+
watcher = null;
|
|
2489
|
+
}
|
|
2490
|
+
clearInterval(snapshotTimer);
|
|
2491
|
+
clearInterval(tailTimer);
|
|
2492
|
+
try {
|
|
2493
|
+
publisher.publishSessionEnded({ sessionId: opts.sessionId, endedAt: now() });
|
|
2494
|
+
} catch {
|
|
2495
|
+
}
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
export { DEFAULT_HQ_REDACTION_POLICY, HQ_AUTH_FILE_VERSION, HQ_PROTOCOL_VERSION, HqPublisher, buildTranscriptFromEvents, createGlobalMailbox, createHqEventEnvelope, createHqPublisherFromEnv, createMailboxEventPayload, createMailboxSnapshotPayload, createMailboxSnapshotPayloadFromMailbox, defaultHqDataDir, emptyHqAuthFile, ensureHqFirstRunAuthFile, hqAuthFilePath, hqRuntimeFilePath, mapMailboxAgentToHqSummary, mapMailboxMessageToHqSummary, mapSessionEventToEntries, mergeToolResults, mintHqBrowserToken, mintHqToken, mutateHqAuthFile, parseHqEventPayload, parseHqFrame, readHqAuthFile, readHqRuntimeFileSync, redactHqEvent, redactHqValue, resolveHqConfig, resolveHqConfigFromEnv, resolveHqDataDir, scrubAndTruncateHqPreview, startAgentMonitorEventBridge, startSessionTelemetryBridge, summarizeHqToolArgs, watchHqAuthFile, writeHqAuthFile, writeHqRuntimeFile };
|
|
1930
2500
|
//# sourceMappingURL=index.js.map
|
|
1931
2501
|
//# sourceMappingURL=index.js.map
|