@gitgov/core 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,14 +10,20 @@
10
10
 
11
11
  This example shows how to create a new task using the `BacklogAdapter`. The SDK uses dependency injection - each adapter requires its dependencies to be explicitly provided.
12
12
 
13
- *Note: This example assumes it is run inside an initialized GitGovernance project.*
13
+ _Note: This example assumes it is run inside an initialized GitGovernance project._
14
14
 
15
15
  ```typescript
16
16
  import { Adapters, Store, EventBus } from "@gitgov/core";
17
- import type { TaskRecord, CycleRecord, ActorRecord, AgentRecord } from "@gitgov/core";
17
+ import type {
18
+ TaskRecord,
19
+ CycleRecord,
20
+ ActorRecord,
21
+ AgentRecord,
22
+ } from "@gitgov/core";
18
23
 
19
24
  // Extract classes from namespaces
20
- const { IdentityAdapter, BacklogAdapter, WorkflowMethodologyAdapter } = Adapters;
25
+ const { IdentityAdapter, BacklogAdapter, WorkflowMethodologyAdapter } =
26
+ Adapters;
21
27
  const { RecordStore } = Store;
22
28
  const { EventBus: EventBusClass } = EventBus;
23
29
 
@@ -97,11 +103,11 @@ console.log({
97
103
  ### Adapter Ecosystem (9/9 Adapters)
98
104
 
99
105
  - **ProjectAdapter**: Project initialization engine with 3-adapter orchestration (18 tests)
100
- - **BacklogAdapter**: Task and cycle lifecycle management with workflow validation (43 tests)
106
+ - **BacklogAdapter**: Task and cycle lifecycle management with workflow validation (71 tests)
101
107
  - **MetricsAdapter**: Pure calculation engine for system analytics (32 tests)
102
108
  - **ChangelogAdapter**: System historian for change documentation (31 tests)
103
109
  - **ExecutionAdapter**: Audit log for work execution (13 tests)
104
- - **FeedbackAdapter**: Structured communication and blocking management (15 tests)
110
+ - **FeedbackAdapter**: Structured communication and blocking management (21 tests)
105
111
  - **IdentityAdapter**: Cryptographic identity and agent management (25 tests)
106
112
  - **WorkflowMethodologyAdapter**: Configurable workflow validation engine (51 tests)
107
113
  - **IndexerAdapter**: Local cache optimization for performance (5 tests)
@@ -229,7 +235,7 @@ const generator = new DiagramGenerator();
229
235
  // Generate Mermaid diagrams from GitGovernance records
230
236
  const result = await generator.generateFromRecords(cycles, tasks, {
231
237
  cycleId: "1704067200-cycle-identity-adapter",
232
- layout: 'TD',
238
+ layout: "TD",
233
239
  showWarnings: true,
234
240
  });
235
241
 
@@ -240,7 +246,7 @@ console.log(result.mermaidCode);
240
246
  ## 🧪 Testing & Development
241
247
 
242
248
  ```bash
243
- # Run all tests (704 tests total)
249
+ # Run all tests (737 tests total)
244
250
  npm test
245
251
  npm run test:coverage # Run tests with coverage report
246
252
 
@@ -266,13 +272,13 @@ npm test -- --watch
266
272
 
267
273
  ### Test Coverage
268
274
 
269
- - **704 tests total** with EARS methodology
275
+ - **737 tests total** with EARS methodology
270
276
  - **ProjectAdapter**: 18 tests (project initialization + template processing + error recovery)
271
- - **BacklogAdapter**: 43 tests (workflow lifecycle + event handlers + E2E simulation)
277
+ - **BacklogAdapter**: 71 tests (workflow lifecycle + event handlers + E2E simulation + deduplication)
272
278
  - **MetricsAdapter**: 32 tests (Tier 1+2 calculations + performance validation)
273
279
  - **ChangelogAdapter**: 31 tests (multi-entity changelog + conditional validation)
274
280
  - **EventBusModule**: 32 tests (20 unit + 12 integration tests with cross-adapter scenarios)
275
- - **FeedbackAdapter**: 15 tests (EARS coverage with dual event emission)
281
+ - **FeedbackAdapter**: 21 tests (EARS coverage with dual event emission + duplicate assignment prevention)
276
282
  - **ExecutionAdapter**: 13 tests (EARS coverage with performance validation)
277
283
  - **WorkflowMethodologyAdapter**: 51 tests (29 unit + 22 integration tests)
278
284
  - **Identity Domain**: 66 tests (Adapter + ActorRecord/AgentRecord factories & validators)
