@usabledev/usable-chat 1.178.3 → 1.180.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/cli.js +850 -97
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -4159,6 +4159,150 @@ var init_zod = __esm({
|
|
|
4159
4159
|
}
|
|
4160
4160
|
});
|
|
4161
4161
|
|
|
4162
|
+
// src/core/todos/types.ts
|
|
4163
|
+
function validateItemInvariants(items, context) {
|
|
4164
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4165
|
+
let inProgressCount = 0;
|
|
4166
|
+
for (const [index2, item] of items.entries()) {
|
|
4167
|
+
if (ids.has(item.id)) {
|
|
4168
|
+
context.addIssue({
|
|
4169
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4170
|
+
message: "Todo item IDs must be unique",
|
|
4171
|
+
path: [index2, "id"]
|
|
4172
|
+
});
|
|
4173
|
+
}
|
|
4174
|
+
ids.add(item.id);
|
|
4175
|
+
if (item.status === "in_progress") inProgressCount += 1;
|
|
4176
|
+
}
|
|
4177
|
+
if (inProgressCount > 1) {
|
|
4178
|
+
context.addIssue({
|
|
4179
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4180
|
+
message: "Only one todo item may be in progress",
|
|
4181
|
+
path: []
|
|
4182
|
+
});
|
|
4183
|
+
}
|
|
4184
|
+
if (new TextEncoder().encode(JSON.stringify(items)).byteLength > MAX_TODO_SERIALIZED_BYTES) {
|
|
4185
|
+
context.addIssue({
|
|
4186
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4187
|
+
message: "Todo list exceeds the serialized size limit",
|
|
4188
|
+
path: []
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
function parseTodoItems(value) {
|
|
4193
|
+
return todoItemsSchema.parse(value);
|
|
4194
|
+
}
|
|
4195
|
+
function parseTodoSnapshot(value) {
|
|
4196
|
+
return todoSnapshotSchema.parse(value);
|
|
4197
|
+
}
|
|
4198
|
+
function createEmptyTodoSnapshot() {
|
|
4199
|
+
return {
|
|
4200
|
+
schemaVersion: TODO_SCHEMA_VERSION,
|
|
4201
|
+
revision: 0,
|
|
4202
|
+
items: [],
|
|
4203
|
+
updatedAt: null,
|
|
4204
|
+
recentCommands: []
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4207
|
+
function createExpiredTodoSnapshot(previous, now2) {
|
|
4208
|
+
const current = parseTodoSnapshot(previous);
|
|
4209
|
+
return parseTodoSnapshot({
|
|
4210
|
+
schemaVersion: TODO_SCHEMA_VERSION,
|
|
4211
|
+
revision: current.revision + 1,
|
|
4212
|
+
items: [],
|
|
4213
|
+
updatedAt: now2.toISOString(),
|
|
4214
|
+
recentCommands: []
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
function createTodoCandidate(input) {
|
|
4218
|
+
const previous = parseTodoSnapshot(input.previous);
|
|
4219
|
+
const items = parseTodoItems(input.items);
|
|
4220
|
+
const revision = previous.revision + 1;
|
|
4221
|
+
return parseTodoSnapshot({
|
|
4222
|
+
schemaVersion: TODO_SCHEMA_VERSION,
|
|
4223
|
+
revision,
|
|
4224
|
+
items,
|
|
4225
|
+
updatedAt: input.now.toISOString(),
|
|
4226
|
+
recentCommands: [
|
|
4227
|
+
...previous.recentCommands,
|
|
4228
|
+
{ id: input.commandId, fingerprint: input.fingerprint, revision }
|
|
4229
|
+
].slice(-MAX_TODO_COMMANDS)
|
|
4230
|
+
});
|
|
4231
|
+
}
|
|
4232
|
+
function isTodoSnapshotExpired(snapshot, now2) {
|
|
4233
|
+
if (!snapshot.updatedAt || snapshot.revision === 0) return false;
|
|
4234
|
+
if (snapshot.items.length === 0 && snapshot.recentCommands.length === 0) return false;
|
|
4235
|
+
const updatedAt = Date.parse(snapshot.updatedAt);
|
|
4236
|
+
return !Number.isFinite(updatedAt) || now2.getTime() - updatedAt >= TODO_TTL_MS;
|
|
4237
|
+
}
|
|
4238
|
+
var TODO_SCHEMA_VERSION, TODO_TTL_MS, MAX_TODO_ITEMS, MAX_TODO_TEXT_LENGTH, MAX_TODO_SERIALIZED_BYTES, MAX_TODO_COMMANDS, todoStatusSchema, todoItemSchema, todoCommandRecordSchema, todoSnapshotSchema, todoItemsSchema, todoUpdateInputSchema;
|
|
4239
|
+
var init_types2 = __esm({
|
|
4240
|
+
"src/core/todos/types.ts"() {
|
|
4241
|
+
"use strict";
|
|
4242
|
+
init_zod();
|
|
4243
|
+
TODO_SCHEMA_VERSION = 1;
|
|
4244
|
+
TODO_TTL_MS = 30 * 60 * 1e3;
|
|
4245
|
+
MAX_TODO_ITEMS = 50;
|
|
4246
|
+
MAX_TODO_TEXT_LENGTH = 300;
|
|
4247
|
+
MAX_TODO_SERIALIZED_BYTES = 16 * 1024;
|
|
4248
|
+
MAX_TODO_COMMANDS = 32;
|
|
4249
|
+
todoStatusSchema = external_exports.enum(["pending", "in_progress", "completed"]);
|
|
4250
|
+
todoItemSchema = external_exports.object({
|
|
4251
|
+
id: external_exports.string().uuid(),
|
|
4252
|
+
content: external_exports.string().trim().min(1).max(MAX_TODO_TEXT_LENGTH),
|
|
4253
|
+
status: todoStatusSchema
|
|
4254
|
+
}).strict();
|
|
4255
|
+
todoCommandRecordSchema = external_exports.object({
|
|
4256
|
+
id: external_exports.string().uuid(),
|
|
4257
|
+
fingerprint: external_exports.string().regex(/^[a-f0-9]{64}$/),
|
|
4258
|
+
revision: external_exports.number().int().positive()
|
|
4259
|
+
}).strict();
|
|
4260
|
+
todoSnapshotSchema = external_exports.object({
|
|
4261
|
+
schemaVersion: external_exports.literal(TODO_SCHEMA_VERSION),
|
|
4262
|
+
revision: external_exports.number().int().nonnegative(),
|
|
4263
|
+
items: external_exports.array(todoItemSchema).max(MAX_TODO_ITEMS),
|
|
4264
|
+
updatedAt: external_exports.string().datetime().nullable(),
|
|
4265
|
+
recentCommands: external_exports.array(todoCommandRecordSchema).max(MAX_TODO_COMMANDS)
|
|
4266
|
+
}).strict().superRefine((snapshot, context) => {
|
|
4267
|
+
validateItemInvariants(snapshot.items, context);
|
|
4268
|
+
if (snapshot.revision === 0 && snapshot.updatedAt !== null) {
|
|
4269
|
+
context.addIssue({
|
|
4270
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4271
|
+
message: "An empty revision must not have an update timestamp",
|
|
4272
|
+
path: ["updatedAt"]
|
|
4273
|
+
});
|
|
4274
|
+
}
|
|
4275
|
+
if (snapshot.revision > 0 && snapshot.updatedAt === null) {
|
|
4276
|
+
context.addIssue({
|
|
4277
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4278
|
+
message: "A persisted revision must have an update timestamp",
|
|
4279
|
+
path: ["updatedAt"]
|
|
4280
|
+
});
|
|
4281
|
+
}
|
|
4282
|
+
if (snapshot.revision === 0 && (snapshot.items.length > 0 || snapshot.recentCommands.length > 0)) {
|
|
4283
|
+
context.addIssue({
|
|
4284
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4285
|
+
message: "Revision zero must be the canonical empty snapshot",
|
|
4286
|
+
path: []
|
|
4287
|
+
});
|
|
4288
|
+
}
|
|
4289
|
+
if (snapshot.recentCommands.some((command) => command.revision > snapshot.revision)) {
|
|
4290
|
+
context.addIssue({
|
|
4291
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4292
|
+
message: "Command revision cannot exceed snapshot revision",
|
|
4293
|
+
path: ["recentCommands"]
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4296
|
+
});
|
|
4297
|
+
todoItemsSchema = external_exports.array(todoItemSchema).max(MAX_TODO_ITEMS).superRefine((items, context) => validateItemInvariants(items, context));
|
|
4298
|
+
todoUpdateInputSchema = external_exports.object({
|
|
4299
|
+
baseRevision: external_exports.number().int().nonnegative(),
|
|
4300
|
+
commandId: external_exports.string().uuid(),
|
|
4301
|
+
items: todoItemsSchema
|
|
4302
|
+
}).strict();
|
|
4303
|
+
}
|
|
4304
|
+
});
|
|
4305
|
+
|
|
4162
4306
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/core.js
|
|
4163
4307
|
// @__NO_SIDE_EFFECTS__
|
|
4164
4308
|
function $constructor(name18, initializer3, params) {
|
|
@@ -22858,7 +23002,7 @@ var init_ComponentLogger = __esm({
|
|
|
22858
23002
|
|
|
22859
23003
|
// node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/diag/types.js
|
|
22860
23004
|
var DiagLogLevel;
|
|
22861
|
-
var
|
|
23005
|
+
var init_types3 = __esm({
|
|
22862
23006
|
"node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/diag/types.js"() {
|
|
22863
23007
|
"use strict";
|
|
22864
23008
|
(function(DiagLogLevel2) {
|
|
@@ -22900,7 +23044,7 @@ function createLogLevelDiagLogger(maxLevel, logger5) {
|
|
|
22900
23044
|
var init_logLevelLogger = __esm({
|
|
22901
23045
|
"node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js"() {
|
|
22902
23046
|
"use strict";
|
|
22903
|
-
|
|
23047
|
+
init_types3();
|
|
22904
23048
|
}
|
|
22905
23049
|
});
|
|
22906
23050
|
|
|
@@ -22911,7 +23055,7 @@ var init_diag = __esm({
|
|
|
22911
23055
|
"use strict";
|
|
22912
23056
|
init_ComponentLogger();
|
|
22913
23057
|
init_logLevelLogger();
|
|
22914
|
-
|
|
23058
|
+
init_types3();
|
|
22915
23059
|
init_global_utils();
|
|
22916
23060
|
__read2 = function(o21, n31) {
|
|
22917
23061
|
var m33 = typeof Symbol === "function" && o21[Symbol.iterator];
|
|
@@ -50502,7 +50646,7 @@ var init_mask_color = __esm({
|
|
|
50502
50646
|
|
|
50503
50647
|
// node_modules/.pnpm/bmp-ts@1.0.9/node_modules/bmp-ts/dist/esm/types.js
|
|
50504
50648
|
var BmpCompression;
|
|
50505
|
-
var
|
|
50649
|
+
var init_types4 = __esm({
|
|
50506
50650
|
"node_modules/.pnpm/bmp-ts@1.0.9/node_modules/bmp-ts/dist/esm/types.js"() {
|
|
50507
50651
|
"use strict";
|
|
50508
50652
|
(function(BmpCompression2) {
|
|
@@ -50522,7 +50666,7 @@ var init_decoder = __esm({
|
|
|
50522
50666
|
"use strict";
|
|
50523
50667
|
init_header_types();
|
|
50524
50668
|
init_mask_color();
|
|
50525
|
-
|
|
50669
|
+
init_types4();
|
|
50526
50670
|
BmpDecoder = class {
|
|
50527
50671
|
// Header
|
|
50528
50672
|
flag;
|
|
@@ -51161,7 +51305,7 @@ var init_esm3 = __esm({
|
|
|
51161
51305
|
"use strict";
|
|
51162
51306
|
init_decoder();
|
|
51163
51307
|
init_encoder();
|
|
51164
|
-
|
|
51308
|
+
init_types4();
|
|
51165
51309
|
}
|
|
51166
51310
|
});
|
|
51167
51311
|
|
|
@@ -79100,7 +79244,7 @@ var init_measure_text = __esm({
|
|
|
79100
79244
|
});
|
|
79101
79245
|
|
|
79102
79246
|
// node_modules/.pnpm/@jimp+plugin-print@1.6.1/node_modules/@jimp/plugin-print/dist/esm/types.js
|
|
79103
|
-
var
|
|
79247
|
+
var init_types5 = __esm({
|
|
79104
79248
|
"node_modules/.pnpm/@jimp+plugin-print@1.6.1/node_modules/@jimp/plugin-print/dist/esm/types.js"() {
|
|
79105
79249
|
"use strict";
|
|
79106
79250
|
}
|
|
@@ -79163,7 +79307,7 @@ var init_esm27 = __esm({
|
|
|
79163
79307
|
init_zod();
|
|
79164
79308
|
init_measure_text();
|
|
79165
79309
|
init_measure_text();
|
|
79166
|
-
|
|
79310
|
+
init_types5();
|
|
79167
79311
|
PrintOptionsSchema = external_exports.object({
|
|
79168
79312
|
/** the x position to draw the image */
|
|
79169
79313
|
x: external_exports.number(),
|
|
@@ -92728,7 +92872,7 @@ function createJsonTransform(fn4) {
|
|
|
92728
92872
|
};
|
|
92729
92873
|
}
|
|
92730
92874
|
var types, NotTagged, Identifier, Parameter, Builder, defaultHandlers, builders, serializers, parsers, mergeUserTypes, escapeIdentifier, inferType, escapeBackslash, escapeQuote, arraySerializer, arrayParserState, arrayParser, toCamel, toPascal, toKebab, fromCamel, fromPascal, fromKebab, camel, pascal, kebab;
|
|
92731
|
-
var
|
|
92875
|
+
var init_types6 = __esm({
|
|
92732
92876
|
"node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/src/types.js"() {
|
|
92733
92877
|
"use strict";
|
|
92734
92878
|
init_query2();
|
|
@@ -93817,7 +93961,7 @@ var connection_default, uid, Sync, Flush, SSLRequest, ExecuteUnnamed, DescribeUn
|
|
|
93817
93961
|
var init_connection = __esm({
|
|
93818
93962
|
"node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/src/connection.js"() {
|
|
93819
93963
|
"use strict";
|
|
93820
|
-
|
|
93964
|
+
init_types6();
|
|
93821
93965
|
init_errors5();
|
|
93822
93966
|
init_result();
|
|
93823
93967
|
init_queue();
|
|
@@ -94554,7 +94698,7 @@ var src_default;
|
|
|
94554
94698
|
var init_src = __esm({
|
|
94555
94699
|
"node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/src/index.js"() {
|
|
94556
94700
|
"use strict";
|
|
94557
|
-
|
|
94701
|
+
init_types6();
|
|
94558
94702
|
init_connection();
|
|
94559
94703
|
init_query2();
|
|
94560
94704
|
init_queue();
|
|
@@ -104058,6 +104202,7 @@ __export(schema_exports, {
|
|
|
104058
104202
|
configCollaborators: () => configCollaborators,
|
|
104059
104203
|
conversationContext: () => conversationContext,
|
|
104060
104204
|
conversationShares: () => conversationShares,
|
|
104205
|
+
conversationTodoState: () => conversationTodoState,
|
|
104061
104206
|
conversations: () => conversations,
|
|
104062
104207
|
customExperts: () => customExperts,
|
|
104063
104208
|
embedKeys: () => embedKeys,
|
|
@@ -104082,7 +104227,7 @@ __export(schema_exports, {
|
|
|
104082
104227
|
vaultSecrets: () => vaultSecrets,
|
|
104083
104228
|
vizDailyStats: () => vizDailyStats
|
|
104084
104229
|
});
|
|
104085
|
-
var pathwayState, pathwayLeases, pathwayInstances, users, projects, conversations, messages2, artifacts, vizDailyStats, conversationShares, projectShares;
|
|
104230
|
+
var pathwayState, pathwayLeases, pathwayInstances, users, projects, conversations, conversationTodoState, messages2, artifacts, vizDailyStats, conversationShares, projectShares;
|
|
104086
104231
|
var init_schema2 = __esm({
|
|
104087
104232
|
"src/lib/db/schema.ts"() {
|
|
104088
104233
|
"use strict";
|
|
@@ -104199,6 +104344,21 @@ var init_schema2 = __esm({
|
|
|
104199
104344
|
parentIdIdx: index("conversations_parent_id_idx").on(table.parentConversationId)
|
|
104200
104345
|
})
|
|
104201
104346
|
);
|
|
104347
|
+
conversationTodoState = pgTable(
|
|
104348
|
+
"conversation_todo_state",
|
|
104349
|
+
{
|
|
104350
|
+
// No FK: conversation projection is eventually consistent and may land
|
|
104351
|
+
// after a first-turn checklist update. Lifecycle handlers remove rows.
|
|
104352
|
+
conversationId: uuid3("conversation_id").primaryKey(),
|
|
104353
|
+
userId: varchar("user_id", { length: 255 }).notNull(),
|
|
104354
|
+
snapshot: jsonb("snapshot").$type().notNull(),
|
|
104355
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull()
|
|
104356
|
+
},
|
|
104357
|
+
(table) => ({
|
|
104358
|
+
userIdIdx: index("conversation_todo_state_user_id_idx").on(table.userId),
|
|
104359
|
+
updatedAtIdx: index("conversation_todo_state_updated_at_idx").on(table.updatedAt)
|
|
104360
|
+
})
|
|
104361
|
+
);
|
|
104202
104362
|
messages2 = pgTable(
|
|
104203
104363
|
"messages",
|
|
104204
104364
|
{
|
|
@@ -110919,9 +111079,9 @@ var require_dist_cjs12 = __commonJS({
|
|
|
110919
111079
|
httpHandler: httpHandlerExtensionConfiguration.httpHandler()
|
|
110920
111080
|
};
|
|
110921
111081
|
}, "resolveHttpHandlerRuntimeConfig");
|
|
110922
|
-
var
|
|
111082
|
+
var import_types25 = require_dist_cjs11();
|
|
110923
111083
|
var _Field = class _Field {
|
|
110924
|
-
constructor({ name: name18, kind =
|
|
111084
|
+
constructor({ name: name18, kind = import_types25.FieldPosition.HEADER, values: values2 = [] }) {
|
|
110925
111085
|
this.name = name18;
|
|
110926
111086
|
this.kind = kind;
|
|
110927
111087
|
this.values = values2;
|
|
@@ -111231,8 +111391,8 @@ var require_dist_cjs14 = __commonJS({
|
|
|
111231
111391
|
normalizeProvider: () => normalizeProvider8
|
|
111232
111392
|
});
|
|
111233
111393
|
module.exports = __toCommonJS2(src_exports2);
|
|
111234
|
-
var
|
|
111235
|
-
var getSmithyContext13 = /* @__PURE__ */ __name((context) => context[
|
|
111394
|
+
var import_types25 = require_dist_cjs13();
|
|
111395
|
+
var getSmithyContext13 = /* @__PURE__ */ __name((context) => context[import_types25.SMITHY_CONTEXT_KEY] || (context[import_types25.SMITHY_CONTEXT_KEY] = {}), "getSmithyContext");
|
|
111236
111396
|
var normalizeProvider8 = /* @__PURE__ */ __name((input) => {
|
|
111237
111397
|
if (typeof input === "function")
|
|
111238
111398
|
return input;
|
|
@@ -113015,12 +113175,12 @@ var require_dist_cjs24 = __commonJS({
|
|
|
113015
113175
|
});
|
|
113016
113176
|
|
|
113017
113177
|
// node_modules/.pnpm/@smithy+core@3.23.11/node_modules/@smithy/core/dist-es/getSmithyContext.js
|
|
113018
|
-
var
|
|
113178
|
+
var import_types13, getSmithyContext;
|
|
113019
113179
|
var init_getSmithyContext = __esm({
|
|
113020
113180
|
"node_modules/.pnpm/@smithy+core@3.23.11/node_modules/@smithy/core/dist-es/getSmithyContext.js"() {
|
|
113021
113181
|
"use strict";
|
|
113022
|
-
|
|
113023
|
-
getSmithyContext = (context) => context[
|
|
113182
|
+
import_types13 = __toESM(require_dist_cjs2());
|
|
113183
|
+
getSmithyContext = (context) => context[import_types13.SMITHY_CONTEXT_KEY] || (context[import_types13.SMITHY_CONTEXT_KEY] = {});
|
|
113024
113184
|
}
|
|
113025
113185
|
});
|
|
113026
113186
|
|
|
@@ -117857,12 +118017,12 @@ var init_DefaultIdentityProviderConfig = __esm({
|
|
|
117857
118017
|
});
|
|
117858
118018
|
|
|
117859
118019
|
// node_modules/.pnpm/@smithy+core@3.23.11/node_modules/@smithy/core/dist-es/util-identity-and-auth/httpAuthSchemes/httpApiKeyAuth.js
|
|
117860
|
-
var import_protocol_http7,
|
|
118020
|
+
var import_protocol_http7, import_types14, HttpApiKeyAuthSigner;
|
|
117861
118021
|
var init_httpApiKeyAuth = __esm({
|
|
117862
118022
|
"node_modules/.pnpm/@smithy+core@3.23.11/node_modules/@smithy/core/dist-es/util-identity-and-auth/httpAuthSchemes/httpApiKeyAuth.js"() {
|
|
117863
118023
|
"use strict";
|
|
117864
118024
|
import_protocol_http7 = __toESM(require_dist_cjs3());
|
|
117865
|
-
|
|
118025
|
+
import_types14 = __toESM(require_dist_cjs2());
|
|
117866
118026
|
HttpApiKeyAuthSigner = class {
|
|
117867
118027
|
async sign(httpRequest, identity, signingProperties) {
|
|
117868
118028
|
if (!signingProperties) {
|
|
@@ -117878,9 +118038,9 @@ var init_httpApiKeyAuth = __esm({
|
|
|
117878
118038
|
throw new Error("request could not be signed with `apiKey` since the `apiKey` is not defined");
|
|
117879
118039
|
}
|
|
117880
118040
|
const clonedRequest = import_protocol_http7.HttpRequest.clone(httpRequest);
|
|
117881
|
-
if (signingProperties.in ===
|
|
118041
|
+
if (signingProperties.in === import_types14.HttpApiKeyAuthLocation.QUERY) {
|
|
117882
118042
|
clonedRequest.query[signingProperties.name] = identity.apiKey;
|
|
117883
|
-
} else if (signingProperties.in ===
|
|
118043
|
+
} else if (signingProperties.in === import_types14.HttpApiKeyAuthLocation.HEADER) {
|
|
117884
118044
|
clonedRequest.headers[signingProperties.name] = signingProperties.scheme ? `${signingProperties.scheme} ${identity.apiKey}` : identity.apiKey;
|
|
117885
118045
|
} else {
|
|
117886
118046
|
throw new Error("request can only be signed with `apiKey` locations `query` or `header`, but found: `" + signingProperties.in + "`");
|
|
@@ -139370,7 +139530,7 @@ var require_dist_cjs81 = __commonJS({
|
|
|
139370
139530
|
const fromContext = context.streamCollector(streamBody);
|
|
139371
139531
|
return import_util_stream3.Uint8ArrayBlobAdapter.mutate(await fromContext);
|
|
139372
139532
|
}, "collectBody");
|
|
139373
|
-
var
|
|
139533
|
+
var import_types25 = require_dist_cjs11();
|
|
139374
139534
|
var _Command = class _Command {
|
|
139375
139535
|
constructor() {
|
|
139376
139536
|
this.middlewareStack = (0, import_middleware_stack.constructStack)();
|
|
@@ -139406,7 +139566,7 @@ var require_dist_cjs81 = __commonJS({
|
|
|
139406
139566
|
commandName,
|
|
139407
139567
|
inputFilterSensitiveLog,
|
|
139408
139568
|
outputFilterSensitiveLog,
|
|
139409
|
-
[
|
|
139569
|
+
[import_types25.SMITHY_CONTEXT_KEY]: {
|
|
139410
139570
|
...smithyContext
|
|
139411
139571
|
},
|
|
139412
139572
|
...additionalContext
|
|
@@ -140092,8 +140252,8 @@ var require_dist_cjs81 = __commonJS({
|
|
|
140092
140252
|
}, "emitWarningIfUnsupportedVersion");
|
|
140093
140253
|
var getChecksumConfiguration = /* @__PURE__ */ __name((runtimeConfig) => {
|
|
140094
140254
|
const checksumAlgorithms = [];
|
|
140095
|
-
for (const id in
|
|
140096
|
-
const algorithmId =
|
|
140255
|
+
for (const id in import_types25.AlgorithmId) {
|
|
140256
|
+
const algorithmId = import_types25.AlgorithmId[id];
|
|
140097
140257
|
if (runtimeConfig[algorithmId] === void 0) {
|
|
140098
140258
|
continue;
|
|
140099
140259
|
}
|
|
@@ -148124,7 +148284,7 @@ var init_zod_compat = __esm({
|
|
|
148124
148284
|
|
|
148125
148285
|
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
148126
148286
|
var LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, JSONRPC_VERSION, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, isInitializedNotification, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
|
|
148127
|
-
var
|
|
148287
|
+
var init_types7 = __esm({
|
|
148128
148288
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
|
|
148129
148289
|
"use strict";
|
|
148130
148290
|
init_v4();
|
|
@@ -150098,7 +150258,7 @@ var init_protocol = __esm({
|
|
|
150098
150258
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js"() {
|
|
150099
150259
|
"use strict";
|
|
150100
150260
|
init_zod_compat();
|
|
150101
|
-
|
|
150261
|
+
init_types7();
|
|
150102
150262
|
init_interfaces();
|
|
150103
150263
|
init_zod_json_schema_compat();
|
|
150104
150264
|
DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
@@ -157972,7 +158132,7 @@ var ExperimentalClientTasks;
|
|
|
157972
158132
|
var init_client6 = __esm({
|
|
157973
158133
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js"() {
|
|
157974
158134
|
"use strict";
|
|
157975
|
-
|
|
158135
|
+
init_types7();
|
|
157976
158136
|
ExperimentalClientTasks = class {
|
|
157977
158137
|
constructor(_client2) {
|
|
157978
158138
|
this._client = _client2;
|
|
@@ -158215,7 +158375,7 @@ var init_client7 = __esm({
|
|
|
158215
158375
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js"() {
|
|
158216
158376
|
"use strict";
|
|
158217
158377
|
init_protocol();
|
|
158218
|
-
|
|
158378
|
+
init_types7();
|
|
158219
158379
|
init_ajv_provider();
|
|
158220
158380
|
init_zod_compat();
|
|
158221
158381
|
init_client6();
|
|
@@ -159595,7 +159755,7 @@ var init_auth4 = __esm({
|
|
|
159595
159755
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js"() {
|
|
159596
159756
|
"use strict";
|
|
159597
159757
|
init_index_node();
|
|
159598
|
-
|
|
159758
|
+
init_types7();
|
|
159599
159759
|
init_auth3();
|
|
159600
159760
|
init_auth3();
|
|
159601
159761
|
init_auth_utils();
|
|
@@ -159616,7 +159776,7 @@ var init_streamableHttp = __esm({
|
|
|
159616
159776
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js"() {
|
|
159617
159777
|
"use strict";
|
|
159618
159778
|
init_transport();
|
|
159619
|
-
|
|
159779
|
+
init_types7();
|
|
159620
159780
|
init_auth4();
|
|
159621
159781
|
init_stream();
|
|
159622
159782
|
DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
@@ -181559,7 +181719,7 @@ var require_websocket = __commonJS({
|
|
|
181559
181719
|
var http3 = __require("http");
|
|
181560
181720
|
var net2 = __require("net");
|
|
181561
181721
|
var tls2 = __require("tls");
|
|
181562
|
-
var { randomBytes: randomBytes5, createHash:
|
|
181722
|
+
var { randomBytes: randomBytes5, createHash: createHash7 } = __require("crypto");
|
|
181563
181723
|
var { Duplex, Readable: Readable3 } = __require("stream");
|
|
181564
181724
|
var { URL: URL2 } = __require("url");
|
|
181565
181725
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -182219,7 +182379,7 @@ var require_websocket = __commonJS({
|
|
|
182219
182379
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
182220
182380
|
return;
|
|
182221
182381
|
}
|
|
182222
|
-
const digest =
|
|
182382
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
182223
182383
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
182224
182384
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
182225
182385
|
return;
|
|
@@ -182586,7 +182746,7 @@ var require_websocket_server = __commonJS({
|
|
|
182586
182746
|
var EventEmitter4 = __require("events");
|
|
182587
182747
|
var http3 = __require("http");
|
|
182588
182748
|
var { Duplex } = __require("stream");
|
|
182589
|
-
var { createHash:
|
|
182749
|
+
var { createHash: createHash7 } = __require("crypto");
|
|
182590
182750
|
var extension2 = require_extension();
|
|
182591
182751
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
182592
182752
|
var subprotocol2 = require_subprotocol();
|
|
@@ -182887,7 +183047,7 @@ var require_websocket_server = __commonJS({
|
|
|
182887
183047
|
);
|
|
182888
183048
|
}
|
|
182889
183049
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
182890
|
-
const digest =
|
|
183050
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
182891
183051
|
const headers = [
|
|
182892
183052
|
"HTTP/1.1 101 Switching Protocols",
|
|
182893
183053
|
"Upgrade: websocket",
|
|
@@ -202533,8 +202693,10 @@ __export(tool_categories_exports, {
|
|
|
202533
202693
|
filterPlanModeTools: () => filterPlanModeTools,
|
|
202534
202694
|
filterToExpertTools: () => filterToExpertTools,
|
|
202535
202695
|
filterToMainAgentTools: () => filterToMainAgentTools,
|
|
202696
|
+
filterToPersonaEnabledTools: () => filterToPersonaEnabledTools,
|
|
202536
202697
|
getExpertForTool: () => getExpertForTool,
|
|
202537
202698
|
getToolsForExpert: () => getToolsForExpert,
|
|
202699
|
+
hasPersonaToolAllowlist: () => hasPersonaToolAllowlist,
|
|
202538
202700
|
isExpertOnlyTool: () => isExpertOnlyTool,
|
|
202539
202701
|
isMainAgentTool: () => isMainAgentTool
|
|
202540
202702
|
});
|
|
@@ -202564,6 +202726,19 @@ function filterToMainAgentTools(allTools) {
|
|
|
202564
202726
|
}
|
|
202565
202727
|
return filtered;
|
|
202566
202728
|
}
|
|
202729
|
+
function hasPersonaToolAllowlist(enabledTools) {
|
|
202730
|
+
return enabledTools !== void 0;
|
|
202731
|
+
}
|
|
202732
|
+
function filterToPersonaEnabledTools(tools, enabledTools) {
|
|
202733
|
+
const enabled = new Set(enabledTools);
|
|
202734
|
+
return Object.fromEntries(
|
|
202735
|
+
Object.entries(tools).filter(([name18]) => {
|
|
202736
|
+
if (name18.startsWith("parent_")) return true;
|
|
202737
|
+
const baseName = extractBaseToolName(name18);
|
|
202738
|
+
return enabled.has(name18) || enabled.has(baseName);
|
|
202739
|
+
})
|
|
202740
|
+
);
|
|
202741
|
+
}
|
|
202567
202742
|
function extractBaseToolName(name18) {
|
|
202568
202743
|
if (name18.includes("__")) return name18.split("__").pop() || name18;
|
|
202569
202744
|
if (name18.startsWith("mcp_usable_")) return name18.slice("mcp_usable_".length);
|
|
@@ -202668,7 +202843,8 @@ var init_tool_categories = __esm({
|
|
|
202668
202843
|
"browser_folder__write_sandbox_file",
|
|
202669
202844
|
"browser_folder__edit_file",
|
|
202670
202845
|
"browser_folder__create_directory",
|
|
202671
|
-
"browser_folder__delete_entry"
|
|
202846
|
+
"browser_folder__delete_entry",
|
|
202847
|
+
"update_todo_list"
|
|
202672
202848
|
];
|
|
202673
202849
|
PLAN_MODE_FILTERED_TOOLS = [
|
|
202674
202850
|
...DISCUSSION_MODE_FILTERED_TOOLS,
|
|
@@ -214659,6 +214835,197 @@ Use this to discover the current state of background work \u2014 running, comple
|
|
|
214659
214835
|
}
|
|
214660
214836
|
});
|
|
214661
214837
|
|
|
214838
|
+
// src/core/tools/todo-list.ts
|
|
214839
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
214840
|
+
function fingerprintUpdate(input) {
|
|
214841
|
+
return createHash6("sha256").update(JSON.stringify({ baseRevision: input.baseRevision, items: input.items })).digest("hex");
|
|
214842
|
+
}
|
|
214843
|
+
async function withTodoMutationLock(conversationId, task) {
|
|
214844
|
+
const previous = mutationQueues.get(conversationId) ?? Promise.resolve();
|
|
214845
|
+
let release;
|
|
214846
|
+
const gate = new Promise((resolve8) => {
|
|
214847
|
+
release = resolve8;
|
|
214848
|
+
});
|
|
214849
|
+
const queued = previous.catch(() => {
|
|
214850
|
+
}).then(() => gate);
|
|
214851
|
+
mutationQueues.set(conversationId, queued);
|
|
214852
|
+
await previous.catch(() => {
|
|
214853
|
+
});
|
|
214854
|
+
try {
|
|
214855
|
+
return await task();
|
|
214856
|
+
} finally {
|
|
214857
|
+
release();
|
|
214858
|
+
if (mutationQueues.get(conversationId) === queued) mutationQueues.delete(conversationId);
|
|
214859
|
+
}
|
|
214860
|
+
}
|
|
214861
|
+
async function writeMirror(context, snapshot) {
|
|
214862
|
+
if (!context.bash) return;
|
|
214863
|
+
await context.bash.fs.writeFile("/persist/todos.json", JSON.stringify(snapshot, null, 2));
|
|
214864
|
+
}
|
|
214865
|
+
async function restoreMirror(context, snapshot) {
|
|
214866
|
+
try {
|
|
214867
|
+
await writeMirror(context, snapshot);
|
|
214868
|
+
} catch {
|
|
214869
|
+
}
|
|
214870
|
+
}
|
|
214871
|
+
function requireConversation(context) {
|
|
214872
|
+
if (!context.conversationId) throw new Error("A conversation is required for todo lists");
|
|
214873
|
+
return { conversationId: context.conversationId, ownerId: context.session.user?.id };
|
|
214874
|
+
}
|
|
214875
|
+
var mutationQueues, readTodoListTool, updateTodoListTool;
|
|
214876
|
+
var init_todo_list = __esm({
|
|
214877
|
+
"src/core/tools/todo-list.ts"() {
|
|
214878
|
+
"use strict";
|
|
214879
|
+
init_zod();
|
|
214880
|
+
init_types2();
|
|
214881
|
+
mutationQueues = /* @__PURE__ */ new Map();
|
|
214882
|
+
readTodoListTool = {
|
|
214883
|
+
name: "read_todo_list",
|
|
214884
|
+
description: "Read the current agent execution checklist. Use this before updating an existing checklist so you have its latest revision.",
|
|
214885
|
+
parameters: external_exports.object({}).strict(),
|
|
214886
|
+
type: "retrieve",
|
|
214887
|
+
async execute(_params, context) {
|
|
214888
|
+
try {
|
|
214889
|
+
const identity = requireConversation(context);
|
|
214890
|
+
const snapshot = context.todoStore && !context.ephemeral ? await context.todoStore.loadTodoSnapshot(identity) : context.todoSession?.snapshot ?? createEmptyTodoSnapshot();
|
|
214891
|
+
if (context.todoSession) context.todoSession.snapshot = snapshot;
|
|
214892
|
+
await restoreMirror(context, snapshot);
|
|
214893
|
+
return {
|
|
214894
|
+
success: true,
|
|
214895
|
+
data: { persistent: Boolean(context.todoStore) && !context.ephemeral, snapshot }
|
|
214896
|
+
};
|
|
214897
|
+
} catch (error41) {
|
|
214898
|
+
return { success: false, error: error41 instanceof Error ? error41.message : String(error41) };
|
|
214899
|
+
}
|
|
214900
|
+
}
|
|
214901
|
+
};
|
|
214902
|
+
updateTodoListTool = {
|
|
214903
|
+
name: "update_todo_list",
|
|
214904
|
+
description: `Replace the agent's complete execution checklist atomically. Use stable UUIDs for retained items, keep list order meaningful, allow at most one in_progress item, and send an empty items array to clear. Read the list first and pass its revision as baseRevision.`,
|
|
214905
|
+
parameters: todoUpdateInputSchema,
|
|
214906
|
+
type: "update",
|
|
214907
|
+
async execute(rawInput, context) {
|
|
214908
|
+
if (context.chatMode === "discussion" || context.chatMode === "plan") {
|
|
214909
|
+
return {
|
|
214910
|
+
success: false,
|
|
214911
|
+
error: `Todo list updates are unavailable in ${context.chatMode} mode`
|
|
214912
|
+
};
|
|
214913
|
+
}
|
|
214914
|
+
let identity;
|
|
214915
|
+
try {
|
|
214916
|
+
identity = requireConversation(context);
|
|
214917
|
+
} catch (error41) {
|
|
214918
|
+
return { success: false, error: error41 instanceof Error ? error41.message : String(error41) };
|
|
214919
|
+
}
|
|
214920
|
+
const input = todoUpdateInputSchema.parse(rawInput);
|
|
214921
|
+
const fingerprint = fingerprintUpdate(input);
|
|
214922
|
+
const transient = context.ephemeral || !context.todoStore;
|
|
214923
|
+
return withTodoMutationLock(identity.conversationId, async () => {
|
|
214924
|
+
try {
|
|
214925
|
+
const previous = transient ? context.todoSession?.snapshot ?? createEmptyTodoSnapshot() : await context.todoStore.loadTodoSnapshot(identity);
|
|
214926
|
+
const priorCommand = previous.recentCommands.find(
|
|
214927
|
+
(command) => command.id === input.commandId
|
|
214928
|
+
);
|
|
214929
|
+
if (priorCommand) {
|
|
214930
|
+
if (priorCommand.fingerprint !== fingerprint) {
|
|
214931
|
+
return {
|
|
214932
|
+
success: false,
|
|
214933
|
+
error: "Todo command ID was already used with a different payload"
|
|
214934
|
+
};
|
|
214935
|
+
}
|
|
214936
|
+
try {
|
|
214937
|
+
await writeMirror(context, previous);
|
|
214938
|
+
} catch (error41) {
|
|
214939
|
+
return {
|
|
214940
|
+
success: false,
|
|
214941
|
+
error: `Could not mirror todo list: ${error41 instanceof Error ? error41.message : String(error41)}`
|
|
214942
|
+
};
|
|
214943
|
+
}
|
|
214944
|
+
if (context.todoSession) context.todoSession.snapshot = previous;
|
|
214945
|
+
return {
|
|
214946
|
+
success: true,
|
|
214947
|
+
data: { persistent: !transient, status: "idempotent", snapshot: previous }
|
|
214948
|
+
};
|
|
214949
|
+
}
|
|
214950
|
+
if (previous.revision !== input.baseRevision) {
|
|
214951
|
+
return {
|
|
214952
|
+
success: false,
|
|
214953
|
+
error: `Todo revision conflict: expected ${input.baseRevision}, current revision is ${previous.revision}`
|
|
214954
|
+
};
|
|
214955
|
+
}
|
|
214956
|
+
const candidate = createTodoCandidate({
|
|
214957
|
+
previous,
|
|
214958
|
+
items: input.items,
|
|
214959
|
+
commandId: input.commandId,
|
|
214960
|
+
fingerprint,
|
|
214961
|
+
now: /* @__PURE__ */ new Date()
|
|
214962
|
+
});
|
|
214963
|
+
try {
|
|
214964
|
+
await writeMirror(context, candidate);
|
|
214965
|
+
} catch (error41) {
|
|
214966
|
+
return {
|
|
214967
|
+
success: false,
|
|
214968
|
+
error: `Could not mirror todo list: ${error41 instanceof Error ? error41.message : String(error41)}`
|
|
214969
|
+
};
|
|
214970
|
+
}
|
|
214971
|
+
let status = "committed";
|
|
214972
|
+
let snapshot = candidate;
|
|
214973
|
+
if (!transient) {
|
|
214974
|
+
let result;
|
|
214975
|
+
try {
|
|
214976
|
+
result = await context.todoStore.compareAndSwapTodoSnapshot({
|
|
214977
|
+
...identity,
|
|
214978
|
+
expectedRevision: input.baseRevision,
|
|
214979
|
+
candidate,
|
|
214980
|
+
commandId: input.commandId,
|
|
214981
|
+
fingerprint
|
|
214982
|
+
});
|
|
214983
|
+
} catch (error41) {
|
|
214984
|
+
await restoreMirror(context, previous);
|
|
214985
|
+
throw error41;
|
|
214986
|
+
}
|
|
214987
|
+
snapshot = parseTodoSnapshot(result.snapshot);
|
|
214988
|
+
if (result.status === "conflict") {
|
|
214989
|
+
await restoreMirror(context, previous);
|
|
214990
|
+
const command = snapshot.recentCommands.find((entry) => entry.id === input.commandId);
|
|
214991
|
+
if (command && command.fingerprint !== fingerprint) {
|
|
214992
|
+
return {
|
|
214993
|
+
success: false,
|
|
214994
|
+
error: "Todo command ID was already used with a different payload"
|
|
214995
|
+
};
|
|
214996
|
+
}
|
|
214997
|
+
return {
|
|
214998
|
+
success: false,
|
|
214999
|
+
error: `Todo revision conflict: expected ${input.baseRevision}, current revision is ${snapshot.revision}`
|
|
215000
|
+
};
|
|
215001
|
+
}
|
|
215002
|
+
status = result.status;
|
|
215003
|
+
}
|
|
215004
|
+
if (context.todoSession) context.todoSession.snapshot = snapshot;
|
|
215005
|
+
if (status === "committed") {
|
|
215006
|
+
const event = {
|
|
215007
|
+
schemaVersion: TODO_SCHEMA_VERSION,
|
|
215008
|
+
conversationId: identity.conversationId,
|
|
215009
|
+
turnId: context.messageId,
|
|
215010
|
+
toolCallId: context.toolCallId ?? input.commandId,
|
|
215011
|
+
persistent: !transient,
|
|
215012
|
+
snapshot
|
|
215013
|
+
};
|
|
215014
|
+
context.emit?.("todo-list-updated", event);
|
|
215015
|
+
}
|
|
215016
|
+
return { success: true, data: { persistent: !transient, status, snapshot } };
|
|
215017
|
+
} catch (error41) {
|
|
215018
|
+
return {
|
|
215019
|
+
success: false,
|
|
215020
|
+
error: `Could not persist todo list: ${error41 instanceof Error ? error41.message : String(error41)}`
|
|
215021
|
+
};
|
|
215022
|
+
}
|
|
215023
|
+
});
|
|
215024
|
+
}
|
|
215025
|
+
};
|
|
215026
|
+
}
|
|
215027
|
+
});
|
|
215028
|
+
|
|
214662
215029
|
// src/core/billing/credit-authorization.ts
|
|
214663
215030
|
async function authorizeCreditBeforeProvider(port, input) {
|
|
214664
215031
|
if (!port) return void 0;
|
|
@@ -214996,7 +215363,9 @@ async function storePauseState(state2) {
|
|
|
214996
215363
|
await redis.set(pauseKey(state2.resumeToken), JSON.stringify(state2), "PX", ttlMs);
|
|
214997
215364
|
return;
|
|
214998
215365
|
} catch (error41) {
|
|
214999
|
-
logger.warn("askQuestion", "Redis store failed, falling back to SQLite", {
|
|
215366
|
+
logger.warn("askQuestion", "Redis store failed, falling back to SQLite", {
|
|
215367
|
+
error: String(error41)
|
|
215368
|
+
});
|
|
215000
215369
|
}
|
|
215001
215370
|
}
|
|
215002
215371
|
sqliteStorePauseState(state2.resumeToken, state2, {
|
|
@@ -215020,7 +215389,9 @@ async function getPauseState(resumeToken) {
|
|
|
215020
215389
|
const inFlightStreamKey = await redis.get(inflightKey(resumeToken));
|
|
215021
215390
|
return { state: state2, consumedAt, inFlightStreamKey };
|
|
215022
215391
|
} catch (error41) {
|
|
215023
|
-
logger.warn("askQuestion", "Redis get failed, falling back to SQLite", {
|
|
215392
|
+
logger.warn("askQuestion", "Redis get failed, falling back to SQLite", {
|
|
215393
|
+
error: String(error41)
|
|
215394
|
+
});
|
|
215024
215395
|
}
|
|
215025
215396
|
}
|
|
215026
215397
|
const row = sqliteGetPauseState(resumeToken);
|
|
@@ -215037,7 +215408,9 @@ async function deletePauseState(resumeToken) {
|
|
|
215037
215408
|
try {
|
|
215038
215409
|
await redis.del(pauseKey(resumeToken), consumedKey(resumeToken), inflightKey(resumeToken));
|
|
215039
215410
|
} catch (error41) {
|
|
215040
|
-
logger.warn("askQuestion", "Redis delete failed, falling back to SQLite", {
|
|
215411
|
+
logger.warn("askQuestion", "Redis delete failed, falling back to SQLite", {
|
|
215412
|
+
error: String(error41)
|
|
215413
|
+
});
|
|
215041
215414
|
}
|
|
215042
215415
|
}
|
|
215043
215416
|
sqliteDeletePauseState(resumeToken);
|
|
@@ -215056,7 +215429,9 @@ async function claimConsume(resumeToken) {
|
|
|
215056
215429
|
);
|
|
215057
215430
|
return result === "OK";
|
|
215058
215431
|
} catch (error41) {
|
|
215059
|
-
logger.warn("askQuestion", "Redis claimConsume failed, falling back to SQLite", {
|
|
215432
|
+
logger.warn("askQuestion", "Redis claimConsume failed, falling back to SQLite", {
|
|
215433
|
+
error: String(error41)
|
|
215434
|
+
});
|
|
215060
215435
|
}
|
|
215061
215436
|
}
|
|
215062
215437
|
return sqliteClaimConsume(resumeToken, idempotencyMs);
|
|
@@ -215069,7 +215444,9 @@ async function setInFlightStreamKey(resumeToken, streamKey) {
|
|
|
215069
215444
|
await redis.set(inflightKey(resumeToken), streamKey, "PX", idempotencyMs);
|
|
215070
215445
|
return;
|
|
215071
215446
|
} catch (error41) {
|
|
215072
|
-
logger.warn("askQuestion", "Redis setInFlightStreamKey failed, falling back to SQLite", {
|
|
215447
|
+
logger.warn("askQuestion", "Redis setInFlightStreamKey failed, falling back to SQLite", {
|
|
215448
|
+
error: String(error41)
|
|
215449
|
+
});
|
|
215073
215450
|
}
|
|
215074
215451
|
}
|
|
215075
215452
|
sqliteSetInFlightStreamKey(resumeToken, streamKey);
|
|
@@ -286854,6 +287231,7 @@ async function drainPendingPause({
|
|
|
286854
287231
|
mcpTools,
|
|
286855
287232
|
questions: data2.questions,
|
|
286856
287233
|
context: data2.context,
|
|
287234
|
+
temporary: context.metadata?.temporary === true,
|
|
286857
287235
|
embedSnapshot,
|
|
286858
287236
|
pausedAt: now2.toISOString(),
|
|
286859
287237
|
expiresAt: expiresAt.toISOString()
|
|
@@ -287263,21 +287641,37 @@ async function orchestrate(request) {
|
|
|
287263
287641
|
return [name18, cleaned];
|
|
287264
287642
|
})
|
|
287265
287643
|
);
|
|
287644
|
+
const todoSession = { snapshot: createEmptyTodoSnapshot() };
|
|
287645
|
+
const agentProgressEnabled = context.metadata?.agentProgressEnabled === true;
|
|
287646
|
+
if (agentProgressEnabled) {
|
|
287647
|
+
const toJsonSchema2 = (await Promise.resolve().then(() => (init_esm2(), esm_exports))).zodToJsonSchema;
|
|
287648
|
+
const asTodoAiTool = (todoTool) => {
|
|
287649
|
+
const parameters = toJsonSchema2(todoTool.parameters, { $refStrategy: "none" });
|
|
287650
|
+
delete parameters.$schema;
|
|
287651
|
+
return {
|
|
287652
|
+
description: todoTool.description,
|
|
287653
|
+
parameters,
|
|
287654
|
+
execute: async (args, options2) => {
|
|
287655
|
+
const toolContext = options2?.executionContext;
|
|
287656
|
+
if (!toolContext) throw new Error("Todo tool execution context is unavailable");
|
|
287657
|
+
toolContext.toolCallId = options2?.toolCallId;
|
|
287658
|
+
toolContext.todoStore = context.todoStore;
|
|
287659
|
+
toolContext.todoSession = todoSession;
|
|
287660
|
+
toolContext.chatMode = context.metadata?.chatMode;
|
|
287661
|
+
toolContext.ephemeral = context.metadata?.temporary === true;
|
|
287662
|
+
const result = await todoTool.execute(args, toolContext);
|
|
287663
|
+
if (!result.success) return { error: result.error };
|
|
287664
|
+
return result.data;
|
|
287665
|
+
}
|
|
287666
|
+
};
|
|
287667
|
+
};
|
|
287668
|
+
aiTools.read_todo_list = asTodoAiTool(readTodoListTool);
|
|
287669
|
+
aiTools.update_todo_list = asTodoAiTool(updateTodoListTool);
|
|
287670
|
+
}
|
|
287266
287671
|
const allToolsForSubagents = { ...aiTools };
|
|
287267
|
-
|
|
287268
|
-
|
|
287269
|
-
|
|
287270
|
-
for (const [name18, tool2] of Object.entries(aiTools)) {
|
|
287271
|
-
if (name18.startsWith("parent_")) {
|
|
287272
|
-
filteredTools[name18] = tool2;
|
|
287273
|
-
continue;
|
|
287274
|
-
}
|
|
287275
|
-
const baseName = name18.includes("__") ? name18.split("__").pop() || name18 : name18;
|
|
287276
|
-
if (customEnabledTools.has(name18) || customEnabledTools.has(baseName)) {
|
|
287277
|
-
filteredTools[name18] = tool2;
|
|
287278
|
-
}
|
|
287279
|
-
}
|
|
287280
|
-
aiTools = filteredTools;
|
|
287672
|
+
delete allToolsForSubagents.update_todo_list;
|
|
287673
|
+
if (hasPersonaToolAllowlist(persona.enabledTools)) {
|
|
287674
|
+
aiTools = filterToPersonaEnabledTools(aiTools, persona.enabledTools);
|
|
287281
287675
|
const parentToolCount = Object.keys(aiTools).filter((n31) => n31.startsWith("parent_")).length;
|
|
287282
287676
|
orchestrationLogger.info("Custom tool filtering applied (embed main agent)", {
|
|
287283
287677
|
totalMcpTools: Object.keys(allToolsForSubagents).length,
|
|
@@ -288850,7 +289244,7 @@ ${allowedWorkspaceIds.map((id, idx) => ` ${idx + 1}. \`${id}\``).join("\n")}
|
|
|
288850
289244
|
- Once you know the workspace, include it in your tool calls
|
|
288851
289245
|
`;
|
|
288852
289246
|
}
|
|
288853
|
-
const hasRestrictedTools = persona.enabledTools
|
|
289247
|
+
const hasRestrictedTools = hasPersonaToolAllowlist(persona.enabledTools);
|
|
288854
289248
|
const availableToolNames = hasRestrictedTools ? persona.enabledTools : null;
|
|
288855
289249
|
let usableKnowledgeBaseSection = "";
|
|
288856
289250
|
if (!hasRestrictedTools) {
|
|
@@ -289040,6 +289434,16 @@ Never treat a markdown file in working memory as a completed deliverable.
|
|
|
289040
289434
|
systemMessageParts.push(LANGUAGE_PROMPT);
|
|
289041
289435
|
}
|
|
289042
289436
|
}
|
|
289437
|
+
if ("update_todo_list" in aiTools) {
|
|
289438
|
+
systemMessageParts.push(`<agent-progress>
|
|
289439
|
+
Use the agent progress checklist only for genuinely multi-step execution work.
|
|
289440
|
+
- Create it early, after you understand the work; do not create one for trivial questions.
|
|
289441
|
+
- Update it immediately after real progress, preserving stable item IDs and list order.
|
|
289442
|
+
- Keep at most one item in progress and never mark required unfinished work complete.
|
|
289443
|
+
- Completed lists remain visible; clear only when the work is explicitly replaced or no longer relevant.
|
|
289444
|
+
This checklist is operational progress, not the plan-mode plan or a user-managed task list.
|
|
289445
|
+
</agent-progress>`);
|
|
289446
|
+
}
|
|
289043
289447
|
if (chatMode === "discussion") {
|
|
289044
289448
|
systemMessageParts.push(`<discussion-mode>
|
|
289045
289449
|
CRITICAL: You are in DISCUSSION MODE (read-only). This is a hard constraint you MUST follow.
|
|
@@ -289324,7 +289728,11 @@ ${combinedSystemMessage}` : combinedSystemMessage;
|
|
|
289324
289728
|
},
|
|
289325
289729
|
// Thread the working-memory bash FS so applet FS tools (mount/write/save)
|
|
289326
289730
|
// can read/write /persist. Same instance the `working_memory` tool uses.
|
|
289327
|
-
bash
|
|
289731
|
+
bash,
|
|
289732
|
+
todoStore: context.todoStore,
|
|
289733
|
+
todoSession,
|
|
289734
|
+
chatMode,
|
|
289735
|
+
ephemeral: context.metadata?.temporary === true
|
|
289328
289736
|
};
|
|
289329
289737
|
const toolWithExecute = tool2;
|
|
289330
289738
|
if (toolWithExecute.execute) {
|
|
@@ -289359,6 +289767,7 @@ ${combinedSystemMessage}` : combinedSystemMessage;
|
|
|
289359
289767
|
if (conversationId && context.chatStore) {
|
|
289360
289768
|
try {
|
|
289361
289769
|
persistedFiles = await context.chatStore.loadWorkingMemory(conversationId);
|
|
289770
|
+
delete persistedFiles["/persist/todos.json"];
|
|
289362
289771
|
if (Object.keys(persistedFiles).length > 0) {
|
|
289363
289772
|
orchestrationLogger.info(
|
|
289364
289773
|
"Loaded persisted working memory",
|
|
@@ -289374,13 +289783,26 @@ ${combinedSystemMessage}` : combinedSystemMessage;
|
|
|
289374
289783
|
});
|
|
289375
289784
|
}
|
|
289376
289785
|
}
|
|
289786
|
+
if (agentProgressEnabled && conversationId && context.todoStore && context.metadata?.temporary !== true) {
|
|
289787
|
+
try {
|
|
289788
|
+
todoSession.snapshot = await context.todoStore.loadTodoSnapshot({
|
|
289789
|
+
conversationId,
|
|
289790
|
+
ownerId: context.session.user?.id
|
|
289791
|
+
});
|
|
289792
|
+
} catch (err) {
|
|
289793
|
+
orchestrationLogger.warn("Failed to load agent todo list", {
|
|
289794
|
+
error: err instanceof Error ? err.message : String(err)
|
|
289795
|
+
});
|
|
289796
|
+
}
|
|
289797
|
+
}
|
|
289377
289798
|
const { Bash: JustBash } = await Promise.resolve().then(() => (init_bundle(), bundle_exports));
|
|
289378
289799
|
const bash = new JustBash({
|
|
289379
289800
|
files: {
|
|
289380
289801
|
"/research/.gitkeep": "",
|
|
289381
289802
|
"/data/.gitkeep": "",
|
|
289382
289803
|
"/persist/.gitkeep": "",
|
|
289383
|
-
...persistedFiles
|
|
289804
|
+
...persistedFiles,
|
|
289805
|
+
...agentProgressEnabled && todoSession.snapshot.revision > 0 ? { "/persist/todos.json": JSON.stringify(todoSession.snapshot, null, 2) } : {}
|
|
289384
289806
|
},
|
|
289385
289807
|
javascript: true
|
|
289386
289808
|
});
|
|
@@ -290313,7 +290735,7 @@ Re-read them (working_memory on web, bash on the CLI \u2014 grep/sed projection,
|
|
|
290313
290735
|
registeredParentToolSchemas: Array.from(
|
|
290314
290736
|
context.registeredParentToolSchemas.values()
|
|
290315
290737
|
),
|
|
290316
|
-
isTemporary:
|
|
290738
|
+
isTemporary: context.metadata?.temporary === true
|
|
290317
290739
|
} : void 0;
|
|
290318
290740
|
await drainPendingPause({
|
|
290319
290741
|
pending: pendingPauseRef.current,
|
|
@@ -290365,7 +290787,7 @@ Re-read them (working_memory on web, bash on the CLI \u2014 grep/sed projection,
|
|
|
290365
290787
|
try {
|
|
290366
290788
|
const allPaths = bash.fs.getAllPaths();
|
|
290367
290789
|
const persistPaths = allPaths.filter(
|
|
290368
|
-
(p29) => p29.startsWith("/persist/") && !p29.endsWith(".gitkeep")
|
|
290790
|
+
(p29) => p29.startsWith("/persist/") && !p29.endsWith(".gitkeep") && p29 !== "/persist/todos.json"
|
|
290369
290791
|
);
|
|
290370
290792
|
const persistData = {};
|
|
290371
290793
|
for (const p29 of persistPaths) {
|
|
@@ -290404,8 +290826,7 @@ Re-read them (working_memory on web, bash on the CLI \u2014 grep/sed projection,
|
|
|
290404
290826
|
});
|
|
290405
290827
|
}
|
|
290406
290828
|
};
|
|
290407
|
-
savePersistFiles()
|
|
290408
|
-
});
|
|
290829
|
+
await savePersistFiles();
|
|
290409
290830
|
}
|
|
290410
290831
|
multiplexer.close();
|
|
290411
290832
|
resolveStreamComplete();
|
|
@@ -290445,7 +290866,7 @@ Re-read them (working_memory on web, bash on the CLI \u2014 grep/sed projection,
|
|
|
290445
290866
|
try {
|
|
290446
290867
|
const allPaths = bash.fs.getAllPaths();
|
|
290447
290868
|
const persistPaths = allPaths.filter(
|
|
290448
|
-
(p29) => p29.startsWith("/persist/") && !p29.endsWith(".gitkeep")
|
|
290869
|
+
(p29) => p29.startsWith("/persist/") && !p29.endsWith(".gitkeep") && p29 !== "/persist/todos.json"
|
|
290449
290870
|
);
|
|
290450
290871
|
const persistData = {};
|
|
290451
290872
|
for (const p29 of persistPaths) {
|
|
@@ -290517,6 +290938,7 @@ function createOrchestratorRequest(messages4, context, config3, persona, apiKey,
|
|
|
290517
290938
|
creditAuthorization: context.creditAuthorization,
|
|
290518
290939
|
chatStore: context.chatStore,
|
|
290519
290940
|
// Persistence port (Drizzle for Next.js, SQLite for CLI)
|
|
290941
|
+
todoStore: context.todoStore,
|
|
290520
290942
|
metadata: context.metadata,
|
|
290521
290943
|
allowedWorkspaceIds: context.allowedWorkspaceIds,
|
|
290522
290944
|
registeredParentToolSchemas: context.registeredParentToolSchemas,
|
|
@@ -290610,6 +291032,8 @@ var init_orchestrator = __esm({
|
|
|
290610
291032
|
init_spawn_subagent();
|
|
290611
291033
|
init_await_subagents();
|
|
290612
291034
|
init_list_subagents();
|
|
291035
|
+
init_todo_list();
|
|
291036
|
+
init_types2();
|
|
290613
291037
|
init_spawned_task_store();
|
|
290614
291038
|
init_redis();
|
|
290615
291039
|
init_executor();
|
|
@@ -291853,7 +292277,7 @@ var ReadBuffer;
|
|
|
291853
292277
|
var init_stdio = __esm({
|
|
291854
292278
|
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js"() {
|
|
291855
292279
|
"use strict";
|
|
291856
|
-
|
|
292280
|
+
init_types7();
|
|
291857
292281
|
ReadBuffer = class {
|
|
291858
292282
|
append(chunk2) {
|
|
291859
292283
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk2]) : chunk2;
|
|
@@ -293349,8 +293773,10 @@ async function runCliTurn(options2) {
|
|
|
293349
293773
|
model = config2.ai.defaultModel,
|
|
293350
293774
|
reasoningEffort,
|
|
293351
293775
|
conversationId,
|
|
293776
|
+
ephemeral,
|
|
293352
293777
|
session,
|
|
293353
293778
|
chatStore,
|
|
293779
|
+
todoStore,
|
|
293354
293780
|
onText,
|
|
293355
293781
|
onEvent,
|
|
293356
293782
|
scriptedLlm,
|
|
@@ -293428,9 +293854,15 @@ async function runCliTurn(options2) {
|
|
|
293428
293854
|
emitter: createEventEmitter({ messageId: crypto.randomUUID() }),
|
|
293429
293855
|
sessionPathway: noopSessionPathway,
|
|
293430
293856
|
chatStore,
|
|
293857
|
+
todoStore,
|
|
293431
293858
|
extensions: extensions2?.runtime,
|
|
293432
293859
|
abortSignal,
|
|
293433
|
-
metadata: {
|
|
293860
|
+
metadata: {
|
|
293861
|
+
conversationId,
|
|
293862
|
+
temporary: ephemeral === true,
|
|
293863
|
+
// The CLI is a local, user-controlled surface without web user grants.
|
|
293864
|
+
agentProgressEnabled: true
|
|
293865
|
+
}
|
|
293434
293866
|
},
|
|
293435
293867
|
{
|
|
293436
293868
|
model,
|
|
@@ -307842,6 +308274,87 @@ var init_tui_markdown = __esm({
|
|
|
307842
308274
|
}
|
|
307843
308275
|
});
|
|
307844
308276
|
|
|
308277
|
+
// src/cli/todo-checklist.ts
|
|
308278
|
+
function reduceTodoListUpdate(current, payload2) {
|
|
308279
|
+
const parsed = todoSnapshotSchema.safeParse(payload2);
|
|
308280
|
+
if (!parsed.success || parsed.data.revision <= current.revision) return current;
|
|
308281
|
+
return parsed.data;
|
|
308282
|
+
}
|
|
308283
|
+
function sanitizeTerminalText(value) {
|
|
308284
|
+
return value.replace(OSC, "").replace(STRING_CONTROL, "").replace(CSI, "").replace(TWO_BYTE_ESCAPE, "").replace(ESCAPE, "").replace(/[\r\n\t]+/g, " ").replace(C0_C1, "").replace(BIDI_CONTROLS, "").replace(/ +/g, " ").trim();
|
|
308285
|
+
}
|
|
308286
|
+
function codePointWidth(character) {
|
|
308287
|
+
const code = character.codePointAt(0) ?? 0;
|
|
308288
|
+
if (new RegExp("\\p{Mark}", "u").test(character) || code === 8205 || code >= 65024 && code <= 65039) {
|
|
308289
|
+
return 0;
|
|
308290
|
+
}
|
|
308291
|
+
if (code >= 4352 && (code <= 4447 || code === 9001 || code === 9002 || code >= 11904 && code <= 42191 && code !== 12351 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65049 || code >= 65072 && code <= 65135 || code >= 65280 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 129791 || code >= 131072 && code <= 262141)) {
|
|
308292
|
+
return 2;
|
|
308293
|
+
}
|
|
308294
|
+
return 1;
|
|
308295
|
+
}
|
|
308296
|
+
function terminalCellWidth(value) {
|
|
308297
|
+
let width = 0;
|
|
308298
|
+
for (const character of value) width += codePointWidth(character);
|
|
308299
|
+
return width;
|
|
308300
|
+
}
|
|
308301
|
+
function truncateToCells(value, maxWidth) {
|
|
308302
|
+
if (maxWidth <= 0) return "";
|
|
308303
|
+
if (terminalCellWidth(value) <= maxWidth) return value;
|
|
308304
|
+
if (maxWidth === 1) return "\u2026";
|
|
308305
|
+
let out = "";
|
|
308306
|
+
let width = 0;
|
|
308307
|
+
for (const character of value) {
|
|
308308
|
+
const next = codePointWidth(character);
|
|
308309
|
+
if (width + next > maxWidth - 1) break;
|
|
308310
|
+
out += character;
|
|
308311
|
+
width += next;
|
|
308312
|
+
}
|
|
308313
|
+
return `${out}\u2026`;
|
|
308314
|
+
}
|
|
308315
|
+
function renderTodoChecklist(list3, width, options2 = {}) {
|
|
308316
|
+
const safeWidth = Math.max(1, Math.floor(width));
|
|
308317
|
+
if (list3.items.length === 0) return [];
|
|
308318
|
+
const completed = list3.items.filter((todo) => todo.status === "completed").length;
|
|
308319
|
+
const persistence = options2.persistent === false ? " (temporary)" : "";
|
|
308320
|
+
const lines = [
|
|
308321
|
+
truncateToCells(
|
|
308322
|
+
`Agent progress${persistence} ${completed}/${list3.items.length} complete`,
|
|
308323
|
+
safeWidth
|
|
308324
|
+
)
|
|
308325
|
+
];
|
|
308326
|
+
const maxItems = options2.expanded ? list3.items.length : Math.max(1, options2.maxCompactItems ?? 4);
|
|
308327
|
+
const visible = list3.items.slice(0, maxItems);
|
|
308328
|
+
for (const todo of visible) {
|
|
308329
|
+
const marker18 = todo.status === "completed" ? "[x]" : todo.status === "in_progress" ? "[>]" : "[ ]";
|
|
308330
|
+
lines.push(truncateToCells(` ${marker18} ${sanitizeTerminalText(todo.content)}`, safeWidth));
|
|
308331
|
+
}
|
|
308332
|
+
const hidden = list3.items.length - visible.length;
|
|
308333
|
+
if (hidden > 0) lines.push(truncateToCells(` ... +${hidden} more`, safeWidth));
|
|
308334
|
+
return lines;
|
|
308335
|
+
}
|
|
308336
|
+
var EMPTY_TODO_LIST, OSC, STRING_CONTROL, CSI, TWO_BYTE_ESCAPE, ESCAPE, C0_C1, BIDI_CONTROLS;
|
|
308337
|
+
var init_todo_checklist = __esm({
|
|
308338
|
+
"src/cli/todo-checklist.ts"() {
|
|
308339
|
+
"use strict";
|
|
308340
|
+
init_types2();
|
|
308341
|
+
EMPTY_TODO_LIST = Object.freeze({
|
|
308342
|
+
schemaVersion: 1,
|
|
308343
|
+
revision: 0,
|
|
308344
|
+
items: [],
|
|
308345
|
+
updatedAt: null,
|
|
308346
|
+
recentCommands: []
|
|
308347
|
+
});
|
|
308348
|
+
OSC = /(?:\u001b\]|\u009d)[\s\S]*?(?:\u0007|\u001b\\|\u009c|$)/g;
|
|
308349
|
+
STRING_CONTROL = /(?:\u001b[P^_X]|[\u0090\u0098\u009e\u009f])[\s\S]*?(?:\u001b\\|\u009c|$)/g;
|
|
308350
|
+
CSI = /(?:\u001b\[|\u009b)[0-?]*[ -/]*[@-~]/g;
|
|
308351
|
+
TWO_BYTE_ESCAPE = /\u001b[0-?]/g;
|
|
308352
|
+
ESCAPE = /\u001b[ -/]*[@-~]/g;
|
|
308353
|
+
C0_C1 = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g;
|
|
308354
|
+
BIDI_CONTROLS = /[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g;
|
|
308355
|
+
}
|
|
308356
|
+
});
|
|
308357
|
+
|
|
307845
308358
|
// src/cli/warp-agent.ts
|
|
307846
308359
|
import { openSync, writeSync } from "node:fs";
|
|
307847
308360
|
import { basename as basename9 } from "node:path";
|
|
@@ -308001,11 +308514,15 @@ function renderItem(item, width, toolsExpanded) {
|
|
|
308001
308514
|
case "tool":
|
|
308002
308515
|
return renderTool(item, width, toolsExpanded);
|
|
308003
308516
|
case "system":
|
|
308004
|
-
return [
|
|
308517
|
+
return [
|
|
308518
|
+
...wrap(item.text, width).map((l14) => fg3(item.tone === "error" ? "#f87171" : "#9ca3af", l14)),
|
|
308519
|
+
""
|
|
308520
|
+
];
|
|
308005
308521
|
}
|
|
308006
308522
|
}
|
|
308007
308523
|
async function launchTui(options2) {
|
|
308008
308524
|
const { runTurn, actions, initialHistory, version: version4, autoSubmit, extensions: extensions2, bannerOverride } = options2;
|
|
308525
|
+
const autoSubmitQueue = autoSubmit ? Array.isArray(autoSubmit) ? [...autoSubmit] : [autoSubmit] : [];
|
|
308009
308526
|
const terminal = options2.terminal ?? new ProcessTerminal();
|
|
308010
308527
|
const exit = options2.onExit ?? ((code) => process.exit(code));
|
|
308011
308528
|
const ui2 = new TUI(terminal);
|
|
@@ -308013,6 +308530,25 @@ async function launchTui(options2) {
|
|
|
308013
308530
|
editor.focused = true;
|
|
308014
308531
|
const bangTools = createLocalTools();
|
|
308015
308532
|
let items = [...initialHistory];
|
|
308533
|
+
let todoList = reduceTodoListUpdate(EMPTY_TODO_LIST, options2.initialTodos);
|
|
308534
|
+
let todoPersistent = true;
|
|
308535
|
+
let todoTransient = null;
|
|
308536
|
+
let endedTransientTurns = [];
|
|
308537
|
+
let todoExpiryTimer = null;
|
|
308538
|
+
let todoExpiredView = false;
|
|
308539
|
+
function scheduleTodoExpiry() {
|
|
308540
|
+
if (todoExpiryTimer) clearTimeout(todoExpiryTimer);
|
|
308541
|
+
todoExpiryTimer = null;
|
|
308542
|
+
if (!todoPersistent || !todoList.updatedAt || todoList.items.length === 0) return;
|
|
308543
|
+
const remaining = Date.parse(todoList.updatedAt) + TODO_TTL_MS - Date.now();
|
|
308544
|
+
const expire = () => {
|
|
308545
|
+
todoExpiredView = true;
|
|
308546
|
+
todoExpiryTimer = null;
|
|
308547
|
+
ui2.requestRender();
|
|
308548
|
+
};
|
|
308549
|
+
if (remaining <= 0) expire();
|
|
308550
|
+
else todoExpiryTimer = setTimeout(expire, Math.min(remaining, 2147483647));
|
|
308551
|
+
}
|
|
308016
308552
|
let compactedPrefix = [];
|
|
308017
308553
|
let busy = false;
|
|
308018
308554
|
let status = "";
|
|
@@ -308156,9 +308692,27 @@ async function launchTui(options2) {
|
|
|
308156
308692
|
case "new":
|
|
308157
308693
|
actions.newSession();
|
|
308158
308694
|
items = [];
|
|
308695
|
+
todoList = EMPTY_TODO_LIST;
|
|
308696
|
+
todoPersistent = true;
|
|
308697
|
+
todoTransient = null;
|
|
308698
|
+
endedTransientTurns = [];
|
|
308699
|
+
todoExpiredView = false;
|
|
308700
|
+
scheduleTodoExpiry();
|
|
308159
308701
|
compactedPrefix = [];
|
|
308160
308702
|
sys("Started a new session.");
|
|
308161
308703
|
return;
|
|
308704
|
+
case "todos": {
|
|
308705
|
+
const lines = renderTodoChecklist(
|
|
308706
|
+
todoExpiredView ? EMPTY_TODO_LIST : todoList,
|
|
308707
|
+
Math.max(1, terminal.columns),
|
|
308708
|
+
{
|
|
308709
|
+
expanded: true,
|
|
308710
|
+
persistent: todoPersistent
|
|
308711
|
+
}
|
|
308712
|
+
);
|
|
308713
|
+
sys(lines.length > 0 ? lines.join("\n") : "No todos yet for this session.");
|
|
308714
|
+
return;
|
|
308715
|
+
}
|
|
308162
308716
|
case "compact":
|
|
308163
308717
|
case "summarize": {
|
|
308164
308718
|
if (busy) {
|
|
@@ -308285,7 +308839,10 @@ Edit it, then /verify-extension ${arg.trim()} to check it loads, /trust (project
|
|
|
308285
308839
|
pendingImages.push(await compressToDataUrl2(bytes, "image/png"));
|
|
308286
308840
|
sys(`\u{1F4CE} image attached from clipboard \u2014 send a message to include it`, "info");
|
|
308287
308841
|
} catch (err) {
|
|
308288
|
-
sys(
|
|
308842
|
+
sys(
|
|
308843
|
+
`Could not attach clipboard image: ${err instanceof Error ? err.message : String(err)}`,
|
|
308844
|
+
"error"
|
|
308845
|
+
);
|
|
308289
308846
|
}
|
|
308290
308847
|
}
|
|
308291
308848
|
async function submit(raw) {
|
|
@@ -308301,7 +308858,10 @@ Edit it, then /verify-extension ${arg.trim()} to check it loads, /trust (project
|
|
|
308301
308858
|
pendingImages.push(await readImageFileAsDataUrl2(p29));
|
|
308302
308859
|
attached++;
|
|
308303
308860
|
} catch (err) {
|
|
308304
|
-
sys(
|
|
308861
|
+
sys(
|
|
308862
|
+
`Could not attach ${p29}: ${err instanceof Error ? err.message : String(err)}`,
|
|
308863
|
+
"error"
|
|
308864
|
+
);
|
|
308305
308865
|
}
|
|
308306
308866
|
}
|
|
308307
308867
|
text3 = cleanedText;
|
|
@@ -308352,10 +308912,7 @@ Edit it, then /verify-extension ${arg.trim()} to check it loads, /trust (project
|
|
|
308352
308912
|
busy = false;
|
|
308353
308913
|
ui2.requestRender();
|
|
308354
308914
|
if (autoSubmit) {
|
|
308355
|
-
|
|
308356
|
-
teardown();
|
|
308357
|
-
exit(0);
|
|
308358
|
-
}, 25);
|
|
308915
|
+
continueAutoSubmitOrExit(25);
|
|
308359
308916
|
}
|
|
308360
308917
|
}
|
|
308361
308918
|
return;
|
|
@@ -308422,6 +308979,40 @@ Edit it, then /verify-extension ${arg.trim()} to check it loads, /trust (project
|
|
|
308422
308979
|
push({ kind: "system", text: plan, tone: "info" });
|
|
308423
308980
|
ui2.requestRender();
|
|
308424
308981
|
}
|
|
308982
|
+
} else if (e15.type === "todo-list-updated") {
|
|
308983
|
+
const data2 = e15.data;
|
|
308984
|
+
if (data2?.persistent === false) {
|
|
308985
|
+
if (!data2.turnId || endedTransientTurns.includes(data2.turnId)) return;
|
|
308986
|
+
if (!todoTransient || todoTransient.turnId !== data2.turnId) {
|
|
308987
|
+
if (todoTransient) {
|
|
308988
|
+
endedTransientTurns = [...endedTransientTurns, todoTransient.turnId].slice(-32);
|
|
308989
|
+
}
|
|
308990
|
+
todoTransient = {
|
|
308991
|
+
turnId: data2.turnId,
|
|
308992
|
+
previous: todoTransient?.previous ?? todoList
|
|
308993
|
+
};
|
|
308994
|
+
todoList = reduceTodoListUpdate(EMPTY_TODO_LIST, data2.snapshot);
|
|
308995
|
+
} else {
|
|
308996
|
+
todoList = reduceTodoListUpdate(todoList, data2.snapshot);
|
|
308997
|
+
}
|
|
308998
|
+
todoPersistent = false;
|
|
308999
|
+
todoExpiredView = false;
|
|
309000
|
+
if (todoExpiryTimer) clearTimeout(todoExpiryTimer);
|
|
309001
|
+
todoExpiryTimer = null;
|
|
309002
|
+
gotOutput = true;
|
|
309003
|
+
ui2.requestRender();
|
|
309004
|
+
return;
|
|
309005
|
+
}
|
|
309006
|
+
todoTransient = null;
|
|
309007
|
+
const next = reduceTodoListUpdate(todoList, data2?.snapshot);
|
|
309008
|
+
if (next !== todoList) {
|
|
309009
|
+
gotOutput = true;
|
|
309010
|
+
todoList = next;
|
|
309011
|
+
todoPersistent = true;
|
|
309012
|
+
todoExpiredView = false;
|
|
309013
|
+
scheduleTodoExpiry();
|
|
309014
|
+
ui2.requestRender();
|
|
309015
|
+
}
|
|
308425
309016
|
} else if (e15.type === "compaction") {
|
|
308426
309017
|
const data2 = e15.data;
|
|
308427
309018
|
finalize();
|
|
@@ -308449,6 +309040,14 @@ ${data2.summary}` : `${head}.`;
|
|
|
308449
309040
|
sys(`Error: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
308450
309041
|
} finally {
|
|
308451
309042
|
finalize();
|
|
309043
|
+
if (todoTransient) {
|
|
309044
|
+
endedTransientTurns = [...endedTransientTurns, todoTransient.turnId].slice(-32);
|
|
309045
|
+
todoList = todoTransient.previous;
|
|
309046
|
+
todoPersistent = true;
|
|
309047
|
+
todoExpiredView = false;
|
|
309048
|
+
todoTransient = null;
|
|
309049
|
+
scheduleTodoExpiry();
|
|
309050
|
+
}
|
|
308452
309051
|
if (!gotOutput) {
|
|
308453
309052
|
push({ kind: "system", text: "(no response \u2014 see ~/.usable/usable.log)", tone: "error" });
|
|
308454
309053
|
}
|
|
@@ -308458,16 +309057,23 @@ ${data2.summary}` : `${head}.`;
|
|
|
308458
309057
|
notifyWarp("stop");
|
|
308459
309058
|
ui2.requestRender();
|
|
308460
309059
|
if (autoSubmit) {
|
|
308461
|
-
|
|
308462
|
-
teardown();
|
|
308463
|
-
exit(0);
|
|
308464
|
-
}, 100);
|
|
309060
|
+
continueAutoSubmitOrExit(100);
|
|
308465
309061
|
}
|
|
308466
309062
|
}
|
|
308467
309063
|
}
|
|
308468
309064
|
editor.onSubmit = (text3) => {
|
|
308469
309065
|
void submit(text3);
|
|
308470
309066
|
};
|
|
309067
|
+
function continueAutoSubmitOrExit(delay2) {
|
|
309068
|
+
const next = autoSubmitQueue.shift();
|
|
309069
|
+
setTimeout(() => {
|
|
309070
|
+
if (next) void submit(next);
|
|
309071
|
+
else {
|
|
309072
|
+
teardown();
|
|
309073
|
+
exit(0);
|
|
309074
|
+
}
|
|
309075
|
+
}, delay2);
|
|
309076
|
+
}
|
|
308471
309077
|
const reasoningCompletions = REASONING_OPTIONS.map((o21) => ({
|
|
308472
309078
|
value: o21.value,
|
|
308473
309079
|
label: o21.label,
|
|
@@ -308497,6 +309103,7 @@ ${data2.summary}` : `${head}.`;
|
|
|
308497
309103
|
getArgumentCompletions: (prefix) => reasoningCompletions.filter((o21) => o21.value.startsWith(prefix.toLowerCase()))
|
|
308498
309104
|
},
|
|
308499
309105
|
{ name: "sessions", description: "list sessions for this project" },
|
|
309106
|
+
{ name: "todos", description: "show the complete agent progress checklist" },
|
|
308500
309107
|
{ name: "compact", description: "summarize the conversation into a checkpoint" },
|
|
308501
309108
|
{ name: "summarize", description: "alias of /compact" },
|
|
308502
309109
|
{ name: "provider", description: "switch model provider" },
|
|
@@ -308598,11 +309205,16 @@ ${data2.summary}` : `${head}.`;
|
|
|
308598
309205
|
body.push("");
|
|
308599
309206
|
}
|
|
308600
309207
|
for (const it7 of items) body.push(...renderItem(it7, width, toolsExpanded));
|
|
309208
|
+
const todoLines = renderTodoChecklist(todoExpiredView ? EMPTY_TODO_LIST : todoList, width, {
|
|
309209
|
+
persistent: todoPersistent
|
|
309210
|
+
});
|
|
309211
|
+
if (todoLines.length > 0) body.push(...todoLines, "");
|
|
308601
309212
|
const statusLine = picker ? "" : dim3(short(statusText, width));
|
|
308602
309213
|
return [...body, statusLine, ...editorLines];
|
|
308603
309214
|
}
|
|
308604
309215
|
};
|
|
308605
309216
|
function teardown() {
|
|
309217
|
+
if (todoExpiryTimer) clearTimeout(todoExpiryTimer);
|
|
308606
309218
|
try {
|
|
308607
309219
|
ui2.stop();
|
|
308608
309220
|
} catch {
|
|
@@ -308635,7 +309247,9 @@ ${data2.summary}` : `${head}.`;
|
|
|
308635
309247
|
terminal.setTitle(appTitle());
|
|
308636
309248
|
notifyWarp("session_start");
|
|
308637
309249
|
ui2.requestRender();
|
|
308638
|
-
|
|
309250
|
+
scheduleTodoExpiry();
|
|
309251
|
+
const firstAutoSubmit = autoSubmitQueue.shift();
|
|
309252
|
+
if (firstAutoSubmit) setTimeout(() => void submit(firstAutoSubmit), 10);
|
|
308639
309253
|
return new Promise(() => {
|
|
308640
309254
|
});
|
|
308641
309255
|
}
|
|
@@ -308644,9 +309258,11 @@ var init_tui2 = __esm({
|
|
|
308644
309258
|
"src/cli/tui.ts"() {
|
|
308645
309259
|
"use strict";
|
|
308646
309260
|
init_dist8();
|
|
309261
|
+
init_types2();
|
|
308647
309262
|
init_tui_select();
|
|
308648
309263
|
init_tools();
|
|
308649
309264
|
init_tui_markdown();
|
|
309265
|
+
init_todo_checklist();
|
|
308650
309266
|
init_warp_agent();
|
|
308651
309267
|
BANNER_LINES = [
|
|
308652
309268
|
" _ _ ___ __ _| |__ | | ___",
|
|
@@ -308661,6 +309277,7 @@ var init_tui2 = __esm({
|
|
|
308661
309277
|
"/model [<id>] pick from a list, or switch directly by id",
|
|
308662
309278
|
"/reasoning [lvl] set reasoning effort (low|medium|high)",
|
|
308663
309279
|
"/sessions list sessions for this project",
|
|
309280
|
+
"/todos show the complete agent progress checklist",
|
|
308664
309281
|
"/new-extension <n> scaffold a starter extension in .usable/extensions/",
|
|
308665
309282
|
"/verify-extension <n> check an extension loads (no tsc needed)",
|
|
308666
309283
|
"/compact, /summarize summarize the conversation into a checkpoint (frees context)",
|
|
@@ -308793,6 +309410,7 @@ function loadCliConfig(env2 = process.env) {
|
|
|
308793
309410
|
}
|
|
308794
309411
|
|
|
308795
309412
|
// src/adapters/cli/store.ts
|
|
309413
|
+
init_types2();
|
|
308796
309414
|
import { existsSync as existsSync2, mkdirSync } from "node:fs";
|
|
308797
309415
|
import { createRequire } from "node:module";
|
|
308798
309416
|
import { dirname, join as join2 } from "node:path";
|
|
@@ -308811,7 +309429,7 @@ function allRows(db3, sql2, ...params) {
|
|
|
308811
309429
|
return db3.prepare(sql2).all(...params);
|
|
308812
309430
|
}
|
|
308813
309431
|
function runSql(db3, sql2, params = []) {
|
|
308814
|
-
db3.prepare(sql2).run(...params);
|
|
309432
|
+
return Number(db3.prepare(sql2).run(...params).changes);
|
|
308815
309433
|
}
|
|
308816
309434
|
var SCHEMA = `
|
|
308817
309435
|
CREATE TABLE IF NOT EXISTS project (
|
|
@@ -308846,7 +309464,23 @@ CREATE TABLE IF NOT EXISTS working_memory (
|
|
|
308846
309464
|
files TEXT NOT NULL,
|
|
308847
309465
|
updated_at INTEGER NOT NULL
|
|
308848
309466
|
);
|
|
309467
|
+
CREATE TABLE IF NOT EXISTS todo_snapshot (
|
|
309468
|
+
conversation_id TEXT NOT NULL,
|
|
309469
|
+
owner_id TEXT NOT NULL,
|
|
309470
|
+
snapshot TEXT NOT NULL,
|
|
309471
|
+
updated_at INTEGER NOT NULL,
|
|
309472
|
+
PRIMARY KEY (conversation_id, owner_id)
|
|
309473
|
+
);
|
|
308849
309474
|
`;
|
|
309475
|
+
function parseTodoSnapshot2(value) {
|
|
309476
|
+
try {
|
|
309477
|
+
const candidate = typeof value === "string" ? JSON.parse(value) : value;
|
|
309478
|
+
const parsed = todoSnapshotSchema.safeParse(candidate);
|
|
309479
|
+
return parsed.success ? parsed.data : null;
|
|
309480
|
+
} catch {
|
|
309481
|
+
return null;
|
|
309482
|
+
}
|
|
309483
|
+
}
|
|
308850
309484
|
function now() {
|
|
308851
309485
|
return Date.now();
|
|
308852
309486
|
}
|
|
@@ -308861,6 +309495,7 @@ var CliStore = class {
|
|
|
308861
309495
|
this.db.exec("PRAGMA foreign_keys = ON;");
|
|
308862
309496
|
this.db.exec(SCHEMA);
|
|
308863
309497
|
this.chatStore = this.buildChatStore();
|
|
309498
|
+
this.todoStore = this.buildTodoStore();
|
|
308864
309499
|
}
|
|
308865
309500
|
/** Resolve (or create) the project row for a git root, returning its id. */
|
|
308866
309501
|
resolveProject(gitRoot2, name18) {
|
|
@@ -308932,7 +309567,15 @@ var CliStore = class {
|
|
|
308932
309567
|
this.db,
|
|
308933
309568
|
`INSERT INTO message (id, session_id, parent_uuid, role, created_at, seq, data)
|
|
308934
309569
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
308935
|
-
[
|
|
309570
|
+
[
|
|
309571
|
+
id,
|
|
309572
|
+
input.sessionId,
|
|
309573
|
+
input.parentUuid ?? null,
|
|
309574
|
+
input.role,
|
|
309575
|
+
ts3,
|
|
309576
|
+
seq,
|
|
309577
|
+
JSON.stringify(input.message)
|
|
309578
|
+
]
|
|
308936
309579
|
);
|
|
308937
309580
|
runSql(this.db, "UPDATE session SET updated_at = ? WHERE id = ?", [ts3, input.sessionId]);
|
|
308938
309581
|
return id;
|
|
@@ -308998,6 +309641,100 @@ var CliStore = class {
|
|
|
308998
309641
|
}
|
|
308999
309642
|
};
|
|
309000
309643
|
}
|
|
309644
|
+
buildTodoStore() {
|
|
309645
|
+
const db3 = this.db;
|
|
309646
|
+
const load = (input) => {
|
|
309647
|
+
const ownerId = input.ownerId ?? "";
|
|
309648
|
+
const row = getRow(
|
|
309649
|
+
db3,
|
|
309650
|
+
`SELECT snapshot, updated_at FROM todo_snapshot
|
|
309651
|
+
WHERE conversation_id = ? AND owner_id = ? LIMIT 1`,
|
|
309652
|
+
input.conversationId,
|
|
309653
|
+
ownerId
|
|
309654
|
+
);
|
|
309655
|
+
if (!row) return createEmptyTodoSnapshot();
|
|
309656
|
+
const currentTime = (input.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
309657
|
+
const parsed = parseTodoSnapshot2(row.snapshot);
|
|
309658
|
+
if (!parsed) {
|
|
309659
|
+
const recovered = {
|
|
309660
|
+
...createEmptyTodoSnapshot(),
|
|
309661
|
+
revision: 1,
|
|
309662
|
+
updatedAt: new Date(currentTime).toISOString()
|
|
309663
|
+
};
|
|
309664
|
+
const changed = runSql(
|
|
309665
|
+
db3,
|
|
309666
|
+
"UPDATE todo_snapshot SET snapshot = ?, updated_at = ? WHERE conversation_id = ? AND owner_id = ? AND updated_at = ?",
|
|
309667
|
+
[JSON.stringify(recovered), currentTime, input.conversationId, ownerId, row.updated_at]
|
|
309668
|
+
);
|
|
309669
|
+
return changed > 0 ? recovered : load(input);
|
|
309670
|
+
}
|
|
309671
|
+
if (isTodoSnapshotExpired(parsed, new Date(currentTime))) {
|
|
309672
|
+
const expired = createExpiredTodoSnapshot(parsed, new Date(currentTime));
|
|
309673
|
+
const changed = runSql(
|
|
309674
|
+
db3,
|
|
309675
|
+
"UPDATE todo_snapshot SET snapshot = ?, updated_at = ? WHERE conversation_id = ? AND owner_id = ? AND updated_at = ?",
|
|
309676
|
+
[JSON.stringify(expired), currentTime, input.conversationId, ownerId, row.updated_at]
|
|
309677
|
+
);
|
|
309678
|
+
return changed > 0 ? expired : load(input);
|
|
309679
|
+
}
|
|
309680
|
+
return parsed;
|
|
309681
|
+
};
|
|
309682
|
+
return {
|
|
309683
|
+
async loadTodoSnapshot(input) {
|
|
309684
|
+
return load(input);
|
|
309685
|
+
},
|
|
309686
|
+
async compareAndSwapTodoSnapshot(input) {
|
|
309687
|
+
const candidate = parseTodoSnapshot(input.candidate);
|
|
309688
|
+
if (candidate.revision !== input.expectedRevision + 1) {
|
|
309689
|
+
throw new Error("Todo candidate revision must advance exactly once");
|
|
309690
|
+
}
|
|
309691
|
+
const candidateCommand = candidate.recentCommands.find(
|
|
309692
|
+
(entry) => entry.id === input.commandId
|
|
309693
|
+
);
|
|
309694
|
+
if (!candidateCommand || candidateCommand.fingerprint !== input.fingerprint || candidateCommand.revision !== candidate.revision) {
|
|
309695
|
+
throw new Error("Todo candidate must contain its command fingerprint");
|
|
309696
|
+
}
|
|
309697
|
+
db3.exec("BEGIN IMMEDIATE");
|
|
309698
|
+
try {
|
|
309699
|
+
const current = load(input);
|
|
309700
|
+
const priorCommand = current.recentCommands.find((entry) => entry.id === input.commandId);
|
|
309701
|
+
if (priorCommand) {
|
|
309702
|
+
db3.exec("COMMIT");
|
|
309703
|
+
return {
|
|
309704
|
+
status: priorCommand.fingerprint === input.fingerprint ? "idempotent" : "conflict",
|
|
309705
|
+
snapshot: current
|
|
309706
|
+
};
|
|
309707
|
+
}
|
|
309708
|
+
if (current.revision !== input.expectedRevision) {
|
|
309709
|
+
db3.exec("COMMIT");
|
|
309710
|
+
return { status: "conflict", snapshot: current };
|
|
309711
|
+
}
|
|
309712
|
+
runSql(
|
|
309713
|
+
db3,
|
|
309714
|
+
`INSERT INTO todo_snapshot (conversation_id, owner_id, snapshot, updated_at)
|
|
309715
|
+
VALUES (?, ?, ?, ?)
|
|
309716
|
+
ON CONFLICT(conversation_id, owner_id) DO UPDATE SET
|
|
309717
|
+
snapshot = excluded.snapshot,
|
|
309718
|
+
updated_at = excluded.updated_at`,
|
|
309719
|
+
[
|
|
309720
|
+
input.conversationId,
|
|
309721
|
+
input.ownerId ?? "",
|
|
309722
|
+
JSON.stringify(candidate),
|
|
309723
|
+
Date.parse(candidate.updatedAt)
|
|
309724
|
+
]
|
|
309725
|
+
);
|
|
309726
|
+
db3.exec("COMMIT");
|
|
309727
|
+
return { status: "committed", snapshot: candidate };
|
|
309728
|
+
} catch (error41) {
|
|
309729
|
+
try {
|
|
309730
|
+
db3.exec("ROLLBACK");
|
|
309731
|
+
} catch {
|
|
309732
|
+
}
|
|
309733
|
+
throw error41;
|
|
309734
|
+
}
|
|
309735
|
+
}
|
|
309736
|
+
};
|
|
309737
|
+
}
|
|
309001
309738
|
};
|
|
309002
309739
|
|
|
309003
309740
|
// src/cli/index.ts
|
|
@@ -309297,7 +310034,7 @@ init_tui_select();
|
|
|
309297
310034
|
init_model_registry();
|
|
309298
310035
|
|
|
309299
310036
|
// package.json
|
|
309300
|
-
var version2 = "1.
|
|
310037
|
+
var version2 = "1.180.0";
|
|
309301
310038
|
|
|
309302
310039
|
// src/adapters/cli/model-catalog.ts
|
|
309303
310040
|
init_codex_auth();
|
|
@@ -310051,9 +310788,14 @@ async function resolveProvider(cfg) {
|
|
|
310051
310788
|
const { getCodexAuth: getCodexAuth2 } = await Promise.resolve().then(() => (init_codex_auth(), codex_auth_exports));
|
|
310052
310789
|
const auth2 = await getCodexAuth2(cfg);
|
|
310053
310790
|
if (!auth2) {
|
|
310054
|
-
throw new Error(
|
|
310791
|
+
throw new Error(
|
|
310792
|
+
"Codex provider selected but not signed in \u2014 run `usable-chat login` and choose Codex."
|
|
310793
|
+
);
|
|
310055
310794
|
}
|
|
310056
|
-
return {
|
|
310795
|
+
return {
|
|
310796
|
+
name: "codex",
|
|
310797
|
+
codexAuth: { accessToken: auth2.accessToken, accountId: auth2.accountId }
|
|
310798
|
+
};
|
|
310057
310799
|
}
|
|
310058
310800
|
return { name: "openrouter", zdr: cfg.ai.zdr };
|
|
310059
310801
|
}
|
|
@@ -310130,7 +310872,11 @@ async function compactSession(history, opts) {
|
|
|
310130
310872
|
}
|
|
310131
310873
|
const checkpoint = buildSummaryCheckpoint(summary, history.length, extractFileOps(history));
|
|
310132
310874
|
if (!opts.noSave) opts.store.replaceSessionMessages(opts.sessionId, [checkpoint]);
|
|
310133
|
-
return {
|
|
310875
|
+
return {
|
|
310876
|
+
ok: true,
|
|
310877
|
+
note: `\u{1F9F9} Compacted ${history.length} messages into a checkpoint.`,
|
|
310878
|
+
checkpoint
|
|
310879
|
+
};
|
|
310134
310880
|
}
|
|
310135
310881
|
function printUsage() {
|
|
310136
310882
|
process.stderr.write(
|
|
@@ -310256,13 +311002,17 @@ function silenceConsole(logFile) {
|
|
|
310256
311002
|
console.error = append;
|
|
310257
311003
|
}
|
|
310258
311004
|
function readScriptedLlm() {
|
|
310259
|
-
if (process.env.E2E_ALLOW_TEST_SEAMS !== "true" || !process.env.USABLE_CLI_SCRIPT)
|
|
311005
|
+
if (process.env.E2E_ALLOW_TEST_SEAMS !== "true" || !process.env.USABLE_CLI_SCRIPT)
|
|
311006
|
+
return void 0;
|
|
310260
311007
|
try {
|
|
310261
311008
|
return JSON.parse(process.env.USABLE_CLI_SCRIPT);
|
|
310262
311009
|
} catch {
|
|
310263
311010
|
return void 0;
|
|
310264
311011
|
}
|
|
310265
311012
|
}
|
|
311013
|
+
function scriptedSession() {
|
|
311014
|
+
return { user: { id: "cli-e2e-user", accessToken: "" } };
|
|
311015
|
+
}
|
|
310266
311016
|
async function resolveImageArgs(specs) {
|
|
310267
311017
|
const images = [];
|
|
310268
311018
|
const errors = [];
|
|
@@ -310281,7 +311031,8 @@ async function resolveImageArgs(specs) {
|
|
|
310281
311031
|
async function runTui(cfg, store, projectId, values2) {
|
|
310282
311032
|
applyEnv(cfg);
|
|
310283
311033
|
silenceConsole(join21(cfg.paths.dataDir, "usable.log"));
|
|
310284
|
-
|
|
311034
|
+
const scriptedLlm = readScriptedLlm();
|
|
311035
|
+
let session = scriptedLlm ? scriptedSession() : await loadSession(cfg);
|
|
310285
311036
|
let model = values2.model ?? cfg.ai.defaultModel;
|
|
310286
311037
|
let reasoning = cfg.ai.reasoningEffort;
|
|
310287
311038
|
let provider = cfg.ai.provider;
|
|
@@ -310306,7 +311057,6 @@ async function runTui(cfg, store, projectId, values2) {
|
|
|
310306
311057
|
} else {
|
|
310307
311058
|
sessionId2 = store.createSession({ projectId, directory: process.cwd(), model });
|
|
310308
311059
|
}
|
|
310309
|
-
const scriptedLlm = readScriptedLlm();
|
|
310310
311060
|
const { runCliTurn: runCliTurn2 } = await Promise.resolve().then(() => (init_run(), run_exports));
|
|
310311
311061
|
const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui2(), tui_exports));
|
|
310312
311062
|
const extLogFile = join21(cfg.paths.dataDir, "usable.log");
|
|
@@ -310327,7 +311077,7 @@ async function runTui(cfg, store, projectId, values2) {
|
|
|
310327
311077
|
const ext2 = await setupExtensions(process.cwd(), extUi, extLog);
|
|
310328
311078
|
ext2.current.fireSessionStart({ sessionId: sessionId2 });
|
|
310329
311079
|
if (resumedExisting) ext2.current.fireSessionSwitch({ sessionId: sessionId2 });
|
|
310330
|
-
let providerRoute = await resolveProvider(cfg);
|
|
311080
|
+
let providerRoute = scriptedLlm ? void 0 : await resolveProvider(cfg);
|
|
310331
311081
|
const runTurn = async (prompt, hist, { onText, onEvent, abortSignal, images }) => {
|
|
310332
311082
|
const result = await runCliTurn2({
|
|
310333
311083
|
prompt,
|
|
@@ -310339,8 +311089,10 @@ async function runTui(cfg, store, projectId, values2) {
|
|
|
310339
311089
|
skills: { enabled: cfg.ai.skills !== false, workspaceId: cfg.mcp.defaultWorkspaceId },
|
|
310340
311090
|
usableApiHost: cfg.ai.usableApiHost,
|
|
310341
311091
|
conversationId: sessionId2,
|
|
311092
|
+
ephemeral: values2["no-save"] === true,
|
|
310342
311093
|
session,
|
|
310343
311094
|
chatStore: store.chatStore,
|
|
311095
|
+
todoStore: store.todoStore,
|
|
310344
311096
|
scriptedLlm,
|
|
310345
311097
|
enableMcp: true,
|
|
310346
311098
|
extensions: ext2.current,
|
|
@@ -310424,6 +311176,10 @@ async function runTui(cfg, store, projectId, values2) {
|
|
|
310424
311176
|
kind: m33.role === "assistant" ? "assistant" : "user",
|
|
310425
311177
|
text: typeof m33.content === "string" ? m33.content : JSON.stringify(m33.content)
|
|
310426
311178
|
}));
|
|
311179
|
+
const initialTodos = values2["no-save"] ? void 0 : await store.todoStore.loadTodoSnapshot({
|
|
311180
|
+
conversationId: sessionId2,
|
|
311181
|
+
ownerId: session.user?.id
|
|
311182
|
+
});
|
|
310427
311183
|
const updateNotice = getUpdateNotice({
|
|
310428
311184
|
currentVersion: version2,
|
|
310429
311185
|
dataDir: cfg.paths.dataDir
|
|
@@ -310435,6 +311191,7 @@ async function runTui(cfg, store, projectId, values2) {
|
|
|
310435
311191
|
runTurn,
|
|
310436
311192
|
actions,
|
|
310437
311193
|
initialHistory,
|
|
311194
|
+
initialTodos,
|
|
310438
311195
|
initialImages: initialImages.length > 0 ? initialImages : void 0,
|
|
310439
311196
|
loggedIn: Boolean(session.user?.accessToken),
|
|
310440
311197
|
user: session.user?.id,
|
|
@@ -310526,7 +311283,8 @@ async function main() {
|
|
|
310526
311283
|
}
|
|
310527
311284
|
applyEnv(cfg);
|
|
310528
311285
|
reserveStdout();
|
|
310529
|
-
const
|
|
311286
|
+
const scriptedLlm = readScriptedLlm();
|
|
311287
|
+
const session = scriptedLlm ? scriptedSession() : await loadSession(cfg);
|
|
310530
311288
|
let sessionId2;
|
|
310531
311289
|
let history = [];
|
|
310532
311290
|
if (values2.resume) {
|
|
@@ -310550,13 +311308,6 @@ async function main() {
|
|
|
310550
311308
|
model: values2.model ?? cfg.ai.defaultModel
|
|
310551
311309
|
});
|
|
310552
311310
|
}
|
|
310553
|
-
let scriptedLlm;
|
|
310554
|
-
if (process.env.E2E_ALLOW_TEST_SEAMS === "true" && process.env.USABLE_CLI_SCRIPT) {
|
|
310555
|
-
try {
|
|
310556
|
-
scriptedLlm = JSON.parse(process.env.USABLE_CLI_SCRIPT);
|
|
310557
|
-
} catch {
|
|
310558
|
-
}
|
|
310559
|
-
}
|
|
310560
311311
|
const { runCliTurn: runCliTurn2 } = await Promise.resolve().then(() => (init_run(), run_exports));
|
|
310561
311312
|
const headlessUi = {
|
|
310562
311313
|
notify: (m33) => process.stderr.write(`${m33}
|
|
@@ -310592,8 +311343,10 @@ async function main() {
|
|
|
310592
311343
|
skills: { enabled: cfg.ai.skills !== false, workspaceId: cfg.mcp.defaultWorkspaceId },
|
|
310593
311344
|
usableApiHost: cfg.ai.usableApiHost,
|
|
310594
311345
|
conversationId: sessionId2,
|
|
311346
|
+
ephemeral: values2["no-save"] === true,
|
|
310595
311347
|
session,
|
|
310596
311348
|
chatStore: store.chatStore,
|
|
311349
|
+
todoStore: store.todoStore,
|
|
310597
311350
|
scriptedLlm,
|
|
310598
311351
|
enableMcp: true,
|
|
310599
311352
|
extensions: ext2?.current,
|