crewly 1.4.82 → 1.5.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/config/domain-sops/EXAMPLE.sop.md +21 -0
- package/config/overlays/can-decide.md +5 -0
- package/config/overlays/can-delegate.md +5 -0
- package/config/overlays/can-user-reply.md +5 -0
- package/config/overlays/can-verify.md +5 -0
- package/config/risk-policies/EXAMPLE.policy.md +22 -0
- package/config/roles/developer/fragments/role-boundary.md +30 -0
- package/config/roles/orchestrator/fragments/role-boundary.md +25 -0
- package/config/roles/orchestrator/prompt.md +40 -6
- package/config/roles/team-leader/fragments/role-boundary.md +22 -0
- package/config/skills/agent/core/get-my-tasks/execute.sh +16 -0
- package/config/skills/agent/core/save-working-state/execute.sh +19 -0
- package/config/skills/agent/core/update-user-profile/execute.sh +13 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +34 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +107 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.routes.js +5 -1
- package/dist/backend/backend/src/controllers/chat/chat.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/index.d.ts +1 -1
- package/dist/backend/backend/src/controllers/chat/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/index.js +1 -1
- package/dist/backend/backend/src/controllers/chat/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/index.d.ts +1 -1
- package/dist/backend/backend/src/controllers/memory/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/index.js +1 -1
- package/dist/backend/backend/src/controllers/memory/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts +35 -0
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js +61 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts +2 -0
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js +5 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/cron-task.controller.d.ts +1 -0
- package/dist/backend/backend/src/controllers/system/cron-task.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/cron-task.controller.js +12 -6
- package/dist/backend/backend/src/controllers/system/cron-task.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +24 -0
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +107 -0
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +49 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +46 -42
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.js +5 -0
- package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +24 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +104 -2
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts +33 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/capability-overlay.module.js +70 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/capability-overlay.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts +35 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/domain-sop.module.js +50 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/domain-sop.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts +46 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/markdown-file-module.js +44 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/markdown-file-module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +13 -3
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +22 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js +2 -11
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js +10 -2
- package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts +35 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/risk-policy.module.js +50 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/risk-policy.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts +67 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +172 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts +5 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/user-profile-reference.module.js +18 -2
- package/dist/backend/backend/src/services/ai/prompt-modules/user-profile-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +9 -2
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +11 -0
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.js +41 -5
- package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory.service.d.ts +22 -0
- package/dist/backend/backend/src/services/memory/agent-memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory.service.js +103 -6
- package/dist/backend/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/index.d.ts +2 -1
- package/dist/backend/backend/src/services/memory/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/index.js +1 -0
- package/dist/backend/backend/src/services/memory/index.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.d.ts +43 -0
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +96 -0
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/user-profile.service.d.ts +77 -0
- package/dist/backend/backend/src/services/memory/user-profile.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/user-profile.service.js +171 -0
- package/dist/backend/backend/src/services/memory/user-profile.service.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts +8 -3
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +41 -16
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/thread-status-queue.service.d.ts +144 -1
- package/dist/backend/backend/src/services/messaging/thread-status-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/thread-status-queue.service.js +259 -2
- package/dist/backend/backend/src/services/messaging/thread-status-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +58 -2
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +189 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.js +12 -0
- package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.js +14 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +12 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/memory.types.d.ts +53 -0
- package/dist/backend/backend/src/types/memory.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/memory.types.js.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts +28 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
- package/dist/backend/backend/src/types/thread-status.types.d.ts +4 -0
- package/dist/backend/backend/src/types/thread-status.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/thread-status.types.js +4 -1
- package/dist/backend/backend/src/types/thread-status.types.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +157 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js +37 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts +22 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/agent-memory.service.js +103 -6
- package/dist/cli/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/goal-tracking.service.d.ts +239 -0
- package/dist/cli/backend/src/services/memory/goal-tracking.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/goal-tracking.service.js +353 -0
- package/dist/cli/backend/src/services/memory/goal-tracking.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +43 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +96 -0
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/project/task-tracking.service.d.ts +171 -0
- package/dist/cli/backend/src/services/project/task-tracking.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project/task-tracking.service.js +725 -0
- package/dist/cli/backend/src/services/project/task-tracking.service.js.map +1 -0
- package/dist/cli/backend/src/types/index.d.ts +12 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/memory.types.d.ts +53 -0
- package/dist/cli/backend/src/types/memory.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/memory.types.js.map +1 -1
- package/dist/cli/backend/src/types/task-tracking.types.d.ts +206 -0
- package/dist/cli/backend/src/types/task-tracking.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/task-tracking.types.js +5 -0
- package/dist/cli/backend/src/types/task-tracking.types.js.map +1 -0
- package/dist/cli/backend/src/types/thread-status.types.d.ts +4 -0
- package/dist/cli/backend/src/types/thread-status.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/thread-status.types.js +4 -1
- package/dist/cli/backend/src/types/thread-status.types.js.map +1 -1
- package/frontend/dist/assets/index-512efc8e.js +4921 -0
- package/frontend/dist/assets/{index-975ccc95.css → index-dc6ac165.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-d28d1135.js +0 -5215
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal Tracking Service
|
|
3
|
+
*
|
|
4
|
+
* Manages project-level goal files, current team focus, and a decisions log
|
|
5
|
+
* with retrospective outcomes. All files are stored as Markdown under
|
|
6
|
+
* `{projectPath}/.crewly/goals/`.
|
|
7
|
+
*
|
|
8
|
+
* Files managed:
|
|
9
|
+
* - `goals.md` — Append-only log of user-stated goals
|
|
10
|
+
* - `current_focus.md` — Overwritten each time the team focus changes
|
|
11
|
+
* - `decisions_log.md` — Append-only decisions with mutable outcome sections
|
|
12
|
+
*
|
|
13
|
+
* @module services/memory/goal-tracking.service
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'fs/promises';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { ensureDir, atomicWriteFile } from '../../utils/file-io.utils.js';
|
|
18
|
+
import { MEMORY_CONSTANTS } from '../../constants.js';
|
|
19
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
20
|
+
/**
|
|
21
|
+
* Service for tracking project goals, team focus, and architectural decisions.
|
|
22
|
+
*
|
|
23
|
+
* Follows the singleton pattern for consistent state management across
|
|
24
|
+
* the backend. Uses atomic writes for full-file overwrites and plain
|
|
25
|
+
* `fs.appendFile` for append-only logs (goals, decisions) where partial
|
|
26
|
+
* writes are acceptable.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const goalService = GoalTrackingService.getInstance();
|
|
31
|
+
*
|
|
32
|
+
* // Set a project goal
|
|
33
|
+
* await goalService.setGoal('/path/to/project', 'Ship v2.0 by March 15th', 'user');
|
|
34
|
+
*
|
|
35
|
+
* // Update team focus
|
|
36
|
+
* await goalService.updateFocus('/path/to/project', 'Completing auth module');
|
|
37
|
+
*
|
|
38
|
+
* // Log a decision
|
|
39
|
+
* const decId = await goalService.logDecision('/path/to/project', {
|
|
40
|
+
* title: 'Use PostgreSQL over MongoDB',
|
|
41
|
+
* decision: 'PostgreSQL for primary data store',
|
|
42
|
+
* rationale: 'Relational data model fits our schema better',
|
|
43
|
+
* decidedBy: 'orchestrator',
|
|
44
|
+
* alternatives: ['MongoDB', 'DynamoDB'],
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // Later, record the outcome
|
|
48
|
+
* await goalService.updateDecisionOutcome(
|
|
49
|
+
* '/path/to/project',
|
|
50
|
+
* decId,
|
|
51
|
+
* 'Successful - query performance is excellent',
|
|
52
|
+
* 'Invest time in schema design upfront to avoid migrations',
|
|
53
|
+
* );
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export class GoalTrackingService {
|
|
57
|
+
static instance = null;
|
|
58
|
+
/** Monotonic counter to ensure unique decision IDs even within the same millisecond */
|
|
59
|
+
decisionCounter = 0;
|
|
60
|
+
logger = LoggerService.getInstance().createComponentLogger('GoalTrackingService');
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new GoalTrackingService instance.
|
|
63
|
+
* Use {@link getInstance} for the singleton.
|
|
64
|
+
*/
|
|
65
|
+
constructor() {
|
|
66
|
+
// No initialization needed — all paths are derived from projectPath at call time
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Gets the singleton instance of GoalTrackingService.
|
|
70
|
+
*
|
|
71
|
+
* @returns The singleton GoalTrackingService instance
|
|
72
|
+
*/
|
|
73
|
+
static getInstance() {
|
|
74
|
+
if (!GoalTrackingService.instance) {
|
|
75
|
+
GoalTrackingService.instance = new GoalTrackingService();
|
|
76
|
+
}
|
|
77
|
+
return GoalTrackingService.instance;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Clears the singleton instance.
|
|
81
|
+
* Intended for test isolation only — never call in production.
|
|
82
|
+
*/
|
|
83
|
+
static clearInstance() {
|
|
84
|
+
GoalTrackingService.instance = null;
|
|
85
|
+
}
|
|
86
|
+
// ========================= HELPERS =========================
|
|
87
|
+
/**
|
|
88
|
+
* Returns the absolute path to the goals directory for a project.
|
|
89
|
+
*
|
|
90
|
+
* @param projectPath - Absolute path to the project root
|
|
91
|
+
* @returns Absolute path to `{projectPath}/.crewly/goals`
|
|
92
|
+
*/
|
|
93
|
+
getGoalsDir(projectPath) {
|
|
94
|
+
return path.join(projectPath, '.crewly', MEMORY_CONSTANTS.PATHS.GOALS_DIR);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Safely reads a file and returns its content, or `null` if the file
|
|
98
|
+
* does not exist.
|
|
99
|
+
*
|
|
100
|
+
* Permission errors and other unexpected failures are re-thrown.
|
|
101
|
+
*
|
|
102
|
+
* @param filePath - Absolute path to the file
|
|
103
|
+
* @returns File content as a UTF-8 string, or `null` if not found
|
|
104
|
+
*/
|
|
105
|
+
async safeReadFile(filePath) {
|
|
106
|
+
try {
|
|
107
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error.code === 'ENOENT') {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ========================= PUBLIC INTERFACE =========================
|
|
117
|
+
/**
|
|
118
|
+
* Appends a new goal entry to `goals.md`.
|
|
119
|
+
*
|
|
120
|
+
* If the file does not yet exist it is created with a Markdown header
|
|
121
|
+
* before the first entry is appended.
|
|
122
|
+
*
|
|
123
|
+
* @param projectPath - Absolute path to the project root
|
|
124
|
+
* @param goal - The goal text to record
|
|
125
|
+
* @param setBy - Who set the goal (defaults to `'user'`)
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* await goalService.setGoal('/projects/phoenix', 'Achieve 80% test coverage', 'user');
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async setGoal(projectPath, goal, setBy = 'user') {
|
|
133
|
+
const goalsDir = this.getGoalsDir(projectPath);
|
|
134
|
+
await ensureDir(goalsDir);
|
|
135
|
+
const goalsFile = path.join(goalsDir, MEMORY_CONSTANTS.PATHS.GOALS_FILE);
|
|
136
|
+
const existing = await this.safeReadFile(goalsFile);
|
|
137
|
+
const timestamp = new Date().toISOString();
|
|
138
|
+
const entry = `\n### [${timestamp}] Set by ${setBy}\n${goal}\n`;
|
|
139
|
+
if (existing === null) {
|
|
140
|
+
const header = `# Project Goals\n\n`;
|
|
141
|
+
await fs.writeFile(goalsFile, header + entry, 'utf-8');
|
|
142
|
+
this.logger.debug('Created goals file with first entry', { projectPath, setBy });
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
await fs.appendFile(goalsFile, entry, 'utf-8');
|
|
146
|
+
this.logger.debug('Appended goal entry', { projectPath, setBy });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Reads and returns the full contents of `goals.md`.
|
|
151
|
+
*
|
|
152
|
+
* @param projectPath - Absolute path to the project root
|
|
153
|
+
* @returns The goals file content, or `null` if the file does not exist
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const goals = await goalService.getGoals('/projects/phoenix');
|
|
158
|
+
* if (goals) {
|
|
159
|
+
* console.log(goals);
|
|
160
|
+
* }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
async getGoals(projectPath) {
|
|
164
|
+
const goalsFile = path.join(this.getGoalsDir(projectPath), MEMORY_CONSTANTS.PATHS.GOALS_FILE);
|
|
165
|
+
return this.safeReadFile(goalsFile);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Overwrites `current_focus.md` with the new focus description.
|
|
169
|
+
*
|
|
170
|
+
* Uses {@link atomicWriteFile} to ensure the file is never left in a
|
|
171
|
+
* partial-write state.
|
|
172
|
+
*
|
|
173
|
+
* @param projectPath - Absolute path to the project root
|
|
174
|
+
* @param focus - The new focus description
|
|
175
|
+
* @param updatedBy - Who updated the focus (defaults to `'orchestrator'`)
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* await goalService.updateFocus(
|
|
180
|
+
* '/projects/phoenix',
|
|
181
|
+
* 'Completing the authentication module and writing integration tests',
|
|
182
|
+
* 'orchestrator',
|
|
183
|
+
* );
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
async updateFocus(projectPath, focus, updatedBy = 'orchestrator') {
|
|
187
|
+
const goalsDir = this.getGoalsDir(projectPath);
|
|
188
|
+
await ensureDir(goalsDir);
|
|
189
|
+
const focusFile = path.join(goalsDir, MEMORY_CONSTANTS.PATHS.FOCUS_FILE);
|
|
190
|
+
const timestamp = new Date().toISOString();
|
|
191
|
+
const content = `# Current Focus\n` +
|
|
192
|
+
`\n` +
|
|
193
|
+
`**Updated:** ${timestamp}\n` +
|
|
194
|
+
`**By:** ${updatedBy}\n` +
|
|
195
|
+
`\n` +
|
|
196
|
+
`${focus}\n`;
|
|
197
|
+
await atomicWriteFile(focusFile, content);
|
|
198
|
+
this.logger.debug('Updated current focus', { projectPath, updatedBy });
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Reads and returns the full contents of `current_focus.md`.
|
|
202
|
+
*
|
|
203
|
+
* @param projectPath - Absolute path to the project root
|
|
204
|
+
* @returns The current focus file content, or `null` if the file does not exist
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const focus = await goalService.getCurrentFocus('/projects/phoenix');
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
async getCurrentFocus(projectPath) {
|
|
212
|
+
const focusFile = path.join(this.getGoalsDir(projectPath), MEMORY_CONSTANTS.PATHS.FOCUS_FILE);
|
|
213
|
+
return this.safeReadFile(focusFile);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Appends a new decision entry to `decisions_log.md` and returns a
|
|
217
|
+
* unique decision ID.
|
|
218
|
+
*
|
|
219
|
+
* If the file does not yet exist it is created with a Markdown header
|
|
220
|
+
* before the first entry is appended.
|
|
221
|
+
*
|
|
222
|
+
* The outcome field is initially set to `_pending_` and can be updated
|
|
223
|
+
* later via {@link updateDecisionOutcome}.
|
|
224
|
+
*
|
|
225
|
+
* @param projectPath - Absolute path to the project root
|
|
226
|
+
* @param decision - Decision parameters (title, decision, rationale, etc.)
|
|
227
|
+
* @returns The generated decision ID (format: `dec-{timestamp}-{counter}`)
|
|
228
|
+
*
|
|
229
|
+
* @throws {Error} If the file system write fails
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* const decisionId = await goalService.logDecision('/projects/phoenix', {
|
|
234
|
+
* title: 'Use Redis for caching',
|
|
235
|
+
* decision: 'Redis over Memcached',
|
|
236
|
+
* rationale: 'Better data structure support and persistence options',
|
|
237
|
+
* decidedBy: 'orchestrator',
|
|
238
|
+
* alternatives: ['Memcached', 'In-memory Map'],
|
|
239
|
+
* });
|
|
240
|
+
* // decisionId => 'dec-1707500000000-0'
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
async logDecision(projectPath, decision) {
|
|
244
|
+
const goalsDir = this.getGoalsDir(projectPath);
|
|
245
|
+
await ensureDir(goalsDir);
|
|
246
|
+
const decisionsFile = path.join(goalsDir, MEMORY_CONSTANTS.PATHS.DECISIONS_LOG);
|
|
247
|
+
const existing = await this.safeReadFile(decisionsFile);
|
|
248
|
+
const timestamp = new Date().toISOString();
|
|
249
|
+
const decisionId = `dec-${Date.now()}-${this.decisionCounter++}`;
|
|
250
|
+
const alternativesText = decision.alternatives?.join(', ') || 'None recorded';
|
|
251
|
+
const entry = `\n## [${decisionId}] ${decision.title}\n` +
|
|
252
|
+
`**Date:** ${timestamp}\n` +
|
|
253
|
+
`**By:** ${decision.decidedBy}\n` +
|
|
254
|
+
`**Decision:** ${decision.decision}\n` +
|
|
255
|
+
`**Rationale:** ${decision.rationale}\n` +
|
|
256
|
+
`**Alternatives:** ${alternativesText}\n` +
|
|
257
|
+
`**Outcome:** _pending_\n` +
|
|
258
|
+
`\n---\n`;
|
|
259
|
+
if (existing === null) {
|
|
260
|
+
const header = `# Decisions Log\n\n`;
|
|
261
|
+
await fs.writeFile(decisionsFile, header + entry, 'utf-8');
|
|
262
|
+
this.logger.debug('Created decisions log with first entry', { projectPath, decisionId });
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
await fs.appendFile(decisionsFile, entry, 'utf-8');
|
|
266
|
+
this.logger.debug('Appended decision entry', { projectPath, decisionId });
|
|
267
|
+
}
|
|
268
|
+
return decisionId;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Updates the outcome of a previously logged decision.
|
|
272
|
+
*
|
|
273
|
+
* Reads `decisions_log.md`, locates the section matching the given
|
|
274
|
+
* `decisionId`, replaces the `**Outcome:** _pending_` line with the
|
|
275
|
+
* actual outcome (plus optional learnings and a timestamp), and writes
|
|
276
|
+
* the file back atomically.
|
|
277
|
+
*
|
|
278
|
+
* If the decision ID is not found or the file does not exist, a warning
|
|
279
|
+
* is logged and the method returns without throwing.
|
|
280
|
+
*
|
|
281
|
+
* @param projectPath - Absolute path to the project root
|
|
282
|
+
* @param decisionId - The decision ID returned by {@link logDecision}
|
|
283
|
+
* @param outcome - Description of the actual outcome
|
|
284
|
+
* @param learnings - Optional lessons learned from this decision
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* await goalService.updateDecisionOutcome(
|
|
289
|
+
* '/projects/phoenix',
|
|
290
|
+
* 'dec-1707500000000',
|
|
291
|
+
* 'Successful - Redis reduced API latency by 40%',
|
|
292
|
+
* 'Set explicit TTLs on all cache keys to prevent stale data',
|
|
293
|
+
* );
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
async updateDecisionOutcome(projectPath, decisionId, outcome, learnings) {
|
|
297
|
+
const decisionsFile = path.join(this.getGoalsDir(projectPath), MEMORY_CONSTANTS.PATHS.DECISIONS_LOG);
|
|
298
|
+
const content = await this.safeReadFile(decisionsFile);
|
|
299
|
+
if (content === null) {
|
|
300
|
+
this.logger.warn('Decisions log not found, cannot update outcome', { projectPath, decisionId });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// Verify the decision ID exists in the file
|
|
304
|
+
if (!content.includes(`[${decisionId}]`)) {
|
|
305
|
+
this.logger.warn('Decision ID not found in decisions log', { projectPath, decisionId });
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const timestamp = new Date().toISOString();
|
|
309
|
+
const learningsText = learnings || 'None recorded';
|
|
310
|
+
const replacement = `**Outcome:** ${outcome}\n` +
|
|
311
|
+
`**Learnings:** ${learningsText}\n` +
|
|
312
|
+
`**Recorded:** ${timestamp}`;
|
|
313
|
+
// Replace the first occurrence of _pending_ that belongs to this decision.
|
|
314
|
+
// We find the decision section header then replace the pending outcome within it.
|
|
315
|
+
const sectionMarker = `[${decisionId}]`;
|
|
316
|
+
const sectionStart = content.indexOf(sectionMarker);
|
|
317
|
+
if (sectionStart === -1) {
|
|
318
|
+
this.logger.warn('Decision section not found', { projectPath, decisionId });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
// Find the **Outcome:** _pending_ line within this decision's section
|
|
322
|
+
const pendingPattern = '**Outcome:** _pending_';
|
|
323
|
+
const pendingIndex = content.indexOf(pendingPattern, sectionStart);
|
|
324
|
+
if (pendingIndex === -1) {
|
|
325
|
+
this.logger.warn('Decision outcome already recorded or not in pending state', { projectPath, decisionId });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const updatedContent = content.substring(0, pendingIndex) +
|
|
329
|
+
replacement +
|
|
330
|
+
content.substring(pendingIndex + pendingPattern.length);
|
|
331
|
+
await atomicWriteFile(decisionsFile, updatedContent);
|
|
332
|
+
this.logger.debug('Updated decision outcome', { projectPath, decisionId });
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Reads and returns the full contents of `decisions_log.md`.
|
|
336
|
+
*
|
|
337
|
+
* @param projectPath - Absolute path to the project root
|
|
338
|
+
* @returns The decisions log content, or `null` if the file does not exist
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* const log = await goalService.getDecisionsLog('/projects/phoenix');
|
|
343
|
+
* if (log) {
|
|
344
|
+
* console.log(log);
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
async getDecisionsLog(projectPath) {
|
|
349
|
+
const decisionsFile = path.join(this.getGoalsDir(projectPath), MEMORY_CONSTANTS.PATHS.DECISIONS_LOG);
|
|
350
|
+
return this.safeReadFile(decisionsFile);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=goal-tracking.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-tracking.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/memory/goal-tracking.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ import { IAgentMemoryService } from './agent-memory.service.js';
|
|
|
10
10
|
import { IProjectMemoryService } from './project-memory.service.js';
|
|
11
11
|
import type { KnowledgeDocumentSummary } from '../../types/knowledge.types.js';
|
|
12
12
|
import type { PatternCategory, GotchaSeverity } from '../../types/memory.types.js';
|
|
13
|
+
import type { TaskTrackingService } from '../project/task-tracking.service.js';
|
|
13
14
|
/**
|
|
14
15
|
* Categories for the unified remember operation
|
|
15
16
|
*/
|
|
@@ -58,6 +59,16 @@ export interface RememberParams {
|
|
|
58
59
|
relationshipType?: 'depends-on' | 'uses' | 'extends' | 'implements' | 'calls' | 'imported-by';
|
|
59
60
|
/** Target component for relationships */
|
|
60
61
|
targetComponent?: string;
|
|
62
|
+
/** Task ID where this knowledge was learned */
|
|
63
|
+
sourceTaskId?: string;
|
|
64
|
+
/** Objective/goal ID this knowledge relates to */
|
|
65
|
+
sourceObjectiveId?: string;
|
|
66
|
+
/** Outcome of the task where this was learned */
|
|
67
|
+
sourceOutcome?: string;
|
|
68
|
+
/** What contexts/domains this knowledge applies to */
|
|
69
|
+
appliesTo?: string[];
|
|
70
|
+
/** ID of entry being superseded by this one */
|
|
71
|
+
supersedes?: string;
|
|
61
72
|
};
|
|
62
73
|
}
|
|
63
74
|
/**
|
|
@@ -87,6 +98,17 @@ export interface RecallResult {
|
|
|
87
98
|
combined: string;
|
|
88
99
|
/** Matching knowledge documents (optional, from knowledge base search) */
|
|
89
100
|
knowledgeDocuments?: KnowledgeDocumentSummary[];
|
|
101
|
+
/** Current project goals (if projectPath provided) */
|
|
102
|
+
activeGoals?: string[];
|
|
103
|
+
/** Current team focus (if projectPath provided) */
|
|
104
|
+
currentFocus?: string;
|
|
105
|
+
/** Active tasks for this agent */
|
|
106
|
+
activeTasks?: Array<{
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
status: string;
|
|
110
|
+
hasWorkingNotes: boolean;
|
|
111
|
+
}>;
|
|
90
112
|
}
|
|
91
113
|
/**
|
|
92
114
|
* Parameters for recording a learning
|
|
@@ -148,6 +170,8 @@ export declare class MemoryService implements IMemoryService {
|
|
|
148
170
|
private static instance;
|
|
149
171
|
private readonly agentMemory;
|
|
150
172
|
private readonly projectMemory;
|
|
173
|
+
/** Shared or lazily-cached TaskTrackingService instance for operational context enrichment */
|
|
174
|
+
private taskTrackingServiceRef;
|
|
151
175
|
private readonly logger;
|
|
152
176
|
private embeddingProvider;
|
|
153
177
|
private embeddingProviderInitialized;
|
|
@@ -155,6 +179,20 @@ export declare class MemoryService implements IMemoryService {
|
|
|
155
179
|
* Creates a new MemoryService instance
|
|
156
180
|
*/
|
|
157
181
|
private constructor();
|
|
182
|
+
/**
|
|
183
|
+
* Set the shared TaskTrackingService instance to avoid creating
|
|
184
|
+
* disposable instances on every recall. Call during app startup.
|
|
185
|
+
*
|
|
186
|
+
* @param service - The application's shared TaskTrackingService
|
|
187
|
+
*/
|
|
188
|
+
setTaskTrackingService(service: TaskTrackingService): void;
|
|
189
|
+
/**
|
|
190
|
+
* Get or lazily create a TaskTrackingService.
|
|
191
|
+
* Prefers the shared instance set via setTaskTrackingService().
|
|
192
|
+
*
|
|
193
|
+
* @returns TaskTrackingService instance
|
|
194
|
+
*/
|
|
195
|
+
private getTaskTrackingService;
|
|
158
196
|
/**
|
|
159
197
|
* Lazily initializes the embedding provider on first use.
|
|
160
198
|
* Returns null if no embedding API key is configured.
|
|
@@ -298,6 +336,11 @@ export declare class MemoryService implements IMemoryService {
|
|
|
298
336
|
* ```
|
|
299
337
|
*/
|
|
300
338
|
recall(params: RecallParams): Promise<RecallResult>;
|
|
339
|
+
/**
|
|
340
|
+
* Enrich recall result with operational context: goals, focus, active tasks.
|
|
341
|
+
* All lookups are non-fatal — missing data is silently skipped.
|
|
342
|
+
*/
|
|
343
|
+
private enrichWithOperationalContext;
|
|
301
344
|
/**
|
|
302
345
|
* Searches knowledge documents across global and project scopes.
|
|
303
346
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/memory/memory.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAsB,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAwB,qBAAqB,EAAiB,MAAM,6BAA6B,CAAC;AAOzG,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,KAAK,EAGV,eAAe,EACf,cAAc,EAGf,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"memory.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/memory/memory.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,8 @@ export class MemoryService {
|
|
|
46
46
|
static instance = null;
|
|
47
47
|
agentMemory;
|
|
48
48
|
projectMemory;
|
|
49
|
+
/** Shared or lazily-cached TaskTrackingService instance for operational context enrichment */
|
|
50
|
+
taskTrackingServiceRef = null;
|
|
49
51
|
logger = LoggerService.getInstance().createComponentLogger('MemoryService');
|
|
50
52
|
embeddingProvider = null;
|
|
51
53
|
embeddingProviderInitialized = false;
|
|
@@ -56,6 +58,30 @@ export class MemoryService {
|
|
|
56
58
|
this.agentMemory = AgentMemoryService.getInstance();
|
|
57
59
|
this.projectMemory = ProjectMemoryService.getInstance();
|
|
58
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Set the shared TaskTrackingService instance to avoid creating
|
|
63
|
+
* disposable instances on every recall. Call during app startup.
|
|
64
|
+
*
|
|
65
|
+
* @param service - The application's shared TaskTrackingService
|
|
66
|
+
*/
|
|
67
|
+
setTaskTrackingService(service) {
|
|
68
|
+
this.taskTrackingServiceRef = service;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get or lazily create a TaskTrackingService.
|
|
72
|
+
* Prefers the shared instance set via setTaskTrackingService().
|
|
73
|
+
*
|
|
74
|
+
* @returns TaskTrackingService instance
|
|
75
|
+
*/
|
|
76
|
+
async getTaskTrackingService() {
|
|
77
|
+
if (this.taskTrackingServiceRef) {
|
|
78
|
+
return this.taskTrackingServiceRef;
|
|
79
|
+
}
|
|
80
|
+
// Lazy fallback: create and cache one instance
|
|
81
|
+
const { TaskTrackingService: TTS } = await import('../project/task-tracking.service.js');
|
|
82
|
+
this.taskTrackingServiceRef = new TTS();
|
|
83
|
+
return this.taskTrackingServiceRef;
|
|
84
|
+
}
|
|
59
85
|
/**
|
|
60
86
|
* Lazily initializes the embedding provider on first use.
|
|
61
87
|
* Returns null if no embedding API key is configured.
|
|
@@ -369,6 +395,11 @@ export class MemoryService {
|
|
|
369
395
|
content: params.content,
|
|
370
396
|
learnedFrom: params.metadata?.taskId,
|
|
371
397
|
confidence: 0.5,
|
|
398
|
+
// v2: Task-linked provenance
|
|
399
|
+
sourceTaskId: params.metadata?.sourceTaskId || params.metadata?.taskId,
|
|
400
|
+
sourceObjectiveId: params.metadata?.sourceObjectiveId,
|
|
401
|
+
sourceOutcome: params.metadata?.sourceOutcome,
|
|
402
|
+
appliesTo: params.metadata?.appliesTo,
|
|
372
403
|
});
|
|
373
404
|
case 'preference':
|
|
374
405
|
await this.agentMemory.updatePreferences(params.agentId, this.parsePreference(params.content));
|
|
@@ -393,6 +424,9 @@ export class MemoryService {
|
|
|
393
424
|
example: params.metadata?.example,
|
|
394
425
|
files: params.metadata?.files,
|
|
395
426
|
discoveredBy: params.agentId,
|
|
427
|
+
// v2: provenance
|
|
428
|
+
sourceTaskId: params.metadata?.sourceTaskId || params.metadata?.taskId,
|
|
429
|
+
sourceOutcome: params.metadata?.sourceOutcome,
|
|
396
430
|
});
|
|
397
431
|
case 'decision':
|
|
398
432
|
return this.projectMemory.addDecision(params.projectPath, {
|
|
@@ -410,6 +444,9 @@ export class MemoryService {
|
|
|
410
444
|
solution: params.metadata?.solution || '',
|
|
411
445
|
severity: params.metadata?.severity || 'medium',
|
|
412
446
|
discoveredBy: params.agentId,
|
|
447
|
+
// v2: provenance
|
|
448
|
+
sourceTaskId: params.metadata?.sourceTaskId || params.metadata?.taskId,
|
|
449
|
+
sourceOutcome: params.metadata?.sourceOutcome,
|
|
413
450
|
});
|
|
414
451
|
case 'relationship':
|
|
415
452
|
if (!params.metadata?.targetComponent) {
|
|
@@ -503,9 +540,68 @@ export class MemoryService {
|
|
|
503
540
|
}));
|
|
504
541
|
}
|
|
505
542
|
await Promise.all(promises);
|
|
543
|
+
// v2: Enrich with operational context (goals, focus, active tasks)
|
|
544
|
+
await this.enrichWithOperationalContext(result, params);
|
|
506
545
|
result.combined = this.combineMemories(result);
|
|
546
|
+
// v2: Append operational context to combined text
|
|
547
|
+
if (result.activeGoals?.length || result.currentFocus || result.activeTasks?.length) {
|
|
548
|
+
const opLines = ['\n### Operational Context'];
|
|
549
|
+
if (result.currentFocus)
|
|
550
|
+
opLines.push(`**Current Focus:** ${result.currentFocus}`);
|
|
551
|
+
if (result.activeGoals?.length)
|
|
552
|
+
opLines.push(`**Goals:** ${result.activeGoals.join('; ')}`);
|
|
553
|
+
if (result.activeTasks?.length) {
|
|
554
|
+
opLines.push('**Your Active Tasks:**');
|
|
555
|
+
for (const t of result.activeTasks) {
|
|
556
|
+
opLines.push(`- [${t.status}] ${t.name}${t.hasWorkingNotes ? ' (has working notes)' : ''}`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
result.combined += opLines.join('\n');
|
|
560
|
+
}
|
|
507
561
|
return result;
|
|
508
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Enrich recall result with operational context: goals, focus, active tasks.
|
|
565
|
+
* All lookups are non-fatal — missing data is silently skipped.
|
|
566
|
+
*/
|
|
567
|
+
async enrichWithOperationalContext(result, params) {
|
|
568
|
+
const opPromises = [];
|
|
569
|
+
if (params.projectPath) {
|
|
570
|
+
opPromises.push((async () => {
|
|
571
|
+
try {
|
|
572
|
+
const { GoalTrackingService } = await import('./goal-tracking.service.js');
|
|
573
|
+
const gts = GoalTrackingService.getInstance();
|
|
574
|
+
const goalsText = await gts.getGoals(params.projectPath);
|
|
575
|
+
if (goalsText)
|
|
576
|
+
result.activeGoals = [goalsText];
|
|
577
|
+
const focus = await gts.getCurrentFocus(params.projectPath);
|
|
578
|
+
if (focus)
|
|
579
|
+
result.currentFocus = focus;
|
|
580
|
+
}
|
|
581
|
+
catch { /* non-fatal — goal tracking may not be initialized */ }
|
|
582
|
+
})());
|
|
583
|
+
}
|
|
584
|
+
if (params.agentId) {
|
|
585
|
+
opPromises.push((async () => {
|
|
586
|
+
try {
|
|
587
|
+
const tts = await this.getTaskTrackingService();
|
|
588
|
+
const tasks = await tts.getTasksBySessionName(params.agentId);
|
|
589
|
+
const terminalStatuses = ['completed', 'verified', 'cancelled'];
|
|
590
|
+
const active = tasks.filter((t) => !terminalStatuses.includes(t.status));
|
|
591
|
+
if (active.length) {
|
|
592
|
+
result.activeTasks = active.map((t) => ({
|
|
593
|
+
id: t.id,
|
|
594
|
+
name: t.taskName,
|
|
595
|
+
status: t.status,
|
|
596
|
+
hasWorkingNotes: !!t.workingNotes,
|
|
597
|
+
}));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
catch { /* non-fatal */ }
|
|
601
|
+
})());
|
|
602
|
+
}
|
|
603
|
+
await Promise.all(opPromises);
|
|
604
|
+
}
|
|
509
605
|
/**
|
|
510
606
|
* Searches knowledge documents across global and project scopes.
|
|
511
607
|
*
|