@hasna/todos 0.11.41 → 0.11.42
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/README.md +20 -0
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/index.js +741 -141
- package/dist/cli-mcp-parity.d.ts.map +1 -1
- package/dist/contracts.js +73 -6
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +519 -103
- package/dist/json-contracts.d.ts.map +1 -1
- package/dist/lib/local-bridge.d.ts +2 -0
- package/dist/lib/local-bridge.d.ts.map +1 -1
- package/dist/lib/saved-search-views.d.ts +60 -0
- package/dist/lib/saved-search-views.d.ts.map +1 -0
- package/dist/lib/todos-md.d.ts.map +1 -1
- package/dist/mcp/index.js +544 -96
- package/dist/mcp/token-utils.d.ts.map +1 -1
- package/dist/mcp/tools/task-meta-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-project-tools.d.ts.map +1 -1
- package/dist/mcp.js +4 -0
- package/dist/registry.js +86 -7
- package/dist/release-provenance.json +3 -3
- package/dist/server/index.js +24 -0
- package/dist/storage.js +24 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -979,6 +979,19 @@ var init_migrations = __esm(() => {
|
|
|
979
979
|
);
|
|
980
980
|
CREATE INDEX IF NOT EXISTS idx_handoff_acks_agent ON handoff_acknowledgements(agent_id, acknowledged_at);
|
|
981
981
|
INSERT OR IGNORE INTO _migrations (id) VALUES (54);
|
|
982
|
+
`,
|
|
983
|
+
`
|
|
984
|
+
CREATE TABLE IF NOT EXISTS saved_search_views (
|
|
985
|
+
id TEXT PRIMARY KEY,
|
|
986
|
+
name TEXT NOT NULL UNIQUE,
|
|
987
|
+
description TEXT,
|
|
988
|
+
scope TEXT NOT NULL DEFAULT 'tasks' CHECK(scope IN ('all', 'tasks', 'projects', 'plans', 'runs', 'comments')),
|
|
989
|
+
filters TEXT NOT NULL DEFAULT '{}',
|
|
990
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
991
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
992
|
+
);
|
|
993
|
+
CREATE INDEX IF NOT EXISTS idx_saved_search_views_scope ON saved_search_views(scope);
|
|
994
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (55);
|
|
982
995
|
`
|
|
983
996
|
];
|
|
984
997
|
});
|
|
@@ -1155,6 +1168,17 @@ function ensureSchema(db) {
|
|
|
1155
1168
|
PRIMARY KEY (handoff_id, agent_id)
|
|
1156
1169
|
)`);
|
|
1157
1170
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_handoff_acks_agent ON handoff_acknowledgements(agent_id, acknowledged_at)");
|
|
1171
|
+
ensureTable("saved_search_views", `
|
|
1172
|
+
CREATE TABLE saved_search_views (
|
|
1173
|
+
id TEXT PRIMARY KEY,
|
|
1174
|
+
name TEXT NOT NULL UNIQUE,
|
|
1175
|
+
description TEXT,
|
|
1176
|
+
scope TEXT NOT NULL DEFAULT 'tasks' CHECK(scope IN ('all', 'tasks', 'projects', 'plans', 'runs', 'comments')),
|
|
1177
|
+
filters TEXT NOT NULL DEFAULT '{}',
|
|
1178
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1179
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1180
|
+
)`);
|
|
1181
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_saved_search_views_scope ON saved_search_views(scope)");
|
|
1158
1182
|
ensureTable("task_relationships", `
|
|
1159
1183
|
CREATE TABLE task_relationships (
|
|
1160
1184
|
id TEXT PRIMARY KEY,
|
|
@@ -2713,6 +2737,39 @@ var TODOS_JSON_CONTRACTS = [
|
|
|
2713
2737
|
created: field("object", "Flags and source types created by this bootstrap run.")
|
|
2714
2738
|
},
|
|
2715
2739
|
optional: {}
|
|
2740
|
+
}),
|
|
2741
|
+
contract({
|
|
2742
|
+
id: "saved_search_view",
|
|
2743
|
+
name: "Saved Search View",
|
|
2744
|
+
description: "Local saved search view for repeatable task, project, plan, run, comment, or cross-entity searches.",
|
|
2745
|
+
surfaces: ["cli", "mcp", "sdk"],
|
|
2746
|
+
stability: "stable",
|
|
2747
|
+
required: {
|
|
2748
|
+
id: idField,
|
|
2749
|
+
name: field("string", "Human-readable unique view name."),
|
|
2750
|
+
description: field(["string", "null"], "Optional view description.", true),
|
|
2751
|
+
scope: field("string", "Search scope: all, tasks, projects, plans, runs, or comments."),
|
|
2752
|
+
filters: field("object", "Saved local filter object."),
|
|
2753
|
+
created_at: isoDateField,
|
|
2754
|
+
updated_at: isoDateField
|
|
2755
|
+
},
|
|
2756
|
+
optional: {}
|
|
2757
|
+
}),
|
|
2758
|
+
contract({
|
|
2759
|
+
id: "saved_search_run_result",
|
|
2760
|
+
name: "Saved Search Run Result",
|
|
2761
|
+
description: "Stable JSON envelope returned when running a saved search view or cross-entity search.",
|
|
2762
|
+
surfaces: ["cli", "mcp", "sdk"],
|
|
2763
|
+
stability: "stable",
|
|
2764
|
+
required: {
|
|
2765
|
+
scope: field("string", "Search scope used for the run."),
|
|
2766
|
+
filters: field("object", "Applied local filters."),
|
|
2767
|
+
count: field("integer", "Number of returned result records."),
|
|
2768
|
+
results: field("array", "Result records with entity_type and entity.")
|
|
2769
|
+
},
|
|
2770
|
+
optional: {
|
|
2771
|
+
view: field("object", "Saved view metadata when the run came from a named view.")
|
|
2772
|
+
}
|
|
2716
2773
|
})
|
|
2717
2774
|
];
|
|
2718
2775
|
function expectedTypes(contract2) {
|
|
@@ -6247,7 +6304,8 @@ var dataKeys = [
|
|
|
6247
6304
|
"task_files",
|
|
6248
6305
|
"task_commits",
|
|
6249
6306
|
"task_git_refs",
|
|
6250
|
-
"task_verifications"
|
|
6307
|
+
"task_verifications",
|
|
6308
|
+
"saved_views"
|
|
6251
6309
|
];
|
|
6252
6310
|
var insertColumns = {
|
|
6253
6311
|
projects: ["id", "name", "path", "description", "task_list_id", "task_prefix", "task_counter", "created_at", "updated_at", "machine_id", "synced_at"],
|
|
@@ -6319,7 +6377,8 @@ var insertColumns = {
|
|
|
6319
6377
|
task_files: ["id", "task_id", "path", "status", "agent_id", "note", "created_at", "updated_at", "machine_id"],
|
|
6320
6378
|
task_commits: ["id", "task_id", "sha", "message", "author", "files_changed", "committed_at", "created_at"],
|
|
6321
6379
|
task_git_refs: ["id", "task_id", "ref_type", "name", "url", "provider", "metadata", "created_at", "updated_at"],
|
|
6322
|
-
task_verifications: ["id", "task_id", "command", "status", "output_summary", "artifact_path", "agent_id", "run_at", "created_at"]
|
|
6380
|
+
task_verifications: ["id", "task_id", "command", "status", "output_summary", "artifact_path", "agent_id", "run_at", "created_at"],
|
|
6381
|
+
saved_views: ["id", "name", "description", "scope", "filters", "created_at", "updated_at"]
|
|
6323
6382
|
};
|
|
6324
6383
|
var tableByKey = {
|
|
6325
6384
|
projects: "projects",
|
|
@@ -6335,9 +6394,10 @@ var tableByKey = {
|
|
|
6335
6394
|
task_files: "task_files",
|
|
6336
6395
|
task_commits: "task_commits",
|
|
6337
6396
|
task_git_refs: "task_git_refs",
|
|
6338
|
-
task_verifications: "task_verifications"
|
|
6397
|
+
task_verifications: "task_verifications",
|
|
6398
|
+
saved_views: "saved_search_views"
|
|
6339
6399
|
};
|
|
6340
|
-
var jsonColumns = new Set(["metadata", "tags", "data", "files_changed"]);
|
|
6400
|
+
var jsonColumns = new Set(["metadata", "tags", "data", "files_changed", "filters"]);
|
|
6341
6401
|
function packageSource(version) {
|
|
6342
6402
|
return {
|
|
6343
6403
|
packageName: "@hasna/todos",
|
|
@@ -6410,6 +6470,9 @@ function rowToRunEvent(row) {
|
|
|
6410
6470
|
function rowToCommit(row) {
|
|
6411
6471
|
return { ...row, files_changed: row.files_changed ? parseJsonArray(row.files_changed) : null };
|
|
6412
6472
|
}
|
|
6473
|
+
function rowToSavedView(row) {
|
|
6474
|
+
return { ...row, filters: parseJsonObject(row.filters) };
|
|
6475
|
+
}
|
|
6413
6476
|
function bridgeStats(data) {
|
|
6414
6477
|
return Object.fromEntries(dataKeys.map((key) => [key, data[key].length]));
|
|
6415
6478
|
}
|
|
@@ -6433,7 +6496,8 @@ function createLocalBridgeBundle(options = {}, db) {
|
|
|
6433
6496
|
task_files: queryByTaskIds(d, "SELECT * FROM task_files WHERE task_id IN (__TASK_IDS__) ORDER BY path, id", taskIds),
|
|
6434
6497
|
task_commits: queryByTaskIds(d, "SELECT * FROM task_commits WHERE task_id IN (__TASK_IDS__) ORDER BY created_at, id", taskIds).map(rowToCommit),
|
|
6435
6498
|
task_git_refs: queryByTaskIds(d, "SELECT * FROM task_git_refs WHERE task_id IN (__TASK_IDS__) ORDER BY created_at, id", taskIds).map(rowWithMetadata),
|
|
6436
|
-
task_verifications: queryByTaskIds(d, "SELECT * FROM task_verifications WHERE task_id IN (__TASK_IDS__) ORDER BY run_at, id", taskIds)
|
|
6499
|
+
task_verifications: queryByTaskIds(d, "SELECT * FROM task_verifications WHERE task_id IN (__TASK_IDS__) ORDER BY run_at, id", taskIds),
|
|
6500
|
+
saved_views: (options.project_id ? d.query("SELECT * FROM saved_search_views WHERE json_extract(filters, '$.project_id') = ? ORDER BY name").all(options.project_id) : d.query("SELECT * FROM saved_search_views ORDER BY name").all()).map(rowToSavedView)
|
|
6437
6501
|
};
|
|
6438
6502
|
const artifactContents = data.run_artifacts.map((artifact) => exportStoredArtifactContent({
|
|
6439
6503
|
id: artifact.id,
|
|
@@ -6472,6 +6536,8 @@ function validateLocalBridgeBundle(value) {
|
|
|
6472
6536
|
issues.push("data must be an object");
|
|
6473
6537
|
} else {
|
|
6474
6538
|
for (const key of dataKeys) {
|
|
6539
|
+
if (key === "saved_views" && data[key] === undefined)
|
|
6540
|
+
continue;
|
|
6475
6541
|
if (!Array.isArray(data[key]))
|
|
6476
6542
|
issues.push(`data.${key} must be an array`);
|
|
6477
6543
|
}
|
|
@@ -6644,7 +6710,8 @@ function importLocalBridgeBundle(bundle, options = {}, db) {
|
|
|
6644
6710
|
const conflictStrategy = options.conflictStrategy ?? "skip";
|
|
6645
6711
|
const data = {
|
|
6646
6712
|
...bundle.data,
|
|
6647
|
-
tasks: sortedTasks(bundle.data.tasks)
|
|
6713
|
+
tasks: sortedTasks(bundle.data.tasks),
|
|
6714
|
+
saved_views: bundle.data.saved_views ?? []
|
|
6648
6715
|
};
|
|
6649
6716
|
for (const key of dataKeys) {
|
|
6650
6717
|
for (const row of data[key]) {
|
|
@@ -7255,6 +7322,10 @@ var MCP_TOOL_GROUPS = {
|
|
|
7255
7322
|
"request_task_review",
|
|
7256
7323
|
"reschedule_task",
|
|
7257
7324
|
"search_tasks",
|
|
7325
|
+
"save_search_view",
|
|
7326
|
+
"list_search_views",
|
|
7327
|
+
"run_search_view",
|
|
7328
|
+
"delete_search_view",
|
|
7258
7329
|
"standup",
|
|
7259
7330
|
"set_task_contract",
|
|
7260
7331
|
"task_context",
|
|
@@ -8214,6 +8285,10 @@ var TODOS_CLI_MCP_PARITY = [
|
|
|
8214
8285
|
domain: "search",
|
|
8215
8286
|
cliCommands: [
|
|
8216
8287
|
"todos search",
|
|
8288
|
+
"todos views save",
|
|
8289
|
+
"todos views list",
|
|
8290
|
+
"todos views run",
|
|
8291
|
+
"todos views delete",
|
|
8217
8292
|
"todos status",
|
|
8218
8293
|
"todos recap",
|
|
8219
8294
|
"todos standup",
|
|
@@ -8225,6 +8300,10 @@ var TODOS_CLI_MCP_PARITY = [
|
|
|
8225
8300
|
],
|
|
8226
8301
|
mcpTools: [
|
|
8227
8302
|
"search_tasks",
|
|
8303
|
+
"save_search_view",
|
|
8304
|
+
"list_search_views",
|
|
8305
|
+
"run_search_view",
|
|
8306
|
+
"delete_search_view",
|
|
8228
8307
|
"get_status",
|
|
8229
8308
|
"standup",
|
|
8230
8309
|
"get_task_stats",
|
|
@@ -8233,7 +8312,7 @@ var TODOS_CLI_MCP_PARITY = [
|
|
|
8233
8312
|
"get_task_graph",
|
|
8234
8313
|
"get_recent_activity"
|
|
8235
8314
|
],
|
|
8236
|
-
jsonContracts: ["task", "status_summary", "audit_history", "structured_error", "api_error"],
|
|
8315
|
+
jsonContracts: ["task", "saved_search_view", "saved_search_run_result", "status_summary", "audit_history", "structured_error", "api_error"],
|
|
8237
8316
|
errorContracts: ["structured_error", "api_error"],
|
|
8238
8317
|
status: "matched",
|
|
8239
8318
|
example: {
|
|
@@ -11359,6 +11438,426 @@ function searchTasks(options, projectId, taskListId, db) {
|
|
|
11359
11438
|
const rows = d.query(sql).all(...params);
|
|
11360
11439
|
return rows.map(rowToTask4);
|
|
11361
11440
|
}
|
|
11441
|
+
// src/lib/saved-search-views.ts
|
|
11442
|
+
init_database();
|
|
11443
|
+
|
|
11444
|
+
// src/lib/local-fields.ts
|
|
11445
|
+
init_database();
|
|
11446
|
+
init_types();
|
|
11447
|
+
var LOCAL_FIELDS_KEY = "local_fields";
|
|
11448
|
+
function normalizeList(values) {
|
|
11449
|
+
return [...new Set((values || []).map((value) => value.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
11450
|
+
}
|
|
11451
|
+
function metadataFields(task) {
|
|
11452
|
+
const value = task.metadata[LOCAL_FIELDS_KEY];
|
|
11453
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
11454
|
+
}
|
|
11455
|
+
function sameCustomValue(actual, expected) {
|
|
11456
|
+
return JSON.stringify(actual) === JSON.stringify(expected);
|
|
11457
|
+
}
|
|
11458
|
+
function hasOwnField(fields, key) {
|
|
11459
|
+
return Object.prototype.hasOwnProperty.call(fields, key);
|
|
11460
|
+
}
|
|
11461
|
+
function getTaskLocalFields(taskId, db) {
|
|
11462
|
+
const d = db || getDatabase();
|
|
11463
|
+
const task = getTask(taskId, d);
|
|
11464
|
+
if (!task)
|
|
11465
|
+
throw new TaskNotFoundError(taskId);
|
|
11466
|
+
const fields = metadataFields(task);
|
|
11467
|
+
return {
|
|
11468
|
+
labels: normalizeList(fields.labels),
|
|
11469
|
+
priority: task.priority,
|
|
11470
|
+
severity: typeof fields.severity === "string" ? fields.severity : null,
|
|
11471
|
+
owner: hasOwnField(fields, "owner") ? typeof fields.owner === "string" ? fields.owner : null : task.assigned_to,
|
|
11472
|
+
area: typeof fields.area === "string" ? fields.area : null,
|
|
11473
|
+
custom: fields.custom && typeof fields.custom === "object" && !Array.isArray(fields.custom) ? fields.custom : {}
|
|
11474
|
+
};
|
|
11475
|
+
}
|
|
11476
|
+
function setTaskLocalFields(taskId, input, db) {
|
|
11477
|
+
const d = db || getDatabase();
|
|
11478
|
+
const task = getTask(taskId, d);
|
|
11479
|
+
if (!task)
|
|
11480
|
+
throw new TaskNotFoundError(taskId);
|
|
11481
|
+
const currentFields = getTaskLocalFields(taskId, d);
|
|
11482
|
+
const labels = input.labels !== undefined ? normalizeList(input.labels) : currentFields.labels;
|
|
11483
|
+
const custom = input.custom !== undefined ? redactValue(input.merge_custom === false ? input.custom : { ...currentFields.custom, ...input.custom }) : currentFields.custom;
|
|
11484
|
+
const nextFields = {
|
|
11485
|
+
labels,
|
|
11486
|
+
priority: input.priority || task.priority,
|
|
11487
|
+
severity: input.severity !== undefined ? input.severity : currentFields.severity,
|
|
11488
|
+
owner: input.owner !== undefined ? input.owner : currentFields.owner,
|
|
11489
|
+
area: input.area !== undefined ? input.area : currentFields.area,
|
|
11490
|
+
custom
|
|
11491
|
+
};
|
|
11492
|
+
const nextMetadata = {
|
|
11493
|
+
...task.metadata,
|
|
11494
|
+
[LOCAL_FIELDS_KEY]: nextFields
|
|
11495
|
+
};
|
|
11496
|
+
const previousLabels = new Set(currentFields.labels);
|
|
11497
|
+
const nextTags = normalizeList([...task.tags.filter((tag) => !previousLabels.has(tag)), ...labels]);
|
|
11498
|
+
const updates = {
|
|
11499
|
+
version: task.version,
|
|
11500
|
+
priority: input.priority,
|
|
11501
|
+
tags: nextTags,
|
|
11502
|
+
metadata: nextMetadata
|
|
11503
|
+
};
|
|
11504
|
+
if (input.owner !== undefined)
|
|
11505
|
+
updates.assigned_to = nextFields.owner;
|
|
11506
|
+
return updateTask(taskId, updates, d);
|
|
11507
|
+
}
|
|
11508
|
+
function queryTasksByLocalFields(query, db) {
|
|
11509
|
+
const d = db || getDatabase();
|
|
11510
|
+
const tasks = listTasks({
|
|
11511
|
+
priority: query.priority,
|
|
11512
|
+
tags: query.labels,
|
|
11513
|
+
limit: 1e4
|
|
11514
|
+
}, d);
|
|
11515
|
+
const matches = tasks.filter((task) => {
|
|
11516
|
+
const fields = getTaskLocalFields(task.id, d);
|
|
11517
|
+
if (query.labels && !query.labels.every((label) => fields.labels.includes(label)))
|
|
11518
|
+
return false;
|
|
11519
|
+
if (query.severity && fields.severity !== query.severity)
|
|
11520
|
+
return false;
|
|
11521
|
+
if (query.owner && fields.owner !== query.owner)
|
|
11522
|
+
return false;
|
|
11523
|
+
if (query.area && fields.area !== query.area)
|
|
11524
|
+
return false;
|
|
11525
|
+
if (query.custom) {
|
|
11526
|
+
for (const [key, expected] of Object.entries(query.custom)) {
|
|
11527
|
+
if (!sameCustomValue(fields.custom[key], expected))
|
|
11528
|
+
return false;
|
|
11529
|
+
}
|
|
11530
|
+
}
|
|
11531
|
+
return true;
|
|
11532
|
+
});
|
|
11533
|
+
return matches.slice(0, query.limit || 100);
|
|
11534
|
+
}
|
|
11535
|
+
|
|
11536
|
+
// src/lib/saved-search-views.ts
|
|
11537
|
+
function parseFilters(value) {
|
|
11538
|
+
if (!value)
|
|
11539
|
+
return {};
|
|
11540
|
+
try {
|
|
11541
|
+
const parsed = JSON.parse(value);
|
|
11542
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
11543
|
+
} catch {
|
|
11544
|
+
return {};
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
function rowToSavedSearchView(row) {
|
|
11548
|
+
return {
|
|
11549
|
+
...row,
|
|
11550
|
+
scope: normalizeScope(row.scope),
|
|
11551
|
+
filters: parseFilters(row.filters)
|
|
11552
|
+
};
|
|
11553
|
+
}
|
|
11554
|
+
function normalizeScope(scope) {
|
|
11555
|
+
if (scope === "all" || scope === "tasks" || scope === "projects" || scope === "plans" || scope === "runs" || scope === "comments") {
|
|
11556
|
+
return scope;
|
|
11557
|
+
}
|
|
11558
|
+
return "tasks";
|
|
11559
|
+
}
|
|
11560
|
+
function normalizeName(name) {
|
|
11561
|
+
const normalized = name.trim();
|
|
11562
|
+
if (!normalized)
|
|
11563
|
+
throw new Error("Saved view name is required");
|
|
11564
|
+
return normalized;
|
|
11565
|
+
}
|
|
11566
|
+
function normalizeLimit(limit) {
|
|
11567
|
+
if (!Number.isFinite(limit) || !limit || limit <= 0)
|
|
11568
|
+
return 100;
|
|
11569
|
+
return Math.min(Math.trunc(limit), 1000);
|
|
11570
|
+
}
|
|
11571
|
+
function valuesList(value) {
|
|
11572
|
+
if (value === undefined)
|
|
11573
|
+
return [];
|
|
11574
|
+
return (Array.isArray(value) ? value : [value]).map((item) => item.trim()).filter(Boolean);
|
|
11575
|
+
}
|
|
11576
|
+
function addStatusFilter(sql, params, column, value) {
|
|
11577
|
+
const values = valuesList(value);
|
|
11578
|
+
if (values.length === 0)
|
|
11579
|
+
return sql;
|
|
11580
|
+
params.push(...values);
|
|
11581
|
+
return `${sql} AND ${column} IN (${values.map(() => "?").join(",")})`;
|
|
11582
|
+
}
|
|
11583
|
+
function addDateFilter(sql, params, column, value) {
|
|
11584
|
+
if (!value)
|
|
11585
|
+
return sql;
|
|
11586
|
+
params.push(value);
|
|
11587
|
+
return `${sql} AND ${column} > ?`;
|
|
11588
|
+
}
|
|
11589
|
+
function likePattern(query) {
|
|
11590
|
+
const trimmed = query?.trim();
|
|
11591
|
+
if (!trimmed || trimmed === "*")
|
|
11592
|
+
return null;
|
|
11593
|
+
return `%${trimmed}%`;
|
|
11594
|
+
}
|
|
11595
|
+
function parseJsonObject2(value) {
|
|
11596
|
+
if (!value)
|
|
11597
|
+
return {};
|
|
11598
|
+
if (typeof value === "object" && !Array.isArray(value))
|
|
11599
|
+
return value;
|
|
11600
|
+
if (typeof value !== "string")
|
|
11601
|
+
return {};
|
|
11602
|
+
try {
|
|
11603
|
+
const parsed = JSON.parse(value);
|
|
11604
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
11605
|
+
} catch {
|
|
11606
|
+
return {};
|
|
11607
|
+
}
|
|
11608
|
+
}
|
|
11609
|
+
function rowToTaskRun(row) {
|
|
11610
|
+
return { ...row, metadata: parseJsonObject2(row.metadata) };
|
|
11611
|
+
}
|
|
11612
|
+
function taskMatchesSavedFilters(task, filters, db) {
|
|
11613
|
+
if (filters.plan_id && task.plan_id !== filters.plan_id)
|
|
11614
|
+
return false;
|
|
11615
|
+
if (filters.tags && !filters.tags.every((tag) => task.tags.includes(tag)))
|
|
11616
|
+
return false;
|
|
11617
|
+
if (filters.depends_on) {
|
|
11618
|
+
const row = db.query("SELECT 1 FROM task_dependencies WHERE task_id = ? AND depends_on = ?").get(task.id, filters.depends_on);
|
|
11619
|
+
if (!row)
|
|
11620
|
+
return false;
|
|
11621
|
+
}
|
|
11622
|
+
if (filters.blocks) {
|
|
11623
|
+
const row = db.query("SELECT 1 FROM task_dependencies WHERE task_id = ? AND depends_on = ?").get(filters.blocks, task.id);
|
|
11624
|
+
if (!row)
|
|
11625
|
+
return false;
|
|
11626
|
+
}
|
|
11627
|
+
return true;
|
|
11628
|
+
}
|
|
11629
|
+
function searchTaskEntities(filters, db) {
|
|
11630
|
+
let tasks;
|
|
11631
|
+
if (filters.local_fields) {
|
|
11632
|
+
const localMatches = queryTasksByLocalFields({ ...filters.local_fields, limit: 1e4 }, db);
|
|
11633
|
+
const allowedIds = new Set(localMatches.map((task) => task.id));
|
|
11634
|
+
tasks = searchTasks({
|
|
11635
|
+
query: filters.query,
|
|
11636
|
+
project_id: filters.project_id,
|
|
11637
|
+
task_list_id: filters.task_list_id,
|
|
11638
|
+
status: filters.status,
|
|
11639
|
+
priority: filters.priority,
|
|
11640
|
+
assigned_to: filters.assigned_to,
|
|
11641
|
+
agent_id: filters.agent_id,
|
|
11642
|
+
created_after: filters.created_after,
|
|
11643
|
+
updated_after: filters.updated_after,
|
|
11644
|
+
has_dependencies: filters.has_dependencies,
|
|
11645
|
+
is_blocked: filters.is_blocked
|
|
11646
|
+
}, undefined, undefined, db).filter((task) => allowedIds.has(task.id));
|
|
11647
|
+
} else {
|
|
11648
|
+
tasks = searchTasks({
|
|
11649
|
+
query: filters.query,
|
|
11650
|
+
project_id: filters.project_id,
|
|
11651
|
+
task_list_id: filters.task_list_id,
|
|
11652
|
+
status: filters.status,
|
|
11653
|
+
priority: filters.priority,
|
|
11654
|
+
assigned_to: filters.assigned_to,
|
|
11655
|
+
agent_id: filters.agent_id,
|
|
11656
|
+
created_after: filters.created_after,
|
|
11657
|
+
updated_after: filters.updated_after,
|
|
11658
|
+
has_dependencies: filters.has_dependencies,
|
|
11659
|
+
is_blocked: filters.is_blocked
|
|
11660
|
+
}, undefined, undefined, db);
|
|
11661
|
+
}
|
|
11662
|
+
return tasks.filter((task) => taskMatchesSavedFilters(task, filters, db)).slice(0, normalizeLimit(filters.limit));
|
|
11663
|
+
}
|
|
11664
|
+
function searchProjects(filters, db) {
|
|
11665
|
+
const params = [];
|
|
11666
|
+
let sql = "SELECT * FROM projects WHERE 1=1";
|
|
11667
|
+
if (filters.project_id) {
|
|
11668
|
+
sql += " AND id = ?";
|
|
11669
|
+
params.push(filters.project_id);
|
|
11670
|
+
}
|
|
11671
|
+
const pattern = likePattern(filters.query);
|
|
11672
|
+
if (pattern) {
|
|
11673
|
+
sql += " AND (name LIKE ? OR description LIKE ? OR path LIKE ?)";
|
|
11674
|
+
params.push(pattern, pattern, pattern);
|
|
11675
|
+
}
|
|
11676
|
+
sql = addDateFilter(sql, params, "created_at", filters.created_after);
|
|
11677
|
+
sql = addDateFilter(sql, params, "updated_at", filters.updated_after);
|
|
11678
|
+
sql += " ORDER BY name LIMIT ?";
|
|
11679
|
+
params.push(normalizeLimit(filters.limit));
|
|
11680
|
+
return db.query(sql).all(...params);
|
|
11681
|
+
}
|
|
11682
|
+
function searchPlans(filters, db) {
|
|
11683
|
+
const params = [];
|
|
11684
|
+
let sql = "SELECT * FROM plans WHERE 1=1";
|
|
11685
|
+
if (filters.project_id) {
|
|
11686
|
+
sql += " AND project_id = ?";
|
|
11687
|
+
params.push(filters.project_id);
|
|
11688
|
+
}
|
|
11689
|
+
if (filters.task_list_id) {
|
|
11690
|
+
sql += " AND task_list_id = ?";
|
|
11691
|
+
params.push(filters.task_list_id);
|
|
11692
|
+
}
|
|
11693
|
+
if (filters.agent_id) {
|
|
11694
|
+
sql += " AND agent_id = ?";
|
|
11695
|
+
params.push(filters.agent_id);
|
|
11696
|
+
}
|
|
11697
|
+
sql = addStatusFilter(sql, params, "status", filters.status);
|
|
11698
|
+
const pattern = likePattern(filters.query);
|
|
11699
|
+
if (pattern) {
|
|
11700
|
+
sql += " AND (name LIKE ? OR description LIKE ?)";
|
|
11701
|
+
params.push(pattern, pattern);
|
|
11702
|
+
}
|
|
11703
|
+
sql = addDateFilter(sql, params, "created_at", filters.created_after);
|
|
11704
|
+
sql = addDateFilter(sql, params, "updated_at", filters.updated_after);
|
|
11705
|
+
sql += " ORDER BY updated_at DESC, created_at DESC LIMIT ?";
|
|
11706
|
+
params.push(normalizeLimit(filters.limit));
|
|
11707
|
+
return db.query(sql).all(...params);
|
|
11708
|
+
}
|
|
11709
|
+
function searchRuns(filters, db) {
|
|
11710
|
+
const params = [];
|
|
11711
|
+
let sql = `SELECT r.* FROM task_runs r
|
|
11712
|
+
JOIN tasks t ON t.id = r.task_id
|
|
11713
|
+
WHERE 1=1`;
|
|
11714
|
+
if (filters.project_id) {
|
|
11715
|
+
sql += " AND t.project_id = ?";
|
|
11716
|
+
params.push(filters.project_id);
|
|
11717
|
+
}
|
|
11718
|
+
if (filters.task_list_id) {
|
|
11719
|
+
sql += " AND t.task_list_id = ?";
|
|
11720
|
+
params.push(filters.task_list_id);
|
|
11721
|
+
}
|
|
11722
|
+
if (filters.plan_id) {
|
|
11723
|
+
sql += " AND t.plan_id = ?";
|
|
11724
|
+
params.push(filters.plan_id);
|
|
11725
|
+
}
|
|
11726
|
+
if (filters.task_id) {
|
|
11727
|
+
sql += " AND r.task_id = ?";
|
|
11728
|
+
params.push(filters.task_id);
|
|
11729
|
+
}
|
|
11730
|
+
if (filters.agent_id) {
|
|
11731
|
+
sql += " AND r.agent_id = ?";
|
|
11732
|
+
params.push(filters.agent_id);
|
|
11733
|
+
}
|
|
11734
|
+
sql = addStatusFilter(sql, params, "r.status", filters.status);
|
|
11735
|
+
const pattern = likePattern(filters.query);
|
|
11736
|
+
if (pattern) {
|
|
11737
|
+
sql += " AND (r.title LIKE ? OR r.summary LIKE ? OR t.title LIKE ?)";
|
|
11738
|
+
params.push(pattern, pattern, pattern);
|
|
11739
|
+
}
|
|
11740
|
+
sql = addDateFilter(sql, params, "r.created_at", filters.created_after);
|
|
11741
|
+
sql = addDateFilter(sql, params, "r.updated_at", filters.updated_after);
|
|
11742
|
+
sql += " ORDER BY r.started_at DESC, r.created_at DESC LIMIT ?";
|
|
11743
|
+
params.push(normalizeLimit(filters.limit));
|
|
11744
|
+
return db.query(sql).all(...params).map(rowToTaskRun);
|
|
11745
|
+
}
|
|
11746
|
+
function searchComments(filters, db) {
|
|
11747
|
+
const params = [];
|
|
11748
|
+
let sql = `SELECT c.* FROM task_comments c
|
|
11749
|
+
JOIN tasks t ON t.id = c.task_id
|
|
11750
|
+
WHERE 1=1`;
|
|
11751
|
+
if (filters.project_id) {
|
|
11752
|
+
sql += " AND t.project_id = ?";
|
|
11753
|
+
params.push(filters.project_id);
|
|
11754
|
+
}
|
|
11755
|
+
if (filters.task_list_id) {
|
|
11756
|
+
sql += " AND t.task_list_id = ?";
|
|
11757
|
+
params.push(filters.task_list_id);
|
|
11758
|
+
}
|
|
11759
|
+
if (filters.plan_id) {
|
|
11760
|
+
sql += " AND t.plan_id = ?";
|
|
11761
|
+
params.push(filters.plan_id);
|
|
11762
|
+
}
|
|
11763
|
+
if (filters.task_id) {
|
|
11764
|
+
sql += " AND c.task_id = ?";
|
|
11765
|
+
params.push(filters.task_id);
|
|
11766
|
+
}
|
|
11767
|
+
if (filters.agent_id) {
|
|
11768
|
+
sql += " AND c.agent_id = ?";
|
|
11769
|
+
params.push(filters.agent_id);
|
|
11770
|
+
}
|
|
11771
|
+
const pattern = likePattern(filters.query);
|
|
11772
|
+
if (pattern) {
|
|
11773
|
+
sql += " AND (c.content LIKE ? OR t.title LIKE ?)";
|
|
11774
|
+
params.push(pattern, pattern);
|
|
11775
|
+
}
|
|
11776
|
+
sql = addDateFilter(sql, params, "c.created_at", filters.created_after);
|
|
11777
|
+
sql += " ORDER BY c.created_at DESC, c.id LIMIT ?";
|
|
11778
|
+
params.push(normalizeLimit(filters.limit));
|
|
11779
|
+
return db.query(sql).all(...params);
|
|
11780
|
+
}
|
|
11781
|
+
function toResults(entityType, rows) {
|
|
11782
|
+
return rows.map((entity) => ({ entity_type: entityType, entity }));
|
|
11783
|
+
}
|
|
11784
|
+
function runSavedSearch(filters = {}, scope = "tasks", db) {
|
|
11785
|
+
const d = db || getDatabase();
|
|
11786
|
+
const normalizedScope = normalizeScope(scope);
|
|
11787
|
+
const scopes = normalizedScope === "all" ? ["tasks", "projects", "plans", "runs", "comments"] : [normalizedScope];
|
|
11788
|
+
const results = [];
|
|
11789
|
+
for (const item of scopes) {
|
|
11790
|
+
if (item === "tasks")
|
|
11791
|
+
results.push(...toResults("tasks", searchTaskEntities(filters, d)));
|
|
11792
|
+
if (item === "projects")
|
|
11793
|
+
results.push(...toResults("projects", searchProjects(filters, d)));
|
|
11794
|
+
if (item === "plans")
|
|
11795
|
+
results.push(...toResults("plans", searchPlans(filters, d)));
|
|
11796
|
+
if (item === "runs")
|
|
11797
|
+
results.push(...toResults("runs", searchRuns(filters, d)));
|
|
11798
|
+
if (item === "comments")
|
|
11799
|
+
results.push(...toResults("comments", searchComments(filters, d)));
|
|
11800
|
+
}
|
|
11801
|
+
return {
|
|
11802
|
+
scope: normalizedScope,
|
|
11803
|
+
filters,
|
|
11804
|
+
count: results.length,
|
|
11805
|
+
results: results.slice(0, normalizeLimit(filters.limit))
|
|
11806
|
+
};
|
|
11807
|
+
}
|
|
11808
|
+
function saveSearchView(input, db) {
|
|
11809
|
+
const d = db || getDatabase();
|
|
11810
|
+
const name = normalizeName(input.name);
|
|
11811
|
+
const timestamp = now();
|
|
11812
|
+
const existing = getSearchView(name, d);
|
|
11813
|
+
if (existing) {
|
|
11814
|
+
d.run(`UPDATE saved_search_views
|
|
11815
|
+
SET description = ?, scope = ?, filters = ?, updated_at = ?
|
|
11816
|
+
WHERE id = ?`, [
|
|
11817
|
+
input.description ?? existing.description,
|
|
11818
|
+
normalizeScope(input.scope ?? existing.scope),
|
|
11819
|
+
JSON.stringify(input.filters ?? existing.filters),
|
|
11820
|
+
timestamp,
|
|
11821
|
+
existing.id
|
|
11822
|
+
]);
|
|
11823
|
+
return getSearchView(existing.id, d);
|
|
11824
|
+
}
|
|
11825
|
+
const id = uuid();
|
|
11826
|
+
d.run(`INSERT INTO saved_search_views (id, name, description, scope, filters, created_at, updated_at)
|
|
11827
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`, [
|
|
11828
|
+
id,
|
|
11829
|
+
name,
|
|
11830
|
+
input.description ?? null,
|
|
11831
|
+
normalizeScope(input.scope),
|
|
11832
|
+
JSON.stringify(input.filters ?? {}),
|
|
11833
|
+
timestamp,
|
|
11834
|
+
timestamp
|
|
11835
|
+
]);
|
|
11836
|
+
return getSearchView(id, d);
|
|
11837
|
+
}
|
|
11838
|
+
function getSearchView(idOrName, db) {
|
|
11839
|
+
const d = db || getDatabase();
|
|
11840
|
+
const row = d.query("SELECT * FROM saved_search_views WHERE id = ? OR name = ?").get(idOrName, idOrName);
|
|
11841
|
+
return row ? rowToSavedSearchView(row) : null;
|
|
11842
|
+
}
|
|
11843
|
+
function listSearchViews(scope, db) {
|
|
11844
|
+
const d = db || getDatabase();
|
|
11845
|
+
const normalizedScope = scope ? normalizeScope(scope) : null;
|
|
11846
|
+
const rows = normalizedScope ? d.query("SELECT * FROM saved_search_views WHERE scope = ? ORDER BY name").all(normalizedScope) : d.query("SELECT * FROM saved_search_views ORDER BY name").all();
|
|
11847
|
+
return rows.map(rowToSavedSearchView);
|
|
11848
|
+
}
|
|
11849
|
+
function deleteSearchView(idOrName, db) {
|
|
11850
|
+
const d = db || getDatabase();
|
|
11851
|
+
const result = d.run("DELETE FROM saved_search_views WHERE id = ? OR name = ?", [idOrName, idOrName]);
|
|
11852
|
+
return result.changes > 0;
|
|
11853
|
+
}
|
|
11854
|
+
function runSearchView(idOrName, db) {
|
|
11855
|
+
const d = db || getDatabase();
|
|
11856
|
+
const view = getSearchView(idOrName, d);
|
|
11857
|
+
if (!view)
|
|
11858
|
+
throw new Error(`Saved search view not found: ${idOrName}`);
|
|
11859
|
+
return { ...runSavedSearch(view.filters, view.scope, d), view };
|
|
11860
|
+
}
|
|
11362
11861
|
// src/lib/claude-tasks.ts
|
|
11363
11862
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
11364
11863
|
import { join as join7 } from "path";
|
|
@@ -13449,97 +13948,6 @@ function assertApprovalGate(taskId, gateName, db) {
|
|
|
13449
13948
|
throw new Error(result.reasons.join("; "));
|
|
13450
13949
|
return result.gate;
|
|
13451
13950
|
}
|
|
13452
|
-
// src/lib/local-fields.ts
|
|
13453
|
-
init_database();
|
|
13454
|
-
init_types();
|
|
13455
|
-
var LOCAL_FIELDS_KEY = "local_fields";
|
|
13456
|
-
function normalizeList(values) {
|
|
13457
|
-
return [...new Set((values || []).map((value) => value.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
13458
|
-
}
|
|
13459
|
-
function metadataFields(task) {
|
|
13460
|
-
const value = task.metadata[LOCAL_FIELDS_KEY];
|
|
13461
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
13462
|
-
}
|
|
13463
|
-
function sameCustomValue(actual, expected) {
|
|
13464
|
-
return JSON.stringify(actual) === JSON.stringify(expected);
|
|
13465
|
-
}
|
|
13466
|
-
function hasOwnField(fields, key) {
|
|
13467
|
-
return Object.prototype.hasOwnProperty.call(fields, key);
|
|
13468
|
-
}
|
|
13469
|
-
function getTaskLocalFields(taskId, db) {
|
|
13470
|
-
const d = db || getDatabase();
|
|
13471
|
-
const task = getTask(taskId, d);
|
|
13472
|
-
if (!task)
|
|
13473
|
-
throw new TaskNotFoundError(taskId);
|
|
13474
|
-
const fields = metadataFields(task);
|
|
13475
|
-
return {
|
|
13476
|
-
labels: normalizeList(fields.labels),
|
|
13477
|
-
priority: task.priority,
|
|
13478
|
-
severity: typeof fields.severity === "string" ? fields.severity : null,
|
|
13479
|
-
owner: hasOwnField(fields, "owner") ? typeof fields.owner === "string" ? fields.owner : null : task.assigned_to,
|
|
13480
|
-
area: typeof fields.area === "string" ? fields.area : null,
|
|
13481
|
-
custom: fields.custom && typeof fields.custom === "object" && !Array.isArray(fields.custom) ? fields.custom : {}
|
|
13482
|
-
};
|
|
13483
|
-
}
|
|
13484
|
-
function setTaskLocalFields(taskId, input, db) {
|
|
13485
|
-
const d = db || getDatabase();
|
|
13486
|
-
const task = getTask(taskId, d);
|
|
13487
|
-
if (!task)
|
|
13488
|
-
throw new TaskNotFoundError(taskId);
|
|
13489
|
-
const currentFields = getTaskLocalFields(taskId, d);
|
|
13490
|
-
const labels = input.labels !== undefined ? normalizeList(input.labels) : currentFields.labels;
|
|
13491
|
-
const custom = input.custom !== undefined ? redactValue(input.merge_custom === false ? input.custom : { ...currentFields.custom, ...input.custom }) : currentFields.custom;
|
|
13492
|
-
const nextFields = {
|
|
13493
|
-
labels,
|
|
13494
|
-
priority: input.priority || task.priority,
|
|
13495
|
-
severity: input.severity !== undefined ? input.severity : currentFields.severity,
|
|
13496
|
-
owner: input.owner !== undefined ? input.owner : currentFields.owner,
|
|
13497
|
-
area: input.area !== undefined ? input.area : currentFields.area,
|
|
13498
|
-
custom
|
|
13499
|
-
};
|
|
13500
|
-
const nextMetadata = {
|
|
13501
|
-
...task.metadata,
|
|
13502
|
-
[LOCAL_FIELDS_KEY]: nextFields
|
|
13503
|
-
};
|
|
13504
|
-
const previousLabels = new Set(currentFields.labels);
|
|
13505
|
-
const nextTags = normalizeList([...task.tags.filter((tag) => !previousLabels.has(tag)), ...labels]);
|
|
13506
|
-
const updates = {
|
|
13507
|
-
version: task.version,
|
|
13508
|
-
priority: input.priority,
|
|
13509
|
-
tags: nextTags,
|
|
13510
|
-
metadata: nextMetadata
|
|
13511
|
-
};
|
|
13512
|
-
if (input.owner !== undefined)
|
|
13513
|
-
updates.assigned_to = nextFields.owner;
|
|
13514
|
-
return updateTask(taskId, updates, d);
|
|
13515
|
-
}
|
|
13516
|
-
function queryTasksByLocalFields(query, db) {
|
|
13517
|
-
const d = db || getDatabase();
|
|
13518
|
-
const tasks = listTasks({
|
|
13519
|
-
priority: query.priority,
|
|
13520
|
-
tags: query.labels,
|
|
13521
|
-
limit: 1e4
|
|
13522
|
-
}, d);
|
|
13523
|
-
const matches = tasks.filter((task) => {
|
|
13524
|
-
const fields = getTaskLocalFields(task.id, d);
|
|
13525
|
-
if (query.labels && !query.labels.every((label) => fields.labels.includes(label)))
|
|
13526
|
-
return false;
|
|
13527
|
-
if (query.severity && fields.severity !== query.severity)
|
|
13528
|
-
return false;
|
|
13529
|
-
if (query.owner && fields.owner !== query.owner)
|
|
13530
|
-
return false;
|
|
13531
|
-
if (query.area && fields.area !== query.area)
|
|
13532
|
-
return false;
|
|
13533
|
-
if (query.custom) {
|
|
13534
|
-
for (const [key, expected] of Object.entries(query.custom)) {
|
|
13535
|
-
if (!sameCustomValue(fields.custom[key], expected))
|
|
13536
|
-
return false;
|
|
13537
|
-
}
|
|
13538
|
-
}
|
|
13539
|
-
return true;
|
|
13540
|
-
});
|
|
13541
|
-
return matches.slice(0, query.limit || 100);
|
|
13542
|
-
}
|
|
13543
13951
|
// src/lib/task-dedupe.ts
|
|
13544
13952
|
init_database();
|
|
13545
13953
|
var DEFAULT_THRESHOLD = 0.74;
|
|
@@ -13978,7 +14386,7 @@ var DEFAULT_CAPABILITIES = {
|
|
|
13978
14386
|
browser: ["browser", "screenshot", "artifact", "evidence"],
|
|
13979
14387
|
script: ["script", "command", "retry", "evidence"]
|
|
13980
14388
|
};
|
|
13981
|
-
function
|
|
14389
|
+
function normalizeName2(name) {
|
|
13982
14390
|
const normalized = name.trim().toLowerCase();
|
|
13983
14391
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
13984
14392
|
throw new Error("verification provider name must use lowercase letters, numbers, dashes, or underscores");
|
|
@@ -13997,10 +14405,10 @@ function timeoutMs(value) {
|
|
|
13997
14405
|
return Math.max(1, Math.min(24 * 60 * 60000, Math.floor(value)));
|
|
13998
14406
|
}
|
|
13999
14407
|
function getProvider(name) {
|
|
14000
|
-
return loadConfig().verification_providers?.[
|
|
14408
|
+
return loadConfig().verification_providers?.[normalizeName2(name)] || null;
|
|
14001
14409
|
}
|
|
14002
14410
|
function upsertVerificationProvider(input) {
|
|
14003
|
-
const name =
|
|
14411
|
+
const name = normalizeName2(input.name);
|
|
14004
14412
|
const config = loadConfig();
|
|
14005
14413
|
const existing = config.verification_providers?.[name];
|
|
14006
14414
|
const timestamp = new Date().toISOString();
|
|
@@ -14030,7 +14438,7 @@ function listVerificationProviders() {
|
|
|
14030
14438
|
return Object.values(loadConfig().verification_providers || {}).sort((a, b) => a.name.localeCompare(b.name));
|
|
14031
14439
|
}
|
|
14032
14440
|
function removeVerificationProvider(name) {
|
|
14033
|
-
const normalized =
|
|
14441
|
+
const normalized = normalizeName2(name);
|
|
14034
14442
|
const config = loadConfig();
|
|
14035
14443
|
if (!config.verification_providers?.[normalized])
|
|
14036
14444
|
return false;
|
|
@@ -14879,7 +15287,8 @@ function emptyCounts2() {
|
|
|
14879
15287
|
task_files: 0,
|
|
14880
15288
|
task_commits: 0,
|
|
14881
15289
|
task_git_refs: 0,
|
|
14882
|
-
task_verifications: 0
|
|
15290
|
+
task_verifications: 0,
|
|
15291
|
+
saved_views: 0
|
|
14883
15292
|
};
|
|
14884
15293
|
}
|
|
14885
15294
|
function bridgeToMarkdownPayload(bundle) {
|
|
@@ -15963,8 +16372,11 @@ export {
|
|
|
15963
16372
|
searchTasks,
|
|
15964
16373
|
scoreTask,
|
|
15965
16374
|
saveSnapshot,
|
|
16375
|
+
saveSearchView,
|
|
15966
16376
|
runVerificationProvider,
|
|
15967
16377
|
runTodosDoctor,
|
|
16378
|
+
runSearchView,
|
|
16379
|
+
runSavedSearch,
|
|
15968
16380
|
runNextAgentDispatch,
|
|
15969
16381
|
runDueDispatches,
|
|
15970
16382
|
revokeApiKey,
|
|
@@ -16009,6 +16421,7 @@ export {
|
|
|
16009
16421
|
parseRecurrenceRule,
|
|
16010
16422
|
parseGitHubUrl,
|
|
16011
16423
|
now,
|
|
16424
|
+
normalizeScope,
|
|
16012
16425
|
normalizeGeneratedAgentNames,
|
|
16013
16426
|
normalizeApiUrl,
|
|
16014
16427
|
nextTaskShortId,
|
|
@@ -16033,6 +16446,7 @@ export {
|
|
|
16033
16446
|
listTaskFiles,
|
|
16034
16447
|
listSnapshots,
|
|
16035
16448
|
listSessions,
|
|
16449
|
+
listSearchViews,
|
|
16036
16450
|
listRunnerSandboxProfiles,
|
|
16037
16451
|
listProjects,
|
|
16038
16452
|
listProjectSources,
|
|
@@ -16097,6 +16511,7 @@ export {
|
|
|
16097
16511
|
getStatus,
|
|
16098
16512
|
getStaleTasks,
|
|
16099
16513
|
getSession,
|
|
16514
|
+
getSearchView,
|
|
16100
16515
|
getRunnerSandboxProfile,
|
|
16101
16516
|
getReviewQueue,
|
|
16102
16517
|
getRelated,
|
|
@@ -16193,6 +16608,7 @@ export {
|
|
|
16193
16608
|
deleteTaskList,
|
|
16194
16609
|
deleteTask,
|
|
16195
16610
|
deleteSession,
|
|
16611
|
+
deleteSearchView,
|
|
16196
16612
|
deleteProject,
|
|
16197
16613
|
deletePlan,
|
|
16198
16614
|
deleteOrg,
|