agent-tasks 1.5.0 → 1.6.5

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.
Files changed (49) hide show
  1. package/README.md +149 -42
  2. package/dist/context.d.ts +4 -0
  3. package/dist/context.d.ts.map +1 -1
  4. package/dist/context.js +11 -0
  5. package/dist/context.js.map +1 -1
  6. package/dist/domain/approvals.d.ts +1 -0
  7. package/dist/domain/approvals.d.ts.map +1 -1
  8. package/dist/domain/approvals.js +13 -3
  9. package/dist/domain/approvals.js.map +1 -1
  10. package/dist/domain/collaborators.d.ts +1 -0
  11. package/dist/domain/collaborators.d.ts.map +1 -1
  12. package/dist/domain/collaborators.js +14 -1
  13. package/dist/domain/collaborators.js.map +1 -1
  14. package/dist/domain/comments.d.ts.map +1 -1
  15. package/dist/domain/comments.js +6 -3
  16. package/dist/domain/comments.js.map +1 -1
  17. package/dist/domain/events.d.ts +1 -0
  18. package/dist/domain/events.d.ts.map +1 -1
  19. package/dist/domain/events.js +13 -4
  20. package/dist/domain/events.js.map +1 -1
  21. package/dist/domain/rules.js +46 -46
  22. package/dist/domain/tasks.d.ts +8 -2
  23. package/dist/domain/tasks.d.ts.map +1 -1
  24. package/dist/domain/tasks.js +61 -22
  25. package/dist/domain/tasks.js.map +1 -1
  26. package/dist/domain/validate.d.ts +2 -0
  27. package/dist/domain/validate.d.ts.map +1 -1
  28. package/dist/domain/validate.js +5 -2
  29. package/dist/domain/validate.js.map +1 -1
  30. package/dist/index.js +13 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/storage/database.js +10 -1
  33. package/dist/storage/database.js.map +1 -1
  34. package/dist/transport/mcp.d.ts.map +1 -1
  35. package/dist/transport/mcp.js +165 -7
  36. package/dist/transport/mcp.js.map +1 -1
  37. package/dist/transport/rest.d.ts.map +1 -1
  38. package/dist/transport/rest.js +183 -12
  39. package/dist/transport/rest.js.map +1 -1
  40. package/dist/transport/ws.d.ts.map +1 -1
  41. package/dist/transport/ws.js +39 -25
  42. package/dist/transport/ws.js.map +1 -1
  43. package/dist/types.d.ts +2 -1
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/types.js.map +1 -1
  46. package/dist/ui/app.js +1956 -648
  47. package/dist/ui/index.html +97 -14
  48. package/dist/ui/styles.css +2023 -316
  49. package/package.json +84 -78
package/README.md CHANGED
@@ -1,26 +1,92 @@
1
1
  # agent-tasks
2
2
 
