@gitgov/core 1.0.2 → 1.2.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/dist/src/index.d.ts +26 -2
- package/dist/src/index.js +263 -10
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
package/dist/src/index.d.ts
CHANGED
|
@@ -1763,13 +1763,17 @@ interface IBacklogAdapter {
|
|
|
1763
1763
|
updateTask(taskId: string, payload: Partial<TaskRecord>): Promise<TaskRecord>;
|
|
1764
1764
|
activateTask(taskId: string, actorId: string): Promise<TaskRecord>;
|
|
1765
1765
|
completeTask(taskId: string, actorId: string): Promise<TaskRecord>;
|
|
1766
|
+
pauseTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
|
|
1766
1767
|
resumeTask(taskId: string, actorId: string, force?: boolean): Promise<TaskRecord>;
|
|
1767
1768
|
discardTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
|
|
1769
|
+
deleteTask(taskId: string, actorId: string): Promise<void>;
|
|
1768
1770
|
createCycle(payload: Partial<CycleRecord>, actorId: string): Promise<CycleRecord>;
|
|
1769
1771
|
getCycle(cycleId: string): Promise<CycleRecord | null>;
|
|
1770
1772
|
getAllCycles(): Promise<CycleRecord[]>;
|
|
1771
1773
|
updateCycle(cycleId: string, payload: Partial<CycleRecord>): Promise<CycleRecord>;
|
|
1772
1774
|
addTaskToCycle(cycleId: string, taskId: string): Promise<void>;
|
|
1775
|
+
removeTasksFromCycle(cycleId: string, taskIds: string[]): Promise<void>;
|
|
1776
|
+
moveTasksBetweenCycles(targetCycleId: string, taskIds: string[], sourceCycleId: string): Promise<void>;
|
|
1773
1777
|
getTasksAssignedToActor(actorId: string): Promise<TaskRecord[]>;
|
|
1774
1778
|
handleFeedbackCreated(event: FeedbackCreatedEvent): Promise<void>;
|
|
1775
1779
|
handleFeedbackResolved(event: FeedbackStatusChangedEvent): Promise<void>;
|
|
@@ -1845,6 +1849,10 @@ declare class BacklogAdapter implements IBacklogAdapter {
|
|
|
1845
1849
|
* Activates a task transitioning from ready to active with permission validation
|
|
1846
1850
|
*/
|
|
1847
1851
|
activateTask(taskId: string, actorId: string): Promise<TaskRecord>;
|
|
1852
|
+
/**
|
|
1853
|
+
* Pauses a task manually transitioning from active to paused with optional reason
|
|
1854
|
+
*/
|
|
1855
|
+
pauseTask(taskId: string, actorId: string, reason?: string): Promise<TaskRecord>;
|
|
1848
1856
|
/**
|
|
1849
1857
|
* Resumes a paused task transitioning back to active with optional force override
|
|
1850
1858
|
*/
|
|
@@ -1858,6 +1866,11 @@ declare class BacklogAdapter implements IBacklogAdapter {
|
|
|
1858
1866
|
* Supports both cancellation (ready/active) and rejection (review) operations
|
|
1859
1867
|
*/
|
|
1860
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>;
|
|
1861
1874
|
/**
|
|
1862
1875
|
* Updates a task with new payload
|
|
1863
1876
|
*/
|
|
@@ -1926,6 +1939,17 @@ declare class BacklogAdapter implements IBacklogAdapter {
|
|
|
1926
1939
|
* Creates bidirectional link between task and cycle
|
|
1927
1940
|
*/
|
|
1928
1941
|
addTaskToCycle(cycleId: string, taskId: string): Promise<void>;
|
|
1942
|
+
/**
|
|
1943
|
+
* Removes multiple tasks from a cycle with bidirectional unlinking
|
|
1944
|
+
* All business logic and validation happens here in the adapter
|
|
1945
|
+
*/
|
|
1946
|
+
removeTasksFromCycle(cycleId: string, taskIds: string[]): Promise<void>;
|
|
1947
|
+
/**
|
|
1948
|
+
* Moves multiple tasks from one cycle to another atomically
|
|
1949
|
+
* Provides transactional semantics - all tasks move or none do
|
|
1950
|
+
* All business logic and validation happens here in the adapter
|
|
1951
|
+
*/
|
|
1952
|
+
moveTasksBetweenCycles(targetCycleId: string, taskIds: string[], sourceCycleId: string): Promise<void>;
|
|
1929
1953
|
lint(): Promise<LintReport>;
|
|
1930
1954
|
audit(): Promise<AuditReport>;
|
|
1931
1955
|
processChanges(_changes: unknown[]): Promise<ExecutionRecord[]>;
|
|
@@ -5405,7 +5429,7 @@ declare class DiagramGenerator {
|
|
|
5405
5429
|
cycleId?: string;
|
|
5406
5430
|
taskId?: string;
|
|
5407
5431
|
packageName?: string;
|
|
5408
|
-
}): Promise<string>;
|
|
5432
|
+
}, showArchived?: boolean): Promise<string>;
|
|
5409
5433
|
/**
|
|
5410
5434
|
* Convenience method to generate from .gitgov/ directory
|
|
5411
5435
|
*/
|
|
@@ -5413,7 +5437,7 @@ declare class DiagramGenerator {
|
|
|
5413
5437
|
cycleId?: string;
|
|
5414
5438
|
taskId?: string;
|
|
5415
5439
|
packageName?: string;
|
|
5416
|
-
}): Promise<string>;
|
|
5440
|
+
}, showArchived?: boolean): Promise<string>;
|
|
5417
5441
|
/**
|
|
5418
5442
|
* Loads all cycle records from the filesystem
|
|
5419
5443
|
*/
|
package/dist/src/index.js
CHANGED
|
@@ -4236,6 +4236,55 @@ var BacklogAdapter = class {
|
|
|
4236
4236
|
});
|
|
4237
4237
|
return updatedPayload;
|
|
4238
4238
|
}
|
|
4239
|
+
/**
|
|
4240
|
+
* Pauses a task manually transitioning from active to paused with optional reason
|
|
4241
|
+
*/
|
|
4242
|
+
async pauseTask(taskId, actorId, reason) {
|
|
4243
|
+
const taskRecord = await this.taskStore.read(taskId);
|
|
4244
|
+
if (!taskRecord) {
|
|
4245
|
+
throw new Error(`RecordNotFoundError: Task not found: ${taskId}`);
|
|
4246
|
+
}
|
|
4247
|
+
const task = taskRecord.payload;
|
|
4248
|
+
if (task.status !== "active") {
|
|
4249
|
+
throw new Error(`ProtocolViolationError: Task is in '${task.status}' state. Cannot pause (requires active).`);
|
|
4250
|
+
}
|
|
4251
|
+
const actor = await this.getActor(actorId);
|
|
4252
|
+
const context = {
|
|
4253
|
+
task,
|
|
4254
|
+
actor,
|
|
4255
|
+
signatures: taskRecord.header.signatures,
|
|
4256
|
+
transitionTo: "paused"
|
|
4257
|
+
};
|
|
4258
|
+
const transitionRule = await this.workflowMethodologyAdapter.getTransitionRule("active", "paused", context);
|
|
4259
|
+
if (!transitionRule) {
|
|
4260
|
+
throw new Error("ProtocolViolationError: Workflow methodology rejected active\u2192paused transition");
|
|
4261
|
+
}
|
|
4262
|
+
const updatedPayload = {
|
|
4263
|
+
...task,
|
|
4264
|
+
status: "paused",
|
|
4265
|
+
// Add reason to notes with [PAUSED] prefix if provided
|
|
4266
|
+
...reason && {
|
|
4267
|
+
notes: `${task.notes || ""}
|
|
4268
|
+
[PAUSED] ${reason} (${(/* @__PURE__ */ new Date()).toISOString()})`.trim()
|
|
4269
|
+
}
|
|
4270
|
+
};
|
|
4271
|
+
const updatedRecord = { ...taskRecord, payload: updatedPayload };
|
|
4272
|
+
const signedRecord = await this.identity.signRecord(updatedRecord, actorId, "pauser");
|
|
4273
|
+
await this.taskStore.write(signedRecord);
|
|
4274
|
+
this.eventBus.publish({
|
|
4275
|
+
type: "task.status.changed",
|
|
4276
|
+
timestamp: Date.now(),
|
|
4277
|
+
source: "backlog_adapter",
|
|
4278
|
+
payload: {
|
|
4279
|
+
taskId,
|
|
4280
|
+
oldStatus: "active",
|
|
4281
|
+
newStatus: "paused",
|
|
4282
|
+
actorId,
|
|
4283
|
+
reason: reason || "Task manually paused"
|
|
4284
|
+
}
|
|
4285
|
+
});
|
|
4286
|
+
return updatedPayload;
|
|
4287
|
+
}
|
|
4239
4288
|
/**
|
|
4240
4289
|
* Resumes a paused task transitioning back to active with optional force override
|
|
4241
4290
|
*/
|
|
@@ -4334,6 +4383,9 @@ var BacklogAdapter = class {
|
|
|
4334
4383
|
const task = taskRecord.payload;
|
|
4335
4384
|
const actor = await this.getActor(actorId);
|
|
4336
4385
|
if (!["ready", "active", "review"].includes(task.status)) {
|
|
4386
|
+
if (task.status === "draft") {
|
|
4387
|
+
throw new Error(`ProtocolViolationError: Cannot cancel task in 'draft' state. Use 'gitgov task delete ${taskId}' to remove draft tasks.`);
|
|
4388
|
+
}
|
|
4337
4389
|
throw new Error(`ProtocolViolationError: Task is in '${task.status}' state. Cannot cancel from this state. Only 'ready', 'active', and 'review' tasks can be cancelled.`);
|
|
4338
4390
|
}
|
|
4339
4391
|
const context = {
|
|
@@ -4372,6 +4424,39 @@ ${task.status === "review" ? "[REJECTED]" : "[CANCELLED]"} ${reason} (${(/* @__P
|
|
|
4372
4424
|
});
|
|
4373
4425
|
return updatedPayload;
|
|
4374
4426
|
}
|
|
4427
|
+
/**
|
|
4428
|
+
* Deletes a draft task completely (no discarded state)
|
|
4429
|
+
* Only works for tasks in 'draft' status that never entered formal workflow
|
|
4430
|
+
*/
|
|
4431
|
+
async deleteTask(taskId, actorId) {
|
|
4432
|
+
const taskRecord = await this.taskStore.read(taskId);
|
|
4433
|
+
if (!taskRecord) {
|
|
4434
|
+
throw new Error(`RecordNotFoundError: Task not found: ${taskId}`);
|
|
4435
|
+
}
|
|
4436
|
+
const task = taskRecord.payload;
|
|
4437
|
+
if (task.status !== "draft") {
|
|
4438
|
+
if (task.status === "review") {
|
|
4439
|
+
throw new Error(`ProtocolViolationError: Cannot delete task in 'review' state. Use 'gitgov task reject ${taskId}' to discard tasks under review.`);
|
|
4440
|
+
} else if (task.status === "ready" || task.status === "active") {
|
|
4441
|
+
throw new Error(`ProtocolViolationError: Cannot delete task in '${task.status}' state. Use 'gitgov task cancel ${taskId}' to discard tasks from ready/active states.`);
|
|
4442
|
+
}
|
|
4443
|
+
throw new Error(`ProtocolViolationError: Cannot delete task in '${task.status}' state. Only draft tasks can be deleted.`);
|
|
4444
|
+
}
|
|
4445
|
+
await this.getActor(actorId);
|
|
4446
|
+
await this.taskStore.delete(taskId);
|
|
4447
|
+
this.eventBus.publish({
|
|
4448
|
+
type: "task.status.changed",
|
|
4449
|
+
timestamp: Date.now(),
|
|
4450
|
+
source: "backlog_adapter",
|
|
4451
|
+
payload: {
|
|
4452
|
+
taskId,
|
|
4453
|
+
oldStatus: "draft",
|
|
4454
|
+
newStatus: "deleted",
|
|
4455
|
+
actorId,
|
|
4456
|
+
reason: "Draft task deleted"
|
|
4457
|
+
}
|
|
4458
|
+
});
|
|
4459
|
+
}
|
|
4375
4460
|
/**
|
|
4376
4461
|
* Updates a task with new payload
|
|
4377
4462
|
*/
|
|
@@ -4801,6 +4886,156 @@ ${task.status === "review" ? "[REJECTED]" : "[CANCELLED]"} ${reason} (${(/* @__P
|
|
|
4801
4886
|
this.taskStore.write(signedTaskRecord)
|
|
4802
4887
|
]);
|
|
4803
4888
|
}
|
|
4889
|
+
/**
|
|
4890
|
+
* Removes multiple tasks from a cycle with bidirectional unlinking
|
|
4891
|
+
* All business logic and validation happens here in the adapter
|
|
4892
|
+
*/
|
|
4893
|
+
async removeTasksFromCycle(cycleId, taskIds) {
|
|
4894
|
+
if (!cycleId || typeof cycleId !== "string") {
|
|
4895
|
+
throw new Error("ValidationError: cycleId must be a non-empty string");
|
|
4896
|
+
}
|
|
4897
|
+
if (!Array.isArray(taskIds) || taskIds.length === 0) {
|
|
4898
|
+
throw new Error("ValidationError: taskIds must be a non-empty array");
|
|
4899
|
+
}
|
|
4900
|
+
const cycleRecord = await this.cycleStore.read(cycleId);
|
|
4901
|
+
if (!cycleRecord) {
|
|
4902
|
+
throw new Error(`RecordNotFoundError: Cycle not found: ${cycleId}`);
|
|
4903
|
+
}
|
|
4904
|
+
const taskRecords = await Promise.all(
|
|
4905
|
+
taskIds.map(async (taskId) => {
|
|
4906
|
+
const taskRecord = await this.taskStore.read(taskId);
|
|
4907
|
+
if (!taskRecord) {
|
|
4908
|
+
throw new Error(`RecordNotFoundError: Task not found: ${taskId}`);
|
|
4909
|
+
}
|
|
4910
|
+
return { taskId, record: taskRecord };
|
|
4911
|
+
})
|
|
4912
|
+
);
|
|
4913
|
+
const cycleTaskIds = cycleRecord.payload.taskIds || [];
|
|
4914
|
+
const notLinkedTasks = taskIds.filter((taskId) => !cycleTaskIds.includes(taskId));
|
|
4915
|
+
if (notLinkedTasks.length > 0) {
|
|
4916
|
+
throw new Error(`ValidationError: Tasks not linked to cycle ${cycleId}: ${notLinkedTasks.join(", ")}`);
|
|
4917
|
+
}
|
|
4918
|
+
const updatedCycle = {
|
|
4919
|
+
...cycleRecord.payload,
|
|
4920
|
+
taskIds: cycleTaskIds.filter((id) => !taskIds.includes(id))
|
|
4921
|
+
};
|
|
4922
|
+
const currentActor = await this.identity.getCurrentActor();
|
|
4923
|
+
const signedCycleRecord = await this.identity.signRecord(
|
|
4924
|
+
{ ...cycleRecord, payload: updatedCycle },
|
|
4925
|
+
currentActor.id,
|
|
4926
|
+
"author"
|
|
4927
|
+
);
|
|
4928
|
+
const signedTaskRecords = await Promise.all(
|
|
4929
|
+
taskRecords.map(async ({ record }) => {
|
|
4930
|
+
const taskCycleIds = record.payload.cycleIds || [];
|
|
4931
|
+
const updatedTask = {
|
|
4932
|
+
...record.payload,
|
|
4933
|
+
cycleIds: taskCycleIds.filter((id) => id !== cycleId)
|
|
4934
|
+
};
|
|
4935
|
+
return await this.identity.signRecord(
|
|
4936
|
+
{ ...record, payload: updatedTask },
|
|
4937
|
+
currentActor.id,
|
|
4938
|
+
"author"
|
|
4939
|
+
);
|
|
4940
|
+
})
|
|
4941
|
+
);
|
|
4942
|
+
await Promise.all([
|
|
4943
|
+
this.cycleStore.write(signedCycleRecord),
|
|
4944
|
+
...signedTaskRecords.map(
|
|
4945
|
+
(signedTask) => this.taskStore.write(signedTask)
|
|
4946
|
+
)
|
|
4947
|
+
]);
|
|
4948
|
+
}
|
|
4949
|
+
/**
|
|
4950
|
+
* Moves multiple tasks from one cycle to another atomically
|
|
4951
|
+
* Provides transactional semantics - all tasks move or none do
|
|
4952
|
+
* All business logic and validation happens here in the adapter
|
|
4953
|
+
*/
|
|
4954
|
+
async moveTasksBetweenCycles(targetCycleId, taskIds, sourceCycleId) {
|
|
4955
|
+
if (!sourceCycleId || typeof sourceCycleId !== "string") {
|
|
4956
|
+
throw new Error("ValidationError: sourceCycleId must be a non-empty string");
|
|
4957
|
+
}
|
|
4958
|
+
if (!targetCycleId || typeof targetCycleId !== "string") {
|
|
4959
|
+
throw new Error("ValidationError: targetCycleId must be a non-empty string");
|
|
4960
|
+
}
|
|
4961
|
+
if (!Array.isArray(taskIds) || taskIds.length === 0) {
|
|
4962
|
+
throw new Error("ValidationError: taskIds must be a non-empty array");
|
|
4963
|
+
}
|
|
4964
|
+
if (sourceCycleId === targetCycleId) {
|
|
4965
|
+
throw new Error("ValidationError: Source and target cycles must be different");
|
|
4966
|
+
}
|
|
4967
|
+
const [sourceCycleRecord, targetCycleRecord] = await Promise.all([
|
|
4968
|
+
this.cycleStore.read(sourceCycleId),
|
|
4969
|
+
this.cycleStore.read(targetCycleId)
|
|
4970
|
+
]);
|
|
4971
|
+
if (!sourceCycleRecord) {
|
|
4972
|
+
throw new Error(`RecordNotFoundError: Source cycle not found: ${sourceCycleId}`);
|
|
4973
|
+
}
|
|
4974
|
+
if (!targetCycleRecord) {
|
|
4975
|
+
throw new Error(`RecordNotFoundError: Target cycle not found: ${targetCycleId}`);
|
|
4976
|
+
}
|
|
4977
|
+
const taskRecords = await Promise.all(
|
|
4978
|
+
taskIds.map(async (taskId) => {
|
|
4979
|
+
const taskRecord = await this.taskStore.read(taskId);
|
|
4980
|
+
if (!taskRecord) {
|
|
4981
|
+
throw new Error(`RecordNotFoundError: Task not found: ${taskId}`);
|
|
4982
|
+
}
|
|
4983
|
+
return { taskId, record: taskRecord };
|
|
4984
|
+
})
|
|
4985
|
+
);
|
|
4986
|
+
const sourceTaskIds = sourceCycleRecord.payload.taskIds || [];
|
|
4987
|
+
const notLinkedTasks = taskIds.filter((taskId) => !sourceTaskIds.includes(taskId));
|
|
4988
|
+
if (notLinkedTasks.length > 0) {
|
|
4989
|
+
throw new Error(`ValidationError: Tasks not linked to source cycle ${sourceCycleId}: ${notLinkedTasks.join(", ")}`);
|
|
4990
|
+
}
|
|
4991
|
+
const updatedSourceCycle = {
|
|
4992
|
+
...sourceCycleRecord.payload,
|
|
4993
|
+
taskIds: sourceTaskIds.filter((id) => !taskIds.includes(id))
|
|
4994
|
+
};
|
|
4995
|
+
const updatedTargetCycle = {
|
|
4996
|
+
...targetCycleRecord.payload,
|
|
4997
|
+
taskIds: [...targetCycleRecord.payload.taskIds || [], ...taskIds]
|
|
4998
|
+
};
|
|
4999
|
+
const currentActor = await this.identity.getCurrentActor();
|
|
5000
|
+
const [signedSourceCycle, signedTargetCycle] = await Promise.all([
|
|
5001
|
+
this.identity.signRecord(
|
|
5002
|
+
{ ...sourceCycleRecord, payload: updatedSourceCycle },
|
|
5003
|
+
currentActor.id,
|
|
5004
|
+
"author"
|
|
5005
|
+
),
|
|
5006
|
+
this.identity.signRecord(
|
|
5007
|
+
{ ...targetCycleRecord, payload: updatedTargetCycle },
|
|
5008
|
+
currentActor.id,
|
|
5009
|
+
"author"
|
|
5010
|
+
)
|
|
5011
|
+
]);
|
|
5012
|
+
const signedTaskRecords = await Promise.all(
|
|
5013
|
+
taskRecords.map(async ({ record }) => {
|
|
5014
|
+
const taskCycleIds = record.payload.cycleIds || [];
|
|
5015
|
+
const updatedTask = {
|
|
5016
|
+
...record.payload,
|
|
5017
|
+
cycleIds: taskCycleIds.filter((id) => id !== sourceCycleId).concat(targetCycleId)
|
|
5018
|
+
// Add target
|
|
5019
|
+
};
|
|
5020
|
+
return await this.identity.signRecord(
|
|
5021
|
+
{ ...record, payload: updatedTask },
|
|
5022
|
+
currentActor.id,
|
|
5023
|
+
"author"
|
|
5024
|
+
);
|
|
5025
|
+
})
|
|
5026
|
+
);
|
|
5027
|
+
try {
|
|
5028
|
+
await Promise.all([
|
|
5029
|
+
this.cycleStore.write(signedSourceCycle),
|
|
5030
|
+
this.cycleStore.write(signedTargetCycle),
|
|
5031
|
+
...signedTaskRecords.map(
|
|
5032
|
+
(signedTask) => this.taskStore.write(signedTask)
|
|
5033
|
+
)
|
|
5034
|
+
]);
|
|
5035
|
+
} catch (error) {
|
|
5036
|
+
throw new Error(`AtomicOperationError: Failed to move tasks between cycles: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
4804
5039
|
// TODO: Implement when lint_command.md is implemented
|
|
4805
5040
|
async lint() {
|
|
4806
5041
|
throw new Error("NotImplementedError: lint() will be implemented when lint_command.md is ready");
|
|
@@ -5442,7 +5677,18 @@ var ProjectAdapter = class {
|
|
|
5442
5677
|
{
|
|
5443
5678
|
type: "human",
|
|
5444
5679
|
displayName: options.actorName || "Project Owner",
|
|
5445
|
-
roles: [
|
|
5680
|
+
roles: [
|
|
5681
|
+
"admin",
|
|
5682
|
+
// Platform admin (future use)
|
|
5683
|
+
"author",
|
|
5684
|
+
// Create & submit tasks
|
|
5685
|
+
"approver:product",
|
|
5686
|
+
// Approve tasks (product decisions)
|
|
5687
|
+
"approver:quality",
|
|
5688
|
+
// Complete tasks (quality validation)
|
|
5689
|
+
"developer"
|
|
5690
|
+
// General development work
|
|
5691
|
+
]
|
|
5446
5692
|
},
|
|
5447
5693
|
"bootstrap"
|
|
5448
5694
|
);
|
|
@@ -5848,7 +6094,8 @@ var workflow_methodology_default_default = {
|
|
|
5848
6094
|
},
|
|
5849
6095
|
active: {
|
|
5850
6096
|
from: [
|
|
5851
|
-
"ready"
|
|
6097
|
+
"ready",
|
|
6098
|
+
"paused"
|
|
5852
6099
|
],
|
|
5853
6100
|
requires: {
|
|
5854
6101
|
event: "first_execution_record_created",
|
|
@@ -6018,7 +6265,8 @@ var workflow_methodology_scrum_default = {
|
|
|
6018
6265
|
},
|
|
6019
6266
|
active: {
|
|
6020
6267
|
from: [
|
|
6021
|
-
"ready"
|
|
6268
|
+
"ready",
|
|
6269
|
+
"paused"
|
|
6022
6270
|
],
|
|
6023
6271
|
requires: {
|
|
6024
6272
|
event: "sprint_started",
|
|
@@ -7714,8 +7962,8 @@ var DiagramGenerator = class {
|
|
|
7714
7962
|
/**
|
|
7715
7963
|
* Primary API - Performance optimized with caching
|
|
7716
7964
|
*/
|
|
7717
|
-
async generateFromRecords(cycles, tasks, filters) {
|
|
7718
|
-
const cacheKey = this.generateCacheKey(cycles, tasks);
|
|
7965
|
+
async generateFromRecords(cycles, tasks, filters, showArchived = false) {
|
|
7966
|
+
const cacheKey = this.generateCacheKey(cycles, tasks, showArchived);
|
|
7719
7967
|
if (this.cache.has(cacheKey)) {
|
|
7720
7968
|
this.metrics.incrementCacheHits();
|
|
7721
7969
|
return this.renderFromCache(cacheKey);
|
|
@@ -7724,8 +7972,12 @@ var DiagramGenerator = class {
|
|
|
7724
7972
|
try {
|
|
7725
7973
|
let finalCycles = cycles;
|
|
7726
7974
|
let finalTasks = tasks;
|
|
7975
|
+
if (!showArchived) {
|
|
7976
|
+
finalCycles = cycles.filter((cycle) => cycle.status !== "archived");
|
|
7977
|
+
finalTasks = tasks.filter((task) => task.status !== "archived");
|
|
7978
|
+
}
|
|
7727
7979
|
if (filters && (filters.cycleId || filters.taskId || filters.packageName)) {
|
|
7728
|
-
const filtered = this.analyzer.filterEntities(
|
|
7980
|
+
const filtered = this.analyzer.filterEntities(finalCycles, finalTasks, filters);
|
|
7729
7981
|
finalCycles = filtered.filteredCycles;
|
|
7730
7982
|
finalTasks = filtered.filteredTasks;
|
|
7731
7983
|
}
|
|
@@ -7743,10 +7995,10 @@ var DiagramGenerator = class {
|
|
|
7743
7995
|
/**
|
|
7744
7996
|
* Convenience method to generate from .gitgov/ directory
|
|
7745
7997
|
*/
|
|
7746
|
-
async generateFromFiles(gitgovPath = ".gitgov", filters) {
|
|
7998
|
+
async generateFromFiles(gitgovPath = ".gitgov", filters, showArchived = false) {
|
|
7747
7999
|
const cycles = await this.loadCycleRecords(gitgovPath);
|
|
7748
8000
|
const tasks = await this.loadTaskRecords(gitgovPath);
|
|
7749
|
-
return this.generateFromRecords(cycles, tasks, filters);
|
|
8001
|
+
return this.generateFromRecords(cycles, tasks, filters, showArchived);
|
|
7750
8002
|
}
|
|
7751
8003
|
/**
|
|
7752
8004
|
* Loads all cycle records from the filesystem
|
|
@@ -7830,13 +8082,14 @@ var DiagramGenerator = class {
|
|
|
7830
8082
|
/**
|
|
7831
8083
|
* Generates cache key for efficient lookups
|
|
7832
8084
|
*/
|
|
7833
|
-
generateCacheKey(cycles, tasks) {
|
|
8085
|
+
generateCacheKey(cycles, tasks, showArchived = false) {
|
|
7834
8086
|
const cycleIds = [...new Set(cycles.map((c) => c.id))].sort();
|
|
7835
8087
|
const taskIds = [...new Set(tasks.map((t) => t.id))].sort();
|
|
7836
8088
|
const cycleHash = this.hashArray(cycleIds);
|
|
7837
8089
|
const taskHash = this.hashArray(taskIds);
|
|
7838
8090
|
const optionsHash = this.hashString(JSON.stringify(this.options));
|
|
7839
|
-
|
|
8091
|
+
const archivedFlag = showArchived ? "with-archived" : "no-archived";
|
|
8092
|
+
return `diagram:${cycleHash}-${taskHash}-${optionsHash}-${archivedFlag}`;
|
|
7840
8093
|
}
|
|
7841
8094
|
/**
|
|
7842
8095
|
* Efficient hash function for arrays
|