@hasna/todos 0.13.10 → 0.13.11
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/assignee-guard.d.ts +8 -1
- package/dist/cli/assignee-guard.d.ts.map +1 -1
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +9 -8
- package/dist/contracts.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/assignee-validation.d.ts +22 -0
- package/dist/lib/assignee-validation.d.ts.map +1 -1
- package/dist/mcp/index.js +3 -2
- package/dist/mcp.js +1 -1
- package/dist/registry.js +1 -1
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +3 -2
- package/package.json +1 -1
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Refusal exits the process via `handleError` (typed `never`), so a caller
|
|
10
10
|
* cannot accidentally fall through to a silent self-assign.
|
|
11
|
+
*
|
|
12
|
+
* `buildSeatHint` is REQUIRED, not optional, and deliberately has no default:
|
|
13
|
+
* every call site takes the assignee on a different real shape (a
|
|
14
|
+
* `--assign <agent>` flag on three verbs, a bare positional on the fourth),
|
|
15
|
+
* so there is no invocation-shaped default that is correct everywhere. See
|
|
16
|
+
* {@link AssigneeContext.seatHint} for why a shared default was exactly the
|
|
17
|
+
* bug (todos 75296282).
|
|
11
18
|
*/
|
|
12
|
-
export declare function resolveValidatedAssignee(value: string, allowSeat: boolean): Promise<string>;
|
|
19
|
+
export declare function resolveValidatedAssignee(value: string, allowSeat: boolean, buildSeatHint: (value: string) => string): Promise<string>;
|
|
13
20
|
//# sourceMappingURL=assignee-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assignee-guard.d.ts","sourceRoot":"","sources":["../../src/cli/assignee-guard.ts"],"names":[],"mappings":"AAmBA
|
|
1
|
+
{"version":3,"file":"assignee-guard.d.ts","sourceRoot":"","sources":["../../src/cli/assignee-guard.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,EAClB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GACvC,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/query-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgPzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"query-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/query-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgPzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,QA6qGrD"}
|
|
@@ -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;AA0DzC,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAkPD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,
|
|
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;AA0DzC,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAkPD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAqiDpD"}
|
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.13.
|
|
2126
|
+
version: "0.13.11",
|
|
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",
|
|
@@ -19090,10 +19090,11 @@ function validateAssignee(input, ctx) {
|
|
|
19090
19090
|
if (ctx.allowSeat) {
|
|
19091
19091
|
return { ok: true, assignee: byId ? byId.name : raw, agentId: byId?.id, isSeat: true };
|
|
19092
19092
|
}
|
|
19093
|
+
const hint = ctx.seatHint?.(raw);
|
|
19093
19094
|
return {
|
|
19094
19095
|
ok: false,
|
|
19095
19096
|
reason: "seat",
|
|
19096
|
-
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or
|
|
19097
|
+
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or repeat the command with --assign-seat added to confirm the seat is deliberate` + (hint ? `: ${hint}` : " (see --help for this command's exact form).")
|
|
19097
19098
|
};
|
|
19098
19099
|
}
|
|
19099
19100
|
if (byId) {
|
|
@@ -19821,10 +19822,10 @@ var init_agents = __esm(() => {
|
|
|
19821
19822
|
|
|
19822
19823
|
// src/cli/assignee-guard.ts
|
|
19823
19824
|
import chalk2 from "chalk";
|
|
19824
|
-
async function resolveValidatedAssignee(value, allowSeat) {
|
|
19825
|
+
async function resolveValidatedAssignee(value, allowSeat, buildSeatHint) {
|
|
19825
19826
|
const cloud = getTodosCloudClient();
|
|
19826
19827
|
const ctx = await loadAssigneeContext(() => cloud ? cloudListAgents(cloud) : listAgents(), allowSeat);
|
|
19827
|
-
const verdict = validateAssignee(value, ctx);
|
|
19828
|
+
const verdict = validateAssignee(value, { ...ctx, seatHint: buildSeatHint });
|
|
19828
19829
|
if (!verdict.ok) {
|
|
19829
19830
|
handleError(new Error(`Cannot assign to '${value}'. ${verdict.message}`));
|
|
19830
19831
|
}
|
|
@@ -20344,7 +20345,7 @@ function registerTaskCommands(program2) {
|
|
|
20344
20345
|
opts.list = opts.list || opts.taskList;
|
|
20345
20346
|
const creator = resolveCreatorIdentity(opts.createdBy || globalOpts.agent);
|
|
20346
20347
|
const router = resolveWritableIdentity(opts.createdBy || globalOpts.agent);
|
|
20347
|
-
const requestedAssign = opts.assign ? await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat)) : undefined;
|
|
20348
|
+
const requestedAssign = opts.assign ? await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat), (v) => `--assign ${v} --assign-seat`) : undefined;
|
|
20348
20349
|
const assignee = requestedAssign || (opts.unassigned ? undefined : router.agent_id || undefined);
|
|
20349
20350
|
if (!assignee && !opts.unassigned) {
|
|
20350
20351
|
console.error(chalk3.yellow("Warning: task is ownerless and unattributable \u2014 export TODOS_AGENT_ID=<name> for this session, or pass --agent/--assign <agent> or --unassigned."));
|
|
@@ -20447,7 +20448,7 @@ function registerTaskCommands(program2) {
|
|
|
20447
20448
|
opts.tags = opts.tags || opts.tag;
|
|
20448
20449
|
opts.list = opts.list || opts.taskList;
|
|
20449
20450
|
if (opts.assign) {
|
|
20450
|
-
opts.assign = await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat));
|
|
20451
|
+
opts.assign = await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat), (v) => `--assign ${v} --assign-seat`);
|
|
20451
20452
|
}
|
|
20452
20453
|
const explicitProject = opts.project || globalOpts.project;
|
|
20453
20454
|
const cloud = getTodosCloudClient();
|
|
@@ -21108,7 +21109,7 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
21108
21109
|
handleError(new Error("Use either --working-dir or --clear-working-dir, not both."));
|
|
21109
21110
|
}
|
|
21110
21111
|
if (opts.assign) {
|
|
21111
|
-
opts.assign = await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat));
|
|
21112
|
+
opts.assign = await resolveValidatedAssignee(opts.assign, Boolean(opts.assignSeat), (v) => `--assign ${v} --assign-seat`);
|
|
21112
21113
|
}
|
|
21113
21114
|
const cloud = getTodosCloudClient();
|
|
21114
21115
|
if (cloud) {
|
|
@@ -68355,7 +68356,7 @@ No task claimed (nothing available).`));
|
|
|
68355
68356
|
});
|
|
68356
68357
|
program2.command("assign <id> <agent>").description("Assign a task to an agent").option("-j, --json", "Output as JSON").option("--assign-seat", "Allow <agent> to name a durable seat (a seat queue has no session watching it)").action(async (id, agentInput, opts) => {
|
|
68357
68358
|
const globalOpts = program2.opts();
|
|
68358
|
-
const agent = await resolveValidatedAssignee(agentInput, Boolean(opts.assignSeat));
|
|
68359
|
+
const agent = await resolveValidatedAssignee(agentInput, Boolean(opts.assignSeat), (v) => `${id} ${v} --assign-seat`);
|
|
68359
68360
|
const cloud = getTodosCloudClient();
|
|
68360
68361
|
if (cloud) {
|
|
68361
68362
|
try {
|
package/dist/contracts.js
CHANGED
|
@@ -12009,7 +12009,7 @@ var init_tasks = __esm(() => {
|
|
|
12009
12009
|
// package.json
|
|
12010
12010
|
var package_default = {
|
|
12011
12011
|
name: "@hasna/todos",
|
|
12012
|
-
version: "0.13.
|
|
12012
|
+
version: "0.13.11",
|
|
12013
12013
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12014
12014
|
type: "module",
|
|
12015
12015
|
main: "dist/index.js",
|
package/dist/index.js
CHANGED
|
@@ -12122,7 +12122,7 @@ var init_dispatches = __esm(() => {
|
|
|
12122
12122
|
// package.json
|
|
12123
12123
|
var package_default = {
|
|
12124
12124
|
name: "@hasna/todos",
|
|
12125
|
-
version: "0.13.
|
|
12125
|
+
version: "0.13.11",
|
|
12126
12126
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12127
12127
|
type: "module",
|
|
12128
12128
|
main: "dist/index.js",
|
|
@@ -10,6 +10,28 @@ export interface AssigneeContext {
|
|
|
10
10
|
seats: Set<string>;
|
|
11
11
|
/** Caller passed `--assign-seat`: filing at a seat is deliberate. */
|
|
12
12
|
allowSeat?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Builds the exact runnable suffix that pairs `--assign-seat` with the
|
|
15
|
+
* refused value, FOR THE VERB THE CALLER IS ACTUALLY ON.
|
|
16
|
+
*
|
|
17
|
+
* This function is shared by four call sites — `add`, `update`,
|
|
18
|
+
* `task upsert`, and the standalone `assign <id> <agent>` — and three of
|
|
19
|
+
* them take the assignee via a `--assign <agent>` FLAG while the fourth
|
|
20
|
+
* takes it POSITIONALLY with no `--assign` flag at all. A single hardcoded
|
|
21
|
+
* `--assign <value> --assign-seat` snippet is therefore correct for three
|
|
22
|
+
* verbs and `error: unknown option '--assign'` on the fourth (todos
|
|
23
|
+
* 75296282, PR hasna/todos#162 review by pr162-reviewer, cycle 1): the
|
|
24
|
+
* seat-refusal message recommended an invocation the verb it was printed
|
|
25
|
+
* from does not accept — the exact class of defect the message exists to
|
|
26
|
+
* remove, relocated rather than fixed.
|
|
27
|
+
*
|
|
28
|
+
* Each call site supplies its own builder naming its own real shape, so the
|
|
29
|
+
* message can never again claim a flag a given verb does not have.
|
|
30
|
+
* Undefined falls back to naming `--assign-seat` in prose with no runnable
|
|
31
|
+
* snippet, which is always safe because it recommends no invocation shape
|
|
32
|
+
* at all.
|
|
33
|
+
*/
|
|
34
|
+
seatHint?: (value: string) => string;
|
|
13
35
|
}
|
|
14
36
|
/**
|
|
15
37
|
* Three outcomes, and the split between REFUSE and WARN is evidence-driven
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assignee-validation.d.ts","sourceRoot":"","sources":["../../src/lib/assignee-validation.ts"],"names":[],"mappings":"AA2CA,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,gEAAgE;IAChE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"assignee-validation.d.ts","sourceRoot":"","sources":["../../src/lib/assignee-validation.ts"],"names":[],"mappings":"AA2CA,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,gEAAgE;IAChE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAK9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAgC,GAAG,GAAG,CAAC,MAAM,CAAC,CAajF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,eAAe,CAsErF"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -18012,10 +18012,11 @@ function validateAssignee(input, ctx) {
|
|
|
18012
18012
|
if (ctx.allowSeat) {
|
|
18013
18013
|
return { ok: true, assignee: byId ? byId.name : raw, agentId: byId?.id, isSeat: true };
|
|
18014
18014
|
}
|
|
18015
|
+
const hint = ctx.seatHint?.(raw);
|
|
18015
18016
|
return {
|
|
18016
18017
|
ok: false,
|
|
18017
18018
|
reason: "seat",
|
|
18018
|
-
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or
|
|
18019
|
+
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or repeat the command with --assign-seat added to confirm the seat is deliberate` + (hint ? `: ${hint}` : " (see --help for this command's exact form).")
|
|
18019
18020
|
};
|
|
18020
18021
|
}
|
|
18021
18022
|
if (byId) {
|
|
@@ -34842,7 +34843,7 @@ var package_default;
|
|
|
34842
34843
|
var init_package = __esm(() => {
|
|
34843
34844
|
package_default = {
|
|
34844
34845
|
name: "@hasna/todos",
|
|
34845
|
-
version: "0.13.
|
|
34846
|
+
version: "0.13.11",
|
|
34846
34847
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
34847
34848
|
type: "module",
|
|
34848
34849
|
main: "dist/index.js",
|
package/dist/mcp.js
CHANGED
|
@@ -41,7 +41,7 @@ var __require = import.meta.require;
|
|
|
41
41
|
// package.json
|
|
42
42
|
var package_default = {
|
|
43
43
|
name: "@hasna/todos",
|
|
44
|
-
version: "0.13.
|
|
44
|
+
version: "0.13.11",
|
|
45
45
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
46
46
|
type: "module",
|
|
47
47
|
main: "dist/index.js",
|
package/dist/registry.js
CHANGED
|
@@ -12009,7 +12009,7 @@ var init_tasks = __esm(() => {
|
|
|
12009
12009
|
// package.json
|
|
12010
12010
|
var package_default = {
|
|
12011
12011
|
name: "@hasna/todos",
|
|
12012
|
-
version: "0.13.
|
|
12012
|
+
version: "0.13.11",
|
|
12013
12013
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12014
12014
|
type: "module",
|
|
12015
12015
|
main: "dist/index.js",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@hasna/todos",
|
|
3
|
-
"packageVersion": "0.13.
|
|
3
|
+
"packageVersion": "0.13.11",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"gitTree": "
|
|
7
|
-
"sourceTreeSha256": "
|
|
8
|
-
"generatedAt": "2026-08-
|
|
5
|
+
"gitCommit": "af551bd57da4ef1835d763232c1e3b3b8cee4f9f",
|
|
6
|
+
"gitTree": "23029d1f9a1afeecf519674e13746e615431ae8b",
|
|
7
|
+
"sourceTreeSha256": "b14e57ef9ec0cbd0e0142681b993aa34c941d59a18649ddd499f3ee1a62cfef9",
|
|
8
|
+
"generatedAt": "2026-08-02T06:21:53.000Z"
|
|
9
9
|
}
|
package/dist/server/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var package_default;
|
|
|
70
70
|
var init_package = __esm(() => {
|
|
71
71
|
package_default = {
|
|
72
72
|
name: "@hasna/todos",
|
|
73
|
-
version: "0.13.
|
|
73
|
+
version: "0.13.11",
|
|
74
74
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
75
75
|
type: "module",
|
|
76
76
|
main: "dist/index.js",
|
|
@@ -44798,10 +44798,11 @@ function validateAssignee(input, ctx) {
|
|
|
44798
44798
|
if (ctx.allowSeat) {
|
|
44799
44799
|
return { ok: true, assignee: byId ? byId.name : raw, agentId: byId?.id, isSeat: true };
|
|
44800
44800
|
}
|
|
44801
|
+
const hint = ctx.seatHint?.(raw);
|
|
44801
44802
|
return {
|
|
44802
44803
|
ok: false,
|
|
44803
44804
|
reason: "seat",
|
|
44804
|
-
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or
|
|
44805
|
+
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or repeat the command with --assign-seat added to confirm the seat is deliberate` + (hint ? `: ${hint}` : " (see --help for this command's exact form).")
|
|
44805
44806
|
};
|
|
44806
44807
|
}
|
|
44807
44808
|
if (byId) {
|