@hasna/todos 0.13.6 → 0.13.8

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.
@@ -0,0 +1,72 @@
1
+ /** The subset of an agent row this validator needs. */
2
+ export interface KnownAgent {
3
+ id: string;
4
+ name: string;
5
+ }
6
+ export interface AssigneeContext {
7
+ /** Every agent row known to the store. */
8
+ agents: KnownAgent[];
9
+ /** Roster seat slugs, normalised. See {@link loadSeatSlugs}. */
10
+ seats: Set<string>;
11
+ /** Caller passed `--assign-seat`: filing at a seat is deliberate. */
12
+ allowSeat?: boolean;
13
+ }
14
+ /**
15
+ * Three outcomes, and the split between REFUSE and WARN is evidence-driven
16
+ * rather than a matter of taste:
17
+ *
18
+ * - `seat` REFUSES. The seat list is a closed, declared set and an owner
19
+ * directive says the row is ownerless. There is no honest reading of
20
+ * `--assign agent-ceo` that means "a session will pick this up".
21
+ * - `ambiguous` REFUSES. The name certainly exists; what cannot be done is
22
+ * PICK, and picking the first row is precisely how a task lands on a
23
+ * stranger. A fresh store cannot trip this, because a name has to occupy two
24
+ * rows to be ambiguous.
25
+ * - `unknown` only WARNS. Assigning to an agent that has not registered yet is
26
+ * a REAL, EXISTING, TESTED contract in this CLI — `todos add --assign
27
+ * brutus` against a store where brutus has never registered must succeed
28
+ * (src/cli/creator-attribution.test.ts). Refusing it broke 9 existing tests
29
+ * when this validator was first written to refuse, which is exactly the
30
+ * legitimate flow that measurement was supposed to find. The check cannot
31
+ * tell a typo from a not-yet-registered agent, so it says so and gets out of
32
+ * the way.
33
+ */
34
+ export type AssigneeVerdict = {
35
+ ok: true;
36
+ assignee: string;
37
+ agentId?: string;
38
+ isSeat: boolean;
39
+ warning?: string;
40
+ } | {
41
+ ok: false;
42
+ reason: "seat" | "ambiguous";
43
+ message: string;
44
+ candidates?: KnownAgent[];
45
+ };
46
+ /**
47
+ * The canonical declarative seat roster, in the `AgentRoster` format shipped
48
+ * by `@hasna/identities`. `identities` has no built-in path for it — every
49
+ * consumer passes `--roster <file>` — so the path is config here, not a
50
+ * constant baked into a code path.
51
+ */
52
+ export declare function defaultSeatRosterPath(): string;
53
+ /**
54
+ * Read seat slugs out of the roster file.
55
+ *
56
+ * Returns an EMPTY SET on a missing or malformed roster, and never throws. The
57
+ * roster is a station-local file that does not exist inside an e2b sandbox or
58
+ * a cloud runner, and a validator that refused every assignment when it could
59
+ * not find its config would be a worse defect than the one it fixes. The cost
60
+ * of degrading is bounded and stated: without the roster the seat check is
61
+ * skipped, while the unknown-agent and ambiguous-name checks still apply.
62
+ */
63
+ export declare function loadSeatSlugs(path?: string): Set<string>;
64
+ /**
65
+ * Resolve and validate an `--assign` value.
66
+ *
67
+ * Accepts either an agent name (case-insensitive) or an agent ID. An ID is
68
+ * resolved to its name first, so that passing a seat's ID is caught by the
69
+ * seat rule exactly as passing its slug is.
70
+ */
71
+ export declare function validateAssignee(input: string, ctx: AssigneeContext): AssigneeVerdict;
72
+ //# sourceMappingURL=assignee-validation.d.ts.map
@@ -0,0 +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;CACrB;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,CAoErF"}
@@ -1 +1 @@
1
- {"version":3,"file":"claude-tasks.d.ts","sourceRoot":"","sources":["../../src/lib/claude-tasks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwF9D;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CA4GZ;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAwFZ;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAQZ"}
1
+ {"version":3,"file":"claude-tasks.d.ts","sourceRoot":"","sources":["../../src/lib/claude-tasks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA0F9D;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAgHZ;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAwFZ;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAQZ"}
@@ -66,5 +66,35 @@ export declare function clearPersistedIdentity(): boolean;
66
66
  * exists to remove.
67
67
  */
68
68
  export declare function canonicalAgentRef(value: string): string;
69
+ /**
70
+ * Is this identity bound to THIS PROCESS, or merely lying around on the disk?
71
+ *
72
+ * `explicit` (--agent) and `env` (TODOS_AGENT_ID) travel with the process, so two
73
+ * concurrent sessions cannot be handed the same one by accident. `persisted` is a
74
+ * single file keyed on $HOME, and this fleet runs many named agent sessions per
75
+ * station under one HOME — so it identifies the STATION, never the caller.
76
+ *
77
+ * The write side was already guarded: `todos init` refuses to clobber a foreign
78
+ * identity (detectIdentityCollision). Nothing guarded the read side, and that is
79
+ * the whole defect — refusing to record session B's identity silently converted
80
+ * into attributing B's work to A. Measured on station01 2026-07-31: one agent ran
81
+ * `todos init` at 17:31:04Z and every unregistered session on the box filed as it
82
+ * from 17:37:36Z onward.
83
+ *
84
+ * So an ambient identity may be DISPLAYED, but it must never be written into a
85
+ * task. A wrong name is worse than a missing one — this module's own doctrine —
86
+ * and it is worse here in the direction that costs most: `assigned_to` is the
87
+ * queue every seat reads, and `agent_id` is a filterable column
88
+ * (task-crud.ts `filter.agent_id`) that also stands in as the acting agent
89
+ * wherever `assigned_to` is null (`task.assigned_to || task.agent_id`).
90
+ */
91
+ export declare function isProcessBoundSource(source: CreatorIdentitySource): boolean;
92
+ /**
93
+ * The identity this process may WRITE onto a task, or null when it has none.
94
+ *
95
+ * Deliberately narrower than `resolveCreatorIdentity`, which still reports the
96
+ * ambient identity so that `todos init`/diagnostics can show what is on disk.
97
+ */
98
+ export declare function resolveWritableIdentity(explicit?: string | null): ResolvedCreatorIdentity;
69
99
  export declare function resolveCreatorIdentity(explicit?: string | null): ResolvedCreatorIdentity;
70
100
  //# sourceMappingURL=creator-identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"creator-identity.d.ts","sourceRoot":"","sources":["../../src/lib/creator-identity.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,IAAI,CAMhE;AAED,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAOrG;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAU3H;AAED,6GAA6G;AAC7G,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,uBAAuB,CAmBxF"}
1
+ {"version":3,"file":"creator-identity.d.ts","sourceRoot":"","sources":["../../src/lib/creator-identity.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,IAAI,CAMhE;AAED,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAOrG;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAU3H;AAED,6GAA6G;AAC7G,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,uBAAuB,CAIzF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,uBAAuB,CAmBxF"}
@@ -1,4 +1,5 @@
1
1
  import type { SyncConflict } from "./sync-types.js";
2
+ export declare const TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint";
2
3
  export declare const HOME: string;
3
4
  export declare function getHomeDir(): string;
4
5
  export declare function getTodosGlobalDir(): string;
@@ -11,4 +12,10 @@ export declare function writeHighWaterMark(dir: string, value: number): void;
11
12
  export declare function getFileMtimeMs(path: string): number | null;
12
13
  export declare function parseTimestamp(value: unknown): number | null;
13
14
  export declare function appendSyncConflict(metadata: Record<string, unknown>, conflict: SyncConflict, limit?: number): Record<string, unknown>;
15
+ export declare function withSyncFingerprint<T extends {
16
+ metadata: Record<string, unknown>;
17
+ }>(record: T): T;
18
+ export declare function hasSyncFingerprintChanged(record: {
19
+ metadata?: Record<string, unknown>;
20
+ }): boolean | null;
14
21
  //# sourceMappingURL=sync-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-utils.d.ts","sourceRoot":"","sources":["../../src/lib/sync-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,eAAO,MAAM,IAAI,QAA2D,CAAC;AAE7E,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGnD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAMtD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI5D;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,YAAY,EACtB,KAAK,SAAI,GACR,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzB"}
1
+ {"version":3,"file":"sync-utils.d.ts","sourceRoot":"","sources":["../../src/lib/sync-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAElE,eAAO,MAAM,IAAI,QAA2D,CAAC;AAE7E,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGnD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAMtD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI5D;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,YAAY,EACtB,KAAK,SAAI,GACR,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzB;AAsBD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CASjG;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,OAAO,GAAG,IAAI,CAIxG"}