koneck 2.25.76 → 2.27.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/doctor.d.ts +15 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +28 -8
- package/dist/doctor.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +4 -1
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -4
- package/dist/index.js.map +1 -1
- package/dist/ink-chat.d.ts +10 -0
- package/dist/ink-chat.d.ts.map +1 -1
- package/dist/ink-chat.js +156 -22
- package/dist/ink-chat.js.map +1 -1
- package/dist/quality-gate.d.ts +5 -1
- package/dist/quality-gate.d.ts.map +1 -1
- package/dist/quality-gate.js +8 -6
- package/dist/quality-gate.js.map +1 -1
- package/dist/session.d.ts +10 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +12 -1
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/web/api.d.ts +31 -0
- package/dist/web/api.d.ts.map +1 -0
- package/dist/web/api.js +295 -0
- package/dist/web/api.js.map +1 -0
- package/dist/web/changes.d.ts +55 -0
- package/dist/web/changes.d.ts.map +1 -0
- package/dist/web/changes.js +215 -0
- package/dist/web/changes.js.map +1 -0
- package/dist/web/events.d.ts +172 -0
- package/dist/web/events.d.ts.map +1 -0
- package/dist/web/events.js +52 -0
- package/dist/web/events.js.map +1 -0
- package/dist/web/history.d.ts +61 -0
- package/dist/web/history.d.ts.map +1 -0
- package/dist/web/history.js +197 -0
- package/dist/web/history.js.map +1 -0
- package/dist/web/mark.d.ts +15 -0
- package/dist/web/mark.d.ts.map +1 -0
- package/dist/web/mark.js +15 -0
- package/dist/web/mark.js.map +1 -0
- package/dist/web/sessions.d.ts +82 -0
- package/dist/web/sessions.d.ts.map +1 -0
- package/dist/web/sessions.js +197 -0
- package/dist/web/sessions.js.map +1 -0
- package/dist/web/ui-client.d.ts +14 -0
- package/dist/web/ui-client.d.ts.map +1 -0
- package/dist/web/ui-client.js +0 -0
- package/dist/web/ui-client.js.map +1 -0
- package/dist/web/ui-css.d.ts +15 -0
- package/dist/web/ui-css.d.ts.map +1 -0
- package/dist/web/ui-css.js +284 -0
- package/dist/web/ui-css.js.map +1 -0
- package/dist/web/ui.d.ts +11 -0
- package/dist/web/ui.d.ts.map +1 -0
- package/dist/web/ui.js +116 -0
- package/dist/web/ui.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions already on disk, read back as something a browser can show.
|
|
3
|
+
*
|
|
4
|
+
* Every CLI run writes a JSONL transcript into `.koneck/sessions`, and until now the web side
|
|
5
|
+
* listed their titles and could do nothing with them. That is the larger half of what a harness is
|
|
6
|
+
* for: most of the value is in looking at a run that has already happened — what it did, in what
|
|
7
|
+
* order, and where the time went — and none of that needs an agent to be running.
|
|
8
|
+
*
|
|
9
|
+
* The file is the record, so this only reads. A past session cannot be resumed from the browser
|
|
10
|
+
* because resuming is what the CLI does, and pretending otherwise would produce a second live
|
|
11
|
+
* session pointed at the same transcript.
|
|
12
|
+
*/
|
|
13
|
+
import { readdir, readFile, stat } from 'fs/promises';
|
|
14
|
+
import { existsSync } from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { redactSecrets } from '../redact.js';
|
|
17
|
+
import { summarise } from '../trajectory.js';
|
|
18
|
+
const SESSION_DIR = (cwd) => path.join(cwd, '.koneck', 'sessions');
|
|
19
|
+
/** A transcript longer than this is read to here and the rest reported as omitted. */
|
|
20
|
+
export const MAX_ENTRIES = 600;
|
|
21
|
+
/** Only the first line of each file is read: it holds the metadata. */
|
|
22
|
+
export async function listPast(cwd, limit = 60) {
|
|
23
|
+
const dir = SESSION_DIR(cwd);
|
|
24
|
+
if (!existsSync(dir))
|
|
25
|
+
return [];
|
|
26
|
+
let files;
|
|
27
|
+
try {
|
|
28
|
+
files = (await readdir(dir)).filter(f => f.endsWith('.jsonl')).sort().reverse().slice(0, limit);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
try {
|
|
36
|
+
const full = path.join(dir, file);
|
|
37
|
+
const info = await stat(full);
|
|
38
|
+
// Reading the whole file to get one line is wasteful on a large transcript, but a session
|
|
39
|
+
// file is kilobytes and the alternative is a streaming line reader for no gain.
|
|
40
|
+
const first = (await readFile(full, 'utf8')).split('\n', 1)[0] ?? '';
|
|
41
|
+
const parsed = JSON.parse(first);
|
|
42
|
+
const meta = (parsed.data ?? parsed);
|
|
43
|
+
out.push({
|
|
44
|
+
file,
|
|
45
|
+
id: String(meta['id'] ?? file.replace(/\.jsonl$/, '')),
|
|
46
|
+
// Redacted on the way out. A task line is whatever the user typed, and a key pasted into
|
|
47
|
+
// the composer once became exactly this field.
|
|
48
|
+
task: redactSecrets(String(meta['task'] ?? '(no description)')).slice(0, 160),
|
|
49
|
+
model: String(meta['model'] ?? 'unknown'),
|
|
50
|
+
provider: String(meta['provider'] ?? 'unknown'),
|
|
51
|
+
turns: Number(meta['turns'] ?? 0),
|
|
52
|
+
totalTokens: Number(meta['totalTokens'] ?? 0),
|
|
53
|
+
at: Number(meta['at'] ?? info.mtimeMs),
|
|
54
|
+
bytes: info.size,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch { /* a half-written or foreign file is skipped, never fatal */ }
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** Tool arguments as a short line, which is all a transcript row has room for. */
|
|
62
|
+
function argsLine(raw) {
|
|
63
|
+
if (typeof raw !== 'string')
|
|
64
|
+
return '';
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(raw);
|
|
67
|
+
// The interesting argument first: what file, what command, what pattern.
|
|
68
|
+
for (const key of ['path', 'paths', 'command', 'pattern', 'query', 'url', 'text']) {
|
|
69
|
+
if (parsed[key] !== undefined) {
|
|
70
|
+
const value = Array.isArray(parsed[key]) ? parsed[key].join(', ')
|
|
71
|
+
: String(parsed[key]);
|
|
72
|
+
return redactSecrets(value).slice(0, 200);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return redactSecrets(raw).slice(0, 200);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return redactSecrets(raw).slice(0, 200);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* One session, read into entries.
|
|
83
|
+
*
|
|
84
|
+
* The file is a sequence of records; older KONECK versions wrote slightly different shapes, so this
|
|
85
|
+
* accepts what it recognises and ignores the rest rather than refusing to open an old transcript.
|
|
86
|
+
*/
|
|
87
|
+
export async function readPast(cwd, file) {
|
|
88
|
+
// The name comes from a URL, so it is checked rather than trusted: only a plain file inside the
|
|
89
|
+
// session directory, no separators and no traversal.
|
|
90
|
+
if (!/^[A-Za-z0-9._-]+\.jsonl$/.test(file))
|
|
91
|
+
return null;
|
|
92
|
+
const full = path.join(SESSION_DIR(cwd), file);
|
|
93
|
+
if (!existsSync(full))
|
|
94
|
+
return null;
|
|
95
|
+
let raw;
|
|
96
|
+
try {
|
|
97
|
+
raw = await readFile(full, 'utf8');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const info = await stat(full).catch(() => null);
|
|
103
|
+
const lines = raw.split('\n').filter(l => l.trim() !== '');
|
|
104
|
+
const entries = [];
|
|
105
|
+
const trajectory = [];
|
|
106
|
+
let meta = {};
|
|
107
|
+
/** Tool calls awaiting their result, so a pair can be shown as one row. */
|
|
108
|
+
const pending = new Map();
|
|
109
|
+
let truncated = false;
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
let record;
|
|
112
|
+
try {
|
|
113
|
+
record = JSON.parse(line);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (record['type'] === 'meta') {
|
|
119
|
+
meta = (record['data'] ?? {});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (record['type'] === 'trajectory' && Array.isArray(record['data'])) {
|
|
123
|
+
trajectory.push(...record['data']);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (record['t'] !== undefined && record['at'] !== undefined) {
|
|
127
|
+
trajectory.push(record); // a bare event
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const message = (record['type'] === 'message' ? record['data'] : record);
|
|
131
|
+
const role = message?.['role'];
|
|
132
|
+
if (typeof role !== 'string')
|
|
133
|
+
continue;
|
|
134
|
+
if (entries.length >= MAX_ENTRIES) {
|
|
135
|
+
truncated = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (role === 'user') {
|
|
139
|
+
const text = typeof message['content'] === 'string' ? message['content']
|
|
140
|
+
: JSON.stringify(message['content']);
|
|
141
|
+
entries.push({ kind: 'user', text: redactSecrets(text) });
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (role === 'assistant') {
|
|
145
|
+
const calls = message['tool_calls'];
|
|
146
|
+
if (Array.isArray(calls)) {
|
|
147
|
+
for (const call of calls) {
|
|
148
|
+
const fn = (call['function'] ?? {});
|
|
149
|
+
pending.set(String(call['id'] ?? ''), {
|
|
150
|
+
name: String(fn['name'] ?? 'tool'),
|
|
151
|
+
args: argsLine(fn['arguments']),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const text = typeof message['content'] === 'string' ? message['content'] : '';
|
|
156
|
+
if (text.trim())
|
|
157
|
+
entries.push({ kind: 'assistant', text: redactSecrets(text) });
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (role === 'tool') {
|
|
161
|
+
const id = String(message['tool_call_id'] ?? '');
|
|
162
|
+
const call = pending.get(id);
|
|
163
|
+
pending.delete(id);
|
|
164
|
+
const result = typeof message['content'] === 'string' ? message['content'] : '';
|
|
165
|
+
entries.push({
|
|
166
|
+
kind: 'tool',
|
|
167
|
+
name: call?.name ?? 'tool',
|
|
168
|
+
args: call?.args ?? '',
|
|
169
|
+
// Trimmed: a transcript row shows what happened, and the whole of a file read belongs
|
|
170
|
+
// behind a click rather than in the flow.
|
|
171
|
+
result: redactSecrets(result).slice(0, 4_000),
|
|
172
|
+
ok: !/^(error|failed|✖)/i.test(result.trim()),
|
|
173
|
+
});
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (role === 'system')
|
|
177
|
+
continue; // the prompt, which is not the conversation
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
meta: {
|
|
181
|
+
file,
|
|
182
|
+
id: String(meta['id'] ?? file.replace(/\.jsonl$/, '')),
|
|
183
|
+
task: redactSecrets(String(meta['task'] ?? '(no description)')).slice(0, 160),
|
|
184
|
+
model: String(meta['model'] ?? 'unknown'),
|
|
185
|
+
provider: String(meta['provider'] ?? 'unknown'),
|
|
186
|
+
turns: Number(meta['turns'] ?? 0),
|
|
187
|
+
totalTokens: Number(meta['totalTokens'] ?? 0),
|
|
188
|
+
at: Number(meta['at'] ?? info?.mtimeMs ?? 0),
|
|
189
|
+
bytes: info?.size ?? raw.length,
|
|
190
|
+
},
|
|
191
|
+
entries,
|
|
192
|
+
trajectory,
|
|
193
|
+
summary: trajectory.length ? summarise(trajectory) : null,
|
|
194
|
+
truncated,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/web/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The KONECK mark, from kk.png.
|
|
3
|
+
*
|
|
4
|
+
* Stored as the shape's coverage — a greyscale PNG whose value is how much ink is at each point —
|
|
5
|
+
* and used as a CSS mask over `currentColor`. So it is the real mark, antialiasing and all, and it
|
|
6
|
+
* takes the colour of whatever it sits in: one asset for the light theme, the dark theme, the cyan
|
|
7
|
+
* brand mark and a muted footer, with no second file to keep in step.
|
|
8
|
+
*
|
|
9
|
+
* Tracing it to paths was the first attempt and the wrong one — a hand-rolled contour follower
|
|
10
|
+
* produced 275KB of polygon for a shape that is 5KB as pixels, and a mask needs no tracing to be
|
|
11
|
+
* exact. Mirrored before scaling, so the halves are identical rather than nearly so.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MARK_ASPECT = 1.0234;
|
|
14
|
+
export declare const MARK_MASK = "data:image/png;base64,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";
|
|
15
|
+
//# sourceMappingURL=mark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../src/web/mark.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,eAAO,MAAM,SAAS,+/MACw+M,CAAC"}
|
package/dist/web/mark.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The KONECK mark, from kk.png.
|
|
3
|
+
*
|
|
4
|
+
* Stored as the shape's coverage — a greyscale PNG whose value is how much ink is at each point —
|
|
5
|
+
* and used as a CSS mask over `currentColor`. So it is the real mark, antialiasing and all, and it
|
|
6
|
+
* takes the colour of whatever it sits in: one asset for the light theme, the dark theme, the cyan
|
|
7
|
+
* brand mark and a muted footer, with no second file to keep in step.
|
|
8
|
+
*
|
|
9
|
+
* Tracing it to paths was the first attempt and the wrong one — a hand-rolled contour follower
|
|
10
|
+
* produced 275KB of polygon for a shape that is 5KB as pixels, and a mask needs no tracing to be
|
|
11
|
+
* exact. Mirrored before scaling, so the halves are identical rather than nearly so.
|
|
12
|
+
*/
|
|
13
|
+
export const MARK_ASPECT = 1.0234;
|
|
14
|
+
export const MARK_MASK = 'data:image/png;base64,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';
|
|
15
|
+
//# sourceMappingURL=mark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark.js","sourceRoot":"","sources":["../../src/web/mark.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAElC,MAAM,CAAC,MAAM,SAAS,GACpB,4/MAA4/M,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions that live in this process, so the web client talks to an agent rather than to a
|
|
3
|
+
* subprocess.
|
|
4
|
+
*
|
|
5
|
+
* The old /run spawned `node dist/index.js <task>` per request. That meant no state between
|
|
6
|
+
* messages — every message was a fresh agent with no memory of the last one — no permission
|
|
7
|
+
* prompts, because there was no terminal to ask at, and no structure, because the only channel was
|
|
8
|
+
* stdout. Holding the session here gives all three: the conversation continues, a tool call can
|
|
9
|
+
* wait for an answer from the browser, and every callback becomes an event.
|
|
10
|
+
*/
|
|
11
|
+
import type { AgentConfig } from '../types.js';
|
|
12
|
+
import { EventBus } from './events.js';
|
|
13
|
+
import type { TrajectoryEvent } from '../trajectory.js';
|
|
14
|
+
export interface WebSessionInfo {
|
|
15
|
+
id: string;
|
|
16
|
+
cwd: string;
|
|
17
|
+
title: string;
|
|
18
|
+
provider: string;
|
|
19
|
+
model: string;
|
|
20
|
+
createdAt: number;
|
|
21
|
+
turns: number;
|
|
22
|
+
totalTokens: number;
|
|
23
|
+
busy: boolean;
|
|
24
|
+
watchers: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class WebSession {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
private config;
|
|
29
|
+
readonly bus: EventBus;
|
|
30
|
+
readonly createdAt: number;
|
|
31
|
+
/**
|
|
32
|
+
* Where this session sits in the order they were made.
|
|
33
|
+
*
|
|
34
|
+
* The listing sorted on createdAt, and two sessions created in the same millisecond have the
|
|
35
|
+
* same one — so "newest first" was arbitrary between them. Found by a test that made two in a
|
|
36
|
+
* row, which is exactly what clicking New twice does.
|
|
37
|
+
*/
|
|
38
|
+
order: number;
|
|
39
|
+
title: string;
|
|
40
|
+
turns: number;
|
|
41
|
+
totalTokens: number;
|
|
42
|
+
busy: boolean;
|
|
43
|
+
private agent;
|
|
44
|
+
private readonly pending;
|
|
45
|
+
private askCounter;
|
|
46
|
+
private toolCounter;
|
|
47
|
+
/** Start times by tool call, so a duration can be reported without the engine providing one. */
|
|
48
|
+
private readonly toolStarted;
|
|
49
|
+
constructor(id: string, config: AgentConfig);
|
|
50
|
+
info(): WebSessionInfo;
|
|
51
|
+
/** Answers a permission request. Returns false if nothing was waiting on that id. */
|
|
52
|
+
answer(askId: string, allowed: boolean): boolean;
|
|
53
|
+
/** Every request still waiting, so a reconnecting client can show them again. */
|
|
54
|
+
outstandingAsks(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* What happened and when, from the running agent.
|
|
57
|
+
*
|
|
58
|
+
* Empty until the first message, because the agent is not built until there is something for it
|
|
59
|
+
* to do — asking for timings before anything has run is a fair question with a short answer.
|
|
60
|
+
*/
|
|
61
|
+
trajectory(): readonly TrajectoryEvent[];
|
|
62
|
+
private ensureAgent;
|
|
63
|
+
/** Runs one message. Rejects if a turn is already in flight. */
|
|
64
|
+
send(text: string): Promise<void>;
|
|
65
|
+
/** Stops a run in progress, if the engine supports it. */
|
|
66
|
+
abort(): void;
|
|
67
|
+
/** Changes the model or endpoint, which means a new agent on the next message. */
|
|
68
|
+
reconfigure(patch: Partial<AgentConfig>): void;
|
|
69
|
+
}
|
|
70
|
+
/** Every live session, by id. */
|
|
71
|
+
export declare class SessionRegistry {
|
|
72
|
+
private readonly sessions;
|
|
73
|
+
private counter;
|
|
74
|
+
create(config: AgentConfig): WebSession;
|
|
75
|
+
get(id: string): WebSession | undefined;
|
|
76
|
+
list(): WebSessionInfo[];
|
|
77
|
+
remove(id: string): boolean;
|
|
78
|
+
get size(): number;
|
|
79
|
+
}
|
|
80
|
+
/** A workspace is a directory; this is what a picker needs to show one. */
|
|
81
|
+
export declare function workspaceLabel(cwd: string): string;
|
|
82
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/web/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAiB,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAQD,qBAAa,UAAU;IAuBT,QAAQ,CAAC,EAAE,EAAE,MAAM;IAAE,OAAO,CAAC,MAAM;IAtB/C,QAAQ,CAAC,GAAG,WAAkB;IAC9B,QAAQ,CAAC,SAAS,SAAc;IAChC;;;;;;OAMG;IACH,KAAK,SAAK;IACV,KAAK,SAAiB;IACtB,KAAK,SAAK;IACV,WAAW,SAAK;IAChB,IAAI,UAAS;IAEb,OAAO,CAAC,KAAK,CAA+D;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAK;IACxB,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAEpC,EAAE,EAAE,MAAM,EAAU,MAAM,EAAE,WAAW;IAE5D,IAAI,IAAI,cAAc;IAStB,qFAAqF;IACrF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAShD,iFAAiF;IACjF,eAAe,IAAI,MAAM,EAAE;IAE3B;;;;;OAKG;IACH,UAAU,IAAI,SAAS,eAAe,EAAE;YAI1B,WAAW;IAqEzB,gEAAgE;IAC1D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BvC,0DAA0D;IAC1D,KAAK,IAAI,IAAI;IAIb,kFAAkF;IAClF,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;CAM/C;AAED,iCAAiC;AACjC,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,OAAO,CAAK;IAEpB,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU;IAUvC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IACvC,IAAI,IAAI,cAAc,EAAE;IAKxB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAC3B,IAAI,IAAI,IAAI,MAAM,CAA+B;CAClD;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions that live in this process, so the web client talks to an agent rather than to a
|
|
3
|
+
* subprocess.
|
|
4
|
+
*
|
|
5
|
+
* The old /run spawned `node dist/index.js <task>` per request. That meant no state between
|
|
6
|
+
* messages — every message was a fresh agent with no memory of the last one — no permission
|
|
7
|
+
* prompts, because there was no terminal to ask at, and no structure, because the only channel was
|
|
8
|
+
* stdout. Holding the session here gives all three: the conversation continues, a tool call can
|
|
9
|
+
* wait for an answer from the browser, and every callback becomes an event.
|
|
10
|
+
*/
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { createAgentSession } from '../engine.js';
|
|
13
|
+
import { estimateCost } from '../pricing.js';
|
|
14
|
+
import { EventBus } from './events.js';
|
|
15
|
+
import { redactSecrets } from '../redact.js';
|
|
16
|
+
export class WebSession {
|
|
17
|
+
id;
|
|
18
|
+
config;
|
|
19
|
+
bus = new EventBus();
|
|
20
|
+
createdAt = Date.now();
|
|
21
|
+
/**
|
|
22
|
+
* Where this session sits in the order they were made.
|
|
23
|
+
*
|
|
24
|
+
* The listing sorted on createdAt, and two sessions created in the same millisecond have the
|
|
25
|
+
* same one — so "newest first" was arbitrary between them. Found by a test that made two in a
|
|
26
|
+
* row, which is exactly what clicking New twice does.
|
|
27
|
+
*/
|
|
28
|
+
order = 0;
|
|
29
|
+
title = 'New session';
|
|
30
|
+
turns = 0;
|
|
31
|
+
totalTokens = 0;
|
|
32
|
+
busy = false;
|
|
33
|
+
agent = null;
|
|
34
|
+
pending = new Map();
|
|
35
|
+
askCounter = 0;
|
|
36
|
+
toolCounter = 0;
|
|
37
|
+
/** Start times by tool call, so a duration can be reported without the engine providing one. */
|
|
38
|
+
toolStarted = new Map();
|
|
39
|
+
constructor(id, config) {
|
|
40
|
+
this.id = id;
|
|
41
|
+
this.config = config;
|
|
42
|
+
}
|
|
43
|
+
info() {
|
|
44
|
+
return {
|
|
45
|
+
id: this.id, cwd: this.config.cwd, title: this.title,
|
|
46
|
+
provider: this.config.provider, model: this.config.model,
|
|
47
|
+
createdAt: this.createdAt, turns: this.turns, totalTokens: this.totalTokens,
|
|
48
|
+
busy: this.busy, watchers: this.bus.watchers,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Answers a permission request. Returns false if nothing was waiting on that id. */
|
|
52
|
+
answer(askId, allowed) {
|
|
53
|
+
const waiting = this.pending.get(askId);
|
|
54
|
+
if (!waiting)
|
|
55
|
+
return false;
|
|
56
|
+
this.pending.delete(askId);
|
|
57
|
+
waiting.resolve(allowed);
|
|
58
|
+
this.bus.emit({ t: 'ask-done', askId, allowed });
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/** Every request still waiting, so a reconnecting client can show them again. */
|
|
62
|
+
outstandingAsks() { return [...this.pending.keys()]; }
|
|
63
|
+
/**
|
|
64
|
+
* What happened and when, from the running agent.
|
|
65
|
+
*
|
|
66
|
+
* Empty until the first message, because the agent is not built until there is something for it
|
|
67
|
+
* to do — asking for timings before anything has run is a fair question with a short answer.
|
|
68
|
+
*/
|
|
69
|
+
trajectory() {
|
|
70
|
+
return this.agent?.trajectory ?? [];
|
|
71
|
+
}
|
|
72
|
+
async ensureAgent() {
|
|
73
|
+
if (this.agent)
|
|
74
|
+
return this.agent;
|
|
75
|
+
const bus = this.bus;
|
|
76
|
+
this.agent = await createAgentSession({
|
|
77
|
+
...this.config,
|
|
78
|
+
silent: true, // nothing goes to this process's stdout
|
|
79
|
+
// Approval travels to the browser and back. Without a resolver the engine would either
|
|
80
|
+
// block for ever or auto-allow, and auto-allowing a write because the UI is a web page
|
|
81
|
+
// rather than a terminal is not a decision anyone made.
|
|
82
|
+
approve: async (tool, args) => {
|
|
83
|
+
const askId = `ask-${++this.askCounter}`;
|
|
84
|
+
return new Promise(resolve => {
|
|
85
|
+
this.pending.set(askId, { id: askId, resolve });
|
|
86
|
+
bus.emit({ t: 'ask', askId, tool, args: redactSecrets(args),
|
|
87
|
+
waiting: this.pending.size - 1 });
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
onChunk: (text) => bus.emit({ t: 'chunk', text }),
|
|
91
|
+
onThinking: (text, chars) => bus.emit({ t: 'thinking', text, chars }),
|
|
92
|
+
onToolCall: (name, detail) => {
|
|
93
|
+
const id = `tool-${++this.toolCounter}`;
|
|
94
|
+
this.toolStarted.set(name, Date.now());
|
|
95
|
+
bus.emit({ t: 'tool', callId: id, name, detail: redactSecrets(detail ?? '') });
|
|
96
|
+
},
|
|
97
|
+
onToolOutput: (name, line) => bus.emit({ t: 'tool-output', name, line: redactSecrets(line) }),
|
|
98
|
+
onToolResult: (name, ok, ms, detail) => {
|
|
99
|
+
const started = this.toolStarted.get(name);
|
|
100
|
+
this.toolStarted.delete(name);
|
|
101
|
+
bus.emit({ t: 'tool-done', callId: `tool-${this.toolCounter}`, name, ok,
|
|
102
|
+
ms: ms || (started ? Date.now() - started : 0), detail: redactSecrets(detail ?? '') });
|
|
103
|
+
},
|
|
104
|
+
onPlan: (plan) => bus.emit({ t: 'plan', steps: plan.steps.map(s => ({ text: s.text, state: s.state })) }),
|
|
105
|
+
onTokens: (s) => {
|
|
106
|
+
this.totalTokens = s.totalTokens;
|
|
107
|
+
bus.emit({ t: 'tokens', prompt: s.promptTokens, completion: s.completionTokens,
|
|
108
|
+
total: s.totalTokens,
|
|
109
|
+
cost: estimateCost(this.config.model, s.promptTokens, s.completionTokens).total });
|
|
110
|
+
},
|
|
111
|
+
// Everything the engine says about its own condition, in one place: the browser shows these
|
|
112
|
+
// the way the terminal shows a warning, rather than dropping them because there is no
|
|
113
|
+
// obvious home for them in a web layout.
|
|
114
|
+
onLeanMode: (_d, _l, notice) => bus.emit({ t: 'notice', level: 'warn', text: notice }),
|
|
115
|
+
onTruncation: (_w, notice) => bus.emit({ t: 'notice', level: 'warn', text: notice }),
|
|
116
|
+
onCrowdedWindow: (_f, _l, advice) => bus.emit({ t: 'notice', level: 'warn', text: advice }),
|
|
117
|
+
onPromptTrimmed: (_d, _t, notice) => bus.emit({ t: 'notice', level: 'warn', text: notice }),
|
|
118
|
+
onWindowDetected: (limit, source) => bus.emit({ t: 'notice', level: 'info', text: `Context window ${limit.toLocaleString()} (${source}).` }),
|
|
119
|
+
onLooping: (copies) => bus.emit({ t: 'notice', level: 'warn',
|
|
120
|
+
text: `The model repeated itself ${copies} times, so the reply was cut short.` }),
|
|
121
|
+
onIncomplete: (reason) => bus.emit({ t: 'notice', level: 'warn', text: reason }),
|
|
122
|
+
onCompress: (before, after) => bus.emit({ t: 'notice', level: 'info',
|
|
123
|
+
text: `Conversation summarised: ${before} messages to ${after}.` }),
|
|
124
|
+
});
|
|
125
|
+
this.bus.emit({ t: 'session', sessionId: this.id, cwd: this.config.cwd,
|
|
126
|
+
provider: this.config.provider, model: this.config.model });
|
|
127
|
+
return this.agent;
|
|
128
|
+
}
|
|
129
|
+
/** Runs one message. Rejects if a turn is already in flight. */
|
|
130
|
+
async send(text) {
|
|
131
|
+
if (this.busy)
|
|
132
|
+
throw new Error('This session is already working. Wait for it to finish.');
|
|
133
|
+
this.busy = true;
|
|
134
|
+
const started = Date.now();
|
|
135
|
+
if (this.title === 'New session')
|
|
136
|
+
this.title = redactSecrets(text).slice(0, 80);
|
|
137
|
+
this.bus.emit({ t: 'user', text });
|
|
138
|
+
try {
|
|
139
|
+
const agent = await this.ensureAgent();
|
|
140
|
+
const completed = await agent.send(text);
|
|
141
|
+
this.turns++;
|
|
142
|
+
this.bus.emit({ t: 'turn-end', ms: Date.now() - started, completed });
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
this.bus.emit({ t: 'error', text: redactSecrets(err.message) });
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
this.busy = false;
|
|
150
|
+
// Anything still waiting on an answer cannot be answered now, and a promise left unresolved
|
|
151
|
+
// holds the turn open for ever.
|
|
152
|
+
for (const [askId, p] of this.pending) {
|
|
153
|
+
p.resolve(false);
|
|
154
|
+
this.bus.emit({ t: 'ask-done', askId, allowed: false });
|
|
155
|
+
}
|
|
156
|
+
this.pending.clear();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Stops a run in progress, if the engine supports it. */
|
|
160
|
+
abort() {
|
|
161
|
+
this.agent?.abort?.();
|
|
162
|
+
}
|
|
163
|
+
/** Changes the model or endpoint, which means a new agent on the next message. */
|
|
164
|
+
reconfigure(patch) {
|
|
165
|
+
this.config = { ...this.config, ...patch };
|
|
166
|
+
this.agent = null;
|
|
167
|
+
this.bus.emit({ t: 'notice', level: 'info',
|
|
168
|
+
text: `Switched to ${this.config.model} via ${this.config.provider}.` });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** Every live session, by id. */
|
|
172
|
+
export class SessionRegistry {
|
|
173
|
+
sessions = new Map();
|
|
174
|
+
counter = 0;
|
|
175
|
+
create(config) {
|
|
176
|
+
// Readable and unique without a clock, since two created in the same millisecond used to
|
|
177
|
+
// collide — the same fault the CLI's session ids had.
|
|
178
|
+
const id = `w${Date.now().toString(36)}-${(++this.counter).toString(36)}`;
|
|
179
|
+
const session = new WebSession(id, config);
|
|
180
|
+
session.order = this.counter;
|
|
181
|
+
this.sessions.set(id, session);
|
|
182
|
+
return session;
|
|
183
|
+
}
|
|
184
|
+
get(id) { return this.sessions.get(id); }
|
|
185
|
+
list() {
|
|
186
|
+
return [...this.sessions.values()]
|
|
187
|
+
.sort((a, b) => b.order - a.order)
|
|
188
|
+
.map(s => s.info());
|
|
189
|
+
}
|
|
190
|
+
remove(id) { return this.sessions.delete(id); }
|
|
191
|
+
get size() { return this.sessions.size; }
|
|
192
|
+
}
|
|
193
|
+
/** A workspace is a directory; this is what a picker needs to show one. */
|
|
194
|
+
export function workspaceLabel(cwd) {
|
|
195
|
+
return path.basename(cwd) || cwd;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/web/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client, as a string.
|
|
3
|
+
*
|
|
4
|
+
* Plain DOM and no framework: a framework would be larger than the page it renders, and this has
|
|
5
|
+
* one job — turn a stream of typed events into something worth reading, plus three views over data
|
|
6
|
+
* the server already has.
|
|
7
|
+
*
|
|
8
|
+
* All model and file text goes through `el(tag, cls, text)` or `textContent`, never innerHTML. The
|
|
9
|
+
* one exception is the markdown renderer, which escapes everything before it inserts a single tag,
|
|
10
|
+
* and lifts fenced blocks out first so their contents can never be interpreted. Model output is
|
|
11
|
+
* untrusted text and routinely contains HTML, because it is often writing HTML.
|
|
12
|
+
*/
|
|
13
|
+
export declare function clientScript(): string;
|
|
14
|
+
//# sourceMappingURL=ui-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-client.d.ts","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CA0nBrC"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-client.js","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwnBlB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stylesheet, and the three themes.
|
|
3
|
+
*
|
|
4
|
+
* Every colour is a token defined once on `:root`, so a theme is a list of token values rather
|
|
5
|
+
* than a second stylesheet. Three states, which is what "light, dark and system" actually needs:
|
|
6
|
+
* an explicit choice writes `data-theme` on the root and wins; with nothing written, the browser's
|
|
7
|
+
* own preference decides.
|
|
8
|
+
*
|
|
9
|
+
* Contrast was asked for specifically — "font visible well in dark theme". The dark palette's body
|
|
10
|
+
* text is #e6f1f5 on #0d1418, which is about 14:1, and the muted tone is #93aab5 at about 7:1;
|
|
11
|
+
* both clear WCAG AA for body text with room to spare. The first version used #7f9aa6 for anything
|
|
12
|
+
* secondary, which measures 4.6:1 — passable on paper and genuinely hard to read on a dim screen.
|
|
13
|
+
*/
|
|
14
|
+
export declare function css(markUrl: string): string;
|
|
15
|
+
//# sourceMappingURL=ui-css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-css.d.ts","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6Q3C"}
|