crewly 1.20.358 → 1.20.359
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/backend/backend/src/constants.d.ts +59 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +59 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +21 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +162 -11
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js +5 -0
- package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts +10 -0
- package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/startup-briefing.service.js +65 -22
- package/dist/backend/backend/src/services/memory/startup-briefing.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-binding.d.ts +25 -2
- package/dist/backend/backend/src/services/session/session-binding.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-binding.js +32 -4
- package/dist/backend/backend/src/services/session/session-binding.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +3 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts +27 -2
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js +105 -8
- package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.js +194 -0
- package/dist/backend/backend/src/services/wiki/work-record-transcript.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.d.ts +239 -0
- package/dist/backend/backend/src/services/wiki/work-record.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.js +631 -0
- package/dist/backend/backend/src/services/wiki/work-record.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.d.ts +209 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.js +514 -0
- package/dist/backend/backend/src/services/wiki/work-record.service.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +59 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +59 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts +10 -0
- package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/startup-briefing.service.js +65 -22
- package/dist/cli/backend/src/services/memory/startup-briefing.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +3 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.js +194 -0
- package/dist/cli/backend/src/services/wiki/work-record-transcript.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record.d.ts +239 -0
- package/dist/cli/backend/src/services/wiki/work-record.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/work-record.js +631 -0
- package/dist/cli/backend/src/services/wiki/work-record.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkRecordService (#1349) — one work record per finished task, written to
|
|
3
|
+
* the project vault log.
|
|
4
|
+
*
|
|
5
|
+
* The vault log only held what agents volunteered. This service writes, for
|
|
6
|
+
* every WorkItem that reaches a terminal state (done, verified, rejected,
|
|
7
|
+
* cancelled, failed) and for every item parked in `blocked` for more than a
|
|
8
|
+
* day, one structured `(record)` entry: who asked, who did it, what came
|
|
9
|
+
* out, what went wrong and how it was resolved, who helped, how it ended.
|
|
10
|
+
* The entry goes through `WikiIngestService` (source type `work_record`) into
|
|
11
|
+
* the project vault's `llm-curated/log.md` and, when the team has a vault,
|
|
12
|
+
* into that too. From there the weekly digest, search, and the startup
|
|
13
|
+
* briefing pick it up.
|
|
14
|
+
*
|
|
15
|
+
* Sources, all already on disk or in memory: the WorkItem, its linked
|
|
16
|
+
* project ticket or Request, its children (delegations, the verify item),
|
|
17
|
+
* the run trace, and a bounded tail of the doer's transcript. No model
|
|
18
|
+
* calls.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent: a `work-record:<id>#<phase>` key is remembered in
|
|
21
|
+
* `CREWLY_HOME/work-records-state.json` (seeded from the vault log) and the
|
|
22
|
+
* ingest path refuses an identical body. A finished item whose ticket still
|
|
23
|
+
* waits for the owner's OK is deferred (the ticket change retries it; after
|
|
24
|
+
* `DEFER_MAX_MS` it is written as "waiting for the owner's OK").
|
|
25
|
+
*
|
|
26
|
+
* Runs on the terminal events with a short delay, plus an hourly tick that
|
|
27
|
+
* catches up on items of the last `CATCHUP_WINDOW_DAYS` without a record
|
|
28
|
+
* (at most `CATCHUP_MAX_PER_PASS`), deferred items and long-blocked items.
|
|
29
|
+
* `CREWLY_WORK_RECORDS=false` disables it.
|
|
30
|
+
*
|
|
31
|
+
* @module services/wiki/work-record.service
|
|
32
|
+
*/
|
|
33
|
+
import * as path from 'path';
|
|
34
|
+
import * as fs from 'fs/promises';
|
|
35
|
+
import { existsSync } from 'fs';
|
|
36
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
37
|
+
import { ORCHESTRATOR_SESSION_NAME, WIKI_LOG_CONSTANTS, WORK_RECORD_CONSTANTS } from '../../constants.js';
|
|
38
|
+
import { atomicWriteJson, ensureDir, safeReadJson } from '../../utils/file-io.utils.js';
|
|
39
|
+
import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
|
|
40
|
+
import { isLeadRole } from '../../utils/team.utils.js';
|
|
41
|
+
import { collectSecretEnvValues } from '../../utils/secret-env.js';
|
|
42
|
+
import { redactSecrets } from '../../utils/secret-redactor.js';
|
|
43
|
+
import { readProjectTicketLink } from '../../types/project-ticket.types.js';
|
|
44
|
+
import { listTicketPrefixes } from '../project-tickets/ticket-prefixes.js';
|
|
45
|
+
import { memberName } from '../messaging/agent-ask-ledger.service.js';
|
|
46
|
+
import { WikiIngestService } from './wiki-ingest.service.js';
|
|
47
|
+
import { redactSensitive } from './wiki-redaction.js';
|
|
48
|
+
import { parseLogEntries } from './wiki-log-entries.js';
|
|
49
|
+
import { assembleWorkRecord, isRecordableWorkItem, isWorkRecordEntry, renderWorkRecordBody, workItemEndedAt, workRecordRef, } from './work-record.js';
|
|
50
|
+
import { parseClaudeTranscriptWindow, readTranscriptTail, transcriptWorthReading } from './work-record-transcript.js';
|
|
51
|
+
const C = WORK_RECORD_CONSTANTS;
|
|
52
|
+
/** Statuses that close a task and get a `final` record. */
|
|
53
|
+
export const FINAL_RECORD_STATUSES = new Set(['done', 'verified', 'rejected', 'cancelled', 'failed']);
|
|
54
|
+
/** Events that announce a terminal transition. */
|
|
55
|
+
export const WORK_RECORD_EVENT_TYPES = ['task:done', 'task:verified', 'task:rejected', 'task:cancelled', 'task:failed'];
|
|
56
|
+
/**
|
|
57
|
+
* Per-task work records. Start at boot, stop at shutdown.
|
|
58
|
+
*/
|
|
59
|
+
export class WorkRecordService {
|
|
60
|
+
static instance = null;
|
|
61
|
+
logger;
|
|
62
|
+
deps;
|
|
63
|
+
ingest;
|
|
64
|
+
statePath;
|
|
65
|
+
globalVaultPath;
|
|
66
|
+
teamsRoot;
|
|
67
|
+
intervalMs;
|
|
68
|
+
bootDelayMs;
|
|
69
|
+
eventDelayMs;
|
|
70
|
+
nowFn;
|
|
71
|
+
timer = null;
|
|
72
|
+
bootTimer = null;
|
|
73
|
+
pending = new Map();
|
|
74
|
+
unsubscribers = [];
|
|
75
|
+
running = false;
|
|
76
|
+
state = { recorded: {} };
|
|
77
|
+
stateLoaded = false;
|
|
78
|
+
seededVaults = new Set();
|
|
79
|
+
/** Transcript facts cache for the current pass: session → file text. */
|
|
80
|
+
transcriptCache = new Map();
|
|
81
|
+
/** Ticket prefixes of the registered projects, refreshed once per pass. */
|
|
82
|
+
prefixCache = null;
|
|
83
|
+
constructor(deps) {
|
|
84
|
+
this.logger = LoggerService.getInstance().createComponentLogger('WorkRecord');
|
|
85
|
+
this.deps = deps;
|
|
86
|
+
this.ingest = deps.ingest ?? WikiIngestService.getInstance();
|
|
87
|
+
this.statePath = deps.statePath === null ? null : deps.statePath ?? path.join(getCrewlyHomePath(), C.STATE_FILE);
|
|
88
|
+
this.globalVaultPath = deps.globalVaultPath ?? path.join(getCrewlyHomePath(), 'global-wiki');
|
|
89
|
+
this.teamsRoot = deps.teamsRoot ?? path.join(getCrewlyHomePath(), 'teams');
|
|
90
|
+
this.intervalMs = deps.intervalMs ?? C.TICK_MS;
|
|
91
|
+
this.bootDelayMs = deps.bootDelayMs ?? C.BOOT_DELAY_MS;
|
|
92
|
+
this.eventDelayMs = deps.eventDelayMs ?? C.EVENT_DELAY_MS;
|
|
93
|
+
this.nowFn = deps.now ?? (() => Date.now());
|
|
94
|
+
}
|
|
95
|
+
static getInstance() {
|
|
96
|
+
return this.instance;
|
|
97
|
+
}
|
|
98
|
+
/** Wire / detach the production singleton. */
|
|
99
|
+
static setInstance(next) {
|
|
100
|
+
if (this.instance && this.instance !== next)
|
|
101
|
+
this.instance.stop();
|
|
102
|
+
this.instance = next;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Subscribe to the terminal events and the ticket feed, schedule the boot
|
|
106
|
+
* catch-up and the hourly tick. Idempotent. Returns false when the kill
|
|
107
|
+
* switch is set.
|
|
108
|
+
*
|
|
109
|
+
* @returns Whether the service started
|
|
110
|
+
*/
|
|
111
|
+
start() {
|
|
112
|
+
if (this.timer)
|
|
113
|
+
return true;
|
|
114
|
+
if (process.env[C.ENV_KILL_SWITCH] === 'false') {
|
|
115
|
+
this.logger.warn(`WorkRecord disabled via ${C.ENV_KILL_SWITCH}=false — not starting`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (this.deps.eventBus) {
|
|
119
|
+
this.unsubscribers.push(this.deps.eventBus.onInProcess([...WORK_RECORD_EVENT_TYPES], (e) => {
|
|
120
|
+
if (typeof e.workItemId === 'string' && e.workItemId)
|
|
121
|
+
this.schedule(e.workItemId);
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
if (this.deps.onTicketSettled) {
|
|
125
|
+
this.unsubscribers.push(this.deps.onTicketSettled((workItemId) => this.schedule(workItemId)));
|
|
126
|
+
}
|
|
127
|
+
this.bootTimer = setTimeout(() => {
|
|
128
|
+
this.bootTimer = null;
|
|
129
|
+
void this.runOnce();
|
|
130
|
+
}, this.bootDelayMs);
|
|
131
|
+
this.bootTimer.unref?.();
|
|
132
|
+
this.timer = setInterval(() => void this.runOnce(), this.intervalMs);
|
|
133
|
+
this.timer.unref?.();
|
|
134
|
+
this.logger.info('WorkRecord started', { intervalMs: this.intervalMs, bootDelayMs: this.bootDelayMs, events: !!this.deps.eventBus });
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
/** Stop timers and subscriptions. Safe to call more than once. */
|
|
138
|
+
stop() {
|
|
139
|
+
if (this.bootTimer) {
|
|
140
|
+
clearTimeout(this.bootTimer);
|
|
141
|
+
this.bootTimer = null;
|
|
142
|
+
}
|
|
143
|
+
if (this.timer) {
|
|
144
|
+
clearInterval(this.timer);
|
|
145
|
+
this.timer = null;
|
|
146
|
+
}
|
|
147
|
+
for (const t of this.pending.values())
|
|
148
|
+
clearTimeout(t);
|
|
149
|
+
this.pending.clear();
|
|
150
|
+
for (const u of this.unsubscribers.splice(0)) {
|
|
151
|
+
try {
|
|
152
|
+
u();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// detached already
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Record one item soon (coalesced per id): the ticket sync, the verify
|
|
161
|
+
* item and the evidence land in the seconds after the event.
|
|
162
|
+
*
|
|
163
|
+
* @param workItemId - WorkItem id
|
|
164
|
+
*/
|
|
165
|
+
schedule(workItemId) {
|
|
166
|
+
if (this.pending.has(workItemId))
|
|
167
|
+
return;
|
|
168
|
+
const t = setTimeout(() => {
|
|
169
|
+
this.pending.delete(workItemId);
|
|
170
|
+
void this.recordById(workItemId).catch((err) => {
|
|
171
|
+
this.logger.warn('WorkRecord: event-driven record failed (non-fatal)', { workItemId, error: err instanceof Error ? err.message : String(err) });
|
|
172
|
+
});
|
|
173
|
+
}, this.eventDelayMs);
|
|
174
|
+
t.unref?.();
|
|
175
|
+
this.pending.set(workItemId, t);
|
|
176
|
+
}
|
|
177
|
+
/** Items waiting for their event delay (tests). */
|
|
178
|
+
pendingCount() {
|
|
179
|
+
return this.pending.size;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Record one item by id if it is terminal.
|
|
183
|
+
*
|
|
184
|
+
* @param workItemId - WorkItem id
|
|
185
|
+
* @returns What happened
|
|
186
|
+
*/
|
|
187
|
+
async recordById(workItemId) {
|
|
188
|
+
const wi = await this.deps.findWorkItem(workItemId);
|
|
189
|
+
if (!wi)
|
|
190
|
+
return { workItemId, phase: 'final', result: 'missing' };
|
|
191
|
+
if (!FINAL_RECORD_STATUSES.has(wi.status))
|
|
192
|
+
return { workItemId, phase: 'final', result: 'not_terminal' };
|
|
193
|
+
await this.loadState();
|
|
194
|
+
const all = await this.deps.listWorkItems();
|
|
195
|
+
const attempt = await this.recordItem(wi, 'final', all);
|
|
196
|
+
await this.saveState();
|
|
197
|
+
return attempt;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* One pass: finished items of the window without a record (newest first,
|
|
201
|
+
* capped), then long-blocked items. Public for tests and an on-demand run.
|
|
202
|
+
*
|
|
203
|
+
* @returns Counts
|
|
204
|
+
*/
|
|
205
|
+
async runOnce() {
|
|
206
|
+
const result = { candidates: 0, written: 0, deferred: 0, blocked: 0, refused: 0 };
|
|
207
|
+
if (this.running)
|
|
208
|
+
return result;
|
|
209
|
+
this.running = true;
|
|
210
|
+
this.transcriptCache = new Map();
|
|
211
|
+
this.prefixCache = null;
|
|
212
|
+
try {
|
|
213
|
+
await this.loadState();
|
|
214
|
+
const now = this.nowFn();
|
|
215
|
+
const all = await this.deps.listWorkItems();
|
|
216
|
+
const cutoff = now - C.CATCHUP_WINDOW_DAYS * 86_400_000;
|
|
217
|
+
const finals = all
|
|
218
|
+
.filter((wi) => FINAL_RECORD_STATUSES.has(wi.status) && isRecordableWorkItem(wi))
|
|
219
|
+
.filter((wi) => Date.parse(workItemEndedAt(wi)) >= cutoff)
|
|
220
|
+
.filter((wi) => !this.state.recorded[workRecordRef(wi.id, 'final')])
|
|
221
|
+
.sort((a, b) => Date.parse(workItemEndedAt(b)) - Date.parse(workItemEndedAt(a)));
|
|
222
|
+
const blocked = all
|
|
223
|
+
.filter((wi) => wi.status === 'blocked' && isRecordableWorkItem(wi))
|
|
224
|
+
.filter((wi) => now - Date.parse(wi.statusChangedAt ?? wi.createdAt) >= C.BLOCKED_AFTER_MS)
|
|
225
|
+
.filter((wi) => !this.state.recorded[workRecordRef(wi.id, 'blocked')]);
|
|
226
|
+
result.candidates = finals.length + blocked.length;
|
|
227
|
+
let budget = C.CATCHUP_MAX_PER_PASS;
|
|
228
|
+
for (const wi of finals) {
|
|
229
|
+
if (budget <= 0)
|
|
230
|
+
break;
|
|
231
|
+
const a = await this.safeRecord(wi, 'final', all);
|
|
232
|
+
if (a.result === 'written') {
|
|
233
|
+
result.written++;
|
|
234
|
+
budget--;
|
|
235
|
+
}
|
|
236
|
+
else if (a.result === 'deferred')
|
|
237
|
+
result.deferred++;
|
|
238
|
+
else if (a.result === 'refused' || a.result === 'no_vault')
|
|
239
|
+
result.refused++;
|
|
240
|
+
}
|
|
241
|
+
for (const wi of blocked) {
|
|
242
|
+
if (budget <= 0)
|
|
243
|
+
break;
|
|
244
|
+
const a = await this.safeRecord(wi, 'blocked', all);
|
|
245
|
+
if (a.result === 'written') {
|
|
246
|
+
result.blocked++;
|
|
247
|
+
budget--;
|
|
248
|
+
}
|
|
249
|
+
else if (a.result === 'refused' || a.result === 'no_vault')
|
|
250
|
+
result.refused++;
|
|
251
|
+
}
|
|
252
|
+
await this.saveState();
|
|
253
|
+
if (result.candidates > 0)
|
|
254
|
+
this.logger.info('WorkRecord pass', { ...result, remaining: Math.max(0, result.candidates - result.written - result.blocked - result.deferred - result.refused) });
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
this.running = false;
|
|
259
|
+
this.transcriptCache = new Map();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Assemble and write one record. Public for tests.
|
|
264
|
+
*
|
|
265
|
+
* @param wi - The WorkItem (terminal, or blocked for a `blocked` record)
|
|
266
|
+
* @param phase - Record phase
|
|
267
|
+
* @param all - Every WorkItem (children are looked up here)
|
|
268
|
+
* @returns What happened, with the record and body when assembled
|
|
269
|
+
*/
|
|
270
|
+
async recordItem(wi, phase, all) {
|
|
271
|
+
const key = workRecordRef(wi.id, phase);
|
|
272
|
+
const base = { workItemId: wi.id, phase, result: 'written' };
|
|
273
|
+
if (!isRecordableWorkItem(wi))
|
|
274
|
+
return { ...base, result: 'not_recordable' };
|
|
275
|
+
if (this.state.recorded[key])
|
|
276
|
+
return { ...base, result: 'already_recorded' };
|
|
277
|
+
const [teams, projects] = await Promise.all([this.deps.listTeams(), this.deps.listProjects()]);
|
|
278
|
+
const { projectPath, teamId } = this.resolveProject(wi, teams, projects);
|
|
279
|
+
const vaults = await this.resolveVaults(projectPath, teamId);
|
|
280
|
+
if (vaults.length === 0)
|
|
281
|
+
return { ...base, result: 'no_vault' };
|
|
282
|
+
await this.seedFromVault(vaults[0]);
|
|
283
|
+
if (this.state.recorded[key])
|
|
284
|
+
return { ...base, result: 'already_recorded' };
|
|
285
|
+
const link = readProjectTicketLink(wi.metadata);
|
|
286
|
+
const [ticket, request, trace] = await Promise.all([
|
|
287
|
+
link && this.deps.getTicket ? this.deps.getTicket(link.projectPath, link.id).catch(() => null) : Promise.resolve(null),
|
|
288
|
+
wi.requestId && this.deps.getRequest ? this.deps.getRequest(wi.requestId).catch(() => null) : Promise.resolve(null),
|
|
289
|
+
this.deps.readTrace ? this.deps.readTrace(wi).catch(() => []) : Promise.resolve([]),
|
|
290
|
+
]);
|
|
291
|
+
const children = all.filter((c) => c.id !== wi.id && (c.parentWorkItemId === wi.id || c.metadata?.verifyOf === wi.id || c.id.startsWith(`${wi.id}:verify:`) || (!!wi.target && c.metadata?.delegatedBy === wi.target)));
|
|
292
|
+
const transcript = phase === 'final' ? await this.transcriptFacts(wi, projectPath) : null;
|
|
293
|
+
const names = this.nameResolvers(teams);
|
|
294
|
+
const record = assembleWorkRecord({
|
|
295
|
+
workItem: wi,
|
|
296
|
+
phase,
|
|
297
|
+
ticket,
|
|
298
|
+
request,
|
|
299
|
+
children,
|
|
300
|
+
trace: trace.slice(0, C.TRACE_MAX_EVENTS),
|
|
301
|
+
transcript,
|
|
302
|
+
nameOf: names.nameOf,
|
|
303
|
+
kindOf: names.kindOf,
|
|
304
|
+
ticketPrefixes: await this.ticketPrefixes(all, projects),
|
|
305
|
+
now: this.nowFn(),
|
|
306
|
+
});
|
|
307
|
+
if (record.outcome === 'waiting_owner' && this.nowFn() - Date.parse(workItemEndedAt(wi)) < C.DEFER_MAX_MS) {
|
|
308
|
+
return { ...base, result: 'deferred', record };
|
|
309
|
+
}
|
|
310
|
+
const body = this.redact(renderWorkRecordBody(record));
|
|
311
|
+
let written = 0;
|
|
312
|
+
for (const vault of vaults) {
|
|
313
|
+
const outcome = await this.ingest.ingest({
|
|
314
|
+
vaultPath: vault,
|
|
315
|
+
sourceType: C.SOURCE_TYPE,
|
|
316
|
+
sourceRef: key,
|
|
317
|
+
sourceBody: body,
|
|
318
|
+
callerSession: wi.target ?? 'system:work-record',
|
|
319
|
+
});
|
|
320
|
+
if (outcome.ok || outcome.reason === 'duplicate')
|
|
321
|
+
written++;
|
|
322
|
+
else
|
|
323
|
+
this.logger.debug('WorkRecord: ingest refused', { vault, workItemId: wi.id, reason: outcome.reason });
|
|
324
|
+
}
|
|
325
|
+
if (written === 0)
|
|
326
|
+
return { ...base, result: 'refused', record, body, vaults };
|
|
327
|
+
this.remember(key);
|
|
328
|
+
this.logger.info('WorkRecord written', { workItemId: wi.id, phase, outcome: record.outcome, doneBy: record.doneBy.name, vaults: vaults.length, chars: body.length });
|
|
329
|
+
return { ...base, result: 'written', record, body, vaults };
|
|
330
|
+
}
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
async safeRecord(wi, phase, all) {
|
|
333
|
+
try {
|
|
334
|
+
return await this.recordItem(wi, phase, all);
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
this.logger.warn('WorkRecord: record failed (non-fatal)', { workItemId: wi.id, phase, error: err instanceof Error ? err.message : String(err) });
|
|
338
|
+
return { workItemId: wi.id, phase, result: 'refused' };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* The project the item belongs to: `metadata.projectPath`, the ticket's
|
|
343
|
+
* project, else the first project of the doer's (or `metadata.teamId`) team.
|
|
344
|
+
*/
|
|
345
|
+
resolveProject(wi, teams, projects) {
|
|
346
|
+
const metaTeam = typeof wi.metadata?.teamId === 'string' ? wi.metadata.teamId : null;
|
|
347
|
+
const team = teams.find((t) => t.id === metaTeam) ?? teams.find((t) => (t.members ?? []).some((m) => m.sessionName === wi.target || m.agentId === wi.target)) ?? null;
|
|
348
|
+
const link = readProjectTicketLink(wi.metadata);
|
|
349
|
+
let projectPath = typeof wi.metadata?.projectPath === 'string' ? wi.metadata.projectPath : link?.projectPath ?? null;
|
|
350
|
+
if (!projectPath && team) {
|
|
351
|
+
const p = (team.projectIds ?? []).map((id) => projects.find((pr) => pr.id === id)).find((pr) => !!pr);
|
|
352
|
+
projectPath = p?.path ?? null;
|
|
353
|
+
}
|
|
354
|
+
if (!projectPath && typeof wi.metadata?.projectId === 'string') {
|
|
355
|
+
projectPath = projects.find((p) => p.id === wi.metadata?.projectId)?.path ?? null;
|
|
356
|
+
}
|
|
357
|
+
return { projectPath, teamId: team?.id ?? metaTeam };
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Vaults to write: the project vault (falling back to the global vault
|
|
361
|
+
* when the project has none) and the team vault when it exists.
|
|
362
|
+
*/
|
|
363
|
+
async resolveVaults(projectPath, teamId) {
|
|
364
|
+
const out = [];
|
|
365
|
+
const projectVault = projectPath ? path.join(projectPath, '.crewly', 'wiki') : null;
|
|
366
|
+
if (projectVault && existsSync(path.join(projectVault, 'SCHEMA.md')))
|
|
367
|
+
out.push(projectVault);
|
|
368
|
+
else if (existsSync(path.join(this.globalVaultPath, 'SCHEMA.md')))
|
|
369
|
+
out.push(this.globalVaultPath);
|
|
370
|
+
if (teamId) {
|
|
371
|
+
const teamVault = path.join(this.teamsRoot, teamId, 'wiki');
|
|
372
|
+
if (existsSync(path.join(teamVault, 'SCHEMA.md')) && !out.includes(teamVault))
|
|
373
|
+
out.push(teamVault);
|
|
374
|
+
}
|
|
375
|
+
return out;
|
|
376
|
+
}
|
|
377
|
+
nameResolvers(teams) {
|
|
378
|
+
const bySession = new Map();
|
|
379
|
+
for (const team of teams) {
|
|
380
|
+
const leadIds = new Set([team.leaderId, ...(team.leaderIds ?? [])].filter(Boolean));
|
|
381
|
+
for (const m of team.members ?? []) {
|
|
382
|
+
const info = { name: m.name, role: m.role, lead: leadIds.has(m.id) || isLeadRole(m.role) };
|
|
383
|
+
if (m.sessionName)
|
|
384
|
+
bySession.set(m.sessionName, info);
|
|
385
|
+
if (m.agentId)
|
|
386
|
+
bySession.set(m.agentId, info);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const nameOf = (s) => {
|
|
390
|
+
if (s === ORCHESTRATOR_SESSION_NAME)
|
|
391
|
+
return 'the orchestrator';
|
|
392
|
+
return bySession.get(s)?.name ?? memberName(s);
|
|
393
|
+
};
|
|
394
|
+
const kindOf = (s) => {
|
|
395
|
+
if (s === ORCHESTRATOR_SESSION_NAME)
|
|
396
|
+
return 'orchestrator';
|
|
397
|
+
const info = bySession.get(s);
|
|
398
|
+
if (!info)
|
|
399
|
+
return 'agent';
|
|
400
|
+
return info.lead ? 'lead' : 'agent';
|
|
401
|
+
};
|
|
402
|
+
return { nameOf, kindOf };
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Ticket prefixes to strip from owner-facing text: every registered
|
|
406
|
+
* project's ticket counter (one small file each, read once per pass) plus
|
|
407
|
+
* the prefixes seen on pool items.
|
|
408
|
+
*/
|
|
409
|
+
async ticketPrefixes(all, projects) {
|
|
410
|
+
const out = new Set();
|
|
411
|
+
for (const wi of all) {
|
|
412
|
+
const link = readProjectTicketLink(wi.metadata);
|
|
413
|
+
const dash = link?.id.indexOf('-') ?? -1;
|
|
414
|
+
if (link && dash > 0)
|
|
415
|
+
out.add(link.id.slice(0, dash));
|
|
416
|
+
}
|
|
417
|
+
const paths = projects.map((p) => p.path).filter((p) => typeof p === 'string' && p.length > 0);
|
|
418
|
+
this.prefixCache ??= (this.deps.listTicketPrefixes ?? ((roots) => listTicketPrefixes({ listProjectPaths: async () => [...roots] })))(paths).catch(() => []);
|
|
419
|
+
for (const p of await this.prefixCache)
|
|
420
|
+
out.add(p);
|
|
421
|
+
return [...out];
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Facts from the doer's transcript for the task window, when the item is
|
|
425
|
+
* recent enough for the window to be in the tail. One tail read per
|
|
426
|
+
* session per pass.
|
|
427
|
+
*/
|
|
428
|
+
async transcriptFacts(wi, projectPath) {
|
|
429
|
+
if (!this.deps.locateTranscript || !wi.target)
|
|
430
|
+
return null;
|
|
431
|
+
const endedMs = Date.parse(workItemEndedAt(wi));
|
|
432
|
+
if (!transcriptWorthReading(endedMs, this.nowFn()))
|
|
433
|
+
return null;
|
|
434
|
+
const session = wi.target;
|
|
435
|
+
let cached = this.transcriptCache.get(session);
|
|
436
|
+
if (!cached) {
|
|
437
|
+
const locate = this.deps.locateTranscript;
|
|
438
|
+
cached = (async () => {
|
|
439
|
+
try {
|
|
440
|
+
const target = await locate(session);
|
|
441
|
+
if (!target || target.kind !== 'claude')
|
|
442
|
+
return null;
|
|
443
|
+
return { kind: target.kind, text: await readTranscriptTail(target.file) };
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
})();
|
|
449
|
+
this.transcriptCache.set(session, cached);
|
|
450
|
+
}
|
|
451
|
+
const loaded = await cached;
|
|
452
|
+
if (!loaded)
|
|
453
|
+
return null;
|
|
454
|
+
const fromMs = Date.parse(wi.startedAt ?? wi.createdAt);
|
|
455
|
+
return parseClaudeTranscriptWindow(loaded.text, { fromMs: Number.isFinite(fromMs) ? fromMs : endedMs, toMs: endedMs }, projectPath ? [projectPath] : []);
|
|
456
|
+
}
|
|
457
|
+
/** Pattern-based redaction plus the process's known secret values. */
|
|
458
|
+
redact(body) {
|
|
459
|
+
const secrets = this.deps.secrets ? this.deps.secrets() : collectSecretEnvValues(process.env);
|
|
460
|
+
return redactSecrets(redactSensitive(body), secrets);
|
|
461
|
+
}
|
|
462
|
+
/** Seed the recorded set from a vault's log once, so a lost state file does not double-write. */
|
|
463
|
+
async seedFromVault(vault) {
|
|
464
|
+
if (this.seededVaults.has(vault))
|
|
465
|
+
return;
|
|
466
|
+
this.seededVaults.add(vault);
|
|
467
|
+
try {
|
|
468
|
+
const raw = await fs.readFile(path.join(vault, WIKI_LOG_CONSTANTS.LOG_RELATIVE_PATH), 'utf8');
|
|
469
|
+
for (const e of parseLogEntries(raw)) {
|
|
470
|
+
if (isWorkRecordEntry(e) && e.ref && !this.state.recorded[e.ref])
|
|
471
|
+
this.state.recorded[e.ref] = e.timestamp;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
// no log yet
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
remember(key) {
|
|
479
|
+
this.state.recorded[key] = new Date(this.nowFn()).toISOString();
|
|
480
|
+
const keys = Object.keys(this.state.recorded);
|
|
481
|
+
if (keys.length > C.STATE_MAX_KEYS) {
|
|
482
|
+
const sorted = keys.sort((a, b) => Date.parse(this.state.recorded[a]) - Date.parse(this.state.recorded[b]));
|
|
483
|
+
for (const k of sorted.slice(0, keys.length - C.STATE_MAX_KEYS))
|
|
484
|
+
delete this.state.recorded[k];
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async loadState() {
|
|
488
|
+
if (this.stateLoaded)
|
|
489
|
+
return;
|
|
490
|
+
this.stateLoaded = true;
|
|
491
|
+
if (!this.statePath)
|
|
492
|
+
return;
|
|
493
|
+
try {
|
|
494
|
+
const data = await safeReadJson(this.statePath, null);
|
|
495
|
+
if (data?.recorded && typeof data.recorded === 'object')
|
|
496
|
+
this.state = { recorded: { ...data.recorded } };
|
|
497
|
+
}
|
|
498
|
+
catch (err) {
|
|
499
|
+
this.logger.warn('WorkRecord: failed to load state (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async saveState() {
|
|
503
|
+
if (!this.statePath)
|
|
504
|
+
return;
|
|
505
|
+
try {
|
|
506
|
+
await ensureDir(path.dirname(this.statePath));
|
|
507
|
+
await atomicWriteJson(this.statePath, this.state);
|
|
508
|
+
}
|
|
509
|
+
catch (err) {
|
|
510
|
+
this.logger.warn('WorkRecord: failed to persist state (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
//# sourceMappingURL=work-record.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-record.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/work-record.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -2139,6 +2139,65 @@ export declare const AGENT_MEMORY_REFRESH_CONSTANTS: {
|
|
|
2139
2139
|
/** Kill switch env var; the value `false` disables the refresh. */
|
|
2140
2140
|
readonly ENV_KILL_SWITCH: "CREWLY_AGENT_MEMORY_REFRESH";
|
|
2141
2141
|
};
|
|
2142
|
+
/**
|
|
2143
|
+
* Automatic per-task work records (#1349): one `(record)` entry per finished
|
|
2144
|
+
* WorkItem in the project vault log, compiled into the weekly digest.
|
|
2145
|
+
*/
|
|
2146
|
+
export declare const WORK_RECORD_CONSTANTS: {
|
|
2147
|
+
/** Hourly tick: catch-up for finished items without a record, blocked items, deferred items. */
|
|
2148
|
+
readonly TICK_MS: number;
|
|
2149
|
+
/** Delay before the boot-time pass, after the other wiki jobs settled. */
|
|
2150
|
+
readonly BOOT_DELAY_MS: number;
|
|
2151
|
+
/** A terminal event waits this long before the record is assembled (ticket sync, verify item, evidence land first). */
|
|
2152
|
+
readonly EVENT_DELAY_MS: number;
|
|
2153
|
+
/** Catch-up looks at items that ended within this many days. */
|
|
2154
|
+
readonly CATCHUP_WINDOW_DAYS: 7;
|
|
2155
|
+
/** Cap on records written per pass (the rest wait for the next tick). */
|
|
2156
|
+
readonly CATCHUP_MAX_PER_PASS: 200;
|
|
2157
|
+
/** A record waiting for the owner's OK on a ticket is written anyway after this long. */
|
|
2158
|
+
readonly DEFER_MAX_MS: number;
|
|
2159
|
+
/** An item parked in `blocked` for longer than this gets a blocked record. */
|
|
2160
|
+
readonly BLOCKED_AFTER_MS: number;
|
|
2161
|
+
/** Hard cap on one record's body (the `meta:` line always fits). */
|
|
2162
|
+
readonly MAX_CHARS: 2500;
|
|
2163
|
+
/** Characters of the ask quoted. */
|
|
2164
|
+
readonly QUOTE_MAX_CHARS: 160;
|
|
2165
|
+
/** Characters of the result summary kept. */
|
|
2166
|
+
readonly DID_MAX_CHARS: 400;
|
|
2167
|
+
/** Cap on output lines and characters per line. */
|
|
2168
|
+
readonly MAX_OUTPUTS: 8;
|
|
2169
|
+
readonly OUTPUT_MAX_CHARS: 160;
|
|
2170
|
+
/** Cap on error lines and characters per line. */
|
|
2171
|
+
readonly MAX_ERRORS: 5;
|
|
2172
|
+
readonly ERROR_MAX_CHARS: 160;
|
|
2173
|
+
/** Cap on helper lines and characters per line. */
|
|
2174
|
+
readonly MAX_HELPERS: 6;
|
|
2175
|
+
readonly HELPER_MAX_CHARS: 120;
|
|
2176
|
+
/** Bytes read from the end of the agent's transcript for the task window. */
|
|
2177
|
+
readonly TRANSCRIPT_TAIL_BYTES: number;
|
|
2178
|
+
/** Transcripts are consulted only for items that ended within this long (older windows are not in the tail). */
|
|
2179
|
+
readonly TRANSCRIPT_MAX_AGE_MS: number;
|
|
2180
|
+
/** Slack around the task window when slicing the transcript. */
|
|
2181
|
+
readonly TRANSCRIPT_WINDOW_SLACK_MS: number;
|
|
2182
|
+
/** Cap on trace events read per record. */
|
|
2183
|
+
readonly TRACE_MAX_EVENTS: 2000;
|
|
2184
|
+
/** State file (recorded keys), under CREWLY_HOME. */
|
|
2185
|
+
readonly STATE_FILE: "work-records-state.json";
|
|
2186
|
+
/** Cap on remembered record keys. */
|
|
2187
|
+
readonly STATE_MAX_KEYS: 5000;
|
|
2188
|
+
/** Kill switch env var; the value `false` disables work records. */
|
|
2189
|
+
readonly ENV_KILL_SWITCH: "CREWLY_WORK_RECORDS";
|
|
2190
|
+
/** Source type of a record entry in the vault log. */
|
|
2191
|
+
readonly SOURCE_TYPE: "work_record";
|
|
2192
|
+
/** Prefix of a record's `ref:` (`work-record:<workItemId>#<phase>`). */
|
|
2193
|
+
readonly REF_PREFIX: "work-record:";
|
|
2194
|
+
/** Records the startup briefing lists. */
|
|
2195
|
+
readonly BRIEFING_MAX: 5;
|
|
2196
|
+
/** Characters of one record line in the briefing. */
|
|
2197
|
+
readonly BRIEFING_LINE_MAX_CHARS: 240;
|
|
2198
|
+
/** WorkItem types that are bookkeeping, never recorded. */
|
|
2199
|
+
readonly SKIPPED_TYPES: readonly string[];
|
|
2200
|
+
};
|
|
2142
2201
|
/**
|
|
2143
2202
|
* Startup briefing content (#1345): wiki pages, recent lessons and open
|
|
2144
2203
|
* owner threads an agent gets at registration, on top of its session memory.
|