@pellux/goodvibes-sdk 0.33.20 → 0.33.22
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/browser-knowledge.d.ts +49 -0
- package/dist/browser-knowledge.d.ts.map +1 -1
- package/dist/browser-knowledge.js +22 -0
- package/dist/contracts/artifacts/operator-contract.json +4615 -4
- package/dist/events/agents.d.ts +11 -0
- package/dist/events/agents.d.ts.map +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/planner.d.ts +69 -1
- package/dist/events/planner.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-controller.d.ts +19 -0
- package/dist/platform/agents/wrfc-controller.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-controller.js +286 -22
- package/dist/platform/agents/wrfc-reporting.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-reporting.js +5 -1
- package/dist/platform/agents/wrfc-types.d.ts +1 -1
- package/dist/platform/agents/wrfc-types.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-knowledge.js +154 -1
- package/dist/platform/control-plane/operator-contract-schemas-project-planning.d.ts +4 -0
- package/dist/platform/control-plane/operator-contract-schemas-project-planning.d.ts.map +1 -1
- package/dist/platform/control-plane/operator-contract-schemas-project-planning.js +78 -0
- package/dist/platform/core/orchestrator-turn-helpers.d.ts.map +1 -1
- package/dist/platform/core/orchestrator-turn-helpers.js +27 -11
- package/dist/platform/core/orchestrator-turn-loop.d.ts.map +1 -1
- package/dist/platform/core/orchestrator-turn-loop.js +4 -1
- package/dist/platform/core/wrfc-routing.d.ts +5 -0
- package/dist/platform/core/wrfc-routing.d.ts.map +1 -0
- package/dist/platform/core/wrfc-routing.js +51 -0
- package/dist/platform/daemon/http/project-planning-routes.d.ts.map +1 -1
- package/dist/platform/daemon/http/project-planning-routes.js +67 -0
- package/dist/platform/knowledge/index.d.ts +1 -1
- package/dist/platform/knowledge/index.d.ts.map +1 -1
- package/dist/platform/knowledge/project-planning/helpers.d.ts +1 -1
- package/dist/platform/knowledge/project-planning/helpers.d.ts.map +1 -1
- package/dist/platform/knowledge/project-planning/helpers.js +4 -0
- package/dist/platform/knowledge/project-planning/index.d.ts +1 -1
- package/dist/platform/knowledge/project-planning/index.d.ts.map +1 -1
- package/dist/platform/knowledge/project-planning/service.d.ts +21 -1
- package/dist/platform/knowledge/project-planning/service.d.ts.map +1 -1
- package/dist/platform/knowledge/project-planning/service.js +502 -1
- package/dist/platform/knowledge/project-planning/types.d.ts +140 -0
- package/dist/platform/knowledge/project-planning/types.d.ts.map +1 -1
- package/dist/platform/runtime/emitters/agents.d.ts +11 -0
- package/dist/platform/runtime/emitters/agents.d.ts.map +1 -1
- package/dist/platform/runtime/emitters/planner.d.ts +22 -0
- package/dist/platform/runtime/emitters/planner.d.ts.map +1 -1
- package/dist/platform/runtime/emitters/planner.js +15 -0
- package/dist/platform/runtime/events/index.d.ts +1 -1
- package/dist/platform/runtime/events/index.d.ts.map +1 -1
- package/dist/platform/runtime/services.d.ts.map +1 -1
- package/dist/platform/runtime/services.js +2 -0
- package/dist/platform/runtime/store/domains/agents.d.ts +3 -1
- package/dist/platform/runtime/store/domains/agents.d.ts.map +1 -1
- package/dist/platform/runtime/store/helpers/reducers/lifecycle.d.ts.map +1 -1
- package/dist/platform/runtime/store/helpers/reducers/lifecycle.js +25 -6
- package/dist/platform/tools/agent/index.d.ts.map +1 -1
- package/dist/platform/tools/agent/index.js +131 -64
- package/dist/platform/tools/agent/manager.d.ts +1 -0
- package/dist/platform/tools/agent/manager.d.ts.map +1 -1
- package/dist/platform/tools/agent/manager.js +36 -7
- package/dist/platform/tools/agent/schema.d.ts.map +1 -1
- package/dist/platform/tools/agent/schema.js +7 -6
- package/dist/platform/version.js +1 -1
- package/package.json +9 -9
|
@@ -2,5 +2,5 @@ export { ProjectPlanningService } from './service.js';
|
|
|
2
2
|
export type { ProjectPlanningServiceOptions } from './service.js';
|
|
3
3
|
export { PROJECT_PLANNING_CONNECTOR_ID, PROJECT_PLANNING_TAG, projectPlanningCanonicalUri, projectPlanningProjectIdFromPath, projectPlanningSourceId, resolveProjectPlanningSpace, } from './helpers.js';
|
|
4
4
|
export { evaluateProjectPlanningReadiness } from './readiness.js';
|
|
5
|
-
export type { ProjectPlanningAgentAssignment, ProjectPlanningAmbiguity, ProjectPlanningDecision, ProjectPlanningDecisionRecordInput, ProjectPlanningDecisionResult, ProjectPlanningDecisionsResult, ProjectPlanningDecisionStatus, ProjectPlanningDependency, ProjectPlanningEvaluateInput, ProjectPlanningEvaluation, ProjectPlanningGap, ProjectPlanningGapKind, ProjectPlanningGapSeverity, ProjectPlanningGateStatus, ProjectPlanningLanguageArtifact, ProjectPlanningLanguageResult, ProjectPlanningLanguageUpsertInput, ProjectPlanningQuestion, ProjectPlanningQuestionStatus, ProjectPlanningReadiness, ProjectPlanningSpaceInput, ProjectPlanningState, ProjectPlanningStateResult, ProjectPlanningStateUpsertInput, ProjectPlanningStatus, ProjectPlanningTask, ProjectPlanningTaskStatus, ProjectPlanningTerm, ProjectPlanningVerificationGate, } from './types.js';
|
|
5
|
+
export type { ProjectPlanningAgentAssignment, ProjectPlanningAmbiguity, ProjectPlanningDecision, ProjectPlanningDecisionRecordInput, ProjectPlanningDecisionResult, ProjectPlanningDecisionsResult, ProjectPlanningDecisionStatus, ProjectPlanningDependency, ProjectPlanningEvaluateInput, ProjectPlanningEvaluation, ProjectPlanningGap, ProjectPlanningGapKind, ProjectPlanningGapSeverity, ProjectPlanningGateStatus, ProjectPlanningLanguageArtifact, ProjectPlanningLanguageResult, ProjectPlanningLanguageUpsertInput, ProjectPlanningQuestion, ProjectPlanningQuestionStatus, ProjectPlanningReadiness, ProjectPlanningSpaceInput, ProjectPlanningState, ProjectPlanningStateResult, ProjectPlanningStateUpsertInput, ProjectPlanningStatus, ProjectPlanningTask, ProjectPlanningTaskStatus, ProjectPlanningTerm, ProjectPlanningVerificationGate, ProjectWorkPlanArtifact, ProjectWorkPlanClearCompletedInput, ProjectWorkPlanCounts, ProjectWorkPlanMutationResult, ProjectWorkPlanSnapshot, ProjectWorkPlanTask, ProjectWorkPlanTaskCreateInput, ProjectWorkPlanTaskDeleteInput, ProjectWorkPlanTaskGetInput, ProjectWorkPlanTaskListInput, ProjectWorkPlanTaskMutationSource, ProjectWorkPlanTaskReorderInput, ProjectWorkPlanTaskResult, ProjectWorkPlanTaskStatus, ProjectWorkPlanTaskStatusInput, ProjectWorkPlanTaskUpdateInput, } from './types.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/platform/knowledge/project-planning/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,wBAAwB,EACxB,uBAAuB,EACvB,kCAAkC,EAClC,6BAA6B,EAC7B,8BAA8B,EAC9B,6BAA6B,EAC7B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,EAC/B,6BAA6B,EAC7B,kCAAkC,EAClC,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,+BAA+B,EAC/B,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,+BAA+B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/platform/knowledge/project-planning/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,wBAAwB,EACxB,uBAAuB,EACvB,kCAAkC,EAClC,6BAA6B,EAC7B,8BAA8B,EAC9B,6BAA6B,EAC7B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,EAC/B,6BAA6B,EAC7B,kCAAkC,EAClC,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,+BAA+B,EAC/B,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,+BAA+B,EAC/B,uBAAuB,EACvB,kCAAkC,EAClC,qBAAqB,EACrB,6BAA6B,EAC7B,uBAAuB,EACvB,mBAAmB,EACnB,8BAA8B,EAC9B,8BAA8B,EAC9B,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,+BAA+B,EAC/B,yBAAyB,EACzB,yBAAyB,EACzB,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,YAAY,CAAC"}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { KnowledgeStore } from '../store.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RuntimeEventBus } from '../../runtime/events/index.js';
|
|
3
|
+
import type { ProjectPlanningDecisionRecordInput, ProjectPlanningDecisionResult, ProjectPlanningDecisionsResult, ProjectPlanningEvaluateInput, ProjectPlanningEvaluation, ProjectPlanningLanguageResult, ProjectPlanningLanguageUpsertInput, ProjectPlanningSpaceInput, ProjectPlanningStateResult, ProjectPlanningStateUpsertInput, ProjectPlanningStatus, ProjectWorkPlanClearCompletedInput, ProjectWorkPlanMutationResult, ProjectWorkPlanSnapshot, ProjectWorkPlanTaskCreateInput, ProjectWorkPlanTaskDeleteInput, ProjectWorkPlanTaskGetInput, ProjectWorkPlanTaskListInput, ProjectWorkPlanTaskReorderInput, ProjectWorkPlanTaskResult, ProjectWorkPlanTaskStatusInput, ProjectWorkPlanTaskUpdateInput } from './types.js';
|
|
3
4
|
export interface ProjectPlanningServiceOptions {
|
|
4
5
|
readonly defaultProjectId?: string | undefined;
|
|
6
|
+
readonly runtimeBus?: RuntimeEventBus | null | undefined;
|
|
5
7
|
}
|
|
6
8
|
export declare class ProjectPlanningService {
|
|
7
9
|
private readonly store;
|
|
8
10
|
private readonly defaultProjectId;
|
|
11
|
+
private runtimeBus;
|
|
9
12
|
constructor(store: KnowledgeStore, options?: ProjectPlanningServiceOptions);
|
|
13
|
+
attachRuntimeBus(runtimeBus: RuntimeEventBus | null | undefined): void;
|
|
10
14
|
status(input?: ProjectPlanningSpaceInput): Promise<ProjectPlanningStatus>;
|
|
11
15
|
getState(input?: ProjectPlanningSpaceInput & {
|
|
12
16
|
readonly planningId?: string | undefined;
|
|
@@ -17,9 +21,25 @@ export declare class ProjectPlanningService {
|
|
|
17
21
|
recordDecision(input: ProjectPlanningDecisionRecordInput): Promise<ProjectPlanningDecisionResult>;
|
|
18
22
|
getLanguage(input?: ProjectPlanningSpaceInput): Promise<ProjectPlanningLanguageResult>;
|
|
19
23
|
upsertLanguage(input: ProjectPlanningLanguageUpsertInput): Promise<ProjectPlanningLanguageResult>;
|
|
24
|
+
getWorkPlanSnapshot(input?: ProjectWorkPlanTaskListInput): Promise<ProjectWorkPlanSnapshot>;
|
|
25
|
+
getWorkPlanTask(input: ProjectWorkPlanTaskGetInput): Promise<ProjectWorkPlanTaskResult>;
|
|
26
|
+
createWorkPlanTask(input: ProjectWorkPlanTaskCreateInput): Promise<ProjectWorkPlanMutationResult>;
|
|
27
|
+
updateWorkPlanTask(input: ProjectWorkPlanTaskUpdateInput): Promise<ProjectWorkPlanMutationResult>;
|
|
28
|
+
setWorkPlanTaskStatus(input: ProjectWorkPlanTaskStatusInput): Promise<ProjectWorkPlanMutationResult>;
|
|
29
|
+
reorderWorkPlanTasks(input: ProjectWorkPlanTaskReorderInput): Promise<ProjectWorkPlanSnapshot>;
|
|
30
|
+
deleteWorkPlanTask(input: ProjectWorkPlanTaskDeleteInput): Promise<ProjectWorkPlanMutationResult>;
|
|
31
|
+
clearCompletedWorkPlanTasks(input?: ProjectWorkPlanClearCompletedInput): Promise<ProjectWorkPlanMutationResult>;
|
|
20
32
|
private resolveSpace;
|
|
21
33
|
private sourcesForSpace;
|
|
22
34
|
private getArtifactSource;
|
|
35
|
+
private getWorkPlanArtifact;
|
|
36
|
+
private saveWorkPlanArtifact;
|
|
37
|
+
private syncPlanningStateTasksToWorkPlan;
|
|
23
38
|
private upsertArtifactSource;
|
|
39
|
+
private emitWorkPlanTaskCreated;
|
|
40
|
+
private emitWorkPlanTaskUpdated;
|
|
41
|
+
private emitWorkPlanTaskStatusChanged;
|
|
42
|
+
private emitWorkPlanTaskDeleted;
|
|
43
|
+
private emitWorkPlanSnapshotInvalidated;
|
|
24
44
|
}
|
|
25
45
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/platform/knowledge/project-planning/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/platform/knowledge/project-planning/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { knowledgeSpaceMetadata, normalizeProjectId, } from '../spaces.js';
|
|
2
3
|
import { KnowledgeStore } from '../store.js';
|
|
4
|
+
import { emitWorkPlanSnapshotInvalidated, emitWorkPlanTaskCreated, emitWorkPlanTaskDeleted, emitWorkPlanTaskStatusChanged, emitWorkPlanTaskUpdated, } from '../../runtime/emitters/index.js';
|
|
3
5
|
import { PROJECT_PLANNING_CONNECTOR_ID, PROJECT_PLANNING_TAG, projectPlanningArtifactSummary, projectPlanningCanonicalUri, projectPlanningSourceId, readPlanningMetadataObject, resolveProjectPlanningSpace, stablePlanningId, } from './helpers.js';
|
|
4
6
|
import { evaluateProjectPlanningReadiness } from './readiness.js';
|
|
5
7
|
export class ProjectPlanningService {
|
|
6
8
|
store;
|
|
7
9
|
defaultProjectId;
|
|
10
|
+
runtimeBus;
|
|
8
11
|
constructor(store, options = {}) {
|
|
9
12
|
this.store = store;
|
|
10
13
|
this.defaultProjectId = normalizeProjectId(options.defaultProjectId ?? 'default');
|
|
14
|
+
this.runtimeBus = options.runtimeBus ?? null;
|
|
15
|
+
}
|
|
16
|
+
attachRuntimeBus(runtimeBus) {
|
|
17
|
+
this.runtimeBus = runtimeBus ?? null;
|
|
11
18
|
}
|
|
12
19
|
async status(input = {}) {
|
|
13
20
|
await this.store.init();
|
|
@@ -22,12 +29,18 @@ export class ProjectPlanningService {
|
|
|
22
29
|
states: sources.filter((source) => artifactKind(source) === 'state').length,
|
|
23
30
|
decisions: sources.filter((source) => artifactKind(source) === 'decision').length,
|
|
24
31
|
languageArtifacts: sources.filter((source) => artifactKind(source) === 'language').length,
|
|
32
|
+
workPlans: sources.filter((source) => artifactKind(source) === 'work-plan').length,
|
|
33
|
+
workPlanTasks: sources
|
|
34
|
+
.filter((source) => artifactKind(source) === 'work-plan')
|
|
35
|
+
.reduce((count, source) => count + (readWorkPlan(source)?.tasks.length ?? 0), 0),
|
|
25
36
|
},
|
|
26
37
|
capabilities: [
|
|
27
38
|
'project-scoped-storage',
|
|
28
39
|
'planning-state-validation',
|
|
29
40
|
'project-language-artifacts',
|
|
30
41
|
'decision-records',
|
|
42
|
+
'durable-work-plan-tasks',
|
|
43
|
+
'work-plan-transition-events',
|
|
31
44
|
'agent-task-graph-metadata',
|
|
32
45
|
'passive-daemon-only',
|
|
33
46
|
],
|
|
@@ -54,6 +67,7 @@ export class ProjectPlanningService {
|
|
|
54
67
|
const evaluation = evaluateProjectPlanningReadiness(state);
|
|
55
68
|
const normalized = evaluation.state;
|
|
56
69
|
const source = await this.upsertArtifactSource(space, 'state', normalized.id, normalized);
|
|
70
|
+
await this.syncPlanningStateTasksToWorkPlan(space, normalized);
|
|
57
71
|
return {
|
|
58
72
|
ok: true,
|
|
59
73
|
projectId: space.projectId,
|
|
@@ -152,6 +166,205 @@ export class ProjectPlanningService {
|
|
|
152
166
|
source,
|
|
153
167
|
};
|
|
154
168
|
}
|
|
169
|
+
async getWorkPlanSnapshot(input = {}) {
|
|
170
|
+
await this.store.init();
|
|
171
|
+
const space = this.resolveSpace(input);
|
|
172
|
+
const workPlan = this.getWorkPlanArtifact(space, normalizeWorkPlanId(input.workPlanId));
|
|
173
|
+
return snapshotFromWorkPlan(space, workPlan, {
|
|
174
|
+
status: input.status,
|
|
175
|
+
parentTaskId: input.parentTaskId,
|
|
176
|
+
chainId: input.chainId,
|
|
177
|
+
owner: input.owner,
|
|
178
|
+
limit: input.limit,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async getWorkPlanTask(input) {
|
|
182
|
+
await this.store.init();
|
|
183
|
+
const snapshot = await this.getWorkPlanSnapshot(input);
|
|
184
|
+
return {
|
|
185
|
+
ok: true,
|
|
186
|
+
projectId: snapshot.projectId,
|
|
187
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
188
|
+
workPlanId: snapshot.workPlanId,
|
|
189
|
+
task: snapshot.tasks.find((task) => task.taskId === input.taskId) ?? null,
|
|
190
|
+
snapshot,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
async createWorkPlanTask(input) {
|
|
194
|
+
await this.store.init();
|
|
195
|
+
const space = this.resolveSpace(input);
|
|
196
|
+
const workPlanId = normalizeWorkPlanId(input.workPlanId);
|
|
197
|
+
const existing = this.getWorkPlanArtifact(space, workPlanId);
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
const task = normalizeWorkPlanTask(input.task, {
|
|
200
|
+
projectId: space.projectId,
|
|
201
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
202
|
+
now,
|
|
203
|
+
fallbackOrder: nextWorkPlanOrder(existing.tasks),
|
|
204
|
+
});
|
|
205
|
+
if (existing.tasks.some((entry) => entry.taskId === task.taskId)) {
|
|
206
|
+
throw new Error(`Work plan task already exists: ${task.taskId}`);
|
|
207
|
+
}
|
|
208
|
+
const workPlan = await this.saveWorkPlanArtifact(space, {
|
|
209
|
+
...existing,
|
|
210
|
+
tasks: sortWorkPlanTasks([...existing.tasks, task]),
|
|
211
|
+
updatedAt: now,
|
|
212
|
+
});
|
|
213
|
+
const snapshot = snapshotFromWorkPlan(space, workPlan);
|
|
214
|
+
this.emitWorkPlanTaskCreated(snapshot, task);
|
|
215
|
+
return {
|
|
216
|
+
ok: true,
|
|
217
|
+
projectId: space.projectId,
|
|
218
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
219
|
+
workPlanId,
|
|
220
|
+
task,
|
|
221
|
+
snapshot,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
async updateWorkPlanTask(input) {
|
|
225
|
+
await this.store.init();
|
|
226
|
+
const space = this.resolveSpace(input);
|
|
227
|
+
const workPlanId = normalizeWorkPlanId(input.workPlanId);
|
|
228
|
+
const existing = this.getWorkPlanArtifact(space, workPlanId);
|
|
229
|
+
const previousTask = existing.tasks.find((task) => task.taskId === input.taskId);
|
|
230
|
+
if (!previousTask)
|
|
231
|
+
throw new Error(`Work plan task not found: ${input.taskId}`);
|
|
232
|
+
const now = Date.now();
|
|
233
|
+
const task = normalizeWorkPlanTask({
|
|
234
|
+
...previousTask,
|
|
235
|
+
...input.patch,
|
|
236
|
+
metadata: {
|
|
237
|
+
...(previousTask.metadata ?? {}),
|
|
238
|
+
...(input.patch.metadata ?? {}),
|
|
239
|
+
},
|
|
240
|
+
taskId: previousTask.taskId,
|
|
241
|
+
createdAt: previousTask.createdAt,
|
|
242
|
+
updatedAt: now,
|
|
243
|
+
}, {
|
|
244
|
+
projectId: space.projectId,
|
|
245
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
246
|
+
now,
|
|
247
|
+
fallbackOrder: previousTask.order,
|
|
248
|
+
});
|
|
249
|
+
const workPlan = await this.saveWorkPlanArtifact(space, {
|
|
250
|
+
...existing,
|
|
251
|
+
tasks: sortWorkPlanTasks(existing.tasks.map((entry) => entry.taskId === input.taskId ? task : entry)),
|
|
252
|
+
updatedAt: now,
|
|
253
|
+
});
|
|
254
|
+
const snapshot = snapshotFromWorkPlan(space, workPlan);
|
|
255
|
+
this.emitWorkPlanTaskUpdated(snapshot, task, previousTask);
|
|
256
|
+
if (previousTask.status !== task.status) {
|
|
257
|
+
this.emitWorkPlanTaskStatusChanged(snapshot, task, previousTask);
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
ok: true,
|
|
261
|
+
projectId: space.projectId,
|
|
262
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
263
|
+
workPlanId,
|
|
264
|
+
task,
|
|
265
|
+
previousTask,
|
|
266
|
+
snapshot,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async setWorkPlanTaskStatus(input) {
|
|
270
|
+
return this.updateWorkPlanTask({
|
|
271
|
+
projectId: input.projectId,
|
|
272
|
+
knowledgeSpaceId: input.knowledgeSpaceId,
|
|
273
|
+
workPlanId: input.workPlanId,
|
|
274
|
+
taskId: input.taskId,
|
|
275
|
+
patch: {
|
|
276
|
+
status: normalizeWorkPlanStatus(input.status),
|
|
277
|
+
...(input.source ? { source: input.source } : {}),
|
|
278
|
+
metadata: {
|
|
279
|
+
...(input.reason ? { statusReason: input.reason } : {}),
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
async reorderWorkPlanTasks(input) {
|
|
285
|
+
await this.store.init();
|
|
286
|
+
const space = this.resolveSpace(input);
|
|
287
|
+
const workPlanId = normalizeWorkPlanId(input.workPlanId);
|
|
288
|
+
const existing = this.getWorkPlanArtifact(space, workPlanId);
|
|
289
|
+
const previousById = new Map(existing.tasks.map((task) => [task.taskId, task]));
|
|
290
|
+
const orderById = new Map(input.orderedTaskIds.map((taskId, index) => [taskId, index]));
|
|
291
|
+
for (const taskId of orderById.keys()) {
|
|
292
|
+
if (!previousById.has(taskId))
|
|
293
|
+
throw new Error(`Work plan task not found: ${taskId}`);
|
|
294
|
+
}
|
|
295
|
+
const now = Date.now();
|
|
296
|
+
const tasks = sortWorkPlanTasks(existing.tasks.map((task) => ({
|
|
297
|
+
...task,
|
|
298
|
+
order: orderById.get(task.taskId) ?? task.order + input.orderedTaskIds.length,
|
|
299
|
+
updatedAt: orderById.has(task.taskId) ? now : task.updatedAt,
|
|
300
|
+
})));
|
|
301
|
+
const workPlan = await this.saveWorkPlanArtifact(space, {
|
|
302
|
+
...existing,
|
|
303
|
+
tasks,
|
|
304
|
+
updatedAt: now,
|
|
305
|
+
});
|
|
306
|
+
const snapshot = snapshotFromWorkPlan(space, workPlan);
|
|
307
|
+
for (const task of tasks) {
|
|
308
|
+
const previousTask = previousById.get(task.taskId);
|
|
309
|
+
if (previousTask && previousTask.order !== task.order) {
|
|
310
|
+
this.emitWorkPlanTaskUpdated(snapshot, task, previousTask, true);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
this.emitWorkPlanSnapshotInvalidated(snapshot, 'reordered');
|
|
314
|
+
return snapshot;
|
|
315
|
+
}
|
|
316
|
+
async deleteWorkPlanTask(input) {
|
|
317
|
+
await this.store.init();
|
|
318
|
+
const space = this.resolveSpace(input);
|
|
319
|
+
const workPlanId = normalizeWorkPlanId(input.workPlanId);
|
|
320
|
+
const existing = this.getWorkPlanArtifact(space, workPlanId);
|
|
321
|
+
const deletedTask = existing.tasks.find((task) => task.taskId === input.taskId);
|
|
322
|
+
if (!deletedTask)
|
|
323
|
+
throw new Error(`Work plan task not found: ${input.taskId}`);
|
|
324
|
+
const now = Date.now();
|
|
325
|
+
const workPlan = await this.saveWorkPlanArtifact(space, {
|
|
326
|
+
...existing,
|
|
327
|
+
tasks: existing.tasks.filter((task) => task.taskId !== input.taskId),
|
|
328
|
+
updatedAt: now,
|
|
329
|
+
});
|
|
330
|
+
const snapshot = snapshotFromWorkPlan(space, workPlan);
|
|
331
|
+
this.emitWorkPlanTaskDeleted(snapshot, deletedTask);
|
|
332
|
+
return {
|
|
333
|
+
ok: true,
|
|
334
|
+
projectId: space.projectId,
|
|
335
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
336
|
+
workPlanId,
|
|
337
|
+
deletedTask,
|
|
338
|
+
snapshot,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async clearCompletedWorkPlanTasks(input = {}) {
|
|
342
|
+
await this.store.init();
|
|
343
|
+
const space = this.resolveSpace(input);
|
|
344
|
+
const workPlanId = normalizeWorkPlanId(input.workPlanId);
|
|
345
|
+
const existing = this.getWorkPlanArtifact(space, workPlanId);
|
|
346
|
+
const statuses = new Set(input.statuses?.length ? input.statuses.map(normalizeWorkPlanStatus) : ['done']);
|
|
347
|
+
const cleared = existing.tasks.filter((task) => statuses.has(task.status));
|
|
348
|
+
const now = Date.now();
|
|
349
|
+
const workPlan = await this.saveWorkPlanArtifact(space, {
|
|
350
|
+
...existing,
|
|
351
|
+
tasks: existing.tasks.filter((task) => !statuses.has(task.status)),
|
|
352
|
+
updatedAt: now,
|
|
353
|
+
});
|
|
354
|
+
const snapshot = snapshotFromWorkPlan(space, workPlan);
|
|
355
|
+
for (const task of cleared) {
|
|
356
|
+
this.emitWorkPlanTaskDeleted(snapshot, task, true);
|
|
357
|
+
}
|
|
358
|
+
this.emitWorkPlanSnapshotInvalidated(snapshot, 'cleared-completed');
|
|
359
|
+
return {
|
|
360
|
+
ok: true,
|
|
361
|
+
projectId: space.projectId,
|
|
362
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
363
|
+
workPlanId,
|
|
364
|
+
clearedTaskIds: cleared.map((task) => task.taskId),
|
|
365
|
+
snapshot,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
155
368
|
resolveSpace(input = {}) {
|
|
156
369
|
return resolveProjectPlanningSpace(input, this.defaultProjectId);
|
|
157
370
|
}
|
|
@@ -165,6 +378,75 @@ export class ProjectPlanningService {
|
|
|
165
378
|
const sourceId = projectPlanningSourceId(spaceId, kind, id);
|
|
166
379
|
return this.store.getSource(sourceId) ?? this.store.getSourceByCanonicalUri(projectPlanningCanonicalUri(spaceId, kind, id));
|
|
167
380
|
}
|
|
381
|
+
getWorkPlanArtifact(space, workPlanId) {
|
|
382
|
+
const source = this.getArtifactSource(space.knowledgeSpaceId, 'work-plan', workPlanId);
|
|
383
|
+
const value = source?.metadata.value;
|
|
384
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
385
|
+
return normalizeWorkPlanArtifact(value, space, workPlanId);
|
|
386
|
+
}
|
|
387
|
+
const now = Date.now();
|
|
388
|
+
return {
|
|
389
|
+
id: workPlanId,
|
|
390
|
+
projectId: space.projectId,
|
|
391
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
392
|
+
tasks: [],
|
|
393
|
+
createdAt: now,
|
|
394
|
+
updatedAt: now,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
async saveWorkPlanArtifact(space, workPlan) {
|
|
398
|
+
const normalized = normalizeWorkPlanArtifact(workPlan, space, workPlan.id);
|
|
399
|
+
await this.upsertArtifactSource(space, 'work-plan', normalized.id, normalized);
|
|
400
|
+
return normalized;
|
|
401
|
+
}
|
|
402
|
+
async syncPlanningStateTasksToWorkPlan(space, state) {
|
|
403
|
+
for (const [index, task] of state.tasks.entries()) {
|
|
404
|
+
if (!task.title?.trim())
|
|
405
|
+
continue;
|
|
406
|
+
const taskId = normalizeWorkPlanTaskId(`planning-${state.id}-${task.id || task.title}`);
|
|
407
|
+
const workPlanTask = {
|
|
408
|
+
taskId,
|
|
409
|
+
title: task.title,
|
|
410
|
+
notes: task.why,
|
|
411
|
+
owner: task.recommendedAgent,
|
|
412
|
+
status: workPlanStatusFromPlanningTask(task),
|
|
413
|
+
priority: task.needsReview ? 10 : 0,
|
|
414
|
+
order: index,
|
|
415
|
+
source: 'planning',
|
|
416
|
+
tags: [
|
|
417
|
+
'planning',
|
|
418
|
+
...(task.needsReview ? ['needs-review'] : []),
|
|
419
|
+
...(task.blockedOnUserInput ? ['blocked-on-user-input'] : []),
|
|
420
|
+
],
|
|
421
|
+
originSurface: 'daemon',
|
|
422
|
+
metadata: {
|
|
423
|
+
planningId: state.id,
|
|
424
|
+
planningTaskId: task.id,
|
|
425
|
+
dependencies: task.dependencies ?? [],
|
|
426
|
+
likelyFiles: task.likelyFiles ?? [],
|
|
427
|
+
verification: task.verification ?? [],
|
|
428
|
+
canRunConcurrently: task.canRunConcurrently === true,
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
try {
|
|
432
|
+
await this.createWorkPlanTask({
|
|
433
|
+
projectId: space.projectId,
|
|
434
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
435
|
+
task: workPlanTask,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
if (!(error instanceof Error) || !error.message.includes('already exists'))
|
|
440
|
+
throw error;
|
|
441
|
+
await this.updateWorkPlanTask({
|
|
442
|
+
projectId: space.projectId,
|
|
443
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
444
|
+
taskId,
|
|
445
|
+
patch: workPlanTask,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
168
450
|
async upsertArtifactSource(space, kind, id, value) {
|
|
169
451
|
const spaceId = space.knowledgeSpaceId;
|
|
170
452
|
return this.store.upsertSource({
|
|
@@ -185,6 +467,67 @@ export class ProjectPlanningService {
|
|
|
185
467
|
}),
|
|
186
468
|
});
|
|
187
469
|
}
|
|
470
|
+
emitWorkPlanTaskCreated(snapshot, task) {
|
|
471
|
+
if (!this.runtimeBus)
|
|
472
|
+
return;
|
|
473
|
+
emitWorkPlanTaskCreated(this.runtimeBus, workPlanEmitterContext(snapshot), {
|
|
474
|
+
projectId: snapshot.projectId,
|
|
475
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
476
|
+
workPlanId: snapshot.workPlanId,
|
|
477
|
+
task,
|
|
478
|
+
});
|
|
479
|
+
this.emitWorkPlanSnapshotInvalidated(snapshot, 'task-created');
|
|
480
|
+
}
|
|
481
|
+
emitWorkPlanTaskUpdated(snapshot, task, previousTask, skipSnapshotInvalidation = false) {
|
|
482
|
+
if (!this.runtimeBus)
|
|
483
|
+
return;
|
|
484
|
+
emitWorkPlanTaskUpdated(this.runtimeBus, workPlanEmitterContext(snapshot), {
|
|
485
|
+
projectId: snapshot.projectId,
|
|
486
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
487
|
+
workPlanId: snapshot.workPlanId,
|
|
488
|
+
task,
|
|
489
|
+
previousTask,
|
|
490
|
+
});
|
|
491
|
+
if (!skipSnapshotInvalidation)
|
|
492
|
+
this.emitWorkPlanSnapshotInvalidated(snapshot, 'task-updated');
|
|
493
|
+
}
|
|
494
|
+
emitWorkPlanTaskStatusChanged(snapshot, task, previousTask) {
|
|
495
|
+
if (!this.runtimeBus)
|
|
496
|
+
return;
|
|
497
|
+
emitWorkPlanTaskStatusChanged(this.runtimeBus, workPlanEmitterContext(snapshot), {
|
|
498
|
+
projectId: snapshot.projectId,
|
|
499
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
500
|
+
workPlanId: snapshot.workPlanId,
|
|
501
|
+
taskId: task.taskId,
|
|
502
|
+
status: task.status,
|
|
503
|
+
previousStatus: previousTask.status,
|
|
504
|
+
task,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
emitWorkPlanTaskDeleted(snapshot, task, skipSnapshotInvalidation = false) {
|
|
508
|
+
if (!this.runtimeBus)
|
|
509
|
+
return;
|
|
510
|
+
emitWorkPlanTaskDeleted(this.runtimeBus, workPlanEmitterContext(snapshot), {
|
|
511
|
+
projectId: snapshot.projectId,
|
|
512
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
513
|
+
workPlanId: snapshot.workPlanId,
|
|
514
|
+
taskId: task.taskId,
|
|
515
|
+
task,
|
|
516
|
+
});
|
|
517
|
+
if (!skipSnapshotInvalidation)
|
|
518
|
+
this.emitWorkPlanSnapshotInvalidated(snapshot, 'task-deleted');
|
|
519
|
+
}
|
|
520
|
+
emitWorkPlanSnapshotInvalidated(snapshot, reason) {
|
|
521
|
+
if (!this.runtimeBus)
|
|
522
|
+
return;
|
|
523
|
+
emitWorkPlanSnapshotInvalidated(this.runtimeBus, workPlanEmitterContext(snapshot), {
|
|
524
|
+
projectId: snapshot.projectId,
|
|
525
|
+
knowledgeSpaceId: snapshot.knowledgeSpaceId,
|
|
526
|
+
workPlanId: snapshot.workPlanId,
|
|
527
|
+
reason,
|
|
528
|
+
snapshot,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
188
531
|
}
|
|
189
532
|
function normalizeState(input, projectId, knowledgeSpaceId) {
|
|
190
533
|
const now = Date.now();
|
|
@@ -213,6 +556,158 @@ function normalizeState(input, projectId, knowledgeSpaceId) {
|
|
|
213
556
|
metadata: readPlanningMetadataObject(input.metadata),
|
|
214
557
|
};
|
|
215
558
|
}
|
|
559
|
+
function normalizeWorkPlanArtifact(input, space, workPlanId) {
|
|
560
|
+
const now = Date.now();
|
|
561
|
+
const createdAt = typeof input.createdAt === 'number' ? input.createdAt : now;
|
|
562
|
+
const tasks = Array.isArray(input.tasks)
|
|
563
|
+
? input.tasks.map((task, index) => normalizeWorkPlanTask(task, {
|
|
564
|
+
projectId: space.projectId,
|
|
565
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
566
|
+
now,
|
|
567
|
+
fallbackOrder: index,
|
|
568
|
+
}))
|
|
569
|
+
: [];
|
|
570
|
+
return {
|
|
571
|
+
id: normalizeWorkPlanId(input.id ?? workPlanId),
|
|
572
|
+
projectId: space.projectId,
|
|
573
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
574
|
+
tasks: sortWorkPlanTasks(tasks),
|
|
575
|
+
createdAt,
|
|
576
|
+
updatedAt: typeof input.updatedAt === 'number' ? input.updatedAt : now,
|
|
577
|
+
...(input.metadata ? { metadata: readPlanningMetadataObject(input.metadata) } : {}),
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function normalizeWorkPlanTask(input, options) {
|
|
581
|
+
const title = typeof input.title === 'string' ? input.title.trim() : '';
|
|
582
|
+
if (!title)
|
|
583
|
+
throw new Error('Work plan task title is required.');
|
|
584
|
+
const status = normalizeWorkPlanStatus(input.status ?? 'pending');
|
|
585
|
+
const createdAt = typeof input.createdAt === 'number' ? input.createdAt : options.now;
|
|
586
|
+
return {
|
|
587
|
+
taskId: normalizeWorkPlanTaskId(input.taskId ?? `task-${randomUUID().slice(0, 12)}`),
|
|
588
|
+
projectId: options.projectId,
|
|
589
|
+
knowledgeSpaceId: options.knowledgeSpaceId,
|
|
590
|
+
title,
|
|
591
|
+
...(typeof input.notes === 'string' ? { notes: input.notes } : {}),
|
|
592
|
+
...(typeof input.owner === 'string' && input.owner.trim() ? { owner: input.owner.trim() } : {}),
|
|
593
|
+
status,
|
|
594
|
+
...(typeof input.priority === 'number' && Number.isFinite(input.priority) ? { priority: input.priority } : {}),
|
|
595
|
+
order: typeof input.order === 'number' && Number.isFinite(input.order) ? input.order : options.fallbackOrder,
|
|
596
|
+
...(typeof input.source === 'string' && input.source.trim() ? { source: input.source.trim() } : {}),
|
|
597
|
+
tags: stringList(input.tags),
|
|
598
|
+
...(typeof input.parentTaskId === 'string' && input.parentTaskId.trim() ? { parentTaskId: normalizeWorkPlanTaskId(input.parentTaskId) } : {}),
|
|
599
|
+
...(typeof input.chainId === 'string' && input.chainId.trim() ? { chainId: input.chainId.trim() } : {}),
|
|
600
|
+
...(typeof input.phaseId === 'string' && input.phaseId.trim() ? { phaseId: input.phaseId.trim() } : {}),
|
|
601
|
+
...(typeof input.agentId === 'string' && input.agentId.trim() ? { agentId: input.agentId.trim() } : {}),
|
|
602
|
+
...(typeof input.turnId === 'string' && input.turnId.trim() ? { turnId: input.turnId.trim() } : {}),
|
|
603
|
+
...(typeof input.decisionId === 'string' && input.decisionId.trim() ? { decisionId: input.decisionId.trim() } : {}),
|
|
604
|
+
...(typeof input.sourceMessageId === 'string' && input.sourceMessageId.trim() ? { sourceMessageId: input.sourceMessageId.trim() } : {}),
|
|
605
|
+
linkedArtifactIds: stringList(input.linkedArtifactIds),
|
|
606
|
+
linkedSourceIds: stringList(input.linkedSourceIds),
|
|
607
|
+
linkedNodeIds: stringList(input.linkedNodeIds),
|
|
608
|
+
...(typeof input.originSurface === 'string' && input.originSurface.trim() ? { originSurface: input.originSurface.trim() } : {}),
|
|
609
|
+
createdAt,
|
|
610
|
+
updatedAt: typeof input.updatedAt === 'number' ? input.updatedAt : options.now,
|
|
611
|
+
...(status === 'done' || status === 'failed' || status === 'cancelled'
|
|
612
|
+
? { completedAt: typeof input.completedAt === 'number' ? input.completedAt : options.now }
|
|
613
|
+
: {}),
|
|
614
|
+
...(input.metadata ? { metadata: readPlanningMetadataObject(input.metadata) } : {}),
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
function normalizeWorkPlanId(value) {
|
|
618
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
619
|
+
? stablePlanningId('work-plan', value)
|
|
620
|
+
: 'current';
|
|
621
|
+
}
|
|
622
|
+
function normalizeWorkPlanTaskId(value) {
|
|
623
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
624
|
+
? stablePlanningId('task', value)
|
|
625
|
+
: `task-${randomUUID().slice(0, 12)}`;
|
|
626
|
+
}
|
|
627
|
+
function normalizeWorkPlanStatus(value) {
|
|
628
|
+
if (value === 'pending'
|
|
629
|
+
|| value === 'in_progress'
|
|
630
|
+
|| value === 'blocked'
|
|
631
|
+
|| value === 'done'
|
|
632
|
+
|| value === 'failed'
|
|
633
|
+
|| value === 'cancelled') {
|
|
634
|
+
return value;
|
|
635
|
+
}
|
|
636
|
+
if (value === 'in-progress')
|
|
637
|
+
return 'in_progress';
|
|
638
|
+
if (value === 'completed')
|
|
639
|
+
return 'done';
|
|
640
|
+
throw new Error(`Invalid work plan task status: ${String(value)}`);
|
|
641
|
+
}
|
|
642
|
+
function workPlanStatusFromPlanningTask(task) {
|
|
643
|
+
if (task.status === 'in-progress')
|
|
644
|
+
return 'in_progress';
|
|
645
|
+
if (task.status === 'blocked')
|
|
646
|
+
return 'blocked';
|
|
647
|
+
if (task.status === 'completed')
|
|
648
|
+
return 'done';
|
|
649
|
+
if (task.blockedOnUserInput === true)
|
|
650
|
+
return 'blocked';
|
|
651
|
+
return 'pending';
|
|
652
|
+
}
|
|
653
|
+
function stringList(value) {
|
|
654
|
+
if (!Array.isArray(value))
|
|
655
|
+
return [];
|
|
656
|
+
return [...new Set(value.filter((entry) => typeof entry === 'string' && entry.trim().length > 0).map((entry) => entry.trim()))];
|
|
657
|
+
}
|
|
658
|
+
function nextWorkPlanOrder(tasks) {
|
|
659
|
+
return tasks.reduce((max, task) => Math.max(max, task.order), -1) + 1;
|
|
660
|
+
}
|
|
661
|
+
function sortWorkPlanTasks(tasks) {
|
|
662
|
+
return [...tasks].sort((a, b) => a.order - b.order || a.createdAt - b.createdAt || a.taskId.localeCompare(b.taskId));
|
|
663
|
+
}
|
|
664
|
+
function snapshotFromWorkPlan(space, workPlan, filter = {}) {
|
|
665
|
+
const tasks = sortWorkPlanTasks(workPlan.tasks).filter((task) => {
|
|
666
|
+
if (filter.status && task.status !== filter.status)
|
|
667
|
+
return false;
|
|
668
|
+
if (filter.parentTaskId && task.parentTaskId !== filter.parentTaskId)
|
|
669
|
+
return false;
|
|
670
|
+
if (filter.chainId && task.chainId !== filter.chainId)
|
|
671
|
+
return false;
|
|
672
|
+
if (filter.owner && task.owner !== filter.owner)
|
|
673
|
+
return false;
|
|
674
|
+
return true;
|
|
675
|
+
});
|
|
676
|
+
const limit = typeof filter.limit === 'number' && Number.isFinite(filter.limit) && filter.limit > 0
|
|
677
|
+
? Math.floor(filter.limit)
|
|
678
|
+
: undefined;
|
|
679
|
+
return {
|
|
680
|
+
ok: true,
|
|
681
|
+
projectId: space.projectId,
|
|
682
|
+
knowledgeSpaceId: space.knowledgeSpaceId,
|
|
683
|
+
workPlanId: workPlan.id,
|
|
684
|
+
tasks: limit ? tasks.slice(0, limit) : tasks,
|
|
685
|
+
counts: countWorkPlanTasks(workPlan.tasks),
|
|
686
|
+
updatedAt: workPlan.updatedAt,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function countWorkPlanTasks(tasks) {
|
|
690
|
+
const counts = {
|
|
691
|
+
total: tasks.length,
|
|
692
|
+
pending: 0,
|
|
693
|
+
in_progress: 0,
|
|
694
|
+
blocked: 0,
|
|
695
|
+
done: 0,
|
|
696
|
+
failed: 0,
|
|
697
|
+
cancelled: 0,
|
|
698
|
+
};
|
|
699
|
+
for (const task of tasks) {
|
|
700
|
+
counts[task.status] += 1;
|
|
701
|
+
}
|
|
702
|
+
return counts;
|
|
703
|
+
}
|
|
704
|
+
function workPlanEmitterContext(snapshot) {
|
|
705
|
+
return {
|
|
706
|
+
traceId: `project-planning:work-plan:${snapshot.workPlanId}:${snapshot.updatedAt}`,
|
|
707
|
+
sessionId: `project:${snapshot.projectId}`,
|
|
708
|
+
source: 'project-planning.work-plan',
|
|
709
|
+
};
|
|
710
|
+
}
|
|
216
711
|
function normalizePlanningId(value) {
|
|
217
712
|
return typeof value === 'string' && value.trim().length > 0
|
|
218
713
|
? stablePlanningId('plan', value)
|
|
@@ -236,7 +731,7 @@ function arrayOfObjectsOrStrings(value) {
|
|
|
236
731
|
}
|
|
237
732
|
function artifactKind(source) {
|
|
238
733
|
const kind = source.metadata.planningArtifactKind;
|
|
239
|
-
return kind === 'state' || kind === 'decision' || kind === 'language' ? kind : null;
|
|
734
|
+
return kind === 'state' || kind === 'decision' || kind === 'language' || kind === 'work-plan' ? kind : null;
|
|
240
735
|
}
|
|
241
736
|
function readState(source) {
|
|
242
737
|
const value = source.metadata.value;
|
|
@@ -250,10 +745,16 @@ function readLanguage(source) {
|
|
|
250
745
|
const value = source.metadata.value;
|
|
251
746
|
return value && typeof value === 'object' ? value : null;
|
|
252
747
|
}
|
|
748
|
+
function readWorkPlan(source) {
|
|
749
|
+
const value = source.metadata.value;
|
|
750
|
+
return value && typeof value === 'object' ? value : null;
|
|
751
|
+
}
|
|
253
752
|
function titleForArtifact(kind, value) {
|
|
254
753
|
if (kind === 'state')
|
|
255
754
|
return `Planning: ${value.goal || 'Current plan'}`;
|
|
256
755
|
if (kind === 'decision')
|
|
257
756
|
return `Decision: ${value.title}`;
|
|
757
|
+
if (kind === 'work-plan')
|
|
758
|
+
return 'Project Work Plan';
|
|
258
759
|
return 'Project Language';
|
|
259
760
|
}
|