@@ -1766,6 +1766,7 @@ interface IBacklogAdapter {
1766
1766
  pauseTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
1767
1767
  resumeTask(taskId: string, actorId: string, force?: boolean): Promise<TaskRecord>;
1768
1768
  discardTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
1769
+ deleteTask(taskId: string, actorId: string): Promise<void>;
1769
1770
  createCycle(payload: Partial<CycleRecord>, actorId: string): Promise<CycleRecord>;
1770
1771
  getCycle(cycleId: string): Promise<CycleRecord | null>;
1771
1772
  getAllCycles(): Promise<CycleRecord[]>;
@@ -1865,6 +1866,11 @@ declare class BacklogAdapter implements IBacklogAdapter {
1865
1866
  * Supports both cancellation (ready/active) and rejection (review) operations
1866
1867
  */
1867
1868
  discardTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
1869
+ /**
1870
+ * Deletes a draft task completely (no discarded state)
1871
+ * Only works for tasks in 'draft' status that never entered formal workflow
1872
+ */
1873
+ deleteTask(taskId: string, actorId: string): Promise<void>;
1868
1874
  /**
1869
1875
  * Updates a task with new payload
1870
1876
  */
package/dist/src/index.js CHANGED
@@ -2878,6 +2878,15 @@ var FeedbackAdapter = class {
2878
2878
  if (payloadWithEntityId.entityType && !["task", "execution", "changelog", "feedback"].includes(payloadWithEntityId.entityType)) {
2879
2879
  throw new Error("InvalidEntityTypeError: entityType must be task, execution, changelog, or feedback");
2880
2880
  }
2881
+ if (payload.type === "assignment" && payload.assignee) {
2882
+ const existingFeedbacks = await this.getFeedbackByEntity(payloadWithEntityId.entityId);
2883
+ const duplicateAssignment = existingFeedbacks.find(
2884
+ (feedback) => feedback.type === "assignment" && feedback.assignee === payload.assignee && feedback.status === "open"
2885
+ );
2886
+ if (duplicateAssignment) {
2887
+ throw new Error(`DuplicateAssignmentError: Task ${payloadWithEntityId.entityId} is already assigned to ${payload.assignee} (feedback: ${duplicateAssignment.id})`);
2888
+ }
2889
+ }
2881
2890
  const enrichedPayload = {
2882
2891
  ...payload,
2883
2892
  status: "open"
@@ -4383,6 +4392,9 @@ var BacklogAdapter = class {
4383
4392
  const task = taskRecord.payload;
4384
4393
  const actor = await this.getActor(actorId);
4385
4394
  if (!["ready", "active", "review"].includes(task.status)) {
4395
+ if (task.status === "draft") {
4396
+ throw new Error(`ProtocolViolationError: Cannot cancel task in 'draft' state. Use 'gitgov task delete ${taskId}' to remove draft tasks.`);
4397
+ }
4386
4398
  throw new Error(`ProtocolViolationError: Task is in '${task.status}' state. Cannot cancel from this state. Only 'ready', 'active', and 'review' tasks can be cancelled.`);
4387
4399
  }
4388
4400
  const context = {
@@ -4421,6 +4433,39 @@ ${task.status === "review" ? "[REJECTED]" : "[CANCELLED]"} ${reason} (${(/* @__P
4421
4433
  });
4422
4434
  return updatedPayload;
4423
4435
  }
4436
+ /**
4437
+ * Deletes a draft task completely (no discarded state)
4438
+ * Only works for tasks in 'draft' status that never entered formal workflow
4439
+ */
4440
+ async deleteTask(taskId, actorId) {
4441
+ const taskRecord = await this.taskStore.read(taskId);
4442
+ if (!taskRecord) {
4443
+ throw new Error(`RecordNotFoundError: Task not found: ${taskId}`);
4444
+ }
4445
+ const task = taskRecord.payload;
4446
+ if (task.status !== "draft") {
4447
+ if (task.status === "review") {
4448
+ throw new Error(`ProtocolViolationError: Cannot delete task in 'review' state. Use 'gitgov task reject ${taskId}' to discard tasks under review.`);
4449
+ } else if (task.status === "ready" || task.status === "active") {
4450
+ throw new Error(`ProtocolViolationError: Cannot delete task in '${task.status}' state. Use 'gitgov task cancel ${taskId}' to discard tasks from ready/active states.`);
4451
+ }
4452
+ throw new Error(`ProtocolViolationError: Cannot delete task in '${task.status}' state. Only draft tasks can be deleted.`);
4453
+ }
4454
+ await this.getActor(actorId);
4455
+ await this.taskStore.delete(taskId);
4456
+ this.eventBus.publish({
4457
+ type: "task.status.changed",
4458
+ timestamp: Date.now(),
4459
+ source: "backlog_adapter",
4460
+ payload: {
4461
+ taskId,
4462
+ oldStatus: "draft",
4463
+ newStatus: "deleted",
4464
+ actorId,
4465
+ reason: "Draft task deleted"
4466
+ }
4467
+ });
4468
+ }
4424
4469
  /**
4425
4470
  * Updates a task with new payload
4426
4471
  */
@@ -4450,8 +4495,9 @@ ${task.status === "review" ? "[REJECTED]" : "[CANCELLED]"} ${reason} (${(/* @__P
4450
4495
  assignedTaskIds.push(record.payload.entityId);
4451
4496
  }
4452
4497
  }
4498
+ const uniqueTaskIds = [...new Set(assignedTaskIds)];
4453
4499
  const assignedTasks = [];
4454
- for (const taskId of assignedTaskIds) {
4500
+ for (const taskId of uniqueTaskIds) {
4455
4501
  const task = await this.getTask(taskId);
4456
4502
  if (task) {
4457
4503
  assignedTasks.push(task);