@xfey/tutti 0.1.87 → 0.1.89
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/providers/openai/app-server/runtime-telemetry.d.ts +1 -1
- package/dist/providers/openai/app-server/runtime-telemetry.js +197 -50
- package/dist/server-shell/http/routes/project-api/openapi-execution-routes.d.ts +1 -1
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +1 -1
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +2 -2
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +1 -1
- package/dist/server-shell/local-console/server.js +13 -3
- package/dist/server-shell/local-console/session.d.ts +2 -1
- package/dist/server-shell/local-console/session.js +16 -1
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +4 -4
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.js +5 -0
- package/package.json +1 -1
- package/web/assets/{homepage-motion-scene-D9dEIQVd.js → homepage-motion-scene-tPYFCiQb.js} +1 -1
- package/web/assets/{index-75s5OaHg.js → index-BxgVVqiQ.js} +4 -4
- package/web/assets/{index-lNbWftd-.css → index-Cl_lDhdv.css} +1 -1
- package/web/index.html +2 -2
|
@@ -1,46 +1,99 @@
|
|
|
1
1
|
import { extractCodexAppServerTokenUsage } from "../token-usage.js";
|
|
2
|
-
const
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const DEFAULT_ACTION_MIN_VISIBLE_MS = 1_000;
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function itemFromNotification(notification) {
|
|
7
|
+
if (!isRecord(notification.params) || !isRecord(notification.params.item)) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return notification.params.item;
|
|
11
|
+
}
|
|
12
|
+
function itemId(item) {
|
|
13
|
+
return typeof item.id === "string" && item.id !== "" ? item.id : undefined;
|
|
14
|
+
}
|
|
15
|
+
const CHECK_COMMAND_PATTERN = /(?:^|[\s;&|])(?:(?:npm|pnpm|yarn|bun)\s+(?:(?:run|exec|x)\s+)?(?:test|lint|check|typecheck|build)|(?:npx|pnpm\s+exec|yarn\s+exec|bunx)\s+(?:vitest|jest|eslint|tsc|biome|prettier)|pytest|vitest|jest|cargo\s+(?:test|check|clippy|build)|go\s+test|dotnet\s+(?:test|build)|gradle\w*\s+(?:test|check|build)|make\s+(?:test|check|lint|build)|tsc(?:\s|$)|eslint(?:\s|$)|biome\s+check|ruff\s+check|mypy(?:\s|$)|swift\s+test|xcodebuild(?:\s|$))/iu;
|
|
16
|
+
function commandActionFromItem(item) {
|
|
17
|
+
const commandActions = Array.isArray(item.commandActions)
|
|
18
|
+
? item.commandActions.filter(isRecord)
|
|
19
|
+
: [];
|
|
20
|
+
const commands = [item.command, ...commandActions.map((action) => action.command)].filter((command) => typeof command === "string");
|
|
21
|
+
if (commands.some((command) => CHECK_COMMAND_PATTERN.test(command))) {
|
|
22
|
+
return "running_checks";
|
|
23
|
+
}
|
|
24
|
+
const actionTypes = commandActions
|
|
25
|
+
.map((action) => action.type)
|
|
26
|
+
.filter((type) => typeof type === "string");
|
|
27
|
+
if (actionTypes.some((type) => type === "search" || type === "listFiles")) {
|
|
28
|
+
return "searching_codebase";
|
|
6
29
|
}
|
|
7
|
-
if (
|
|
8
|
-
return "";
|
|
30
|
+
if (actionTypes.includes("read")) {
|
|
31
|
+
return "reading_files";
|
|
9
32
|
}
|
|
10
|
-
|
|
11
|
-
const tokens = ["type", "kind", "name", "status", "method", "state"]
|
|
12
|
-
.map((key) => record[key])
|
|
13
|
-
.filter((entry) => typeof entry === "string");
|
|
14
|
-
return tokens.join(" ").toLocaleLowerCase();
|
|
33
|
+
return "running_command";
|
|
15
34
|
}
|
|
16
|
-
function
|
|
35
|
+
function actionFromItem(item) {
|
|
36
|
+
switch (item.type) {
|
|
37
|
+
case "reasoning":
|
|
38
|
+
case "contextCompaction":
|
|
39
|
+
return "analyzing_task";
|
|
40
|
+
case "plan":
|
|
41
|
+
return "planning";
|
|
42
|
+
case "commandExecution":
|
|
43
|
+
return commandActionFromItem(item);
|
|
44
|
+
case "fileChange":
|
|
45
|
+
return "editing_files";
|
|
46
|
+
case "imageView":
|
|
47
|
+
return "reading_files";
|
|
48
|
+
case "mcpToolCall":
|
|
49
|
+
case "dynamicToolCall":
|
|
50
|
+
case "collabAgentToolCall":
|
|
51
|
+
case "subAgentActivity":
|
|
52
|
+
case "webSearch":
|
|
53
|
+
case "imageGeneration":
|
|
54
|
+
return "using_tool";
|
|
55
|
+
default:
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function actionFromNotificationMethod(notification) {
|
|
17
60
|
const method = notification.method;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
61
|
+
if (method === "turn/started" || method.startsWith("item/reasoning/")) {
|
|
62
|
+
return "analyzing_task";
|
|
63
|
+
}
|
|
64
|
+
if (method === "turn/plan/updated" || method.startsWith("item/plan/")) {
|
|
65
|
+
return "planning";
|
|
22
66
|
}
|
|
23
|
-
if (method === "turn/diff/updated" ||
|
|
24
|
-
combined.includes("filechange") ||
|
|
25
|
-
combined.includes("file_change")) {
|
|
67
|
+
if (method === "turn/diff/updated" || method.startsWith("item/fileChange/")) {
|
|
26
68
|
return "editing_files";
|
|
27
69
|
}
|
|
28
|
-
if (method === "turn/
|
|
29
|
-
return "
|
|
70
|
+
if (method === "turn/completed") {
|
|
71
|
+
return "preparing_result";
|
|
30
72
|
}
|
|
31
|
-
if (
|
|
32
|
-
combined.includes("mcp_tool_call") ||
|
|
33
|
-
combined.includes("dynamictoolcall") ||
|
|
34
|
-
combined.includes("dynamic_tool_call") ||
|
|
35
|
-
combined.includes("websearch") ||
|
|
36
|
-
combined.includes("web_search")) {
|
|
73
|
+
if (method.startsWith("item/mcpToolCall/")) {
|
|
37
74
|
return "using_tool";
|
|
38
75
|
}
|
|
39
|
-
if (combined.includes("reasoning")) {
|
|
40
|
-
return "reading_context";
|
|
41
|
-
}
|
|
42
76
|
return undefined;
|
|
43
77
|
}
|
|
78
|
+
function requestKey(value) {
|
|
79
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return `${typeof value}:${String(value)}`;
|
|
83
|
+
}
|
|
84
|
+
function resolvedRequestKey(notification) {
|
|
85
|
+
if (notification.method !== "serverRequest/resolved" || !isRecord(notification.params)) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
return requestKey(notification.params.requestId);
|
|
89
|
+
}
|
|
90
|
+
function isWaitingRequest(request) {
|
|
91
|
+
return (request.method.includes("requestApproval") ||
|
|
92
|
+
request.method === "applyPatchApproval" ||
|
|
93
|
+
request.method === "execCommandApproval" ||
|
|
94
|
+
request.method === "item/tool/requestUserInput" ||
|
|
95
|
+
request.method === "mcpServer/elicitation/request");
|
|
96
|
+
}
|
|
44
97
|
function runtimeTokenUsage(usage) {
|
|
45
98
|
return {
|
|
46
99
|
input_tokens: usage.input_tokens,
|
|
@@ -53,27 +106,47 @@ function runtimeTokenUsage(usage) {
|
|
|
53
106
|
export function createCodexAppServerRuntimeObserver(options) {
|
|
54
107
|
let latest;
|
|
55
108
|
let timer;
|
|
56
|
-
let lastEmittedAt
|
|
57
|
-
|
|
109
|
+
let lastEmittedAt;
|
|
110
|
+
let lastEmittedAction;
|
|
111
|
+
let pendingSnapshot;
|
|
112
|
+
let itemOrder = 0;
|
|
113
|
+
const activeItems = new Map();
|
|
114
|
+
const waitingRequests = new Set();
|
|
115
|
+
const actionMinVisibleMs = Math.max(0, options.actionMinVisibleMs ?? DEFAULT_ACTION_MIN_VISIBLE_MS);
|
|
58
116
|
const now = options.now ?? (() => new Date());
|
|
59
|
-
const emit = () => {
|
|
60
|
-
if (
|
|
117
|
+
const emit = (snapshot = latest) => {
|
|
118
|
+
if (snapshot === undefined || options.onSnapshot === undefined) {
|
|
61
119
|
return;
|
|
62
120
|
}
|
|
63
121
|
lastEmittedAt = Date.now();
|
|
64
|
-
|
|
122
|
+
lastEmittedAction = snapshot.current_action;
|
|
123
|
+
options.onSnapshot(snapshot);
|
|
65
124
|
};
|
|
66
|
-
const
|
|
67
|
-
|
|
125
|
+
const publishPendingSnapshot = () => {
|
|
126
|
+
const snapshot = pendingSnapshot;
|
|
127
|
+
pendingSnapshot = undefined;
|
|
128
|
+
emit(snapshot);
|
|
129
|
+
if (latest?.current_action !== undefined &&
|
|
130
|
+
latest.current_action !== lastEmittedAction) {
|
|
131
|
+
pendingSnapshot = latest;
|
|
132
|
+
schedulePendingSnapshot();
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const schedulePendingSnapshot = () => {
|
|
136
|
+
if (options.onSnapshot === undefined || pendingSnapshot === undefined) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (lastEmittedAt === undefined) {
|
|
140
|
+
publishPendingSnapshot();
|
|
68
141
|
return;
|
|
69
142
|
}
|
|
70
143
|
const elapsed = Date.now() - lastEmittedAt;
|
|
71
|
-
if (elapsed >=
|
|
144
|
+
if (elapsed >= actionMinVisibleMs) {
|
|
72
145
|
if (timer !== undefined) {
|
|
73
146
|
clearTimeout(timer);
|
|
74
147
|
timer = undefined;
|
|
75
148
|
}
|
|
76
|
-
|
|
149
|
+
publishPendingSnapshot();
|
|
77
150
|
return;
|
|
78
151
|
}
|
|
79
152
|
if (timer !== undefined) {
|
|
@@ -81,10 +154,26 @@ export function createCodexAppServerRuntimeObserver(options) {
|
|
|
81
154
|
}
|
|
82
155
|
timer = setTimeout(() => {
|
|
83
156
|
timer = undefined;
|
|
84
|
-
|
|
85
|
-
}, Math.max(1,
|
|
157
|
+
publishPendingSnapshot();
|
|
158
|
+
}, Math.max(1, actionMinVisibleMs - elapsed));
|
|
86
159
|
};
|
|
87
|
-
const
|
|
160
|
+
const scheduleActionEmit = () => {
|
|
161
|
+
if (options.onSnapshot === undefined || latest?.current_action === undefined) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (pendingSnapshot !== undefined) {
|
|
165
|
+
if (latest.current_action !== lastEmittedAction) {
|
|
166
|
+
pendingSnapshot = latest;
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (latest.current_action === lastEmittedAction) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
pendingSnapshot = latest;
|
|
174
|
+
schedulePendingSnapshot();
|
|
175
|
+
};
|
|
176
|
+
const update = (patch, scheduleAction = patch.currentAction !== undefined) => {
|
|
88
177
|
if (patch.currentAction === undefined && patch.tokenUsage === undefined) {
|
|
89
178
|
return;
|
|
90
179
|
}
|
|
@@ -103,18 +192,73 @@ export function createCodexAppServerRuntimeObserver(options) {
|
|
|
103
192
|
if (patch.currentAction !== undefined) {
|
|
104
193
|
latest.current_action = patch.currentAction;
|
|
105
194
|
}
|
|
106
|
-
|
|
195
|
+
if (scheduleAction) {
|
|
196
|
+
scheduleActionEmit();
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const currentItemAction = () => {
|
|
200
|
+
let current;
|
|
201
|
+
for (const item of activeItems.values()) {
|
|
202
|
+
if (current === undefined || item.order > current.order) {
|
|
203
|
+
current = item;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return current?.action;
|
|
207
|
+
};
|
|
208
|
+
const resumeCurrentAction = () => {
|
|
209
|
+
update({
|
|
210
|
+
currentAction: waitingRequests.size > 0
|
|
211
|
+
? "waiting_for_approval"
|
|
212
|
+
: (currentItemAction() ?? "analyzing_task"),
|
|
213
|
+
});
|
|
107
214
|
};
|
|
108
215
|
return {
|
|
109
216
|
notification: (notification) => {
|
|
110
217
|
const tokenUsage = extractCodexAppServerTokenUsage([notification]);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
218
|
+
if (tokenUsage !== undefined) {
|
|
219
|
+
update({ tokenUsage }, false);
|
|
220
|
+
}
|
|
221
|
+
const request = resolvedRequestKey(notification);
|
|
222
|
+
if (request !== undefined) {
|
|
223
|
+
if (waitingRequests.delete(request)) {
|
|
224
|
+
resumeCurrentAction();
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (notification.method === "item/started") {
|
|
229
|
+
const item = itemFromNotification(notification);
|
|
230
|
+
const id = item === undefined ? undefined : itemId(item);
|
|
231
|
+
const action = item === undefined ? undefined : actionFromItem(item);
|
|
232
|
+
if (id !== undefined && action !== undefined) {
|
|
233
|
+
itemOrder += 1;
|
|
234
|
+
activeItems.set(id, { action, order: itemOrder });
|
|
235
|
+
if (waitingRequests.size === 0) {
|
|
236
|
+
update({ currentAction: action });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (notification.method === "item/completed") {
|
|
242
|
+
const item = itemFromNotification(notification);
|
|
243
|
+
const id = item === undefined ? undefined : itemId(item);
|
|
244
|
+
if (id !== undefined && activeItems.delete(id)) {
|
|
245
|
+
resumeCurrentAction();
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const currentAction = actionFromNotificationMethod(notification);
|
|
250
|
+
if (currentAction !== undefined && waitingRequests.size === 0) {
|
|
251
|
+
update({ currentAction });
|
|
252
|
+
}
|
|
116
253
|
},
|
|
117
|
-
serverRequest: () => {
|
|
254
|
+
serverRequest: (request) => {
|
|
255
|
+
if (!isWaitingRequest(request)) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const key = requestKey(request.id);
|
|
259
|
+
if (key !== undefined) {
|
|
260
|
+
waitingRequests.add(key);
|
|
261
|
+
}
|
|
118
262
|
update({ currentAction: "waiting_for_approval" });
|
|
119
263
|
},
|
|
120
264
|
flush: () => {
|
|
@@ -122,7 +266,10 @@ export function createCodexAppServerRuntimeObserver(options) {
|
|
|
122
266
|
clearTimeout(timer);
|
|
123
267
|
timer = undefined;
|
|
124
268
|
}
|
|
125
|
-
|
|
269
|
+
pendingSnapshot = undefined;
|
|
270
|
+
if (latest?.current_action !== undefined && latest.current_action !== lastEmittedAction) {
|
|
271
|
+
emit();
|
|
272
|
+
}
|
|
126
273
|
},
|
|
127
274
|
};
|
|
128
275
|
}
|
|
@@ -202,7 +202,7 @@ export declare const HOST_PROJECT_EXECUTION_OPENAPI_ROUTES: ({
|
|
|
202
202
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
203
203
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
204
204
|
}>>;
|
|
205
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
205
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
206
206
|
}>>;
|
|
207
207
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
208
208
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -1276,7 +1276,7 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
|
|
|
1276
1276
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
1277
1277
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
1278
1278
|
}>>;
|
|
1279
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
1279
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
1280
1280
|
}>>;
|
|
1281
1281
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
1282
1282
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -831,7 +831,7 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
|
|
|
831
831
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
832
832
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
833
833
|
}>>;
|
|
834
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
834
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
835
835
|
}>>;
|
|
836
836
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
837
837
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -2550,7 +2550,7 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
|
|
|
2550
2550
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
2551
2551
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
2552
2552
|
}>>;
|
|
2553
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
2553
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
2554
2554
|
}>>;
|
|
2555
2555
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
2556
2556
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -1240,7 +1240,7 @@ export declare const BootstrapResponseSchema: {
|
|
|
1240
1240
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
1241
1241
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
1242
1242
|
}>>;
|
|
1243
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
1243
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
1244
1244
|
}>>;
|
|
1245
1245
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
1246
1246
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -249,13 +249,16 @@ export function createLocalConsoleServer(options) {
|
|
|
249
249
|
type: "object",
|
|
250
250
|
required: ["access_token"],
|
|
251
251
|
additionalProperties: false,
|
|
252
|
-
properties: {
|
|
252
|
+
properties: {
|
|
253
|
+
access_token: { type: "string", minLength: 1 },
|
|
254
|
+
account_display_name: { type: "string", minLength: 1, maxLength: 80 },
|
|
255
|
+
},
|
|
253
256
|
},
|
|
254
257
|
},
|
|
255
258
|
}, (request, reply) => {
|
|
256
259
|
requireSameOrigin(request);
|
|
257
260
|
const cookie = parseCookieHeader(headerValue(request.headers.cookie));
|
|
258
|
-
const session = sessions.exchangeAccessToken(request.body.access_token, cookie[LOCAL_CONSOLE_SESSION_COOKIE]);
|
|
261
|
+
const session = sessions.exchangeAccessToken(request.body.access_token, cookie[LOCAL_CONSOLE_SESSION_COOKIE], request.body.account_display_name);
|
|
259
262
|
if (session === null) {
|
|
260
263
|
throw new LocalConsoleHttpError(401, "access_token_invalid", "This Local Console access link has expired. Run `tutti` again.");
|
|
261
264
|
}
|
|
@@ -273,7 +276,14 @@ export function createLocalConsoleServer(options) {
|
|
|
273
276
|
const session = requireSession(request);
|
|
274
277
|
const packageUpdateCompletion = options.getPackageUpdateCompletion?.();
|
|
275
278
|
return {
|
|
276
|
-
account_gate:
|
|
279
|
+
account_gate: session.accountReady
|
|
280
|
+
? {
|
|
281
|
+
status: "ready",
|
|
282
|
+
...(session.accountDisplayName === undefined
|
|
283
|
+
? {}
|
|
284
|
+
: { account: { display_name: session.accountDisplayName } }),
|
|
285
|
+
}
|
|
286
|
+
: { status: "required" },
|
|
277
287
|
csrf_token: session.csrfToken,
|
|
278
288
|
version: options.runtime?.version ?? readCliVersion(),
|
|
279
289
|
invocation: session.context.source === "terminal"
|
|
@@ -12,6 +12,7 @@ export type ExchangedLocalConsoleSession = {
|
|
|
12
12
|
};
|
|
13
13
|
export type ReadLocalConsoleSession = {
|
|
14
14
|
accountReady: boolean;
|
|
15
|
+
accountDisplayName?: string;
|
|
15
16
|
csrfToken: string;
|
|
16
17
|
context: LocalConsoleInvocationContext;
|
|
17
18
|
};
|
|
@@ -22,7 +23,7 @@ export declare class LocalConsoleSessionRegistry {
|
|
|
22
23
|
});
|
|
23
24
|
issueAccessToken(context: LocalConsoleInvocationContext): IssuedLocalConsoleAccessToken;
|
|
24
25
|
issueAccountContinuation(context: LocalConsoleInvocationContext): IssuedLocalConsoleAccessToken;
|
|
25
|
-
exchangeAccessToken(token: string, existingSessionToken?: string): ExchangedLocalConsoleSession | null;
|
|
26
|
+
exchangeAccessToken(token: string, existingSessionToken?: string, accountDisplayName?: string): ExchangedLocalConsoleSession | null;
|
|
26
27
|
readSession(token: string | undefined, contextToken?: string): ReadLocalConsoleSession | null;
|
|
27
28
|
}
|
|
28
29
|
export declare function parseCookieHeader(header: string | undefined): Record<string, string>;
|
|
@@ -14,6 +14,12 @@ function secretEquals(value, expectedHash) {
|
|
|
14
14
|
const expected = Buffer.from(expectedHash);
|
|
15
15
|
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
16
16
|
}
|
|
17
|
+
function normalizeAccountDisplayName(value) {
|
|
18
|
+
const normalized = value?.trim();
|
|
19
|
+
return normalized === undefined || normalized === "" || normalized.length > 80
|
|
20
|
+
? undefined
|
|
21
|
+
: normalized;
|
|
22
|
+
}
|
|
17
23
|
export class LocalConsoleSessionRegistry {
|
|
18
24
|
#accessTokens = new Map();
|
|
19
25
|
#sessions = new Map();
|
|
@@ -49,7 +55,7 @@ export class LocalConsoleSessionRegistry {
|
|
|
49
55
|
});
|
|
50
56
|
return { token, expires_at: new Date(expiresAt).toISOString() };
|
|
51
57
|
}
|
|
52
|
-
exchangeAccessToken(token, existingSessionToken) {
|
|
58
|
+
exchangeAccessToken(token, existingSessionToken, accountDisplayName) {
|
|
53
59
|
this.#purgeExpired();
|
|
54
60
|
const accessTokenHash = hashSecret(token);
|
|
55
61
|
const accessToken = this.#accessTokens.get(accessTokenHash);
|
|
@@ -96,9 +102,15 @@ export class LocalConsoleSessionRegistry {
|
|
|
96
102
|
}
|
|
97
103
|
const contextToken = createSecret();
|
|
98
104
|
const contextHash = hashSecret(contextToken);
|
|
105
|
+
const normalizedAccountDisplayName = accessToken.accountReady
|
|
106
|
+
? normalizeAccountDisplayName(accountDisplayName)
|
|
107
|
+
: undefined;
|
|
99
108
|
session.defaultContextHash = contextHash;
|
|
100
109
|
this.#contexts.set(contextHash, {
|
|
101
110
|
accountReady: accessToken.accountReady,
|
|
111
|
+
...(normalizedAccountDisplayName === undefined
|
|
112
|
+
? {}
|
|
113
|
+
: { accountDisplayName: normalizedAccountDisplayName }),
|
|
102
114
|
hash: contextHash,
|
|
103
115
|
expiresAt: session.expiresAt,
|
|
104
116
|
sessionHash,
|
|
@@ -132,6 +144,9 @@ export class LocalConsoleSessionRegistry {
|
|
|
132
144
|
}
|
|
133
145
|
return {
|
|
134
146
|
accountReady: context.accountReady,
|
|
147
|
+
...(context.accountDisplayName === undefined
|
|
148
|
+
? {}
|
|
149
|
+
: { accountDisplayName: context.accountDisplayName }),
|
|
135
150
|
csrfToken: session.csrfToken,
|
|
136
151
|
context: context.context,
|
|
137
152
|
};
|
|
@@ -8,7 +8,7 @@ export declare const ExecutionActivitySummarySchema: import("@sinclair/typebox")
|
|
|
8
8
|
lane: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"foreground">, import("@sinclair/typebox").TLiteral<"scratchpad_background">]>>;
|
|
9
9
|
started_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
10
|
}>;
|
|
11
|
-
export declare const ExecutionRuntimeActionSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>;
|
|
11
|
+
export declare const ExecutionRuntimeActionSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>;
|
|
12
12
|
export declare const ExecutionRuntimeTokenUsageSchema: import("@sinclair/typebox").TObject<{
|
|
13
13
|
input_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
14
14
|
cached_input_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
@@ -28,7 +28,7 @@ export declare const ExecutionRuntimeSnapshotSchema: import("@sinclair/typebox")
|
|
|
28
28
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
29
29
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
30
30
|
}>>;
|
|
31
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
31
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
32
32
|
}>;
|
|
33
33
|
export declare const ExecutionStatusProjectionSchema: import("@sinclair/typebox").TObject<{
|
|
34
34
|
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"idle">, import("@sinclair/typebox").TLiteral<"running">, import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"failed">]>;
|
|
@@ -75,7 +75,7 @@ export declare const ExecutionStatusProjectionSchema: import("@sinclair/typebox"
|
|
|
75
75
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
76
76
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
77
77
|
}>>;
|
|
78
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
78
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
79
79
|
}>>;
|
|
80
80
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
81
81
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -212,7 +212,7 @@ export declare const ExecutionStatusChangedEventPayloadSchema: import("@sinclair
|
|
|
212
212
|
reasoning_output_tokens: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
213
213
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
214
214
|
}>>;
|
|
215
|
-
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
215
|
+
current_action: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"analyzing_task">, import("@sinclair/typebox").TLiteral<"searching_codebase">, import("@sinclair/typebox").TLiteral<"reading_files">, import("@sinclair/typebox").TLiteral<"reading_context">, import("@sinclair/typebox").TLiteral<"planning">, import("@sinclair/typebox").TLiteral<"editing_files">, import("@sinclair/typebox").TLiteral<"running_checks">, import("@sinclair/typebox").TLiteral<"running_command">, import("@sinclair/typebox").TLiteral<"using_tool">, import("@sinclair/typebox").TLiteral<"waiting_for_approval">, import("@sinclair/typebox").TLiteral<"preparing_result">, import("@sinclair/typebox").TLiteral<"finalizing">]>>;
|
|
216
216
|
}>>;
|
|
217
217
|
blocked_by: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
|
|
218
218
|
kind: import("@sinclair/typebox").TLiteral<"clarification">;
|
|
@@ -23,12 +23,17 @@ export const ExecutionActivitySummarySchema = Type.Object({
|
|
|
23
23
|
started_at: Type.Optional(IsoDateTimeStringSchema),
|
|
24
24
|
}, { additionalProperties: false });
|
|
25
25
|
export const ExecutionRuntimeActionSchema = Type.Union([
|
|
26
|
+
Type.Literal("analyzing_task"),
|
|
27
|
+
Type.Literal("searching_codebase"),
|
|
28
|
+
Type.Literal("reading_files"),
|
|
26
29
|
Type.Literal("reading_context"),
|
|
27
30
|
Type.Literal("planning"),
|
|
28
31
|
Type.Literal("editing_files"),
|
|
32
|
+
Type.Literal("running_checks"),
|
|
29
33
|
Type.Literal("running_command"),
|
|
30
34
|
Type.Literal("using_tool"),
|
|
31
35
|
Type.Literal("waiting_for_approval"),
|
|
36
|
+
Type.Literal("preparing_result"),
|
|
32
37
|
Type.Literal("finalizing"),
|
|
33
38
|
]);
|
|
34
39
|
export const ExecutionRuntimeTokenUsageSchema = Type.Object({
|