@hasna/todos 0.13.12 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/agent-commands.d.ts +39 -0
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/dispatch.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +64 -2
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +369 -58
- package/dist/contracts.js +11 -5
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +16 -9
- package/dist/lib/enum-vocabulary.d.ts +72 -0
- package/dist/lib/enum-vocabulary.d.ts.map +1 -0
- package/dist/lib/saved-search-views.d.ts +12 -1
- package/dist/lib/saved-search-views.d.ts.map +1 -1
- package/dist/mcp/index.js +217 -27
- package/dist/mcp/tools/agents.d.ts.map +1 -1
- package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +11 -5
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/v1.generated.d.ts +2 -2
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/index.js +217 -27
- package/dist/server/openapi.d.ts +58 -0
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage.js +12 -4
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2123,7 +2123,7 @@ var package_default;
|
|
|
2123
2123
|
var init_package = __esm(() => {
|
|
2124
2124
|
package_default = {
|
|
2125
2125
|
name: "@hasna/todos",
|
|
2126
|
-
version: "0.
|
|
2126
|
+
version: "0.14.0",
|
|
2127
2127
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
2128
2128
|
type: "module",
|
|
2129
2129
|
main: "dist/index.js",
|
|
@@ -2258,7 +2258,10 @@ var init_package_version = __esm(() => {
|
|
|
2258
2258
|
function isBlockingDependencyStatus(status) {
|
|
2259
2259
|
return status !== "completed" && status !== "cancelled";
|
|
2260
2260
|
}
|
|
2261
|
-
|
|
2261
|
+
function isTerminalStatus(status) {
|
|
2262
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
2263
|
+
}
|
|
2264
|
+
var TASK_STATUSES, TASK_PRIORITIES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
|
|
2262
2265
|
var init_types = __esm(() => {
|
|
2263
2266
|
TASK_STATUSES = [
|
|
2264
2267
|
"pending",
|
|
@@ -2427,6 +2430,7 @@ var init_types = __esm(() => {
|
|
|
2427
2430
|
this.name = "CompletionGuardError";
|
|
2428
2431
|
}
|
|
2429
2432
|
};
|
|
2433
|
+
DISPATCH_STATUSES = ["pending", "sent", "failed", "cancelled"];
|
|
2430
2434
|
DispatchNotFoundError = class DispatchNotFoundError extends Error {
|
|
2431
2435
|
dispatchId;
|
|
2432
2436
|
static code = "DISPATCH_NOT_FOUND";
|
|
@@ -11456,6 +11460,96 @@ var init_lock_display = __esm(() => {
|
|
|
11456
11460
|
init_database();
|
|
11457
11461
|
});
|
|
11458
11462
|
|
|
11463
|
+
// src/lib/enum-vocabulary.ts
|
|
11464
|
+
function editDistance2(a, b) {
|
|
11465
|
+
if (a === b)
|
|
11466
|
+
return 0;
|
|
11467
|
+
if (!a.length)
|
|
11468
|
+
return b.length;
|
|
11469
|
+
if (!b.length)
|
|
11470
|
+
return a.length;
|
|
11471
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
11472
|
+
for (let i = 1;i <= a.length; i += 1) {
|
|
11473
|
+
const current = [i];
|
|
11474
|
+
for (let j = 1;j <= b.length; j += 1) {
|
|
11475
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
11476
|
+
}
|
|
11477
|
+
previous = current;
|
|
11478
|
+
}
|
|
11479
|
+
return previous[b.length];
|
|
11480
|
+
}
|
|
11481
|
+
function suggestVocabularyMatches(value, vocabulary, limit = 3) {
|
|
11482
|
+
const needle = value.trim().toLowerCase();
|
|
11483
|
+
if (!needle)
|
|
11484
|
+
return [];
|
|
11485
|
+
const scored = [];
|
|
11486
|
+
for (const member of vocabulary) {
|
|
11487
|
+
const candidate = member.toLowerCase();
|
|
11488
|
+
if (candidate.startsWith(needle) || needle.startsWith(candidate)) {
|
|
11489
|
+
scored.push({ member, score: 0 });
|
|
11490
|
+
continue;
|
|
11491
|
+
}
|
|
11492
|
+
if (candidate.includes(needle) || needle.includes(candidate)) {
|
|
11493
|
+
scored.push({ member, score: 1 });
|
|
11494
|
+
continue;
|
|
11495
|
+
}
|
|
11496
|
+
const distance = editDistance2(needle, candidate);
|
|
11497
|
+
if (distance <= Math.max(1, Math.floor(candidate.length / 3))) {
|
|
11498
|
+
scored.push({ member, score: 1 + distance });
|
|
11499
|
+
}
|
|
11500
|
+
}
|
|
11501
|
+
return scored.sort((a, b) => a.score - b.score || a.member.localeCompare(b.member)).slice(0, limit).map((entry) => entry.member);
|
|
11502
|
+
}
|
|
11503
|
+
function resolveEnumVocabulary(raw, spec) {
|
|
11504
|
+
const allowList = spec.allowList !== false;
|
|
11505
|
+
const rawElements = (allowList ? raw.split(",") : [raw]).map((element) => element.trim()).filter((element) => element.length > 0);
|
|
11506
|
+
if (rawElements.length === 0) {
|
|
11507
|
+
return {
|
|
11508
|
+
ok: false,
|
|
11509
|
+
message: `${spec.name} requires a value. Allowed values: ${spec.vocabulary.join(", ")}.`,
|
|
11510
|
+
invalid: []
|
|
11511
|
+
};
|
|
11512
|
+
}
|
|
11513
|
+
const normalized = rawElements.map((element) => spec.normalize ? spec.normalize(element) : element);
|
|
11514
|
+
const allowed = new Set(spec.vocabulary);
|
|
11515
|
+
const invalid2 = [];
|
|
11516
|
+
for (let i = 0;i < normalized.length; i += 1) {
|
|
11517
|
+
if (!allowed.has(normalized[i]))
|
|
11518
|
+
invalid2.push(rawElements[i]);
|
|
11519
|
+
}
|
|
11520
|
+
if (invalid2.length === 0) {
|
|
11521
|
+
return { ok: true, values: [...new Set(normalized)] };
|
|
11522
|
+
}
|
|
11523
|
+
const label = invalid2.length === 1 ? "value" : "values";
|
|
11524
|
+
const parts = [
|
|
11525
|
+
`Invalid ${spec.name} ${label}: ${invalid2.join(", ")}.`,
|
|
11526
|
+
`Allowed values: ${spec.vocabulary.join(", ")}.`
|
|
11527
|
+
];
|
|
11528
|
+
const hints = new Set;
|
|
11529
|
+
const suggestions = new Set;
|
|
11530
|
+
for (let i = 0;i < normalized.length; i += 1) {
|
|
11531
|
+
const canonical = normalized[i];
|
|
11532
|
+
if (allowed.has(canonical))
|
|
11533
|
+
continue;
|
|
11534
|
+
const hint = spec.hints?.[canonical.toLowerCase()];
|
|
11535
|
+
if (hint) {
|
|
11536
|
+
hints.add(hint);
|
|
11537
|
+
continue;
|
|
11538
|
+
}
|
|
11539
|
+
for (const match of suggestVocabularyMatches(canonical, spec.vocabulary)) {
|
|
11540
|
+
suggestions.add(match);
|
|
11541
|
+
}
|
|
11542
|
+
}
|
|
11543
|
+
if (suggestions.size > 0)
|
|
11544
|
+
parts.push(`Did you mean ${[...suggestions].join(", ")}?`);
|
|
11545
|
+
for (const hint of hints)
|
|
11546
|
+
parts.push(hint);
|
|
11547
|
+
return { ok: false, message: parts.join(" "), invalid: invalid2 };
|
|
11548
|
+
}
|
|
11549
|
+
function collapseEnumValues(values) {
|
|
11550
|
+
return values.length === 1 ? values[0] : values;
|
|
11551
|
+
}
|
|
11552
|
+
|
|
11459
11553
|
// src/cli/helpers.ts
|
|
11460
11554
|
var exports_helpers = {};
|
|
11461
11555
|
__export(exports_helpers, {
|
|
@@ -11466,9 +11560,13 @@ __export(exports_helpers, {
|
|
|
11466
11560
|
resolveExplicitProject: () => resolveExplicitProject,
|
|
11467
11561
|
priorityColors: () => priorityColors,
|
|
11468
11562
|
printJson: () => printJson,
|
|
11563
|
+
parseEnumFlagList: () => parseEnumFlagList,
|
|
11564
|
+
parseEnumFlag: () => parseEnumFlag,
|
|
11565
|
+
outputRecord: () => outputRecord,
|
|
11469
11566
|
output: () => output,
|
|
11470
11567
|
normalizeStatusList: () => normalizeStatusList,
|
|
11471
11568
|
normalizeStatus: () => normalizeStatus,
|
|
11569
|
+
normalizePriority: () => normalizePriority,
|
|
11472
11570
|
jsonModeRequested: () => jsonModeRequested,
|
|
11473
11571
|
handleError: () => handleError,
|
|
11474
11572
|
getPackageVersion: () => getPackageVersion,
|
|
@@ -11476,7 +11574,10 @@ __export(exports_helpers, {
|
|
|
11476
11574
|
detectGitRoot: () => detectGitRoot,
|
|
11477
11575
|
cacheCloudTaskForIdResolution: () => cacheCloudTaskForIdResolution,
|
|
11478
11576
|
autoProject: () => autoProject,
|
|
11479
|
-
autoDetectProject: () => autoDetectProject
|
|
11577
|
+
autoDetectProject: () => autoDetectProject,
|
|
11578
|
+
TASK_STATUS_FLAG_HINTS: () => TASK_STATUS_FLAG_HINTS,
|
|
11579
|
+
TASK_STATUS_FLAG: () => TASK_STATUS_FLAG,
|
|
11580
|
+
TASK_PRIORITY_FLAG: () => TASK_PRIORITY_FLAG
|
|
11480
11581
|
});
|
|
11481
11582
|
import chalk from "chalk";
|
|
11482
11583
|
import { execSync } from "child_process";
|
|
@@ -11486,8 +11587,19 @@ import { dirname as dirname3, join as join4, resolve as resolve3, sep } from "pa
|
|
|
11486
11587
|
function jsonModeRequested(argv = process.argv) {
|
|
11487
11588
|
return argv.some((arg) => arg === "--json" || /^-[a-z]+$/i.test(arg) && arg.includes("j"));
|
|
11488
11589
|
}
|
|
11590
|
+
function remoteErrorDetail(e) {
|
|
11591
|
+
if (!e || typeof e !== "object")
|
|
11592
|
+
return null;
|
|
11593
|
+
const body = e.body;
|
|
11594
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
11595
|
+
return null;
|
|
11596
|
+
const detail = body.error;
|
|
11597
|
+
return typeof detail === "string" && detail.trim() ? detail.trim() : null;
|
|
11598
|
+
}
|
|
11489
11599
|
function handleError(e) {
|
|
11490
|
-
const
|
|
11600
|
+
const baseMessage = e instanceof Error ? e.message : String(e);
|
|
11601
|
+
const detail = remoteErrorDetail(e);
|
|
11602
|
+
const message = detail && !baseMessage.includes(detail) ? `${baseMessage}: ${detail}` : baseMessage;
|
|
11491
11603
|
console.error(chalk.red(message));
|
|
11492
11604
|
if (jsonModeRequested()) {
|
|
11493
11605
|
console.log(JSON.stringify({ error: message }));
|
|
@@ -11665,7 +11777,8 @@ function autoProject(opts) {
|
|
|
11665
11777
|
return autoDetectProject(opts)?.id;
|
|
11666
11778
|
}
|
|
11667
11779
|
function normalizeStatus(s) {
|
|
11668
|
-
|
|
11780
|
+
const folded = s.toLowerCase().trim();
|
|
11781
|
+
switch (folded) {
|
|
11669
11782
|
case "done":
|
|
11670
11783
|
return "completed";
|
|
11671
11784
|
case "complete":
|
|
@@ -11679,14 +11792,33 @@ function normalizeStatus(s) {
|
|
|
11679
11792
|
case "canceled":
|
|
11680
11793
|
return "cancelled";
|
|
11681
11794
|
default:
|
|
11682
|
-
return
|
|
11795
|
+
return folded;
|
|
11683
11796
|
}
|
|
11684
11797
|
}
|
|
11798
|
+
function normalizePriority(p) {
|
|
11799
|
+
return p.toLowerCase().trim();
|
|
11800
|
+
}
|
|
11685
11801
|
function normalizeStatusList(statuses) {
|
|
11686
11802
|
if (Array.isArray(statuses))
|
|
11687
11803
|
return statuses.map(normalizeStatus);
|
|
11688
11804
|
return normalizeStatus(statuses);
|
|
11689
11805
|
}
|
|
11806
|
+
function parseEnumFlag(raw, spec) {
|
|
11807
|
+
if (raw === undefined || raw === null)
|
|
11808
|
+
return;
|
|
11809
|
+
const result = resolveEnumVocabulary(String(raw), spec);
|
|
11810
|
+
if (!result.ok)
|
|
11811
|
+
handleError(new Error(result.message));
|
|
11812
|
+
return collapseEnumValues(result.values);
|
|
11813
|
+
}
|
|
11814
|
+
function parseEnumFlagList(raw, spec) {
|
|
11815
|
+
if (raw === undefined || raw === null)
|
|
11816
|
+
return;
|
|
11817
|
+
const result = resolveEnumVocabulary(String(raw), spec);
|
|
11818
|
+
if (!result.ok)
|
|
11819
|
+
handleError(new Error(result.message));
|
|
11820
|
+
return result.values;
|
|
11821
|
+
}
|
|
11690
11822
|
function writeStdoutSync(text) {
|
|
11691
11823
|
const buffer = Buffer.from(text);
|
|
11692
11824
|
let offset = 0;
|
|
@@ -11718,6 +11850,41 @@ function output(data, jsonMode) {
|
|
|
11718
11850
|
printJson(data);
|
|
11719
11851
|
}
|
|
11720
11852
|
}
|
|
11853
|
+
function formatRecordLines(data) {
|
|
11854
|
+
if (data === null || data === undefined)
|
|
11855
|
+
return [];
|
|
11856
|
+
if (typeof data !== "object")
|
|
11857
|
+
return [String(data)];
|
|
11858
|
+
if (Array.isArray(data)) {
|
|
11859
|
+
return data.flatMap((entry, index) => [
|
|
11860
|
+
chalk.dim(`[${index}]`),
|
|
11861
|
+
...formatRecordLines(entry).map((line) => ` ${line}`)
|
|
11862
|
+
]);
|
|
11863
|
+
}
|
|
11864
|
+
const lines = [];
|
|
11865
|
+
for (const [key, value] of Object.entries(data)) {
|
|
11866
|
+
if (value === undefined)
|
|
11867
|
+
continue;
|
|
11868
|
+
const rendered = value === null ? chalk.dim("\u2014") : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
11869
|
+
lines.push(` ${chalk.dim(`${key}:`)} ${rendered}`);
|
|
11870
|
+
}
|
|
11871
|
+
return lines;
|
|
11872
|
+
}
|
|
11873
|
+
function outputRecord(data, jsonMode, heading) {
|
|
11874
|
+
if (jsonMode) {
|
|
11875
|
+
printJson(data);
|
|
11876
|
+
return;
|
|
11877
|
+
}
|
|
11878
|
+
if (heading)
|
|
11879
|
+
console.log(chalk.bold(heading));
|
|
11880
|
+
const lines = formatRecordLines(data);
|
|
11881
|
+
if (lines.length === 0) {
|
|
11882
|
+
console.log(chalk.dim("(empty)"));
|
|
11883
|
+
return;
|
|
11884
|
+
}
|
|
11885
|
+
for (const line of lines)
|
|
11886
|
+
console.log(line);
|
|
11887
|
+
}
|
|
11721
11888
|
function formatTaskLine(t) {
|
|
11722
11889
|
const statusFn = statusColors[t.status] || chalk.white;
|
|
11723
11890
|
const priorityFn = priorityColors[t.priority] || chalk.white;
|
|
@@ -11728,16 +11895,33 @@ function formatTaskLine(t) {
|
|
|
11728
11895
|
const plan = t.plan_id ? chalk.magenta(` [plan:${t.plan_id.slice(0, 8)}]`) : "";
|
|
11729
11896
|
return `${chalk.dim(t.id.slice(0, 8))} ${statusFn(t.status.padEnd(11))} ${priorityFn(t.priority.padEnd(8))} ${t.title}${assigned}${lock}${tags}${plan}`;
|
|
11730
11897
|
}
|
|
11731
|
-
var stdoutRetryBuffer, stdoutRetrySignal, TASK_UUID_RE, statusColors, priorityColors;
|
|
11898
|
+
var stdoutRetryBuffer, stdoutRetrySignal, TASK_UUID_RE, TASK_STATUS_FLAG_HINTS, TASK_STATUS_FLAG, TASK_PRIORITY_FLAG, statusColors, priorityColors;
|
|
11732
11899
|
var init_helpers = __esm(() => {
|
|
11733
11900
|
init_cloud_router();
|
|
11734
11901
|
init_database();
|
|
11735
11902
|
init_projects();
|
|
11736
11903
|
init_lock_display();
|
|
11737
11904
|
init_package_version();
|
|
11905
|
+
init_types();
|
|
11738
11906
|
stdoutRetryBuffer = new SharedArrayBuffer(4);
|
|
11739
11907
|
stdoutRetrySignal = new Int32Array(stdoutRetryBuffer);
|
|
11740
11908
|
TASK_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11909
|
+
TASK_STATUS_FLAG_HINTS = {
|
|
11910
|
+
all: "To include every status, use -a/--all instead of a --status value.",
|
|
11911
|
+
any: "To include every status, use -a/--all instead of a --status value.",
|
|
11912
|
+
open: "Unstarted and running work is pending and in_progress (the default when no --status is given)."
|
|
11913
|
+
};
|
|
11914
|
+
TASK_STATUS_FLAG = {
|
|
11915
|
+
name: "--status",
|
|
11916
|
+
vocabulary: TASK_STATUSES,
|
|
11917
|
+
normalize: normalizeStatus,
|
|
11918
|
+
hints: TASK_STATUS_FLAG_HINTS
|
|
11919
|
+
};
|
|
11920
|
+
TASK_PRIORITY_FLAG = {
|
|
11921
|
+
name: "--priority",
|
|
11922
|
+
vocabulary: TASK_PRIORITIES,
|
|
11923
|
+
normalize: normalizePriority
|
|
11924
|
+
};
|
|
11741
11925
|
statusColors = {
|
|
11742
11926
|
pending: chalk.yellow,
|
|
11743
11927
|
in_progress: chalk.blue,
|
|
@@ -15960,11 +16144,13 @@ function updateTask(id, input, db) {
|
|
|
15960
16144
|
}
|
|
15961
16145
|
sets.push("status = ?");
|
|
15962
16146
|
params.push(input.status);
|
|
16147
|
+
if (isTerminalStatus(input.status)) {
|
|
16148
|
+
sets.push("locked_by = NULL");
|
|
16149
|
+
sets.push("locked_at = NULL");
|
|
16150
|
+
}
|
|
15963
16151
|
if (input.status === "completed") {
|
|
15964
16152
|
sets.push("completed_at = ?");
|
|
15965
16153
|
params.push(completionTimestamp);
|
|
15966
|
-
sets.push("locked_by = NULL");
|
|
15967
|
-
sets.push("locked_at = NULL");
|
|
15968
16154
|
} else if (task.status === "completed" && input.completed_at === undefined) {
|
|
15969
16155
|
sets.push("completed_at = NULL");
|
|
15970
16156
|
}
|
|
@@ -16088,6 +16274,7 @@ function updateTask(id, input, db) {
|
|
|
16088
16274
|
logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
|
|
16089
16275
|
const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
|
|
16090
16276
|
const completedNow = input.status === "completed";
|
|
16277
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
16091
16278
|
const updatedTask = {
|
|
16092
16279
|
...task,
|
|
16093
16280
|
...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
|
|
@@ -16095,8 +16282,8 @@ function updateTask(id, input, db) {
|
|
|
16095
16282
|
metadata: input.metadata ?? task.metadata,
|
|
16096
16283
|
version: task.version + 1,
|
|
16097
16284
|
updated_at: timestamp2,
|
|
16098
|
-
locked_by:
|
|
16099
|
-
locked_at:
|
|
16285
|
+
locked_by: terminalNow ? null : task.locked_by,
|
|
16286
|
+
locked_at: terminalNow ? null : task.locked_at,
|
|
16100
16287
|
completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
|
|
16101
16288
|
sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
|
|
16102
16289
|
actual_minutes: input.actual_minutes ?? task.actual_minutes,
|
|
@@ -20214,11 +20401,7 @@ function resolveProjectIdOrSlug(input) {
|
|
|
20214
20401
|
function parseStatus(value) {
|
|
20215
20402
|
if (!value)
|
|
20216
20403
|
return;
|
|
20217
|
-
|
|
20218
|
-
if (!TASK_STATUSES.includes(normalized)) {
|
|
20219
|
-
handleError(new Error(`--status must be one of: ${TASK_STATUSES.join(", ")}`));
|
|
20220
|
-
}
|
|
20221
|
-
return normalized;
|
|
20404
|
+
return parseEnumFlagList(value, { ...TASK_STATUS_FLAG, allowList: false })?.[0];
|
|
20222
20405
|
}
|
|
20223
20406
|
function parseIntOption(value, flag) {
|
|
20224
20407
|
if (value === undefined)
|
|
@@ -20243,10 +20426,7 @@ function resolvePlanId(input) {
|
|
|
20243
20426
|
function parsePriority(value) {
|
|
20244
20427
|
if (!value)
|
|
20245
20428
|
return;
|
|
20246
|
-
|
|
20247
|
-
handleError(new Error("--priority must be one of: low, medium, high, critical"));
|
|
20248
|
-
}
|
|
20249
|
-
return value;
|
|
20429
|
+
return parseEnumFlagList(value, { ...TASK_PRIORITY_FLAG, allowList: false })?.[0];
|
|
20250
20430
|
}
|
|
20251
20431
|
function parseJsonObject3(value, flag) {
|
|
20252
20432
|
if (!value)
|
|
@@ -20631,12 +20811,12 @@ function registerTaskCommands(program2) {
|
|
|
20631
20811
|
filter["task_list_id"] = listId;
|
|
20632
20812
|
}
|
|
20633
20813
|
if (opts.status) {
|
|
20634
|
-
filter["status"] =
|
|
20814
|
+
filter["status"] = parseEnumFlag(opts.status, TASK_STATUS_FLAG);
|
|
20635
20815
|
} else if (!opts.all) {
|
|
20636
20816
|
filter["status"] = ["pending", "in_progress"];
|
|
20637
20817
|
}
|
|
20638
20818
|
if (opts.priority)
|
|
20639
|
-
filter["priority"] = opts.priority;
|
|
20819
|
+
filter["priority"] = parseEnumFlag(opts.priority, TASK_PRIORITY_FLAG);
|
|
20640
20820
|
if (opts.assigned)
|
|
20641
20821
|
filter["assigned_to"] = opts.assigned;
|
|
20642
20822
|
if (opts.createdBy)
|
|
@@ -21609,7 +21789,6 @@ var init_task_commands = __esm(() => {
|
|
|
21609
21789
|
init_assignee_guard();
|
|
21610
21790
|
init_helpers();
|
|
21611
21791
|
init_output_redaction();
|
|
21612
|
-
init_types();
|
|
21613
21792
|
});
|
|
21614
21793
|
|
|
21615
21794
|
// src/lib/plan-artifacts.ts
|
|
@@ -23441,7 +23620,8 @@ __export(exports_saved_search_views, {
|
|
|
23441
23620
|
normalizeScope: () => normalizeScope,
|
|
23442
23621
|
listSearchViews: () => listSearchViews,
|
|
23443
23622
|
getSearchView: () => getSearchView,
|
|
23444
|
-
deleteSearchView: () => deleteSearchView
|
|
23623
|
+
deleteSearchView: () => deleteSearchView,
|
|
23624
|
+
SAVED_SEARCH_SCOPES: () => SAVED_SEARCH_SCOPES
|
|
23445
23625
|
});
|
|
23446
23626
|
function parseFilters(value) {
|
|
23447
23627
|
if (!value)
|
|
@@ -23461,10 +23641,8 @@ function rowToSavedSearchView(row) {
|
|
|
23461
23641
|
};
|
|
23462
23642
|
}
|
|
23463
23643
|
function normalizeScope(scope) {
|
|
23464
|
-
|
|
23465
|
-
|
|
23466
|
-
}
|
|
23467
|
-
return "tasks";
|
|
23644
|
+
const candidate = (scope ?? "").trim().toLowerCase();
|
|
23645
|
+
return SAVED_SEARCH_SCOPES.includes(candidate) ? candidate : "tasks";
|
|
23468
23646
|
}
|
|
23469
23647
|
function normalizeName(name) {
|
|
23470
23648
|
const normalized = name.trim();
|
|
@@ -23767,10 +23945,12 @@ function runSearchView(idOrName, db) {
|
|
|
23767
23945
|
throw new Error(`Saved search view not found: ${idOrName}`);
|
|
23768
23946
|
return { ...runSavedSearch(view.filters, view.scope, d), view };
|
|
23769
23947
|
}
|
|
23948
|
+
var SAVED_SEARCH_SCOPES;
|
|
23770
23949
|
var init_saved_search_views = __esm(() => {
|
|
23771
23950
|
init_database();
|
|
23772
23951
|
init_local_fields();
|
|
23773
23952
|
init_search();
|
|
23953
|
+
SAVED_SEARCH_SCOPES = ["all", "tasks", "projects", "plans", "runs", "comments"];
|
|
23774
23954
|
});
|
|
23775
23955
|
|
|
23776
23956
|
// src/lib/claude-tasks.ts
|
|
@@ -26340,12 +26520,11 @@ function buildSearchFilters(query, opts, projectId) {
|
|
|
26340
26520
|
const customFields = parseJsonObjectOption(opts.fieldCustom, "--field-custom");
|
|
26341
26521
|
const labels = splitList(opts.fieldLabel);
|
|
26342
26522
|
const tags = splitList(opts.tag);
|
|
26343
|
-
const statuses = splitList(opts.status)?.map(normalizeStatus);
|
|
26344
26523
|
const filters = {
|
|
26345
26524
|
query: query || opts.query,
|
|
26346
26525
|
project_id: opts.allProjects ? undefined : projectId,
|
|
26347
|
-
status:
|
|
26348
|
-
priority:
|
|
26526
|
+
status: parseEnumFlagList(opts.status, TASK_STATUS_FLAG),
|
|
26527
|
+
priority: parseEnumFlagList(opts.priority, TASK_PRIORITY_FLAG),
|
|
26349
26528
|
assigned_to: opts.assigned,
|
|
26350
26529
|
agent_id: opts.agentId,
|
|
26351
26530
|
task_list_id: filterPatch?.task_list_id === undefined ? resolveTaskListFilter(opts.taskList, projectId) : undefined,
|
|
@@ -26450,7 +26629,7 @@ function registerProjectCommands(program2) {
|
|
|
26450
26629
|
try {
|
|
26451
26630
|
const cloud = getTodosCloudClient();
|
|
26452
26631
|
const projectId = opts.allProjects ? undefined : cloud ? undefined : autoProject(globalOpts);
|
|
26453
|
-
const scope =
|
|
26632
|
+
const scope = parseEnumFlag(opts.scope, SEARCH_SCOPE_FLAG) ?? "tasks";
|
|
26454
26633
|
const searchOpts = buildSearchFilters(query, opts, projectId);
|
|
26455
26634
|
if (opts.saveAs) {
|
|
26456
26635
|
const view = saveSearchView({
|
|
@@ -26542,7 +26721,7 @@ function registerProjectCommands(program2) {
|
|
|
26542
26721
|
const view = saveSearchView({
|
|
26543
26722
|
name,
|
|
26544
26723
|
description: opts.description,
|
|
26545
|
-
scope:
|
|
26724
|
+
scope: parseEnumFlag(opts.scope, SEARCH_SCOPE_FLAG) ?? "tasks",
|
|
26546
26725
|
filters: buildSearchFilters(opts.query, opts, projectId)
|
|
26547
26726
|
});
|
|
26548
26727
|
output(view, Boolean(globalOpts.json));
|
|
@@ -26555,7 +26734,7 @@ function registerProjectCommands(program2) {
|
|
|
26555
26734
|
views.command("list").description("List local saved search views").option("--scope <scope>", "Filter by scope").action((opts) => {
|
|
26556
26735
|
const globalOpts = program2.opts();
|
|
26557
26736
|
try {
|
|
26558
|
-
const rows = listSearchViews(
|
|
26737
|
+
const rows = listSearchViews(parseEnumFlag(opts.scope, SEARCH_SCOPE_FLAG));
|
|
26559
26738
|
output(rows, Boolean(globalOpts.json));
|
|
26560
26739
|
if (!globalOpts.json) {
|
|
26561
26740
|
if (rows.length === 0) {
|
|
@@ -26751,7 +26930,7 @@ function registerProjectCommands(program2) {
|
|
|
26751
26930
|
const cloud = getTodosCloudClient();
|
|
26752
26931
|
if (opts.show) {
|
|
26753
26932
|
const project = cloud ? await cloudResolveProject(cloud, opts.show) : resolveExplicitProject(opts.show);
|
|
26754
|
-
|
|
26933
|
+
outputRecord(project, Boolean(globalOpts.json), "Project:");
|
|
26755
26934
|
return;
|
|
26756
26935
|
}
|
|
26757
26936
|
if (opts.update) {
|
|
@@ -26765,7 +26944,7 @@ function registerProjectCommands(program2) {
|
|
|
26765
26944
|
}
|
|
26766
26945
|
const current = cloud ? await cloudResolveProject(cloud, opts.update) : resolveExplicitProject(opts.update);
|
|
26767
26946
|
const project = cloud ? await cloudUpdateProject(cloud, current.id, patch) : updateProject(current.id, patch);
|
|
26768
|
-
|
|
26947
|
+
outputRecord(project, Boolean(globalOpts.json), "Project updated:");
|
|
26769
26948
|
return;
|
|
26770
26949
|
}
|
|
26771
26950
|
if (opts.deregister) {
|
|
@@ -27073,6 +27252,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
27073
27252
|
program2.command("export").description("Export tasks").option("-f, --format <format>", "Format: json, md, todos.md, or bridge", "json").option("-o, --output <path>", "Write export output to a file").option("--encrypt", "Encrypt bridge exports with a local encryption profile").option("--encryption-profile <name>", "Encryption profile name", "default").option("--allow-plaintext-sensitive", "Deprecated; bridge exports are redacted unless --encrypt is used").action(async (opts) => {
|
|
27074
27253
|
const { listTasks: listTasks2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
|
|
27075
27254
|
const globalOpts = program2.opts();
|
|
27255
|
+
opts.format = parseEnumFlag(opts.format, EXPORT_FORMAT_FLAG) ?? "json";
|
|
27076
27256
|
const projectId = autoProject(globalOpts);
|
|
27077
27257
|
const writeOutput = async (content) => {
|
|
27078
27258
|
if (opts.output) {
|
|
@@ -27234,7 +27414,7 @@ function resolveTaskListId(partialId) {
|
|
|
27234
27414
|
}
|
|
27235
27415
|
return id;
|
|
27236
27416
|
}
|
|
27237
|
-
var CLOUD_GRAPH_EDGE_CONCURRENCY = 6;
|
|
27417
|
+
var SEARCH_SCOPE_FLAG, EXPORT_FORMATS, EXPORT_FORMAT_FLAG, CLOUD_GRAPH_EDGE_CONCURRENCY = 6;
|
|
27238
27418
|
var init_project_commands = __esm(() => {
|
|
27239
27419
|
init_database();
|
|
27240
27420
|
init_projects();
|
|
@@ -27246,12 +27426,26 @@ var init_project_commands = __esm(() => {
|
|
|
27246
27426
|
init_config();
|
|
27247
27427
|
init_helpers();
|
|
27248
27428
|
init_output_redaction();
|
|
27429
|
+
SEARCH_SCOPE_FLAG = {
|
|
27430
|
+
name: "--scope",
|
|
27431
|
+
vocabulary: SAVED_SEARCH_SCOPES,
|
|
27432
|
+
normalize: (value) => value.toLowerCase().trim(),
|
|
27433
|
+
allowList: false
|
|
27434
|
+
};
|
|
27435
|
+
EXPORT_FORMATS = ["json", "md", "markdown", "todos.md", "todos-md", "bridge"];
|
|
27436
|
+
EXPORT_FORMAT_FLAG = {
|
|
27437
|
+
name: "--format",
|
|
27438
|
+
vocabulary: EXPORT_FORMATS,
|
|
27439
|
+
normalize: (value) => value.toLowerCase().trim(),
|
|
27440
|
+
allowList: false
|
|
27441
|
+
};
|
|
27249
27442
|
});
|
|
27250
27443
|
|
|
27251
27444
|
// src/cli/commands/agent-commands.ts
|
|
27252
27445
|
var exports_agent_commands = {};
|
|
27253
27446
|
__export(exports_agent_commands, {
|
|
27254
|
-
registerAgentCommands: () => registerAgentCommands
|
|
27447
|
+
registerAgentCommands: () => registerAgentCommands,
|
|
27448
|
+
findCaseVariantRows: () => findCaseVariantRows
|
|
27255
27449
|
});
|
|
27256
27450
|
import chalk6 from "chalk";
|
|
27257
27451
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -27265,6 +27459,15 @@ function resolveCloudAgentByNameOrId(agents, nameOrId) {
|
|
|
27265
27459
|
return null;
|
|
27266
27460
|
return matches.reduce((freshest, candidate) => new Date(candidate.last_seen_at).getTime() > new Date(freshest.last_seen_at).getTime() ? candidate : freshest);
|
|
27267
27461
|
}
|
|
27462
|
+
function findCaseVariantRows(agents, requested) {
|
|
27463
|
+
const raw = requested.trim();
|
|
27464
|
+
const target = normalizeAgentNameInput(raw);
|
|
27465
|
+
if (!target)
|
|
27466
|
+
return [];
|
|
27467
|
+
if (agents.some((agent) => agent.name === raw))
|
|
27468
|
+
return [];
|
|
27469
|
+
return agents.filter((agent) => normalizeAgentNameInput(agent.name) === target);
|
|
27470
|
+
}
|
|
27268
27471
|
function clearIdentityIfMine(agentId, agentName) {
|
|
27269
27472
|
const persisted = readPersistedIdentity();
|
|
27270
27473
|
if (!persisted)
|
|
@@ -27278,7 +27481,22 @@ function registerAgentCommands(program2) {
|
|
|
27278
27481
|
const globalOpts = program2.opts();
|
|
27279
27482
|
try {
|
|
27280
27483
|
const cloud = getTodosCloudClient();
|
|
27281
|
-
const
|
|
27484
|
+
const registrationName = name.trim();
|
|
27485
|
+
if (cloud) {
|
|
27486
|
+
let roster = null;
|
|
27487
|
+
try {
|
|
27488
|
+
roster = await cloudListAgents(cloud);
|
|
27489
|
+
} catch {
|
|
27490
|
+
console.error(chalk6.yellow("Warning: could not read the shared roster, so the case-variant check was skipped for this registration."));
|
|
27491
|
+
}
|
|
27492
|
+
const variants = roster ? findCaseVariantRows(roster, registrationName) : [];
|
|
27493
|
+
if (variants.length > 0) {
|
|
27494
|
+
const listed = variants.map((a) => `${a.name} (${a.id})`).join(", ");
|
|
27495
|
+
console.error(chalk6.red(`'${name}' is a case variant of an agent that already exists: ${listed}. ` + `Agent names are ONE case-insensitive identity, so registering this spelling would create a second row ` + `and split the identity in two \u2014 tasks assigned to one spelling are invisible to the other. ` + `Register with the existing spelling instead.`));
|
|
27496
|
+
process.exit(1);
|
|
27497
|
+
}
|
|
27498
|
+
}
|
|
27499
|
+
const result = cloud ? await cloudRegisterAgent(cloud, { name: registrationName, description: opts.description }) : (await Promise.resolve().then(() => (init_agents(), exports_agents))).registerAgent({ name: registrationName, description: opts.description });
|
|
27282
27500
|
const { isAgentConflict: isAgentConflict2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
27283
27501
|
if (isAgentConflict2(result)) {
|
|
27284
27502
|
console.error(chalk6.red("CONFLICT:"), result.message);
|
|
@@ -27623,7 +27841,7 @@ ${isOnline ? chalk6.green("\u25CF") : chalk6.dim("\u25CB")} ${chalk6.bold(agent.
|
|
|
27623
27841
|
const list2 = cloud ? await cloudGetTaskList(cloud, resolved) : getTaskList(resolved);
|
|
27624
27842
|
if (!list2)
|
|
27625
27843
|
throw new Error(`Task list not found: ${ref}`);
|
|
27626
|
-
|
|
27844
|
+
outputRecord(list2, Boolean(globalOpts.json), "Task list:");
|
|
27627
27845
|
return;
|
|
27628
27846
|
}
|
|
27629
27847
|
const patch = {
|
|
@@ -27634,7 +27852,7 @@ ${isOnline ? chalk6.green("\u25CF") : chalk6.dim("\u25CB")} ${chalk6.bold(agent.
|
|
|
27634
27852
|
if (Object.keys(patch).length === 0)
|
|
27635
27853
|
throw new Error("lists --update requires --name, --slug, or --description");
|
|
27636
27854
|
const list = cloud ? await cloudUpdateTaskList(cloud, resolved, patch) : updateTaskList(resolved, patch);
|
|
27637
|
-
|
|
27855
|
+
outputRecord(list, Boolean(globalOpts.json), "Task list updated:");
|
|
27638
27856
|
return;
|
|
27639
27857
|
}
|
|
27640
27858
|
if (opts.delete) {
|
|
@@ -32185,9 +32403,11 @@ async function updateTask2(id, input, store) {
|
|
|
32185
32403
|
throw new Error(`Task ${id} version conflict: expected ${existing.version}, got ${input.version}`);
|
|
32186
32404
|
}
|
|
32187
32405
|
const reopened = existing.status === "completed" && input.status !== undefined && input.status !== "completed" && input.completed_at === undefined;
|
|
32406
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
32188
32407
|
const task = {
|
|
32189
32408
|
...existing,
|
|
32190
32409
|
...definedPatch(input),
|
|
32410
|
+
...terminalNow ? { locked_by: null, locked_at: null } : {},
|
|
32191
32411
|
version: existing.version + 1,
|
|
32192
32412
|
updated_at: new Date().toISOString(),
|
|
32193
32413
|
tags: input.tags ?? existing.tags,
|
|
@@ -34528,8 +34748,19 @@ function handleStats(_ctx, json2) {
|
|
|
34528
34748
|
recurring_tasks: countRecurringTasks()
|
|
34529
34749
|
});
|
|
34530
34750
|
}
|
|
34751
|
+
function taskStatusQueryParam(url) {
|
|
34752
|
+
const raw = url.searchParams.get("status");
|
|
34753
|
+
if (!raw)
|
|
34754
|
+
return { ok: true, value: undefined };
|
|
34755
|
+
const result = resolveEnumVocabulary(raw, { name: "status", vocabulary: TASK_STATUSES });
|
|
34756
|
+
if (!result.ok)
|
|
34757
|
+
return { ok: false, message: result.message };
|
|
34758
|
+
return { ok: true, value: collapseEnumValues(result.values) };
|
|
34759
|
+
}
|
|
34531
34760
|
async function handleListTasks(_req, url, _ctx, json2, taskToSummary2) {
|
|
34532
|
-
const
|
|
34761
|
+
const statusParam = taskStatusQueryParam(url);
|
|
34762
|
+
if (!statusParam.ok)
|
|
34763
|
+
return json2({ error: statusParam.message }, 400);
|
|
34533
34764
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
34534
34765
|
const sessionId = url.searchParams.get("session_id") || undefined;
|
|
34535
34766
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
@@ -34537,7 +34768,7 @@ async function handleListTasks(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
34537
34768
|
const offsetParam = url.searchParams.get("offset");
|
|
34538
34769
|
const fields = parseFieldsParam(url);
|
|
34539
34770
|
const tasks = listTasks({
|
|
34540
|
-
status,
|
|
34771
|
+
status: statusParam.value,
|
|
34541
34772
|
project_id: projectId,
|
|
34542
34773
|
session_id: sessionId,
|
|
34543
34774
|
agent_id: agentId,
|
|
@@ -34602,9 +34833,19 @@ async function handleUpsertTask(req, ctx, json2, taskToSummary2) {
|
|
|
34602
34833
|
}
|
|
34603
34834
|
function handleTasksExport(_req, url, _ctx, _json, taskToSummary2) {
|
|
34604
34835
|
const format = url.searchParams.get("format") || "json";
|
|
34605
|
-
const
|
|
34836
|
+
const statusParam = taskStatusQueryParam(url);
|
|
34837
|
+
if (!statusParam.ok) {
|
|
34838
|
+
return new Response(JSON.stringify({ error: statusParam.message }), {
|
|
34839
|
+
status: 400,
|
|
34840
|
+
headers: { "Content-Type": "application/json" }
|
|
34841
|
+
});
|
|
34842
|
+
}
|
|
34606
34843
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
34607
|
-
const tasks = listTasks({
|
|
34844
|
+
const tasks = listTasks({
|
|
34845
|
+
status: statusParam.value,
|
|
34846
|
+
project_id: projectId,
|
|
34847
|
+
limit: 1e4
|
|
34848
|
+
});
|
|
34608
34849
|
const summaries = tasks.map((t) => taskToSummary2(t));
|
|
34609
34850
|
if (format === "csv") {
|
|
34610
34851
|
const headers = ["id", "short_id", "title", "status", "priority", "project_id", "assigned_to", "agent_id", "created_at", "updated_at", "completed_at", "due_at"];
|
|
@@ -35186,6 +35427,7 @@ var init_routes = __esm(() => {
|
|
|
35186
35427
|
init_tasks();
|
|
35187
35428
|
init_database();
|
|
35188
35429
|
init_types();
|
|
35430
|
+
init_types();
|
|
35189
35431
|
init_projects();
|
|
35190
35432
|
init_agents();
|
|
35191
35433
|
init_plans();
|
|
@@ -37070,8 +37312,38 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
|
|
|
37070
37312
|
operationId: "listTasks",
|
|
37071
37313
|
summary: "List tasks",
|
|
37072
37314
|
parameters: [
|
|
37073
|
-
{
|
|
37074
|
-
|
|
37315
|
+
{
|
|
37316
|
+
name: "status",
|
|
37317
|
+
in: "query",
|
|
37318
|
+
description: `Task status, or a comma-separated list of statuses. Allowed values: ${TASK_STATUSES.join(", ")}.`,
|
|
37319
|
+
style: "form",
|
|
37320
|
+
explode: false,
|
|
37321
|
+
schema: {
|
|
37322
|
+
oneOf: [
|
|
37323
|
+
{ type: "string", enum: [...TASK_STATUSES] },
|
|
37324
|
+
{
|
|
37325
|
+
type: "array",
|
|
37326
|
+
items: { type: "string", enum: [...TASK_STATUSES] }
|
|
37327
|
+
}
|
|
37328
|
+
]
|
|
37329
|
+
}
|
|
37330
|
+
},
|
|
37331
|
+
{
|
|
37332
|
+
name: "priority",
|
|
37333
|
+
in: "query",
|
|
37334
|
+
description: `Task priority, or a comma-separated list of priorities. Allowed values: ${TASK_PRIORITIES.join(", ")}.`,
|
|
37335
|
+
style: "form",
|
|
37336
|
+
explode: false,
|
|
37337
|
+
schema: {
|
|
37338
|
+
oneOf: [
|
|
37339
|
+
{ type: "string", enum: [...TASK_PRIORITIES] },
|
|
37340
|
+
{
|
|
37341
|
+
type: "array",
|
|
37342
|
+
items: { type: "string", enum: [...TASK_PRIORITIES] }
|
|
37343
|
+
}
|
|
37344
|
+
]
|
|
37345
|
+
}
|
|
37346
|
+
},
|
|
37075
37347
|
{ name: "project_id", in: "query", schema: { type: "string" } },
|
|
37076
37348
|
{ name: "parent_id", in: "query", schema: { type: "string", nullable: true } },
|
|
37077
37349
|
{ name: "include_subtasks", in: "query", schema: { type: "boolean" } },
|
|
@@ -37583,6 +37855,7 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
|
|
|
37583
37855
|
var taskSchema, projectSchema, taskListSchema, taskCommentSchema, planSchema, templateTaskSchema, templateSchema, templateVariableSchema, createTemplateTaskInputSchema;
|
|
37584
37856
|
var init_openapi = __esm(() => {
|
|
37585
37857
|
init_package_version();
|
|
37858
|
+
init_types();
|
|
37586
37859
|
taskSchema = {
|
|
37587
37860
|
type: "object",
|
|
37588
37861
|
properties: {
|
|
@@ -37850,6 +38123,15 @@ function json3(body, status = 200) {
|
|
|
37850
38123
|
function error(status, message, extra) {
|
|
37851
38124
|
return json3({ error: message, ...extra ?? {} }, status);
|
|
37852
38125
|
}
|
|
38126
|
+
function enumQueryParam(url, name, vocabulary) {
|
|
38127
|
+
const raw = url.searchParams.get(name);
|
|
38128
|
+
if (raw === null || raw === "")
|
|
38129
|
+
return { ok: true, value: undefined };
|
|
38130
|
+
const result = resolveEnumVocabulary(raw, { name, vocabulary });
|
|
38131
|
+
if (!result.ok)
|
|
38132
|
+
return { ok: false, response: error(400, result.message) };
|
|
38133
|
+
return { ok: true, value: collapseEnumValues(result.values) };
|
|
38134
|
+
}
|
|
37853
38135
|
function validateTaskCompletion(value) {
|
|
37854
38136
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
37855
38137
|
return { ok: false, message: "completion body must be an object" };
|
|
@@ -38270,14 +38552,16 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
38270
38552
|
return error(400, "include_subtasks must be true or false");
|
|
38271
38553
|
}
|
|
38272
38554
|
const hasParentFilter = url.searchParams.has("parent_id");
|
|
38555
|
+
const statusParam = enumQueryParam(url, "status", TASK_STATUSES);
|
|
38556
|
+
if (!statusParam.ok)
|
|
38557
|
+
return statusParam.response;
|
|
38558
|
+
const priorityParam = enumQueryParam(url, "priority", TASK_PRIORITIES);
|
|
38559
|
+
if (!priorityParam.ok)
|
|
38560
|
+
return priorityParam.response;
|
|
38273
38561
|
const filter = {
|
|
38274
38562
|
...url.searchParams.get("q") ? { query: url.searchParams.get("q") } : {},
|
|
38275
|
-
...
|
|
38276
|
-
|
|
38277
|
-
} : {},
|
|
38278
|
-
...url.searchParams.get("priority") ? {
|
|
38279
|
-
priority: url.searchParams.get("priority").includes(",") ? url.searchParams.get("priority").split(",") : url.searchParams.get("priority")
|
|
38280
|
-
} : {},
|
|
38563
|
+
...statusParam.value !== undefined ? { status: statusParam.value } : {},
|
|
38564
|
+
...priorityParam.value !== undefined ? { priority: priorityParam.value } : {},
|
|
38281
38565
|
...url.searchParams.get("project_id") ? { project_id: url.searchParams.get("project_id") } : {},
|
|
38282
38566
|
...hasParentFilter ? { parent_id: url.searchParams.get("parent_id") || null, include_subtasks: true } : includeSubtasks !== null ? { include_subtasks: includeSubtasks === "true" } : {},
|
|
38283
38567
|
...url.searchParams.get("plan_id") ? { plan_id: url.searchParams.get("plan_id") } : {},
|
|
@@ -50421,10 +50705,23 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
50421
50705
|
return { content: [{ type: "text", text: "No active agents available for rebalancing." }] };
|
|
50422
50706
|
const activeTasks = listTasks4({ project_id: resolvedProjectId, status: ["pending", "in_progress"], limit: 1000 }, undefined);
|
|
50423
50707
|
const agentKeyByAlias = new Map;
|
|
50708
|
+
const ambiguousAgentAliases = new Set;
|
|
50709
|
+
const indexAgentAlias = (alias, agentId) => {
|
|
50710
|
+
const normalizedAlias2 = alias.toLowerCase();
|
|
50711
|
+
if (ambiguousAgentAliases.has(normalizedAlias2))
|
|
50712
|
+
return;
|
|
50713
|
+
const existingAgentId = agentKeyByAlias.get(normalizedAlias2);
|
|
50714
|
+
if (existingAgentId !== undefined && existingAgentId !== agentId) {
|
|
50715
|
+
agentKeyByAlias.delete(normalizedAlias2);
|
|
50716
|
+
ambiguousAgentAliases.add(normalizedAlias2);
|
|
50717
|
+
return;
|
|
50718
|
+
}
|
|
50719
|
+
agentKeyByAlias.set(normalizedAlias2, agentId);
|
|
50720
|
+
};
|
|
50424
50721
|
for (const agent of agents) {
|
|
50425
|
-
|
|
50722
|
+
indexAgentAlias(String(agent.id), agent.id);
|
|
50426
50723
|
if (agent.name)
|
|
50427
|
-
|
|
50724
|
+
indexAgentAlias(String(agent.name), agent.id);
|
|
50428
50725
|
}
|
|
50429
50726
|
const canonicalAgentKey = (assignedTo) => assignedTo ? agentKeyByAlias.get(assignedTo.toLowerCase()) : undefined;
|
|
50430
50727
|
const load = new Map(agents.map((agent) => [agent.id, activeTasks.filter((t) => canonicalAgentKey(t.assigned_to) === agent.id).length]));
|
|
@@ -61810,9 +62107,16 @@ ${text2}` }] };
|
|
|
61810
62107
|
return { content: [{ type: "text", text: `Agent not found: ${id || name}` }], isError: true };
|
|
61811
62108
|
}
|
|
61812
62109
|
const oldName = agent.name;
|
|
61813
|
-
const updated = updateAgent(agent.id, { name: new_name });
|
|
61814
62110
|
const db = getDatabase();
|
|
61815
|
-
|
|
62111
|
+
let oldNameUniquelyIdentifiesAgent = false;
|
|
62112
|
+
try {
|
|
62113
|
+
oldNameUniquelyIdentifiesAgent = resolvePartialId(db, "agents", oldName) === agent.id;
|
|
62114
|
+
} catch (error2) {
|
|
62115
|
+
if (!(error2 instanceof IdentityAliasAmbiguousError))
|
|
62116
|
+
throw error2;
|
|
62117
|
+
}
|
|
62118
|
+
const updated = updateAgent(agent.id, { name: new_name });
|
|
62119
|
+
const tasksResult = db.run(oldNameUniquelyIdentifiesAgent ? "UPDATE tasks SET assigned_to = ? WHERE LOWER(assigned_to) = LOWER(?)" : "UPDATE tasks SET assigned_to = ? WHERE assigned_to = ?", [new_name, oldName]);
|
|
61816
62120
|
const taskNote = tasksResult.changes > 0 ? `
|
|
61817
62121
|
Updated assigned_to on ${tasksResult.changes} task(s).` : "";
|
|
61818
62122
|
return {
|
|
@@ -61996,6 +62300,7 @@ var init_agents2 = __esm(() => {
|
|
|
61996
62300
|
init_agents();
|
|
61997
62301
|
init_config();
|
|
61998
62302
|
init_database();
|
|
62303
|
+
init_types();
|
|
61999
62304
|
init_cloud_router();
|
|
62000
62305
|
});
|
|
62001
62306
|
|
|
@@ -72161,7 +72466,11 @@ function registerDispatchCommands(program2) {
|
|
|
72161
72466
|
process.exit(1);
|
|
72162
72467
|
}
|
|
72163
72468
|
}
|
|
72164
|
-
const statuses = opts.status
|
|
72469
|
+
const statuses = parseEnumFlagList(opts.status, {
|
|
72470
|
+
name: "--status",
|
|
72471
|
+
vocabulary: DISPATCH_STATUSES,
|
|
72472
|
+
normalize: (value) => value.toLowerCase().trim()
|
|
72473
|
+
});
|
|
72165
72474
|
const dispatches = listDispatches({ status: statuses, limit: opts.limit ?? 20 });
|
|
72166
72475
|
if (useJson) {
|
|
72167
72476
|
console.log(JSON.stringify(dispatches, null, 2));
|
|
@@ -72194,6 +72503,8 @@ var init_dispatch3 = __esm(() => {
|
|
|
72194
72503
|
init_dispatch();
|
|
72195
72504
|
init_dispatch_formatter();
|
|
72196
72505
|
init_tmux();
|
|
72506
|
+
init_types();
|
|
72507
|
+
init_helpers();
|
|
72197
72508
|
});
|
|
72198
72509
|
|
|
72199
72510
|
// src/cli/commands/machines.tsx
|