3
- Pipeline-driven task management for AI coding agents. An [MCP](https://modelcontextprotocol.io/) server that provides stage-gated task pipelines with dependencies, artifacts, and multi-agent claiming.
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20.11-brightgreen)](https://nodejs.org/)
5
+ [![Tests](https://img.shields.io/badge/tests-337%20passing-brightgreen)]()
6
+ [![MCP Tools](https://img.shields.io/badge/MCP%20tools-31-purple)]()
7
+ [![REST Endpoints](https://img.shields.io/badge/REST-19%20endpoints-orange)]()
4
8
 
5
- Part of the **agent-\*** family: [`agent-comm`](https://github.com/keshrath/agent-comm) (messaging) + `agent-tasks` (pipeline).
9
+ **Pipeline-driven task management for AI coding agents.** An [MCP](https://modelcontextprotocol.io/) server with stage-gated pipelines, multi-agent collaboration, and a real-time kanban dashboard. Tasks flow through configurable stages — `backlog`, `spec`, `plan`, `implement`, `test`, `review`, `done` — with dependency tracking, approval workflows, artifact versioning, and threaded comments.
10
+
11
+ Built for AI coding agents (Claude Code, Codex CLI, Gemini CLI, Aider) but works equally well with any MCP client, REST consumer, or WebSocket listener.
12
+
13
+ ---
14
+
15
+ | Light Theme | Dark Theme |
16
+ | -------------------------------------------------------- | ------------------------------------------------------ |
17
+ | ![Light mode dashboard](docs/assets/dashboard-light.png) | ![Dark mode dashboard](docs/assets/dashboard-dark.png) |
18
+
19
+ ---
20
+
21
+ ## Why agent-tasks?
22
+
23
+ When you run multiple AI agents on the same codebase, they need a shared task pipeline — not just a flat todo list. They need stages, dependencies, approvals, and visibility.
24
+
25
+ ---
6
26
 
7
27
  ## Features
8
28
 
9
- - **Pipeline stages** — tasks flow through configurable stages: `backlog spec plan implement test review done`
10
- - **Dependencies** — tasks can depend on other tasks; advancement is blocked until dependencies are met (with cycle detection)
11
- - **Artifacts** — attach specs, plans, test results, review notes to tasks at each stage
12
- - **Multi-agent claiming** — agents claim tasks from a shared queue; highest-priority unblocked task is served first
13
- - **Per-project pipelines** — customize stage definitions per project
14
- - **SQLite storage** — WAL-mode SQLite via better-sqlite3 for concurrent access
29
+ - **Pipeline stages** — configurable per project: `backlog` > `spec` > `plan` > `implement` > `test` > `review` > `done`
30
+ - **Task dependencies** — DAG with automatic cycle detection; blocks advancement until resolved
31
+ - **Approval workflows** — stage-gated approve/reject with auto-regress on rejection
32
+ - **Multi-agent collaboration** — roles (collaborator, reviewer, watcher), claiming, assignment
33
+ - **Subtask hierarchies** — parent/child task trees with progress tracking
34
+ - **Threaded comments** — async discussions between agents on any task
35
+ - **Artifact versioning** — per-stage document attachments with automatic versioning and diff viewer
36
+ - **Full-text search** — FTS5 search across task titles and descriptions
37
+ - **Real-time kanban dashboard** — drag-and-drop, side panel, inline creation, dark/light theme
38
+ - **3 transport layers** — MCP (stdio), REST API (HTTP), WebSocket (real-time events)
39
+ - **TodoWrite bridge** — intercepts Claude Code's built-in TodoWrite and syncs to the pipeline
40
+ - **Task cleanup hooks** — auto-fails orphaned tasks on session stop and cleans up stale tasks on session start
41
+ - **Agent bridge** — notifies connected agents on task events
42
+
43
+ ---
15
44
 
16
45
  ## Quick Start
17
46
 
47
+ ### Install from npm
48
+
49
+ ```bash
50
+ npm install -g agent-tasks
51
+ ```
52
+
53
+ ### Or clone from source
54
+
18
55
  ```bash
56
+ git clone https://github.com/keshrath/agent-tasks.git
57
+ cd agent-tasks
19
58
  npm install
20
59
  npm run build
21
60
  ```
22
61
 
23
- ### As an MCP server (stdio)
62
+ ### Option 1: MCP server (for AI agents)
63
+
64
+ Add to your MCP client config (Claude Code, Cline, etc.):
65
+
66
+ ```json
67
+ {
68
+ "mcpServers": {
69
+ "agent-tasks": {
70
+ "command": "npx",
71
+ "args": ["agent-tasks"]
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ The dashboard auto-starts at http://localhost:3422 on the first MCP connection.
78
+
79
+ ### Option 2: Standalone server (for REST/WebSocket clients)
80
+
81
+ ```bash
82
+ node dist/server.js --port 3422
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Claude Code Integration
88
+
89
+ Add agent-tasks as an MCP server in `~/.claude/settings.json`:
24
90
 
25
91
  ```json
26
92
  {
@@ -33,42 +99,83 @@ npm run build
33
99
  }
34
100
  ```
35
101
 
36
- ## Tools
37
-
38
- | Tool | Description |
39
- | ------------------------ | ------------------------------------------------------------------------- |
40
- | `task_create` | Create a task with title, description, stage, priority, project, tags |
41
- | `task_list` | List tasks with filters (status, assignee, stage, project) and pagination |
42
- | `task_claim` | Claim a pending task — assigns it and advances from backlog |
43
- | `task_complete` | Mark a task as completed with a result |
44
- | `task_fail` | Mark a task as failed with an error |
45
- | `task_cancel` | Cancel a task |
46
- | `task_advance` | Advance to the next (or a specific) stage; checks dependencies |
47
- | `task_regress` | Send a task back to an earlier stage (e.g. review rejection) |
48
- | `task_update` | Update task metadata (title, description, priority, tags, assignee) |
49
- | `task_next` | Get the highest-priority unassigned task with all dependencies met |
50
- | `task_add_dependency` | Add a dependency between tasks (with cycle detection) |
51
- | `task_remove_dependency` | Remove a dependency |
52
- | `task_add_artifact` | Attach a document/artifact to a task at a specific stage |
53
- | `task_get_artifacts` | Retrieve artifacts for a task |
54
- | `task_pipeline_config` | Get or set pipeline stages for a project |
55
- | `task_set_session` | Set the session identity for tracking who creates/claims tasks |
56
-
57
- ## Configuration
58
-
59
- | Environment Variable | Description | Default |
60
- | -------------------- | ------------------------------------ | -------------------------- |
61
- | `AGENT_TASKS_DB` | Path to SQLite database | `~/.claude/agent-tasks.db` |
62
- | `AGENT_TASKS_TEST` | Use in-memory database (for testing) | — |
63
-
64
- ## Development
102
+ Once configured, Claude Code can use all 31 MCP tools directly — creating tasks, advancing stages, adding artifacts, commenting, and more. See the [Setup Guide](docs/SETUP.md) for detailed integration steps.
103
+
104
+ ---
105
+
106
+ ## MCP Tools (33)
107
+
108
+ | Category | Tools |
109
+ | ----------------------- | ----------------------------------------------------------------------------------------------------------- |
110
+ | **Task lifecycle** (12) | `task_create`, `task_list`, `task_next`, `task_claim`, `task_advance`, `task_regress`, `task_complete`, ... |
111
+ | **Subtasks & deps** (4) | `task_expand`, `task_get_subtasks`, `task_add_dependency`, `task_remove_dependency` |
112
+ | **Artifacts** (2) | `task_add_artifact`, `task_get_artifacts` |
113
+ | **Comments** (2) | `task_comment`, `task_get_comments` |
114
+ | **Collaboration** (2) | `task_add_collaborator`, `task_remove_collaborator` |
115
+ | **Approvals** (5) | `task_request_approval`, `task_approve`, `task_reject`, `task_pending_approvals`, `task_review_cycle` |
116
+ | **Config & utils** (4) | `task_pipeline_config`, `task_set_session`, `task_cleanup`, `task_generate_rules` |
117
+
118
+ See [full API reference](docs/API.md) for detailed descriptions of every tool and endpoint.
119
+
120
+ ## REST API (19 endpoints)
121
+
122
+ All endpoints return JSON. CORS enabled. See [full API reference](docs/API.md#rest-api-18-endpoints) for details.
123
+
124
+ ```
125
+ GET /health Health check with version + uptime
126
+ GET /api/tasks List tasks (status, stage, project, assignee filters)
127
+ GET /api/tasks/:id Get a single task
128
+ GET /api/tasks/:id/subtasks Subtasks of a parent
129
+ GET /api/tasks/:id/artifacts Artifacts (filter by stage)
130
+ GET /api/tasks/:id/comments Comments on a task
131
+ GET /api/tasks/:id/dependencies Dependencies for a task
132
+ GET /api/dependencies All dependencies across all tasks
133
+ GET /api/pipeline Pipeline stage configuration
134
+ GET /api/overview Full state dump
135
+ GET /api/agents Online agents
136
+ GET /api/search?q= Full-text search
137
+
138
+ POST /api/tasks Create a new task
139
+ PUT /api/tasks/:id Update task fields
140
+ PUT /api/tasks/:id/stage Change stage (advance or regress)
141
+ POST /api/tasks/:id/comments Add a comment
142
+ POST /api/cleanup Trigger manual cleanup
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Testing
65
148
 
66
149
  ```bash
67
- npm run dev # watch mode
68
- npm test # run tests
69
- npm run check # typecheck + lint + format + test
150
+ npm test # 337 tests across 12 suites
151
+ npm run test:watch # Watch mode
152
+ npm run test:coverage # Coverage report
153
+ npm run check # Full CI: typecheck + lint + format + test
70
154
  ```
71
155
 
156
+ ---
157
+
158
+ ## Environment variables
159
+
160
+ | Variable | Default | Description |
161
+ | -------------------------- | ------------------------------- | ---------------------------------------------------- |
162
+ | `AGENT_TASKS_DB` | `~/.agent-tasks/agent-tasks.db` | SQLite database file path |
163
+ | `AGENT_TASKS_PORT` | `3422` | Dashboard HTTP/WebSocket port |
164
+ | `AGENT_TASKS_INSTRUCTIONS` | enabled | Set to `0` to disable response-embedded instructions |
165
+ | `AGENT_COMM_URL` | `http://localhost:3421` | Agent-comm REST URL for bridge notifications |
166
+
167
+ ---
168
+
169
+ ## Documentation
170
+
171
+ - [API Reference](docs/API.md) — all 31 MCP tools, 19 REST endpoints, WebSocket protocol
172
+ - [Architecture](docs/ARCHITECTURE.md) — source structure, design principles, database schema
173
+ - [Dashboard](docs/DASHBOARD.md) — kanban board features, keyboard shortcuts, screenshots
174
+ - [Setup Guide](docs/SETUP.md) — installation, client setup (Claude Code, OpenCode, Cursor, Windsurf), hooks
175
+ - [Changelog](CHANGELOG.md)
176
+
177
+ ---
178
+
72
179
  ## License
73
180
 
74
- MIT
181
+ MIT — see [LICENSE](LICENSE)
package/dist/context.d.ts CHANGED
@@ -4,6 +4,8 @@ import { TaskService } from './domain/tasks.js';
4
4
  import { CommentService } from './domain/comments.js';
5
5
  import { CollaboratorService } from './domain/collaborators.js';
6
6
  import { ApprovalService } from './domain/approvals.js';
7
+ import { AgentBridge } from './domain/agent-bridge.js';
8
+ import { CleanupService } from './domain/cleanup.js';
7
9
  export interface AppContext {
8
10
  readonly db: Db;
9
11
  readonly events: EventBus;
@@ -11,6 +13,8 @@ export interface AppContext {
11
13
  readonly comments: CommentService;
12
14
  readonly collaborators: CollaboratorService;
13
15
  readonly approvals: ApprovalService;
16
+ readonly agentBridge: AgentBridge;
17
+ readonly cleanup: CleanupService;
14
18
  close(): void;
15
19
  }
16
20
  export declare function createContext(dbOptions?: DbOptions): AppContext;
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAOA,OAAO,EAAY,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,UAAU,CAwB/D"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAOA,OAAO,EAAY,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,UAAU,CAkC/D"}
package/dist/context.js CHANGED
@@ -10,6 +10,8 @@ import { TaskService } from './domain/tasks.js';
10
10
  import { CommentService } from './domain/comments.js';
11
11
  import { CollaboratorService } from './domain/collaborators.js';
12
12
  import { ApprovalService } from './domain/approvals.js';
13
+ import { AgentBridge } from './domain/agent-bridge.js';
14
+ import { CleanupService } from './domain/cleanup.js';
13
15
  export function createContext(dbOptions) {
14
16
  const db = createDb(dbOptions);
15
17
  const events = new EventBus();
@@ -18,6 +20,11 @@ export function createContext(dbOptions) {
18
20
  const comments = new CommentService(db, events);
19
21
  const collaborators = new CollaboratorService(db, events);
20
22
  const approvals = new ApprovalService(db, events);
23
+ const agentBridge = new AgentBridge(events);
24
+ const retentionDays = parseInt(process.env.AGENT_TASKS_RETENTION_DAYS ?? '30', 10);
25
+ const cleanup = new CleanupService(db, retentionDays);
26
+ agentBridge.start();
27
+ cleanup.start();
21
28
  return {
22
29
  db,
23
30
  events,
@@ -25,10 +32,14 @@ export function createContext(dbOptions) {
25
32
  comments,
26
33
  collaborators,
27
34
  approvals,
35
+ agentBridge,
36
+ cleanup,
28
37
  close() {
29
38
  if (closed)
30
39
  return;
31
40
  closed = true;
41
+ cleanup.stop();
42
+ agentBridge.stop();
32
43
  events.removeAll();
33
44
  db.close();
34
45
  },
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oCAAoC;AACpC,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,gFAAgF;AAEhF,OAAO,EAAE,QAAQ,EAA2B,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAYxD,MAAM,UAAU,aAAa,CAAC,SAAqB;IACjD,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,IAAI,mBAAmB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAElD,OAAO;QACL,EAAE;QACF,MAAM;QACN,KAAK;QACL,QAAQ;QACR,aAAa;QACb,SAAS;QACT,KAAK;YACH,IAAI,MAAM;gBAAE,OAAO;YACnB,MAAM,GAAG,IAAI,CAAC;YACd,MAAM,CAAC,SAAS,EAAE,CAAC;YACnB,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oCAAoC;AACpC,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,gFAAgF;AAEhF,OAAO,EAAE,QAAQ,EAA2B,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAcrD,MAAM,UAAU,aAAa,CAAC,SAAqB;IACjD,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,IAAI,mBAAmB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAEtD,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,OAAO;QACL,EAAE;QACF,MAAM;QACN,KAAK;QACL,QAAQ;QACR,aAAa;QACb,SAAS;QACT,WAAW;QACX,OAAO;QACP,KAAK;YACH,IAAI,MAAM;gBAAE,OAAO;YACnB,MAAM,GAAG,IAAI,CAAC;YACd,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,WAAW,CAAC,IAAI,EAAE,CAAC;YACnB,MAAM,CAAC,SAAS,EAAE,CAAC;YACnB,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -13,6 +13,7 @@ export declare class ApprovalService {
13
13
  isApprovalRequired(stage: string, project?: string): boolean;
14
14
  hasPendingApproval(taskId: number, stage: string): boolean;
15
15
  isApproved(taskId: number, stage: string): boolean;
16
+ private validateReviewer;
16
17
  private resolve;
17
18
  }
18
19
  //# sourceMappingURL=approvals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../src/domain/approvals.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,aAAa,CAAC;AAIhE,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY;IA6BvE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAK7E,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAM5E,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAY7C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAO1C,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAkB5D,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAQlD,OAAO,CAAC,OAAO;CA4BhB"}
1
+ {"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../src/domain/approvals.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,aAAa,CAAC;AAIhE,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY;IAiCvE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAK7E,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAM5E,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAY7C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAO1C,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAkB5D,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAQlD,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;CA4BhB"}
@@ -4,7 +4,7 @@
4
4
  // Stage-gated approvals for pipeline advancement.
5
5
  // =============================================================================
6
6
  import { NotFoundError, ConflictError, ValidationError } from '../types.js';
7
- import { rejectNullBytes } from './validate.js';
7
+ import { rejectNullBytes, rejectControlChars, MAX_AGENT_ID_LENGTH } from './validate.js';
8
8
  export class ApprovalService {
9
9
  db;
10
10
  events;
@@ -16,6 +16,9 @@ export class ApprovalService {
16
16
  const task = this.db.queryOne('SELECT id, project FROM tasks WHERE id = ?', [taskId]);
17
17
  if (!task)
18
18
  throw new NotFoundError('Task', taskId);
19
+ if (reviewer) {
20
+ this.validateReviewer(reviewer);
21
+ }
19
22
  const existing = this.db.queryOne(`SELECT * FROM task_approvals WHERE task_id = ? AND stage = ? AND status = 'pending'`, [taskId, stage]);
20
23
  if (existing)
21
24
  throw new ConflictError(`Pending approval already exists for task ${taskId} at stage ${stage}.`);
@@ -27,11 +30,11 @@ export class ApprovalService {
27
30
  return approval;
28
31
  }
29
32
  approve(approvalId, reviewer, comment) {
30
- rejectNullBytes(reviewer, 'reviewer');
33
+ this.validateReviewer(reviewer);
31
34
  return this.resolve(approvalId, 'approved', reviewer, comment);
32
35
  }
33
36
  reject(approvalId, reviewer, comment) {
34
- rejectNullBytes(reviewer, 'reviewer');
37
+ this.validateReviewer(reviewer);
35
38
  if (!comment?.trim())
36
39
  throw new ValidationError('Rejection requires a comment.');
37
40
  return this.resolve(approvalId, 'rejected', reviewer, comment);
@@ -67,6 +70,13 @@ export class ApprovalService {
67
70
  const approved = this.db.queryOne(`SELECT id FROM task_approvals WHERE task_id = ? AND stage = ? AND status = 'approved'`, [taskId, stage]);
68
71
  return !!approved;
69
72
  }
73
+ validateReviewer(reviewer) {
74
+ rejectNullBytes(reviewer, 'reviewer');
75
+ rejectControlChars(reviewer, 'reviewer');
76
+ if (reviewer.length > MAX_AGENT_ID_LENGTH) {
77
+ throw new ValidationError(`Reviewer name too long (max ${MAX_AGENT_ID_LENGTH} chars).`);
78
+ }
79
+ }
70
80
  resolve(approvalId, status, reviewer, comment) {
71
81
  const approval = this.db.queryOne('SELECT * FROM task_approvals WHERE id = ?', [
72
82
  approvalId,
@@ -1 +1 @@
1
- {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../src/domain/approvals.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../src/domain/approvals.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ export declare class CollaboratorService {
8
8
  add(taskId: number, agentId: string, role?: CollaboratorRole): TaskCollaborator;
9
9
  remove(taskId: number, agentId: string): void;
10
10
  list(taskId: number): TaskCollaborator[];
11
+ listAllByTask(): Record<number, TaskCollaborator[]>;
11
12
  getTasksForAgent(agentId: string): number[];
12
13
  private validateAgent;
13
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"collaborators.d.ts","sourceRoot":"","sources":["../../src/domain/collaborators.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMtE,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAiC,GAAG,gBAAgB;IA4B/F,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAW7C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAOxC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAQ3C,OAAO,CAAC,aAAa;CAKtB"}
1
+ {"version":3,"file":"collaborators.d.ts","sourceRoot":"","sources":["../../src/domain/collaborators.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMtE,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAiC,GAAG,gBAAgB;IA4B/F,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAW7C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAOxC,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAYnD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAQ3C,OAAO,CAAC,aAAa;CAQtB"}
@@ -4,7 +4,7 @@
4
4
  // Multiple agents can collaborate on a single task with defined roles.
5
5
  // =============================================================================
6
6
  import { NotFoundError, ValidationError, ConflictError } from '../types.js';
7
- import { rejectNullBytes, rejectControlChars } from './validate.js';
7
+ import { rejectNullBytes, rejectControlChars, MAX_AGENT_ID_LENGTH } from './validate.js';
8
8
  const VALID_ROLES = ['collaborator', 'reviewer', 'watcher'];
9
9
  export class CollaboratorService {
10
10
  db;
@@ -45,6 +45,16 @@ export class CollaboratorService {
45
45
  list(taskId) {
46
46
  return this.db.queryAll('SELECT * FROM task_collaborators WHERE task_id = ? ORDER BY added_at ASC', [taskId]);
47
47
  }
48
+ listAllByTask() {
49
+ const rows = this.db.queryAll('SELECT * FROM task_collaborators ORDER BY added_at ASC');
50
+ const result = {};
51
+ for (const r of rows) {
52
+ if (!result[r.task_id])
53
+ result[r.task_id] = [];
54
+ result[r.task_id].push(r);
55
+ }
56
+ return result;
57
+ }
48
58
  getTasksForAgent(agentId) {
49
59
  const rows = this.db.queryAll('SELECT task_id FROM task_collaborators WHERE agent_id = ?', [agentId]);
50
60
  return rows.map((r) => r.task_id);
@@ -54,6 +64,9 @@ export class CollaboratorService {
54
64
  rejectControlChars(agentId, 'agent_id');
55
65
  if (!agentId.trim())
56
66
  throw new ValidationError('Agent ID must not be empty.');
67
+ if (agentId.length > MAX_AGENT_ID_LENGTH) {
68
+ throw new ValidationError(`Agent ID too long (max ${MAX_AGENT_ID_LENGTH} chars).`);
69
+ }
57
70
  }
58
71
  }
59
72
  //# sourceMappingURL=collaborators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"collaborators.js","sourceRoot":"","sources":["../../src/domain/collaborators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collaborators.js","sourceRoot":"","sources":["../../src/domain/collaborators.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/domain/comments.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW;IA6B5F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAM,EAAE,MAAM,SAAI,GAAG,WAAW,EAAE;IAO5D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;IAaxC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IASrC,OAAO,CAAC,eAAe;CAQxB"}
1
+ {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/domain/comments.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAS/C,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,QAAQ;IAGnC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW;IAgC5F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAM,EAAE,MAAM,SAAI,GAAG,WAAW,EAAE;IAO5D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;IAaxC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IASrC,OAAO,CAAC,eAAe;CAQxB"}
@@ -4,7 +4,7 @@
4
4
  // Threaded comments on tasks for async multi-agent discussion.
5
5
  // =============================================================================
6
6
  import { NotFoundError, ValidationError } from '../types.js';
7
- import { MAX_DESCRIPTION_LENGTH, rejectNullBytes, rejectControlChars } from './validate.js';
7
+ import { MAX_COMMENT_LENGTH, MAX_AGENT_ID_LENGTH, rejectNullBytes, rejectControlChars, } from './validate.js';
8
8
  export class CommentService {
9
9
  db;
10
10
  events;
@@ -16,6 +16,9 @@ export class CommentService {
16
16
  this.validateContent(content);
17
17
  rejectNullBytes(agentId, 'agent_id');
18
18
  rejectControlChars(agentId, 'agent_id');
19
+ if (agentId.length > MAX_AGENT_ID_LENGTH) {
20
+ throw new ValidationError(`Agent ID too long (max ${MAX_AGENT_ID_LENGTH} chars).`);
21
+ }
19
22
  const task = this.db.queryOne('SELECT id FROM tasks WHERE id = ?', [taskId]);
20
23
  if (!task)
21
24
  throw new NotFoundError('Task', taskId);
@@ -55,8 +58,8 @@ export class CommentService {
55
58
  const trimmed = content.trim();
56
59
  if (!trimmed)
57
60
  throw new ValidationError('Comment content must not be empty.');
58
- if (trimmed.length > MAX_DESCRIPTION_LENGTH) {
59
- throw new ValidationError(`Comment too long (max ${MAX_DESCRIPTION_LENGTH} chars).`);
61
+ if (trimmed.length > MAX_COMMENT_LENGTH) {
62
+ throw new ValidationError(`Comment too long (max ${MAX_COMMENT_LENGTH} chars).`);
60
63
  }
61
64
  }
62
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/domain/comments.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,uCAAuC;AACvC,EAAE;AACF,+DAA+D;AAC/D,gFAAgF;AAKhF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE5F,MAAM,OAAO,cAAc;IAEN;IACA;IAFnB,YACmB,EAAM,EACN,MAAgB;QADhB,OAAE,GAAF,EAAE,CAAI;QACN,WAAM,GAAN,MAAM,CAAU;IAChC,CAAC;IAEJ,GAAG,CAAC,MAAc,EAAE,OAAe,EAAE,OAAe,EAAE,eAAwB;QAC5E,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAC9B,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACrC,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAExC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,mCAAmC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEnD,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,CAC7B,0DAA0D,EAC1D,CAAC,eAAe,EAAE,MAAM,CAAC,CAC1B,CAAC;YACF,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,aAAa,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CACxB,+FAA+F,EAC/F,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,eAAe,IAAI,IAAI,CAAC,CAC3D,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAc,0CAA0C,EAAE;YACxF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;SAC/B,CAAE,CAAC;QAEJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACjD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,CAAC,MAAc,EAAE,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,CAAC;QAC1C,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,CACrB,wFAAwF,EACxF,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CACvC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAc,0CAA0C,EAAE;YACrF,SAAS;SACV,CAAC,CAAC;QACH,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAEzD,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,CACrB,2FAA2F,EAC3F,CAAC,MAAM,EAAE,MAAM,CAAC,CACjB,CAAC;IACJ,CAAC;IAED,WAAW;QACT,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,CAC3B,qEAAqE,CACtE,CAAC;QACF,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;QAChD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,eAAe,CAAC,OAAe;QACrC,eAAe,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,eAAe,CAAC,oCAAoC,CAAC,CAAC;QAC9E,IAAI,OAAO,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;YAC5C,MAAM,IAAI,eAAe,CAAC,yBAAyB,sBAAsB,UAAU,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/domain/comments.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ export declare class EventBus {
4
4
  private readonly listeners;
5
5
  emit(type: EventType, data?: Record<string, unknown>): void;
6
6
  on(type: EventType | '*', handler: EventHandler): () => void;
7
+ listenerCount(type?: EventType | '*'): number;
7
8
  removeAll(): void;
8
9
  }
9
10
  //# sourceMappingURL=events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAEvD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiD;IAE3E,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IA8B/D,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,GAAG,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAY5D,SAAS,IAAI,IAAI;CAGlB"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAEvD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiD;IAE3E,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAkC/D,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,GAAG,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAY5D,aAAa,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,GAAG,MAAM;IAS7C,SAAS,IAAI,IAAI;CAGlB"}
@@ -17,8 +17,8 @@ export class EventBus {
17
17
  try {
18
18
  h(event);
19
19
  }
20
- catch {
21
- /* fail-safe */
20
+ catch (err) {
21
+ process.stderr.write(`[agent-tasks] Event handler error (${type}): ${err instanceof Error ? err.message : String(err)}\n`);
22
22
  }
23
23
  }
24
24
  }
@@ -28,8 +28,8 @@ export class EventBus {
28
28
  try {
29
29
  h(event);
30
30
  }
31
- catch {
32
- /* fail-safe */
31
+ catch (err) {
32
+ process.stderr.write(`[agent-tasks] Event handler error (*): ${err instanceof Error ? err.message : String(err)}\n`);
33
33
  }
34
34
  }
35
35
  }
@@ -45,6 +45,15 @@ export class EventBus {
45
45
  set.delete(handler);
46
46
  };
47
47
  }
48
+ listenerCount(type) {
49
+ if (type) {
50
+ return this.listeners.get(type)?.size ?? 0;
51
+ }
52
+ let total = 0;
53
+ for (const set of this.listeners.values())
54
+ total += set.size;
55
+ return total;
56
+ }
48
57
  removeAll() {
49
58
  this.listeners.clear();
50
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0BAA0B;AAC1B,EAAE;AACF,+CAA+C;AAC/C,gFAAgF;AAMhF,MAAM,OAAO,QAAQ;IACF,SAAS,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE3E,IAAI,CAAC,IAAe,EAAE,OAAgC,EAAE;QACtD,MAAM,KAAK,GAAe;YACxB,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI;SACL,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,CAAC;oBACH,CAAC,CAAC,KAAK,CAAC,CAAC;gBACX,CAAC;gBAAC,MAAM,CAAC;oBACP,eAAe;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC;oBACH,CAAC,CAAC,KAAK,CAAC,CAAC;gBACX,CAAC;gBAAC,MAAM,CAAC;oBACP,eAAe;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,EAAE,CAAC,IAAqB,EAAE,OAAqB;QAC7C,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjB,OAAO,GAAG,EAAE;YACV,GAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED,SAAS;QACP,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0BAA0B;AAC1B,EAAE;AACF,+CAA+C;AAC/C,gFAAgF;AAMhF,MAAM,OAAO,QAAQ;IACF,SAAS,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE3E,IAAI,CAAC,IAAe,EAAE,OAAgC,EAAE;QACtD,MAAM,KAAK,GAAe;YACxB,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI;SACL,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,CAAC;oBACH,CAAC,CAAC,KAAK,CAAC,CAAC;gBACX,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sCAAsC,IAAI,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACrG,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC;oBACH,CAAC,CAAC,KAAK,CAAC,CAAC;gBACX,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0CAA0C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAC/F,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,EAAE,CAAC,IAAqB,EAAE,OAAqB;QAC7C,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjB,OAAO,GAAG,EAAE;YACV,GAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED,aAAa,CAAC,IAAsB;QAClC,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE;YAAE,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,SAAS;QACP,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}