@hasna/todos 0.14.0 → 0.15.1
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 +2 -0
- package/dist/cli/commands/config-serve-commands.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +258 -43
- package/dist/cli/stage-a.d.ts.map +1 -1
- package/dist/contracts.js +113 -112
- package/dist/db/database.d.ts.map +1 -1
- package/dist/index.js +120 -119
- package/dist/lib/bulk-tags.d.ts +57 -0
- package/dist/lib/bulk-tags.d.ts.map +1 -0
- package/dist/lib/enum-vocabulary.d.ts.map +1 -1
- package/dist/lib/run-records.d.ts.map +1 -1
- package/dist/lib/sandbox-profiles.d.ts.map +1 -1
- package/dist/lib/sync-utils.d.ts +1 -1
- package/dist/lib/sync-utils.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +75 -58
- package/dist/mcp/tools/task-crud.d.ts +1 -0
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +113 -112
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +3 -2
- package/dist/server/index.js +31 -14
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage.js +112 -111
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -741,6 +741,8 @@ todos update <task-id> --plan <plan-id> # move one task to another plan
|
|
|
741
741
|
todos update <task-id> --clear-plan # detach from its plan
|
|
742
742
|
todos bulk plan --plan <plan-id> <id> <id> # move many tasks at once
|
|
743
743
|
todos bulk move-plan --clear-plan <id> <id> # detach many tasks at once
|
|
744
|
+
todos bulk tag <id> <id> --tag a,b # add tags to many tasks (merges; never replaces)
|
|
745
|
+
todos bulk untag <id> <id> --tag a # remove tags from many tasks
|
|
744
746
|
todos plans --show <plan-id> # verify the plan's task set
|
|
745
747
|
```
|
|
746
748
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-serve-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/config-serve-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"config-serve-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/config-serve-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,QAo5C3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-hooks-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/mcp-hooks-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-hooks-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/mcp-hooks-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiPzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,QAitCxD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/task-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"task-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/task-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgEzC,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAmUD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAmxDpD"}
|
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.15.1",
|
|
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",
|
|
@@ -2444,11 +2444,30 @@ var init_types = __esm(() => {
|
|
|
2444
2444
|
});
|
|
2445
2445
|
|
|
2446
2446
|
// src/lib/sync-utils.ts
|
|
2447
|
+
var exports_sync_utils = {};
|
|
2448
|
+
__export(exports_sync_utils, {
|
|
2449
|
+
writeJsonFile: () => writeJsonFile,
|
|
2450
|
+
writeHighWaterMark: () => writeHighWaterMark,
|
|
2451
|
+
withSyncFingerprint: () => withSyncFingerprint,
|
|
2452
|
+
readJsonFile: () => readJsonFile,
|
|
2453
|
+
readHighWaterMark: () => readHighWaterMark,
|
|
2454
|
+
parseTimestamp: () => parseTimestamp,
|
|
2455
|
+
listJsonFiles: () => listJsonFiles,
|
|
2456
|
+
hasSyncFingerprintChanged: () => hasSyncFingerprintChanged,
|
|
2457
|
+
getTodosGlobalDir: () => getTodosGlobalDir,
|
|
2458
|
+
getHomeDir: () => getHomeDir,
|
|
2459
|
+
getFileMtimeMs: () => getFileMtimeMs,
|
|
2460
|
+
ensureDir: () => ensureDir,
|
|
2461
|
+
appendSyncConflict: () => appendSyncConflict,
|
|
2462
|
+
TODO_SYNC_FINGERPRINT_KEY: () => TODO_SYNC_FINGERPRINT_KEY,
|
|
2463
|
+
HOME: () => HOME
|
|
2464
|
+
});
|
|
2447
2465
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
2448
2466
|
import { createHash } from "crypto";
|
|
2467
|
+
import { homedir } from "os";
|
|
2449
2468
|
import { join } from "path";
|
|
2450
2469
|
function getHomeDir() {
|
|
2451
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
2470
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
2452
2471
|
}
|
|
2453
2472
|
function getTodosGlobalDir() {
|
|
2454
2473
|
return join(getHomeDir(), ".hasna", "todos");
|
|
@@ -2536,7 +2555,7 @@ function hasSyncFingerprintChanged(record) {
|
|
|
2536
2555
|
}
|
|
2537
2556
|
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
2538
2557
|
var init_sync_utils = __esm(() => {
|
|
2539
|
-
HOME =
|
|
2558
|
+
HOME = getHomeDir();
|
|
2540
2559
|
});
|
|
2541
2560
|
|
|
2542
2561
|
// src/lib/config.ts
|
|
@@ -6414,6 +6433,15 @@ function hasOption(args, option) {
|
|
|
6414
6433
|
function positionalArgs(args) {
|
|
6415
6434
|
return args.filter((arg) => !arg.startsWith("-"));
|
|
6416
6435
|
}
|
|
6436
|
+
function isBundledStaticInvocation(invocation) {
|
|
6437
|
+
const command = invocation.command;
|
|
6438
|
+
if (!command)
|
|
6439
|
+
return false;
|
|
6440
|
+
const storeBackedOptions = BUNDLED_STATIC_STORE_BACKED_OPTIONS.get(command);
|
|
6441
|
+
if (!storeBackedOptions)
|
|
6442
|
+
return false;
|
|
6443
|
+
return !storeBackedOptions.some((option) => hasOption(invocation.commandArgs, option));
|
|
6444
|
+
}
|
|
6417
6445
|
function isReadOnlyConfigInvocation(invocation) {
|
|
6418
6446
|
if (invocation.command !== "config")
|
|
6419
6447
|
return false;
|
|
@@ -6434,6 +6462,8 @@ function isMetadataInvocation(args, invocation) {
|
|
|
6434
6462
|
return true;
|
|
6435
6463
|
if (invocation.command === "manual" && invocation.commandArgs.length === 0)
|
|
6436
6464
|
return true;
|
|
6465
|
+
if (isBundledStaticInvocation(invocation))
|
|
6466
|
+
return true;
|
|
6437
6467
|
if (invocation.command === "help" && invocation.commandArgs.every((arg) => !arg.startsWith("-")))
|
|
6438
6468
|
return true;
|
|
6439
6469
|
if (invocation.command === "config") {
|
|
@@ -6451,6 +6481,14 @@ function firstPresentOption(args, candidates) {
|
|
|
6451
6481
|
function disqualifyingArgument(invocation) {
|
|
6452
6482
|
const command = invocation.command;
|
|
6453
6483
|
const args = invocation.commandArgs;
|
|
6484
|
+
const storeBackedOptions = BUNDLED_STATIC_STORE_BACKED_OPTIONS.get(command);
|
|
6485
|
+
if (storeBackedOptions) {
|
|
6486
|
+
const option = storeBackedOptions.find((candidate) => hasOption(args, candidate));
|
|
6487
|
+
return option ? {
|
|
6488
|
+
blame: option,
|
|
6489
|
+
remedy: `it imports bundled fixtures into the local store, which this route disables; re-run \`${command}\` without it to read the bundled content`
|
|
6490
|
+
} : null;
|
|
6491
|
+
}
|
|
6454
6492
|
switch (command) {
|
|
6455
6493
|
case "task":
|
|
6456
6494
|
return positionalArgs(args)[0] === "upsert" ? null : { blame: "any subcommand other than `upsert`", remedy: "use `todos task upsert`" };
|
|
@@ -6478,13 +6516,22 @@ function disqualifyingArgument(invocation) {
|
|
|
6478
6516
|
const action = positionalArgs(args)[0];
|
|
6479
6517
|
if (action === "plan" || action === "move-plan")
|
|
6480
6518
|
return null;
|
|
6519
|
+
if (action === "tag" || action === "untag") {
|
|
6520
|
+
if (!hasOption(args, "--tag") && !hasOption(args, "--tags")) {
|
|
6521
|
+
return {
|
|
6522
|
+
blame: `\`bulk ${action}\` without --tag`,
|
|
6523
|
+
remedy: `pass --tag <comma-separated>, e.g. bulk ${action} <ids...> --tag directive:k_msd4cz8t_ste6f4`
|
|
6524
|
+
};
|
|
6525
|
+
}
|
|
6526
|
+
return firstPresentOption(args, ["--plan", "--clear-plan"]);
|
|
6527
|
+
}
|
|
6481
6528
|
if (!action) {
|
|
6482
|
-
return { blame: "a missing action", remedy: "pass one of done, complete, start, delete, plan, move-plan" };
|
|
6529
|
+
return { blame: "a missing action", remedy: "pass one of done, complete, start, delete, plan, move-plan, tag, untag" };
|
|
6483
6530
|
}
|
|
6484
6531
|
if (!["done", "complete", "start", "delete"].includes(action)) {
|
|
6485
6532
|
return {
|
|
6486
6533
|
blame: `the \`${action}\` action`,
|
|
6487
|
-
remedy: "use one of done, complete, start, delete, plan, move-plan"
|
|
6534
|
+
remedy: "use one of done, complete, start, delete, plan, move-plan, tag, untag"
|
|
6488
6535
|
};
|
|
6489
6536
|
}
|
|
6490
6537
|
return firstPresentOption(args, ["--plan", "--clear-plan"]);
|
|
@@ -6541,7 +6588,8 @@ function assertRemoteCommandSupported(invocation) {
|
|
|
6541
6588
|
}
|
|
6542
6589
|
if (!command || !commandSupportsRemote(invocation)) {
|
|
6543
6590
|
const blame = command ? disqualifyingArgument(invocation) : null;
|
|
6544
|
-
const
|
|
6591
|
+
const servedBy = command && BUNDLED_STATIC_STORE_BACKED_OPTIONS.has(command) ? `\`${command}\` renders bundled content on this route` : `\`${command}\` is served by the Todos /v1 authority`;
|
|
6592
|
+
const detail = blame ? `${servedBy} but ${blame.blame} is not; ${blame.remedy}` : `${invocationLabel(invocation)} is not supported by the Todos /v1 CLI; local SQLite fallback is disabled`;
|
|
6545
6593
|
throw new Error(`REMOTE_COMMAND_UNSUPPORTED: ${detail}`);
|
|
6546
6594
|
}
|
|
6547
6595
|
}
|
|
@@ -6561,7 +6609,7 @@ function initializeTodosCliAuthority(args = process.argv.slice(2), env = process
|
|
|
6561
6609
|
}
|
|
6562
6610
|
return { route: "remote-http", v1_base_url: client.baseUrl };
|
|
6563
6611
|
}
|
|
6564
|
-
var REGISTERED_CANONICAL_COMMANDS, TODOS_CLI_COMMAND_ALIASES, DIAGNOSTIC_COMMANDS, REMOTE_COMMANDS, COMMAND_CAPABILITY_MATRIX, GLOBAL_OPTIONS_WITH_VALUES, GLOBAL_FLAGS, HELP_FLAGS, VERSION_FLAGS, dropIt = (blame) => ({ blame, remedy: "re-run without it" });
|
|
6612
|
+
var REGISTERED_CANONICAL_COMMANDS, TODOS_CLI_COMMAND_ALIASES, BUNDLED_STATIC_COMMANDS, BUNDLED_STATIC_STORE_BACKED_OPTIONS, DIAGNOSTIC_COMMANDS, REMOTE_COMMANDS, COMMAND_CAPABILITY_MATRIX, GLOBAL_OPTIONS_WITH_VALUES, GLOBAL_FLAGS, HELP_FLAGS, VERSION_FLAGS, dropIt = (blame) => ({ blame, remedy: "re-run without it" });
|
|
6565
6613
|
var init_stage_a = __esm(() => {
|
|
6566
6614
|
init_esm();
|
|
6567
6615
|
init_cloud_router();
|
|
@@ -6751,7 +6799,28 @@ var init_stage_a = __esm(() => {
|
|
|
6751
6799
|
reliability: ["scorecards"],
|
|
6752
6800
|
lists: ["task-lists", "tl"]
|
|
6753
6801
|
};
|
|
6754
|
-
|
|
6802
|
+
BUNDLED_STATIC_COMMANDS = {
|
|
6803
|
+
workflows: [],
|
|
6804
|
+
"template-library": [],
|
|
6805
|
+
onboarding: ["--import"],
|
|
6806
|
+
"sdk-fixtures": ["--show", "--write"]
|
|
6807
|
+
};
|
|
6808
|
+
BUNDLED_STATIC_STORE_BACKED_OPTIONS = new Map;
|
|
6809
|
+
for (const [canonical, storeBackedOptions] of Object.entries(BUNDLED_STATIC_COMMANDS)) {
|
|
6810
|
+
BUNDLED_STATIC_STORE_BACKED_OPTIONS.set(canonical, storeBackedOptions);
|
|
6811
|
+
const aliases = TODOS_CLI_COMMAND_ALIASES[canonical] ?? [];
|
|
6812
|
+
for (const alias of aliases)
|
|
6813
|
+
BUNDLED_STATIC_STORE_BACKED_OPTIONS.set(alias, storeBackedOptions);
|
|
6814
|
+
}
|
|
6815
|
+
DIAGNOSTIC_COMMANDS = new Set([
|
|
6816
|
+
"help",
|
|
6817
|
+
"manual",
|
|
6818
|
+
"completions",
|
|
6819
|
+
"completion",
|
|
6820
|
+
"config",
|
|
6821
|
+
"storage",
|
|
6822
|
+
...Object.keys(BUNDLED_STATIC_COMMANDS)
|
|
6823
|
+
]);
|
|
6755
6824
|
REMOTE_COMMANDS = new Set([
|
|
6756
6825
|
"active",
|
|
6757
6826
|
"add",
|
|
@@ -10773,8 +10842,7 @@ function findGitRoot(startDir) {
|
|
|
10773
10842
|
return null;
|
|
10774
10843
|
}
|
|
10775
10844
|
function getGlobalDbPath() {
|
|
10776
|
-
|
|
10777
|
-
return join3(home, ".hasna", "todos", "todos.db");
|
|
10845
|
+
return join3(getHomeDir(), ".hasna", "todos", "todos.db");
|
|
10778
10846
|
}
|
|
10779
10847
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
10780
10848
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -10996,6 +11064,7 @@ var init_database = __esm(() => {
|
|
|
10996
11064
|
init_machines();
|
|
10997
11065
|
init_identity_mapping();
|
|
10998
11066
|
init_types();
|
|
11067
|
+
init_sync_utils();
|
|
10999
11068
|
ALLOWED_TABLES = new Set(["tasks", "projects", "agents", "plans", "task_lists", "task_templates", "project_knowledge_records", "project_risks", "local_retrospectives"]);
|
|
11000
11069
|
});
|
|
11001
11070
|
|
|
@@ -11502,14 +11571,21 @@ function suggestVocabularyMatches(value, vocabulary, limit = 3) {
|
|
|
11502
11571
|
}
|
|
11503
11572
|
function resolveEnumVocabulary(raw, spec) {
|
|
11504
11573
|
const allowList = spec.allowList !== false;
|
|
11505
|
-
const rawElements = (allowList ? raw.split(",") : [raw]).map((element) => element.trim())
|
|
11506
|
-
if (rawElements.length === 0) {
|
|
11574
|
+
const rawElements = (allowList ? raw.split(",") : [raw]).map((element) => element.trim());
|
|
11575
|
+
if (rawElements.every((element) => element.length === 0)) {
|
|
11507
11576
|
return {
|
|
11508
11577
|
ok: false,
|
|
11509
11578
|
message: `${spec.name} requires a value. Allowed values: ${spec.vocabulary.join(", ")}.`,
|
|
11510
11579
|
invalid: []
|
|
11511
11580
|
};
|
|
11512
11581
|
}
|
|
11582
|
+
if (rawElements.some((element) => element.length === 0)) {
|
|
11583
|
+
return {
|
|
11584
|
+
ok: false,
|
|
11585
|
+
message: `${spec.name} has an empty value in "${raw}" \u2014 remove the stray comma. ` + `Allowed values: ${spec.vocabulary.join(", ")}.`,
|
|
11586
|
+
invalid: []
|
|
11587
|
+
};
|
|
11588
|
+
}
|
|
11513
11589
|
const normalized = rawElements.map((element) => spec.normalize ? spec.normalize(element) : element);
|
|
11514
11590
|
const allowed = new Set(spec.vocabulary);
|
|
11515
11591
|
const invalid2 = [];
|
|
@@ -12707,7 +12783,7 @@ var init_event_hooks = __esm(() => {
|
|
|
12707
12783
|
// node_modules/.bun/@hasna+events@0.1.11/node_modules/@hasna/events/dist/index.js
|
|
12708
12784
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
12709
12785
|
import { existsSync as existsSync6 } from "fs";
|
|
12710
|
-
import { homedir } from "os";
|
|
12786
|
+
import { homedir as homedir2 } from "os";
|
|
12711
12787
|
import { join as join5 } from "path";
|
|
12712
12788
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
12713
12789
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -12809,7 +12885,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
12809
12885
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
12810
12886
|
}
|
|
12811
12887
|
function getEventsDataDir(override) {
|
|
12812
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join5(
|
|
12888
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join5(homedir2(), ".hasna", "events");
|
|
12813
12889
|
}
|
|
12814
12890
|
|
|
12815
12891
|
class JsonEventsStore {
|
|
@@ -19241,6 +19317,49 @@ var init_tasks = __esm(() => {
|
|
|
19241
19317
|
init_calendar();
|
|
19242
19318
|
});
|
|
19243
19319
|
|
|
19320
|
+
// src/lib/bulk-tags.ts
|
|
19321
|
+
function parseTagList(raw) {
|
|
19322
|
+
if (!raw)
|
|
19323
|
+
return [];
|
|
19324
|
+
const seen = new Set;
|
|
19325
|
+
const tags = [];
|
|
19326
|
+
for (const segment of raw.split(",")) {
|
|
19327
|
+
const tag = segment.trim();
|
|
19328
|
+
if (!tag || seen.has(tag))
|
|
19329
|
+
continue;
|
|
19330
|
+
seen.add(tag);
|
|
19331
|
+
tags.push(tag);
|
|
19332
|
+
}
|
|
19333
|
+
return tags;
|
|
19334
|
+
}
|
|
19335
|
+
function resolveTagArgument(tag, tags) {
|
|
19336
|
+
if (tag === undefined)
|
|
19337
|
+
return { ok: true, raw: tags };
|
|
19338
|
+
if (tags === undefined)
|
|
19339
|
+
return { ok: true, raw: tag };
|
|
19340
|
+
const left = parseTagList(tag);
|
|
19341
|
+
const right = parseTagList(tags);
|
|
19342
|
+
const same = left.length === right.length && left.every((entry) => right.includes(entry));
|
|
19343
|
+
if (!same)
|
|
19344
|
+
return { ok: false, conflict: { tag, tags } };
|
|
19345
|
+
return { ok: true, raw: tag };
|
|
19346
|
+
}
|
|
19347
|
+
function resolveBulkTags(current, action, tags) {
|
|
19348
|
+
const existing = Array.isArray(current) ? current.filter((tag) => typeof tag === "string") : [];
|
|
19349
|
+
if (tags.length === 0)
|
|
19350
|
+
return { tags: [...existing], changed: false };
|
|
19351
|
+
if (action === "tag") {
|
|
19352
|
+
const present = new Set(existing);
|
|
19353
|
+
const additions = tags.filter((tag) => !present.has(tag));
|
|
19354
|
+
if (additions.length === 0)
|
|
19355
|
+
return { tags: [...existing], changed: false };
|
|
19356
|
+
return { tags: [...existing, ...additions], changed: true };
|
|
19357
|
+
}
|
|
19358
|
+
const removing = new Set(tags);
|
|
19359
|
+
const remaining = existing.filter((tag) => !removing.has(tag));
|
|
19360
|
+
return { tags: remaining, changed: remaining.length !== existing.length };
|
|
19361
|
+
}
|
|
19362
|
+
|
|
19244
19363
|
// src/cli/claim-guard.ts
|
|
19245
19364
|
function resolveClaimIdentity(verb, explicit) {
|
|
19246
19365
|
const resolved = resolveWritableIdentity(explicit);
|
|
@@ -19261,10 +19380,10 @@ function normalizeAgentNameInput(name) {
|
|
|
19261
19380
|
|
|
19262
19381
|
// src/lib/assignee-validation.ts
|
|
19263
19382
|
import { readFileSync as readFileSync4 } from "fs";
|
|
19264
|
-
import { homedir as
|
|
19383
|
+
import { homedir as homedir3 } from "os";
|
|
19265
19384
|
import { join as join8 } from "path";
|
|
19266
19385
|
function defaultSeatRosterPath() {
|
|
19267
|
-
return process.env["TODOS_SEAT_ROSTER_PATH"] || join8(
|
|
19386
|
+
return process.env["TODOS_SEAT_ROSTER_PATH"] || join8(homedir3(), ".hasna", "identities", "hasna-seats.roster.json");
|
|
19268
19387
|
}
|
|
19269
19388
|
function loadSeatSlugs(path = defaultSeatRosterPath()) {
|
|
19270
19389
|
try {
|
|
@@ -20398,11 +20517,31 @@ function resolveProjectIdOrSlug(input) {
|
|
|
20398
20517
|
return row.id;
|
|
20399
20518
|
handleError(new Error(`Project not found: ${input}`));
|
|
20400
20519
|
}
|
|
20520
|
+
function projectRefFromOpts(opts, globalOpts) {
|
|
20521
|
+
const own = typeof opts.project === "string" ? opts.project : undefined;
|
|
20522
|
+
const global = typeof globalOpts.project === "string" ? globalOpts.project : undefined;
|
|
20523
|
+
return own || global;
|
|
20524
|
+
}
|
|
20525
|
+
function projectOptOut(opts) {
|
|
20526
|
+
return opts.project === false;
|
|
20527
|
+
}
|
|
20528
|
+
function warnMissingProject(resolvedProjectId, optedOut) {
|
|
20529
|
+
if (resolvedProjectId || optedOut)
|
|
20530
|
+
return;
|
|
20531
|
+
console.error(chalk3.yellow("Warning: task filed with no project \u2014 it will not appear in any project list, per-seat report, or drain. " + "Pass --project <id-or-slug>, or --no-project if filing it globally is deliberate."));
|
|
20532
|
+
}
|
|
20401
20533
|
function parseStatus(value) {
|
|
20402
20534
|
if (!value)
|
|
20403
20535
|
return;
|
|
20404
20536
|
return parseEnumFlagList(value, { ...TASK_STATUS_FLAG, allowList: false })?.[0];
|
|
20405
20537
|
}
|
|
20538
|
+
function listScanLimit() {
|
|
20539
|
+
const raw = process.env["TODOS_LIST_SCAN_LIMIT"];
|
|
20540
|
+
if (raw === undefined || raw.trim() === "")
|
|
20541
|
+
return DEFAULT_LIST_SCAN_LIMIT;
|
|
20542
|
+
const parsed = Number.parseInt(raw, 10);
|
|
20543
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_LIST_SCAN_LIMIT;
|
|
20544
|
+
}
|
|
20406
20545
|
function parseIntOption(value, flag) {
|
|
20407
20546
|
if (value === undefined)
|
|
20408
20547
|
return;
|
|
@@ -20540,7 +20679,7 @@ function computeLocalReparent(current, opts) {
|
|
|
20540
20679
|
return patch;
|
|
20541
20680
|
}
|
|
20542
20681
|
function registerTaskCommands(program2) {
|
|
20543
|
-
program2.command("add <title>").description("Create a new task").option("-d, --description <text>", "Task description").option("-p, --priority <level>", "Priority: low, medium, high, critical").option("--parent <id>", "Parent task ID").option("-t, --tags <tags>", "Comma-separated tags").option("--tag <tags>", "Comma-separated tags (alias for --tags)").option("--plan <id>", "Assign to a plan").option("--assign <agent>", "Assign to agent").option("--status <status>", "Initial status").option("--list <id>", "Task list ID").option("--task-list <id>", "Task list ID (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--approval", "Require approval before completion").option("--recurrence <rule>", "Recurrence rule, e.g. 'every day', 'every weekday', 'every 2 weeks'").option("--due <date>", "Due date (ISO string or YYYY-MM-DD)").option("--reason <text>", "Why this task exists").option("--project <id>", "Assign to project by ID or slug (overrides auto-detect)").option("--unassigned", "Deliberately file this task with no assignee").option("--assign-seat", "Allow --assign to name a durable seat (a seat queue has no session watching it)").option("--created-by <agent>", "Record a different filer than the resolved agent identity").action(async (title, opts) => {
|
|
20682
|
+
program2.command("add <title>").description("Create a new task").option("-d, --description <text>", "Task description").option("-p, --priority <level>", "Priority: low, medium, high, critical").option("--parent <id>", "Parent task ID").option("-t, --tags <tags>", "Comma-separated tags").option("--tag <tags>", "Comma-separated tags (alias for --tags)").option("--plan <id>", "Assign to a plan").option("--assign <agent>", "Assign to agent").option("--status <status>", "Initial status").option("--list <id>", "Task list ID").option("--task-list <id>", "Task list ID (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--approval", "Require approval before completion").option("--recurrence <rule>", "Recurrence rule, e.g. 'every day', 'every weekday', 'every 2 weeks'").option("--due <date>", "Due date (ISO string or YYYY-MM-DD)").option("--reason <text>", "Why this task exists").option("--project <id>", "Assign to project by ID or slug (overrides auto-detect)").option("--no-project", "Deliberately file this task with no project (silences the orphan warning)").option("--unassigned", "Deliberately file this task with no assignee").option("--assign-seat", "Allow --assign to name a durable seat (a seat queue has no session watching it)").option("--created-by <agent>", "Record a different filer than the resolved agent identity").action(async (title, opts) => {
|
|
20544
20683
|
const globalOpts = program2.opts();
|
|
20545
20684
|
opts.tags = opts.tags || opts.tag;
|
|
20546
20685
|
opts.list = opts.list || opts.taskList;
|
|
@@ -20555,8 +20694,9 @@ function registerTaskCommands(program2) {
|
|
|
20555
20694
|
if (cloud) {
|
|
20556
20695
|
let task3;
|
|
20557
20696
|
try {
|
|
20558
|
-
const cloudProjectRef = opts
|
|
20697
|
+
const cloudProjectRef = projectRefFromOpts(opts, globalOpts);
|
|
20559
20698
|
const cloudProjectId = cloudProjectRef ? await cloudResolveProjectRef(cloud, cloudProjectRef) : undefined;
|
|
20699
|
+
warnMissingProject(cloudProjectId, projectOptOut(opts));
|
|
20560
20700
|
const cloudTaskListId = opts.list ? await cloudResolveTaskListRef(cloud, opts.list, cloudProjectId) : undefined;
|
|
20561
20701
|
if (opts.list && !cloudTaskListId) {
|
|
20562
20702
|
throw new Error(`Could not resolve task list ID or slug: ${opts.list}`);
|
|
@@ -20579,6 +20719,7 @@ function registerTaskCommands(program2) {
|
|
|
20579
20719
|
created_by: creator.agent_id || undefined,
|
|
20580
20720
|
session_id: globalOpts.session,
|
|
20581
20721
|
project_id: cloudProjectId,
|
|
20722
|
+
working_dir: process.cwd(),
|
|
20582
20723
|
estimated_minutes: opts.estimated !== undefined ? parseIntOption(opts.estimated, "--estimated") : undefined,
|
|
20583
20724
|
sla_minutes: opts.slaMinutes !== undefined || opts.sla !== undefined ? parseIntOption(opts.slaMinutes ?? opts.sla, "--sla-minutes") : undefined,
|
|
20584
20725
|
requires_approval: opts.approval || undefined,
|
|
@@ -20597,8 +20738,9 @@ function registerTaskCommands(program2) {
|
|
|
20597
20738
|
}
|
|
20598
20739
|
return;
|
|
20599
20740
|
}
|
|
20600
|
-
const explicitProject = opts
|
|
20601
|
-
const projectId = explicitProject ? resolveProjectIdOrSlug(explicitProject) : autoProject(globalOpts);
|
|
20741
|
+
const explicitProject = projectRefFromOpts(opts, globalOpts);
|
|
20742
|
+
const projectId = explicitProject ? resolveProjectIdOrSlug(explicitProject) : projectOptOut(opts) ? undefined : autoProject(globalOpts);
|
|
20743
|
+
warnMissingProject(projectId, projectOptOut(opts));
|
|
20602
20744
|
opts.tags = opts.tags || opts.tag;
|
|
20603
20745
|
opts.list = opts.list || opts.taskList;
|
|
20604
20746
|
const taskListId = opts.list ? (() => {
|
|
@@ -20810,15 +20952,19 @@ function registerTaskCommands(program2) {
|
|
|
20810
20952
|
}
|
|
20811
20953
|
filter["task_list_id"] = listId;
|
|
20812
20954
|
}
|
|
20813
|
-
if (opts.status) {
|
|
20955
|
+
if (opts.status !== undefined) {
|
|
20814
20956
|
filter["status"] = parseEnumFlag(opts.status, TASK_STATUS_FLAG);
|
|
20815
20957
|
} else if (!opts.all) {
|
|
20816
20958
|
filter["status"] = ["pending", "in_progress"];
|
|
20817
20959
|
}
|
|
20818
|
-
if (opts.priority)
|
|
20960
|
+
if (opts.priority !== undefined)
|
|
20819
20961
|
filter["priority"] = parseEnumFlag(opts.priority, TASK_PRIORITY_FLAG);
|
|
20820
|
-
|
|
20821
|
-
|
|
20962
|
+
let assignedFilter;
|
|
20963
|
+
let assignedWasTyped = false;
|
|
20964
|
+
if (opts.assigned) {
|
|
20965
|
+
assignedFilter = opts.assigned;
|
|
20966
|
+
assignedWasTyped = true;
|
|
20967
|
+
}
|
|
20822
20968
|
if (opts.createdBy)
|
|
20823
20969
|
filter["created_by"] = canonicalAgentRef(opts.createdBy);
|
|
20824
20970
|
if (opts.notCreatedBy)
|
|
@@ -20829,7 +20975,8 @@ function registerTaskCommands(program2) {
|
|
|
20829
20975
|
console.error(chalk3.red("--inbox needs an agent identity. Run `todos init <name>` or pass --agent <id>."));
|
|
20830
20976
|
process.exit(1);
|
|
20831
20977
|
}
|
|
20832
|
-
|
|
20978
|
+
assignedFilter = me.agent_id;
|
|
20979
|
+
assignedWasTyped = false;
|
|
20833
20980
|
filter["not_created_by"] = me.agent_id;
|
|
20834
20981
|
}
|
|
20835
20982
|
if (opts.tags)
|
|
@@ -20845,8 +20992,11 @@ function registerTaskCommands(program2) {
|
|
|
20845
20992
|
}
|
|
20846
20993
|
}
|
|
20847
20994
|
if (opts.agentName) {
|
|
20848
|
-
|
|
20995
|
+
assignedFilter = opts.agentName;
|
|
20996
|
+
assignedWasTyped = true;
|
|
20849
20997
|
}
|
|
20998
|
+
if (assignedFilter !== undefined)
|
|
20999
|
+
filter["assigned_to"] = assignedFilter;
|
|
20850
21000
|
if (opts.recurring)
|
|
20851
21001
|
filter["has_recurrence"] = true;
|
|
20852
21002
|
if (opts.limit !== undefined) {
|
|
@@ -20858,11 +21008,23 @@ function registerTaskCommands(program2) {
|
|
|
20858
21008
|
}
|
|
20859
21009
|
const creatorFilterActive = Boolean(filter["created_by"] || filter["not_created_by"]);
|
|
20860
21010
|
const requestedLimit = filter["limit"];
|
|
20861
|
-
const
|
|
20862
|
-
|
|
20863
|
-
|
|
20864
|
-
|
|
21011
|
+
const reordersAfterQuery = Boolean(opts.sort);
|
|
21012
|
+
const narrowsAfterQuery = Boolean(opts.dueToday) || Boolean(opts.overdue) || creatorFilterActive && cloud;
|
|
21013
|
+
const withholdLimit = requestedLimit !== undefined && (reordersAfterQuery || narrowsAfterQuery);
|
|
21014
|
+
const scanCeiling = cloud && (withholdLimit || requestedLimit === undefined) ? Math.max(requestedLimit ?? 0, listScanLimit()) : undefined;
|
|
21015
|
+
const serverFilter = (() => {
|
|
21016
|
+
const base = withholdLimit ? (() => {
|
|
21017
|
+
const { limit: _dropped, ...rest } = filter;
|
|
21018
|
+
return rest;
|
|
21019
|
+
})() : filter;
|
|
21020
|
+
return scanCeiling === undefined ? base : { ...base, limit: scanCeiling };
|
|
21021
|
+
})();
|
|
20865
21022
|
let tasks = cloud ? await cloudListTasks(cloud, serverFilter) : listTasks(serverFilter);
|
|
21023
|
+
if (scanCeiling !== undefined && tasks.length >= scanCeiling) {
|
|
21024
|
+
console.error(chalk3.yellow(`Warning: this query reached its ${scanCeiling}-row scan limit, so the rows below were
|
|
21025
|
+
` + ` selected from a truncated set and may not be the true result.
|
|
21026
|
+
` + ` Narrow it (--project, --status, --assigned) or raise TODOS_LIST_SCAN_LIMIT.`));
|
|
21027
|
+
}
|
|
20866
21028
|
if (cloud && creatorFilterActive) {
|
|
20867
21029
|
if (tasks.length > 0 && tasks.every((t) => !("created_by" in t))) {
|
|
20868
21030
|
console.error(chalk3.yellow(`Warning: this server does not record task authorship, so the creator filter matched nothing to exclude.
|
|
@@ -20879,8 +21041,6 @@ function registerTaskCommands(program2) {
|
|
|
20879
21041
|
return false;
|
|
20880
21042
|
return true;
|
|
20881
21043
|
});
|
|
20882
|
-
if (requestedLimit !== undefined)
|
|
20883
|
-
tasks = tasks.slice(0, requestedLimit);
|
|
20884
21044
|
}
|
|
20885
21045
|
if (opts.dueToday) {
|
|
20886
21046
|
const todayEnd = new Date;
|
|
@@ -20905,6 +21065,21 @@ function registerTaskCommands(program2) {
|
|
|
20905
21065
|
return 0;
|
|
20906
21066
|
});
|
|
20907
21067
|
}
|
|
21068
|
+
if (withholdLimit && requestedLimit !== undefined)
|
|
21069
|
+
tasks = tasks.slice(0, requestedLimit);
|
|
21070
|
+
if (assignedWasTyped && assignedFilter && tasks.length === 0) {
|
|
21071
|
+
try {
|
|
21072
|
+
const roster = await loadAssigneeContext(() => cloud ? cloudListAgents(cloud) : listAgents(), true);
|
|
21073
|
+
if (!roster.degraded) {
|
|
21074
|
+
const target = canonicalAgentRef(assignedFilter);
|
|
21075
|
+
const known = roster.agents.some((a) => canonicalAgentRef(a.name) === target || canonicalAgentRef(a.id) === target);
|
|
21076
|
+
if (!known) {
|
|
21077
|
+
console.error(chalk3.yellow(`Warning: no agent named '${assignedFilter}' is registered, so this empty result may be a
|
|
21078
|
+
` + ` mistyped name rather than an empty queue. Check with 'todos agents'.`));
|
|
21079
|
+
}
|
|
21080
|
+
}
|
|
21081
|
+
} catch {}
|
|
21082
|
+
}
|
|
20908
21083
|
const fmt = opts.format || (globalOpts.json ? "json" : "table");
|
|
20909
21084
|
const outputTasks = redactBroadTasks(tasks);
|
|
20910
21085
|
if (fmt === "json") {
|
|
@@ -21676,17 +21851,26 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21676
21851
|
handleError(new Error("Task not found."));
|
|
21677
21852
|
}
|
|
21678
21853
|
});
|
|
21679
|
-
program2.command("bulk <action> <ids...>").description("Bulk operation on multiple tasks (done, start, delete, plan/move-plan)").option("--plan <id>", "Plan ID for the plan/move-plan action").option("--clear-plan", "Remove plan assignment for the plan/move-plan action").action(async (action, ids, opts) => {
|
|
21854
|
+
program2.command("bulk <action> <ids...>").description("Bulk operation on multiple tasks (done, start, delete, plan/move-plan, tag, untag)").option("--plan <id>", "Plan ID for the plan/move-plan action").option("--clear-plan", "Remove plan assignment for the plan/move-plan action").option("--tag <tags>", "Comma-separated tags for the tag/untag action").option("--tags <tags>", "Comma-separated tags for the tag/untag action (alias for --tag)").action(async (action, ids, opts) => {
|
|
21680
21855
|
const globalOpts = program2.opts();
|
|
21681
21856
|
const results = [];
|
|
21682
21857
|
const cloud = getTodosCloudClient();
|
|
21683
21858
|
const isPlanAction = action === "plan" || action === "move-plan";
|
|
21859
|
+
const isTagAction = action === "tag" || action === "untag";
|
|
21684
21860
|
if (isPlanAction && Boolean(opts.plan) === Boolean(opts.clearPlan)) {
|
|
21685
21861
|
handleError(new Error("Use exactly one of --plan or --clear-plan with bulk plan."));
|
|
21686
21862
|
}
|
|
21687
|
-
const knownActions = new Set(["done", "complete", "start", "delete", "plan", "move-plan"]);
|
|
21863
|
+
const knownActions = new Set(["done", "complete", "start", "delete", "plan", "move-plan", "tag", "untag"]);
|
|
21688
21864
|
if (!knownActions.has(action)) {
|
|
21689
|
-
handleError(new Error(`Unknown action: ${action}. Use: done, start, delete, plan (alias: move-plan)`));
|
|
21865
|
+
handleError(new Error(`Unknown action: ${action}. Use: done, start, delete, plan (alias: move-plan), tag, untag`));
|
|
21866
|
+
}
|
|
21867
|
+
const tagArgument = resolveTagArgument(opts.tag, opts.tags);
|
|
21868
|
+
if (isTagAction && !tagArgument.ok) {
|
|
21869
|
+
handleError(new Error(`--tag and --tags name different tag sets (--tag "${tagArgument.conflict.tag}" vs --tags "${tagArgument.conflict.tags}"). ` + "They are aliases; pass one, or pass the same set to both."));
|
|
21870
|
+
}
|
|
21871
|
+
const bulkTags = isTagAction && tagArgument.ok ? parseTagList(tagArgument.raw) : [];
|
|
21872
|
+
if (isTagAction && bulkTags.length === 0) {
|
|
21873
|
+
handleError(new Error(`bulk ${action} needs --tag. Example: todos bulk ${action} <ids...> --tag directive:k_msd4cz8t_ste6f4`));
|
|
21690
21874
|
}
|
|
21691
21875
|
const bulkClaimAgentId = action === "start" ? resolveClaimIdentity("start", globalOpts.agent) : undefined;
|
|
21692
21876
|
if (cloud) {
|
|
@@ -21715,6 +21899,14 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21715
21899
|
await cloudTaskAction(cloud, resolvedId, "start", { agent_id: bulkClaimAgentId });
|
|
21716
21900
|
} else if (action === "delete") {
|
|
21717
21901
|
await cloudDeleteTask(cloud, resolvedId);
|
|
21902
|
+
} else if (isTagAction) {
|
|
21903
|
+
const current = await cloudGetTask(cloud, resolvedId);
|
|
21904
|
+
if (!current)
|
|
21905
|
+
throw new Error(`Task not found: ${rawId}`);
|
|
21906
|
+
const resolution = resolveBulkTags(current.tags, action, bulkTags);
|
|
21907
|
+
if (resolution.changed) {
|
|
21908
|
+
await cloudUpdateTask(cloud, resolvedId, { version: current.version, tags: resolution.tags });
|
|
21909
|
+
}
|
|
21718
21910
|
} else {
|
|
21719
21911
|
const current = await cloudGetTask(cloud, resolvedId);
|
|
21720
21912
|
if (!current)
|
|
@@ -21751,6 +21943,16 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21751
21943
|
} else if (action === "delete") {
|
|
21752
21944
|
deleteTask(resolvedId);
|
|
21753
21945
|
results.push({ id: resolvedId, success: true });
|
|
21946
|
+
} else if (isTagAction) {
|
|
21947
|
+
const current = getTask(resolvedId);
|
|
21948
|
+
if (!current) {
|
|
21949
|
+
throw new Error(`Task not found: ${rawId}`);
|
|
21950
|
+
}
|
|
21951
|
+
const resolution = resolveBulkTags(current.tags, action, bulkTags);
|
|
21952
|
+
if (resolution.changed) {
|
|
21953
|
+
updateTask(resolvedId, { version: current.version, tags: resolution.tags });
|
|
21954
|
+
}
|
|
21955
|
+
results.push({ id: resolvedId, success: true });
|
|
21754
21956
|
} else if (isPlanAction) {
|
|
21755
21957
|
const current = getTask(resolvedId);
|
|
21756
21958
|
if (!current) {
|
|
@@ -21759,7 +21961,7 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21759
21961
|
updateTask(resolvedId, { version: current.version, plan_id: planId });
|
|
21760
21962
|
results.push({ id: resolvedId, success: true });
|
|
21761
21963
|
} else {
|
|
21762
|
-
handleError(new Error(`Unknown action: ${action}. Use: done, start, delete, plan (alias: move-plan)`));
|
|
21964
|
+
handleError(new Error(`Unknown action: ${action}. Use: done, start, delete, plan (alias: move-plan), tag, untag`));
|
|
21763
21965
|
}
|
|
21764
21966
|
} catch (e) {
|
|
21765
21967
|
results.push({ id: rawId, success: false, error: e instanceof Error ? e.message : String(e) });
|
|
@@ -21777,6 +21979,7 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21777
21979
|
}
|
|
21778
21980
|
});
|
|
21779
21981
|
}
|
|
21982
|
+
var DEFAULT_LIST_SCAN_LIMIT = 1e4;
|
|
21780
21983
|
var init_task_commands = __esm(() => {
|
|
21781
21984
|
init_database();
|
|
21782
21985
|
init_projects();
|
|
@@ -21787,6 +21990,8 @@ var init_task_commands = __esm(() => {
|
|
|
21787
21990
|
init_lock_display();
|
|
21788
21991
|
init_claim_guard();
|
|
21789
21992
|
init_assignee_guard();
|
|
21993
|
+
init_assignee_context();
|
|
21994
|
+
init_agents();
|
|
21790
21995
|
init_helpers();
|
|
21791
21996
|
init_output_redaction();
|
|
21792
21997
|
});
|
|
@@ -39195,7 +39400,13 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
39195
39400
|
return error(405, `method ${method} not allowed on /v1/refs/:ref`);
|
|
39196
39401
|
if (!store.gitRefs)
|
|
39197
39402
|
return error(501, "git ref links are not supported by this storage backend");
|
|
39198
|
-
|
|
39403
|
+
let decodedRef;
|
|
39404
|
+
try {
|
|
39405
|
+
decodedRef = decodeURIComponent(id);
|
|
39406
|
+
} catch {
|
|
39407
|
+
return error(400, "ref path segment has invalid percent encoding");
|
|
39408
|
+
}
|
|
39409
|
+
const refs = await store.gitRefs.find(decodedRef);
|
|
39199
39410
|
return json3({ refs, count: refs.length });
|
|
39200
39411
|
}
|
|
39201
39412
|
if (resource === "next" && !id) {
|
|
@@ -43793,7 +44004,7 @@ async function validateMcpAssignee(value, allowSeat) {
|
|
|
43793
44004
|
return verdict.assignee;
|
|
43794
44005
|
}
|
|
43795
44006
|
function registerTaskCrudTools(server, ctx) {
|
|
43796
|
-
const { shouldRegisterTool, resolveId, formatError, formatTask } = ctx;
|
|
44007
|
+
const { shouldRegisterTool, resolveId, formatError, formatTask, applyFocus } = ctx;
|
|
43797
44008
|
function mutationTaskResponse(task) {
|
|
43798
44009
|
const compact = compactTask(task, 240);
|
|
43799
44010
|
compact["version"] = task.version;
|
|
@@ -43869,6 +44080,7 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
43869
44080
|
payload.max_retries = retry_count;
|
|
43870
44081
|
if (deadline)
|
|
43871
44082
|
payload.due_at = deadline;
|
|
44083
|
+
applyFocus(payload, router.agent_id || undefined);
|
|
43872
44084
|
const created = await cloudCreateTask(cloud, payload);
|
|
43873
44085
|
return { content: [{ type: "text", text: mutationTaskResponse(created) }] };
|
|
43874
44086
|
}
|
|
@@ -43895,6 +44107,7 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
43895
44107
|
resolved.max_retries = retry_count;
|
|
43896
44108
|
if (deadline)
|
|
43897
44109
|
resolved.due_at = deadline;
|
|
44110
|
+
applyFocus(resolved, router.agent_id || undefined);
|
|
43898
44111
|
const task = createTask(resolved);
|
|
43899
44112
|
return { content: [{ type: "text", text: mutationTaskResponse(task) }] };
|
|
43900
44113
|
} catch (e) {
|
|
@@ -63133,7 +63346,8 @@ function buildServer() {
|
|
|
63133
63346
|
formatError,
|
|
63134
63347
|
formatTask,
|
|
63135
63348
|
formatTaskDetail,
|
|
63136
|
-
getAgentFocus
|
|
63349
|
+
getAgentFocus,
|
|
63350
|
+
applyFocus
|
|
63137
63351
|
};
|
|
63138
63352
|
registerTaskCrudTools(server, toolContext);
|
|
63139
63353
|
registerTaskProjectTools(server, toolContext);
|
|
@@ -66580,7 +66794,7 @@ ${error2.message}
|
|
|
66580
66794
|
const globalOpts = program2.opts();
|
|
66581
66795
|
const projectId = autoProject(globalOpts);
|
|
66582
66796
|
const interval = parseInt(opts.interval, 10) * 1000;
|
|
66583
|
-
const statusFilter = opts.status
|
|
66797
|
+
const statusFilter = parseEnumFlagList(opts.status, TASK_STATUS_FLAG) ?? ["pending", "in_progress"];
|
|
66584
66798
|
function render2() {
|
|
66585
66799
|
const tasks = listTasks({ project_id: projectId, status: statusFilter });
|
|
66586
66800
|
const all = listTasks({ project_id: projectId });
|
|
@@ -69187,8 +69401,8 @@ Findings`));
|
|
|
69187
69401
|
const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
|
|
69188
69402
|
const { statSync: statSync12 } = await import("fs");
|
|
69189
69403
|
const { join: join27 } = await import("path");
|
|
69190
|
-
const
|
|
69191
|
-
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join27(
|
|
69404
|
+
const { getHomeDir: getHomeDir2 } = await Promise.resolve().then(() => (init_sync_utils(), exports_sync_utils));
|
|
69405
|
+
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join27(getHomeDir2(), ".hasna", "todos", "todos.db");
|
|
69192
69406
|
let size = "unknown";
|
|
69193
69407
|
try {
|
|
69194
69408
|
size = `${(statSync12(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -72353,7 +72567,8 @@ var init_mcp_hooks_commands = __esm(() => {
|
|
|
72353
72567
|
init_tasks();
|
|
72354
72568
|
init_helpers();
|
|
72355
72569
|
init_cloud_router();
|
|
72356
|
-
|
|
72570
|
+
init_sync_utils();
|
|
72571
|
+
HOME2 = getHomeDir();
|
|
72357
72572
|
});
|
|
72358
72573
|
|
|
72359
72574
|
// src/cli/commands/dispatch.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;
|
|
1
|
+
{"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;AAoEvD,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAC9C,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAAG,IAAI,CASnH;AAuWD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,MAAM,EAA0B,EACtC,GAAG,GAAE,GAAwB,GAC5B,+BAA+B,CAgBjC"}
|