chainlesschain 0.45.12 → 0.45.19
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AppLayout-BfLjLMsm.js → AppLayout-B00RARl2.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DP7PO9Li.js → Chat-DXtvKoM0.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-DyQF-7R1.js → Cron-BJ4ODHOy.js} +1 -1
- package/src/assets/web-panel/assets/Dashboard-3iIpp3zd.js +3 -0
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
- package/src/assets/web-panel/assets/{Logs-BOii-AoO.js → Logs-CSeKZEG_.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DmiJtJYr.js → McpTools-BYQAK11r.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-CDRMMobU.js → Memory-gkUAPyuZ.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CVhqqoS1.js → Notes-bjNrQgAo.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Dkt7021l.js → Providers-Dbf57Tbv.js} +1 -1
- package/src/assets/web-panel/assets/{Services-DUDL_UGb.js → Services-CS0oMdxh.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DXXELJc3.js → Skills-B2fgruv8.js} +1 -1
- package/src/assets/web-panel/assets/Tasks-BJjN_YEm.css +1 -0
- package/src/assets/web-panel/assets/Tasks-qULws8pc.js +1 -0
- package/src/assets/web-panel/assets/chat-DnH09sSR.js +1 -0
- package/src/assets/web-panel/assets/{index-vW799KpE.js → index-CF2CqPYX.js} +2 -2
- package/src/assets/web-panel/assets/ws-DjelKkD6.js +1 -0
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +7 -8
- package/src/commands/chat.js +9 -11
- package/src/commands/serve.js +11 -106
- package/src/commands/session.js +101 -0
- package/src/commands/ui.js +10 -151
- package/src/gateways/repl/agent-repl.js +1 -0
- package/src/gateways/repl/chat-repl.js +1 -0
- package/src/gateways/ui/web-ui-server.js +1 -0
- package/src/gateways/ws/action-protocol.js +83 -0
- package/src/gateways/ws/message-dispatcher.js +73 -0
- package/src/gateways/ws/session-protocol.js +396 -0
- package/src/gateways/ws/task-protocol.js +55 -0
- package/src/gateways/ws/worktree-protocol.js +315 -0
- package/src/gateways/ws/ws-server.js +4 -0
- package/src/gateways/ws/ws-session-gateway.js +1 -0
- package/src/harness/background-task-manager.js +506 -0
- package/src/harness/background-task-worker.js +48 -0
- package/src/harness/compression-telemetry.js +214 -0
- package/src/harness/feature-flags.js +157 -0
- package/src/harness/jsonl-session-store.js +452 -0
- package/src/harness/prompt-compressor.js +416 -0
- package/src/harness/worktree-isolator.js +845 -0
- package/src/lib/agent-core.js +246 -45
- package/src/lib/background-task-manager.js +1 -305
- package/src/lib/background-task-worker.js +1 -50
- package/src/lib/compression-telemetry.js +5 -0
- package/src/lib/feature-flags.js +7 -182
- package/src/lib/interaction-adapter.js +32 -6
- package/src/lib/jsonl-session-store.js +21 -237
- package/src/lib/prompt-compressor.js +10 -481
- package/src/lib/sub-agent-context.js +21 -1
- package/src/lib/worktree-isolator.js +13 -231
- package/src/lib/ws-agent-handler.js +1 -0
- package/src/lib/ws-server.js +138 -387
- package/src/lib/ws-session-manager.js +82 -1
- package/src/repl/agent-repl.js +11 -0
- package/src/runtime/agent-runtime.js +417 -0
- package/src/runtime/contracts/agent-turn.js +11 -0
- package/src/runtime/contracts/session-record.js +31 -0
- package/src/runtime/contracts/task-record.js +18 -0
- package/src/runtime/contracts/telemetry-record.js +23 -0
- package/src/runtime/contracts/worktree-record.js +14 -0
- package/src/runtime/index.js +13 -0
- package/src/runtime/policies/agent-policy.js +45 -0
- package/src/runtime/runtime-context.js +14 -0
- package/src/runtime/runtime-events.js +37 -0
- package/src/runtime/runtime-factory.js +50 -0
- package/src/tools/index.js +22 -0
- package/src/tools/legacy-agent-tools.js +171 -0
- package/src/tools/registry.js +141 -0
- package/src/tools/tool-context.js +28 -0
- package/src/tools/tool-permissions.js +28 -0
- package/src/tools/tool-telemetry.js +39 -0
- package/src/assets/web-panel/assets/Dashboard-BGGdnr6t.js +0 -3
- package/src/assets/web-panel/assets/Dashboard-CRFnDUFh.css +0 -1
- package/src/assets/web-panel/assets/Tasks-BwZ63-mq.js +0 -1
- package/src/assets/web-panel/assets/Tasks-Cr_XXNyQ.css +0 -1
- package/src/assets/web-panel/assets/chat-C_hu-qNs.js +0 -1
- package/src/assets/web-panel/assets/ws-DwluTqT5.js +0 -1
|
@@ -1,237 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import { createHash } from "node:crypto";
|
|
23
|
-
import { getHomeDir } from "./paths.js";
|
|
24
|
-
|
|
25
|
-
function getSessionsDir() {
|
|
26
|
-
const dir = join(getHomeDir(), "sessions");
|
|
27
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
28
|
-
return dir;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function sessionPath(sessionId) {
|
|
32
|
-
return join(getSessionsDir(), `${sessionId}.jsonl`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ── Write operations ────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Append a single event to the session log.
|
|
39
|
-
* User messages are written synchronously for crash recovery.
|
|
40
|
-
*/
|
|
41
|
-
export function appendEvent(sessionId, type, data) {
|
|
42
|
-
const line = JSON.stringify({ type, timestamp: Date.now(), data }) + "\n";
|
|
43
|
-
appendFileSync(sessionPath(sessionId), line, "utf-8");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Start a new session (writes session_start event).
|
|
48
|
-
*/
|
|
49
|
-
export function startSession(sessionId, meta = {}) {
|
|
50
|
-
const id =
|
|
51
|
-
sessionId ||
|
|
52
|
-
`session-${Date.now()}-${createHash("sha256").update(Math.random().toString()).digest("hex").slice(0, 6)}`;
|
|
53
|
-
|
|
54
|
-
appendEvent(id, "session_start", {
|
|
55
|
-
title: meta.title || "Untitled",
|
|
56
|
-
provider: meta.provider || "",
|
|
57
|
-
model: meta.model || "",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
return id;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Append a user message (synchronous write for crash recovery).
|
|
65
|
-
*/
|
|
66
|
-
export function appendUserMessage(sessionId, content) {
|
|
67
|
-
appendEvent(sessionId, "user_message", { role: "user", content });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Append an assistant message.
|
|
72
|
-
*/
|
|
73
|
-
export function appendAssistantMessage(sessionId, content) {
|
|
74
|
-
appendEvent(sessionId, "assistant_message", { role: "assistant", content });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Append a tool call event.
|
|
79
|
-
*/
|
|
80
|
-
export function appendToolCall(sessionId, toolName, args) {
|
|
81
|
-
appendEvent(sessionId, "tool_call", { tool: toolName, args });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Append a tool result event.
|
|
86
|
-
*/
|
|
87
|
-
export function appendToolResult(sessionId, toolName, result) {
|
|
88
|
-
appendEvent(sessionId, "tool_result", { tool: toolName, result });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Append a compact event (context was compressed).
|
|
93
|
-
*/
|
|
94
|
-
export function appendCompactEvent(sessionId, stats) {
|
|
95
|
-
appendEvent(sessionId, "compact", stats);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ── Read operations ─────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Read all events from a session file.
|
|
102
|
-
* @returns {Array<{type, timestamp, data}>}
|
|
103
|
-
*/
|
|
104
|
-
export function readEvents(sessionId) {
|
|
105
|
-
const filePath = sessionPath(sessionId);
|
|
106
|
-
if (!existsSync(filePath)) return [];
|
|
107
|
-
|
|
108
|
-
const content = readFileSync(filePath, "utf-8");
|
|
109
|
-
const events = [];
|
|
110
|
-
|
|
111
|
-
for (const line of content.split("\n")) {
|
|
112
|
-
if (!line.trim()) continue;
|
|
113
|
-
try {
|
|
114
|
-
events.push(JSON.parse(line));
|
|
115
|
-
} catch (_e) {
|
|
116
|
-
// Skip malformed lines
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return events;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Reconstruct messages array from JSONL events (for API calls).
|
|
125
|
-
* Skips compact events and rebuilds the current conversation state.
|
|
126
|
-
*/
|
|
127
|
-
export function rebuildMessages(sessionId) {
|
|
128
|
-
const events = readEvents(sessionId);
|
|
129
|
-
const messages = [];
|
|
130
|
-
let lastCompactIndex = -1;
|
|
131
|
-
|
|
132
|
-
// Find the last compact event (start from there)
|
|
133
|
-
for (let i = events.length - 1; i >= 0; i--) {
|
|
134
|
-
if (events[i].type === "compact" && events[i].data.messages) {
|
|
135
|
-
lastCompactIndex = i;
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (lastCompactIndex >= 0 && events[lastCompactIndex].data.messages) {
|
|
141
|
-
messages.push(...events[lastCompactIndex].data.messages);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Replay events after last compact
|
|
145
|
-
const startIndex = lastCompactIndex >= 0 ? lastCompactIndex + 1 : 0;
|
|
146
|
-
|
|
147
|
-
for (let i = startIndex; i < events.length; i++) {
|
|
148
|
-
const event = events[i];
|
|
149
|
-
if (
|
|
150
|
-
event.type === "user_message" ||
|
|
151
|
-
event.type === "assistant_message" ||
|
|
152
|
-
event.type === "system"
|
|
153
|
-
) {
|
|
154
|
-
messages.push(event.data);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return messages;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* List all sessions (reads session_start events from all .jsonl files).
|
|
163
|
-
*/
|
|
164
|
-
export function listJsonlSessions(options = {}) {
|
|
165
|
-
const dir = getSessionsDir();
|
|
166
|
-
if (!existsSync(dir)) return [];
|
|
167
|
-
|
|
168
|
-
const limit = options.limit || 20;
|
|
169
|
-
const files = readdirSync(dir)
|
|
170
|
-
.filter((f) => f.endsWith(".jsonl"))
|
|
171
|
-
.map((f) => {
|
|
172
|
-
const id = basename(f, ".jsonl");
|
|
173
|
-
const events = readEvents(id);
|
|
174
|
-
const startEvent = events.find((e) => e.type === "session_start");
|
|
175
|
-
const lastEvent = events[events.length - 1];
|
|
176
|
-
const messageCount = events.filter(
|
|
177
|
-
(e) => e.type === "user_message" || e.type === "assistant_message",
|
|
178
|
-
).length;
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
id,
|
|
182
|
-
title: startEvent?.data?.title || "Untitled",
|
|
183
|
-
provider: startEvent?.data?.provider || "",
|
|
184
|
-
model: startEvent?.data?.model || "",
|
|
185
|
-
message_count: messageCount,
|
|
186
|
-
created_at: startEvent
|
|
187
|
-
? new Date(startEvent.timestamp).toISOString()
|
|
188
|
-
: "",
|
|
189
|
-
updated_at: lastEvent
|
|
190
|
-
? new Date(lastEvent.timestamp).toISOString()
|
|
191
|
-
: "",
|
|
192
|
-
};
|
|
193
|
-
})
|
|
194
|
-
.sort((a, b) => (b.updated_at > a.updated_at ? 1 : -1))
|
|
195
|
-
.slice(0, limit);
|
|
196
|
-
|
|
197
|
-
return files;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Fork a session — copies all events to a new session ID.
|
|
202
|
-
*/
|
|
203
|
-
export function forkSession(sourceId) {
|
|
204
|
-
const events = readEvents(sourceId);
|
|
205
|
-
if (events.length === 0) return null;
|
|
206
|
-
|
|
207
|
-
const newId = `session-${Date.now()}-${createHash("sha256").update(Math.random().toString()).digest("hex").slice(0, 6)}`;
|
|
208
|
-
const filePath = sessionPath(newId);
|
|
209
|
-
|
|
210
|
-
for (const event of events) {
|
|
211
|
-
const line = JSON.stringify(event) + "\n";
|
|
212
|
-
appendFileSync(filePath, line, "utf-8");
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Mark the fork
|
|
216
|
-
appendEvent(newId, "system", {
|
|
217
|
-
role: "system",
|
|
218
|
-
content: `[Forked from session ${sourceId}]`,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
return newId;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Check if a JSONL session exists.
|
|
226
|
-
*/
|
|
227
|
-
export function sessionExists(sessionId) {
|
|
228
|
-
return existsSync(sessionPath(sessionId));
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Get the most recent session ID (for --continue).
|
|
233
|
-
*/
|
|
234
|
-
export function getLastSessionId() {
|
|
235
|
-
const sessions = listJsonlSessions({ limit: 1 });
|
|
236
|
-
return sessions.length > 0 ? sessions[0].id : null;
|
|
237
|
-
}
|
|
1
|
+
export {
|
|
2
|
+
appendEvent,
|
|
3
|
+
startSession,
|
|
4
|
+
appendUserMessage,
|
|
5
|
+
appendAssistantMessage,
|
|
6
|
+
appendToolCall,
|
|
7
|
+
appendToolResult,
|
|
8
|
+
appendCompactEvent,
|
|
9
|
+
readEvents,
|
|
10
|
+
rebuildMessages,
|
|
11
|
+
listJsonlSessions,
|
|
12
|
+
forkSession,
|
|
13
|
+
sessionExists,
|
|
14
|
+
getLastSessionId,
|
|
15
|
+
migrateLegacySessions,
|
|
16
|
+
migrateLegacySessionsBatch,
|
|
17
|
+
migrateLegacySessionFile,
|
|
18
|
+
validateJsonlSession,
|
|
19
|
+
validateAllJsonlSessions,
|
|
20
|
+
sampleMigratedSessionsValidation,
|
|
21
|
+
} from "../harness/jsonl-session-store.js";
|