@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.
@@ -5,7 +5,7 @@ export type CodexAppServerRuntimeTelemetryOptions = {
5
5
  activityRef: ActivityRef;
6
6
  stageId?: string;
7
7
  startedAt?: string;
8
- throttleMs?: number;
8
+ actionMinVisibleMs?: number;
9
9
  now?: () => Date;
10
10
  onSnapshot?: (snapshot: ExecutionRuntimeSnapshot) => void;
11
11
  };
@@ -1,46 +1,99 @@
1
1
  import { extractCodexAppServerTokenUsage } from "../token-usage.js";
2
- const DEFAULT_THROTTLE_MS = 5_000;
3
- function searchText(value) {
4
- if (typeof value === "string") {
5
- return value.toLocaleLowerCase();
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 (typeof value !== "object" || value === null) {
8
- return "";
30
+ if (actionTypes.includes("read")) {
31
+ return "reading_files";
9
32
  }
10
- const record = value;
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 actionFromNotification(notification) {
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
- const paramsText = searchText(notification.params);
19
- const combined = `${method} ${paramsText}`.toLocaleLowerCase();
20
- if (combined.includes("commandexecution") || combined.includes("command_execution")) {
21
- return "running_command";
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/plan/updated" || combined.includes("plan")) {
29
- return "planning";
70
+ if (method === "turn/completed") {
71
+ return "preparing_result";
30
72
  }
31
- if (combined.includes("mcptoolcall") ||
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 = 0;
57
- const throttleMs = options.throttleMs ?? DEFAULT_THROTTLE_MS;
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 (latest === undefined || options.onSnapshot === undefined) {
117
+ const emit = (snapshot = latest) => {
118
+ if (snapshot === undefined || options.onSnapshot === undefined) {
61
119
  return;
62
120
  }
63
121
  lastEmittedAt = Date.now();
64
- options.onSnapshot(latest);
122
+ lastEmittedAction = snapshot.current_action;
123
+ options.onSnapshot(snapshot);
65
124
  };
66
- const scheduleEmit = () => {
67
- if (options.onSnapshot === undefined) {
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 >= throttleMs) {
144
+ if (elapsed >= actionMinVisibleMs) {
72
145
  if (timer !== undefined) {
73
146
  clearTimeout(timer);
74
147
  timer = undefined;
75
148
  }
76
- emit();
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
- emit();
85
- }, Math.max(1, throttleMs - elapsed));
157
+ publishPendingSnapshot();
158
+ }, Math.max(1, actionMinVisibleMs - elapsed));
86
159
  };
87
- const update = (patch) => {
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
- scheduleEmit();
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
- const currentAction = actionFromNotification(notification);
112
- update({
113
- ...(tokenUsage === undefined ? {} : { tokenUsage }),
114
- ...(currentAction === undefined ? {} : { currentAction }),
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
- emit();
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: { access_token: { type: "string", minLength: 1 } },
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: { status: session.accountReady ? "ready" : "required" },
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfey/tutti",
3
- "version": "0.1.87",
3
+ "version": "0.1.89",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",