crewly 1.20.184 → 1.20.185
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/constants.ts +83 -0
- package/config/index.ts +2 -0
- package/config/oss-boundary-allowlist.json +10 -0
- package/config/skills/agent/core/ask-owner/SKILL.md +5 -2
- package/config/skills/agent/core/complete-task/execute.sh +4 -12
- package/config/skills/agent/core/complete-task/execute.test.sh +11 -0
- package/config/skills/agent/core/report-status/SKILL.md +1 -1
- package/config/skills/agent/core/report-status/execute.sh +5 -10
- package/dist/backend/backend/src/constants.d.ts +40 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +35 -1
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts +11 -1
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.js +38 -0
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.controller.js +3 -2
- package/dist/backend/backend/src/controllers/google/google.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/request/open-items.controller.d.ts +9 -0
- package/dist/backend/backend/src/controllers/request/open-items.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/request/open-items.controller.js +29 -1
- package/dist/backend/backend/src/controllers/request/open-items.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/request/request.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.routes.js +4 -1
- package/dist/backend/backend/src/controllers/request/request.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/standing/standing.controller.d.ts +5 -2
- package/dist/backend/backend/src/controllers/standing/standing.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/standing/standing.controller.js +3 -1
- package/dist/backend/backend/src/controllers/standing/standing.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +15 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/scripts/check-oss-boundary.d.ts +217 -0
- package/dist/backend/backend/src/scripts/check-oss-boundary.d.ts.map +1 -0
- package/dist/backend/backend/src/scripts/check-oss-boundary.js +490 -0
- package/dist/backend/backend/src/scripts/check-oss-boundary.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts +3 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.js +15 -4
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts +31 -4
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.js +60 -2
- package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-skip-command.d.ts +56 -0
- package/dist/backend/backend/src/services/decisions/decision-skip-command.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-skip-command.js +108 -0
- package/dist/backend/backend/src/services/decisions/decision-skip-command.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +105 -2
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +187 -11
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts +8 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.js +25 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory.service.d.ts +19 -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 +48 -0
- package/dist/backend/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +20 -0
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/project-memory.service.d.ts +40 -0
- package/dist/backend/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/project-memory.service.js +101 -0
- package/dist/backend/backend/src/services/memory/project-memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.d.ts +1 -1
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.js.map +1 -1
- package/dist/backend/backend/src/services/memory/standing-answers.service.d.ts +61 -1
- package/dist/backend/backend/src/services/memory/standing-answers.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/standing-answers.service.js +71 -3
- package/dist/backend/backend/src/services/memory/standing-answers.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/standing-refresh.service.d.ts +7 -4
- package/dist/backend/backend/src/services/memory/standing-refresh.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/standing-refresh.service.js +18 -9
- package/dist/backend/backend/src/services/memory/standing-refresh.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/task-log-filter.d.ts +27 -0
- package/dist/backend/backend/src/services/memory/task-log-filter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/task-log-filter.js +56 -0
- package/dist/backend/backend/src/services/memory/task-log-filter.js.map +1 -0
- package/dist/backend/backend/src/services/open-items/open-items-backfill.d.ts +26 -1
- package/dist/backend/backend/src/services/open-items/open-items-backfill.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items-backfill.js +59 -3
- package/dist/backend/backend/src/services/open-items/open-items-backfill.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts +37 -2
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.js +101 -6
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.wiring.js +13 -0
- package/dist/backend/backend/src/services/open-items/open-items.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +13 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +34 -11
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js +4 -2
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts +103 -1
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js +171 -20
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts +60 -0
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js +121 -7
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/types/decision.types.d.ts +18 -3
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/open-item.types.d.ts +4 -1
- package/dist/backend/backend/src/types/v2/open-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/open-item.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/backend/config/constants.d.ts +73 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +80 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/backend/config/index.d.ts +10 -2
- package/dist/backend/config/index.d.ts.map +1 -1
- package/dist/backend/config/index.js +2 -2
- package/dist/backend/config/index.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +40 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +35 -1
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts +3 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.js +15 -4
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts +31 -4
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.js +60 -2
- package/dist/cli/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +105 -2
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +187 -11
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts +19 -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 +48 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +20 -0
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/project-memory.service.d.ts +40 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/project-memory.service.js +101 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.d.ts +1 -1
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.js.map +1 -1
- package/dist/cli/backend/src/services/memory/standing-answers.service.d.ts +61 -1
- package/dist/cli/backend/src/services/memory/standing-answers.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/standing-answers.service.js +71 -3
- package/dist/cli/backend/src/services/memory/standing-answers.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/task-log-filter.d.ts +27 -0
- package/dist/cli/backend/src/services/memory/task-log-filter.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/task-log-filter.js +56 -0
- package/dist/cli/backend/src/services/memory/task-log-filter.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +13 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +34 -11
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +18 -3
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/open-item.types.d.ts +4 -1
- package/dist/cli/backend/src/types/v2/open-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/open-item.types.js.map +1 -1
- package/dist/cli/config/constants.d.ts +73 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +80 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/index.d.ts +10 -2
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +2 -2
- package/dist/cli/config/index.js.map +1 -1
- package/frontend/dist/assets/{index-a6cb8533.js → index-1ee8a9a2.js} +273 -273
- package/frontend/dist/assets/index-a79c7852.css +42 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +2 -1
- package/frontend/dist/assets/index-04d192f8.css +0 -42
|
@@ -30,8 +30,22 @@ import * as fs from 'fs/promises';
|
|
|
30
30
|
import { existsSync } from 'fs';
|
|
31
31
|
import { randomUUID } from 'crypto';
|
|
32
32
|
import { LoggerService } from '../core/logger.service.js';
|
|
33
|
+
import { WIKI_QUEUE_CONSTANTS } from '../../constants.js';
|
|
34
|
+
/**
|
|
35
|
+
* Canonical form of a vault path, so `/p/.crewly/wiki/` and
|
|
36
|
+
* `/p/.crewly/wiki` (or a path with `..`) name the same vault. Queue
|
|
37
|
+
* filters used to compare the raw strings; an item stored with a trailing
|
|
38
|
+
* slash never matched the discovered vault and was never drained (#914).
|
|
39
|
+
*
|
|
40
|
+
* @param vaultPath - Absolute vault path as given by a caller
|
|
41
|
+
* @returns The resolved path without a trailing separator
|
|
42
|
+
*/
|
|
43
|
+
export function normalizeVaultPath(vaultPath) {
|
|
44
|
+
return path.resolve(vaultPath);
|
|
45
|
+
}
|
|
33
46
|
const MAX_CONTENT_BYTES = 64 * 1024;
|
|
34
47
|
const MAX_REASON_BYTES = 2 * 1024;
|
|
48
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
35
49
|
/**
|
|
36
50
|
* File-backed queue. Stateless other than the on-disk JSONs and an
|
|
37
51
|
* in-memory cache of the root directory. Singleton because all writes
|
|
@@ -68,7 +82,7 @@ export class WikiQueueService {
|
|
|
68
82
|
await this.ensureRoot();
|
|
69
83
|
const item = {
|
|
70
84
|
id: randomUUID(),
|
|
71
|
-
vaultPath: input.vaultPath,
|
|
85
|
+
vaultPath: normalizeVaultPath(input.vaultPath),
|
|
72
86
|
queuedAt: new Date().toISOString(),
|
|
73
87
|
queuedBy: input.queuedBy,
|
|
74
88
|
sourceType: input.sourceType,
|
|
@@ -87,27 +101,26 @@ export class WikiQueueService {
|
|
|
87
101
|
});
|
|
88
102
|
return item;
|
|
89
103
|
}
|
|
90
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* List items, optionally filtered. Newest-first unless `order: 'oldest'`.
|
|
106
|
+
* Vault paths are compared in normalised form (see {@link normalizeVaultPath}).
|
|
107
|
+
*
|
|
108
|
+
* @param filter - Vault / status / author filters, limit and order
|
|
109
|
+
* @returns Matching items, sorted and capped
|
|
110
|
+
*/
|
|
91
111
|
async list(filter = {}) {
|
|
92
|
-
await this.ensureRoot();
|
|
93
112
|
const limit = filter.limit ?? 50;
|
|
94
|
-
const
|
|
95
|
-
const items =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
continue;
|
|
106
|
-
if (filter.queuedBy && item.queuedBy !== filter.queuedBy)
|
|
107
|
-
continue;
|
|
108
|
-
items.push(item);
|
|
109
|
-
}
|
|
110
|
-
items.sort((a, b) => (a.queuedAt < b.queuedAt ? 1 : -1));
|
|
113
|
+
const wantVault = filter.vaultPath ? normalizeVaultPath(filter.vaultPath) : null;
|
|
114
|
+
const items = (await this.readAll()).filter((item) => (!wantVault || normalizeVaultPath(item.vaultPath) === wantVault) &&
|
|
115
|
+
(!filter.status || item.status === filter.status) &&
|
|
116
|
+
(!filter.queuedBy || item.queuedBy === filter.queuedBy));
|
|
117
|
+
const oldestFirst = filter.order === 'oldest';
|
|
118
|
+
items.sort((a, b) => {
|
|
119
|
+
if (a.queuedAt === b.queuedAt)
|
|
120
|
+
return 0;
|
|
121
|
+
const aFirst = oldestFirst ? a.queuedAt < b.queuedAt : a.queuedAt > b.queuedAt;
|
|
122
|
+
return aFirst ? -1 : 1;
|
|
123
|
+
});
|
|
111
124
|
return items.slice(0, limit);
|
|
112
125
|
}
|
|
113
126
|
/** Fetch one by id. Returns null when missing. */
|
|
@@ -186,12 +199,100 @@ export class WikiQueueService {
|
|
|
186
199
|
processed: 0,
|
|
187
200
|
skipped: 0,
|
|
188
201
|
total: items.length,
|
|
202
|
+
oldestPendingQueuedAt: null,
|
|
189
203
|
};
|
|
190
204
|
for (const it of items) {
|
|
191
205
|
counts[it.status]++;
|
|
206
|
+
if (it.status === 'pending' &&
|
|
207
|
+
(counts.oldestPendingQueuedAt === null || it.queuedAt < counts.oldestPendingQueuedAt)) {
|
|
208
|
+
counts.oldestPendingQueuedAt = it.queuedAt;
|
|
209
|
+
}
|
|
192
210
|
}
|
|
193
211
|
return counts;
|
|
194
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Housekeeping pass over the whole queue (#914). One read of the
|
|
215
|
+
* directory does three things:
|
|
216
|
+
*
|
|
217
|
+
* 1. A `claimed` item whose claim is older than `claimTimeoutMs` goes
|
|
218
|
+
* back to `pending` — the agent that claimed it died or forgot to
|
|
219
|
+
* call process/skip, and nothing else would ever release it.
|
|
220
|
+
* 2. A `pending`/`claimed` item queued longer ago than `maxItemAgeMs`
|
|
221
|
+
* moves to `<root>/dead-letter/<id>.json` with `expiredAt` +
|
|
222
|
+
* `expireReason`. Never deleted; one warn line per item.
|
|
223
|
+
* 3. Reports the remaining pending backlog per vault (count + oldest
|
|
224
|
+
* `queuedAt`) so the caller can alert on stale vaults and on items
|
|
225
|
+
* whose vault is not discovered.
|
|
226
|
+
*
|
|
227
|
+
* Processed/skipped items are left alone (they are the audit trail).
|
|
228
|
+
*
|
|
229
|
+
* @param opts - Clock and age thresholds (defaults from WIKI_QUEUE_CONSTANTS)
|
|
230
|
+
* @returns Expired items, released claim ids and per-vault backlog
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* const { expired, backlog } = await WikiQueueService.getInstance().sweep();
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
async sweep(opts = {}) {
|
|
238
|
+
const now = opts.now ?? Date.now();
|
|
239
|
+
const maxAge = opts.maxItemAgeMs ?? WIKI_QUEUE_CONSTANTS.MAX_ITEM_AGE_MS;
|
|
240
|
+
const claimTimeout = opts.claimTimeoutMs ?? WIKI_QUEUE_CONSTANTS.CLAIM_TIMEOUT_MS;
|
|
241
|
+
const result = { expired: [], releasedClaims: [], backlog: [] };
|
|
242
|
+
const backlog = new Map();
|
|
243
|
+
for (const item of await this.readAll()) {
|
|
244
|
+
if (item.status !== 'pending' && item.status !== 'claimed')
|
|
245
|
+
continue;
|
|
246
|
+
const queuedMs = Date.parse(item.queuedAt);
|
|
247
|
+
if (Number.isFinite(queuedMs) && now - queuedMs > maxAge) {
|
|
248
|
+
await this.deadLetter(item, now, queuedMs);
|
|
249
|
+
result.expired.push(item);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
let current = item;
|
|
253
|
+
if (item.status === 'claimed') {
|
|
254
|
+
const claimedMs = Date.parse(item.claimedAt ?? '');
|
|
255
|
+
if (Number.isFinite(claimedMs) && now - claimedMs <= claimTimeout)
|
|
256
|
+
continue;
|
|
257
|
+
current = { ...item, status: 'pending', claimedBy: undefined, claimedAt: undefined };
|
|
258
|
+
await this.writeItem(current);
|
|
259
|
+
result.releasedClaims.push(item.id);
|
|
260
|
+
this.logger.warn('WikiQueue claim released — claimant never processed or skipped it', {
|
|
261
|
+
id: item.id,
|
|
262
|
+
vaultPath: item.vaultPath,
|
|
263
|
+
claimedBy: item.claimedBy,
|
|
264
|
+
claimedAt: item.claimedAt,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const vaultPath = normalizeVaultPath(current.vaultPath);
|
|
268
|
+
const entry = backlog.get(vaultPath);
|
|
269
|
+
if (!entry) {
|
|
270
|
+
backlog.set(vaultPath, { vaultPath, pending: 1, oldestQueuedAt: current.queuedAt });
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
entry.pending++;
|
|
274
|
+
if (current.queuedAt < entry.oldestQueuedAt)
|
|
275
|
+
entry.oldestQueuedAt = current.queuedAt;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
result.backlog = [...backlog.values()].sort((a, b) => a.vaultPath.localeCompare(b.vaultPath));
|
|
279
|
+
if (result.expired.length > 0 || result.releasedClaims.length > 0) {
|
|
280
|
+
this.logger.warn('WikiQueue sweep', {
|
|
281
|
+
expired: result.expired.length,
|
|
282
|
+
releasedClaims: result.releasedClaims.length,
|
|
283
|
+
deadLetterDir: this.getDeadLetterDir(),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Folder that holds expired items.
|
|
290
|
+
*
|
|
291
|
+
* @returns Absolute path of the dead-letter folder
|
|
292
|
+
*/
|
|
293
|
+
getDeadLetterDir() {
|
|
294
|
+
return path.join(this.rootDir, WIKI_QUEUE_CONSTANTS.DEAD_LETTER_DIR);
|
|
295
|
+
}
|
|
195
296
|
// ---------------------------------------------------------------------------
|
|
196
297
|
// Internals
|
|
197
298
|
// ---------------------------------------------------------------------------
|
|
@@ -220,6 +321,56 @@ export class WikiQueueService {
|
|
|
220
321
|
throw new Error(`WikiQueue.add: reason exceeds ${MAX_REASON_BYTES} bytes`);
|
|
221
322
|
}
|
|
222
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Read every well-formed item in the queue root (not the dead-letter
|
|
326
|
+
* folder — `readdir` is not recursive).
|
|
327
|
+
*
|
|
328
|
+
* @returns All items, unsorted
|
|
329
|
+
*/
|
|
330
|
+
async readAll() {
|
|
331
|
+
await this.ensureRoot();
|
|
332
|
+
const entries = await fs.readdir(this.rootDir, { withFileTypes: true });
|
|
333
|
+
const items = [];
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
if (!entry.isFile() || !entry.name.endsWith('.json'))
|
|
336
|
+
continue;
|
|
337
|
+
const item = await this.readItemFile(path.join(this.rootDir, entry.name));
|
|
338
|
+
if (item)
|
|
339
|
+
items.push(item);
|
|
340
|
+
}
|
|
341
|
+
return items;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Move one item to the dead-letter folder, stamped with why. Written
|
|
345
|
+
* there first, then removed from the queue, so a crash in between
|
|
346
|
+
* leaves a duplicate rather than a loss.
|
|
347
|
+
*
|
|
348
|
+
* @param item - Item to expire
|
|
349
|
+
* @param now - Current epoch ms
|
|
350
|
+
* @param queuedMs - Item's `queuedAt` in epoch ms
|
|
351
|
+
*/
|
|
352
|
+
async deadLetter(item, now, queuedMs) {
|
|
353
|
+
const ageDays = Math.floor((now - queuedMs) / MS_PER_DAY);
|
|
354
|
+
const expired = {
|
|
355
|
+
...item,
|
|
356
|
+
expiredAt: new Date(now).toISOString(),
|
|
357
|
+
expireReason: `still ${item.status} after ${ageDays} days`,
|
|
358
|
+
};
|
|
359
|
+
const dir = this.getDeadLetterDir();
|
|
360
|
+
await fs.mkdir(dir, { recursive: true });
|
|
361
|
+
const target = path.join(dir, `${item.id}.json`);
|
|
362
|
+
await fs.writeFile(`${target}.tmp`, JSON.stringify(expired, null, 2), 'utf8');
|
|
363
|
+
await fs.rename(`${target}.tmp`, target);
|
|
364
|
+
await fs.rm(path.join(this.rootDir, `${item.id}.json`), { force: true });
|
|
365
|
+
this.logger.warn('WikiQueue item expired to dead-letter', {
|
|
366
|
+
id: item.id,
|
|
367
|
+
vaultPath: item.vaultPath,
|
|
368
|
+
status: item.status,
|
|
369
|
+
queuedAt: item.queuedAt,
|
|
370
|
+
ageDays,
|
|
371
|
+
file: target,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
223
374
|
async ensureRoot() {
|
|
224
375
|
if (this.initPromise) {
|
|
225
376
|
await this.initPromise;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wiki-queue.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-queue.service.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wiki-queue.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-queue.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -89,6 +89,24 @@ export interface WikiWorkItemBridgeOptions {
|
|
|
89
89
|
cleanupService?: WikiCleanupService;
|
|
90
90
|
/** Task pool override (test seam). */
|
|
91
91
|
taskPool?: TaskPoolService;
|
|
92
|
+
/**
|
|
93
|
+
* Absolute path of `config/skills/orchestrator`. Substituted for
|
|
94
|
+
* `{{ORCHESTRATOR_SKILLS_PATH}}` in WI briefs: a brief is read raw by
|
|
95
|
+
* whoever claims it (poll-tasks), and since drains route to team leaders
|
|
96
|
+
* — whose prompts never define that placeholder — the literal string
|
|
97
|
+
* was all they got to run (#914). Null/omitted leaves it as-is.
|
|
98
|
+
*/
|
|
99
|
+
orchestratorSkillsPath?: string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Owner notification for a stale queue (oldest pending item older than
|
|
102
|
+
* {@link WIKI_QUEUE_CONSTANTS.STALE_ALERT_AGE_MS}). Boot wires the Slack
|
|
103
|
+
* owner notification, like auto-update. Omitted → warn log only.
|
|
104
|
+
*/
|
|
105
|
+
notifyOwner?: (title: string, message: string) => Promise<unknown>;
|
|
106
|
+
/** Queue max item age override (default {@link WIKI_QUEUE_CONSTANTS.MAX_ITEM_AGE_MS}). */
|
|
107
|
+
maxItemAgeMs?: number;
|
|
108
|
+
/** Stale-alert age override (default {@link WIKI_QUEUE_CONSTANTS.STALE_ALERT_AGE_MS}). */
|
|
109
|
+
staleAlertAgeMs?: number;
|
|
92
110
|
}
|
|
93
111
|
export interface WikiBridgeTickResult {
|
|
94
112
|
scannedVaults: string[];
|
|
@@ -103,6 +121,14 @@ export interface WikiBridgeTickResult {
|
|
|
103
121
|
skippedByCooldown: string[];
|
|
104
122
|
/** Vault paths for which a cleanup WI was created this tick. */
|
|
105
123
|
createdCleanupForVault: string[];
|
|
124
|
+
/** Queue items moved to dead-letter by this tick's sweep. */
|
|
125
|
+
expiredQueueItems: number;
|
|
126
|
+
/** Abandoned claims released back to pending by this tick's sweep. */
|
|
127
|
+
releasedQueueClaims: number;
|
|
128
|
+
/** Vault paths with pending items that discovery does not return (never drained). */
|
|
129
|
+
orphanQueueVaults: string[];
|
|
130
|
+
/** Vault paths whose oldest pending item is older than the stale-alert age. */
|
|
131
|
+
staleQueueVaults: string[];
|
|
106
132
|
}
|
|
107
133
|
/**
|
|
108
134
|
* Periodic bridge: pending wiki queue items + migration candidates
|
|
@@ -144,6 +170,12 @@ export declare class WikiWorkItemBridgeService {
|
|
|
144
170
|
private readonly statePath;
|
|
145
171
|
/** True after `loadStateFromDisk` has either populated or no-op'd. */
|
|
146
172
|
private stateLoaded;
|
|
173
|
+
private readonly orchestratorSkillsPath;
|
|
174
|
+
private readonly notifyOwner;
|
|
175
|
+
private readonly maxItemAgeMs;
|
|
176
|
+
private readonly staleAlertAgeMs;
|
|
177
|
+
/** vaultPath → epoch ms of the last stale-queue owner alert. */
|
|
178
|
+
private readonly lastStaleAlertAt;
|
|
147
179
|
constructor(opts?: WikiWorkItemBridgeOptions);
|
|
148
180
|
/**
|
|
149
181
|
* Hydrate {@link lastCreatedAt} from disk. Idempotent — runs once per
|
|
@@ -194,6 +226,34 @@ export declare class WikiWorkItemBridgeService {
|
|
|
194
226
|
* terminal — i.e. it's still queued/claimed/running/etc.
|
|
195
227
|
*/
|
|
196
228
|
private snapshotInflight;
|
|
229
|
+
/**
|
|
230
|
+
* Queue housekeeping at the start of each tick (#914): release abandoned
|
|
231
|
+
* claims, dead-letter items past the max age, warn about pending items
|
|
232
|
+
* whose vault discovery does not return (nothing would ever drain them),
|
|
233
|
+
* and alert the owner when a vault's oldest pending item is older than
|
|
234
|
+
* the stale-alert age. Failures are logged and never abort the tick.
|
|
235
|
+
*
|
|
236
|
+
* @param vaults - Vault paths discovery returned this tick
|
|
237
|
+
* @param result - Tick result to fill in
|
|
238
|
+
*/
|
|
239
|
+
private sweepQueue;
|
|
240
|
+
/**
|
|
241
|
+
* Report one stale vault: a warn log line always, plus the owner
|
|
242
|
+
* notification when one is wired.
|
|
243
|
+
*
|
|
244
|
+
* @param backlog - The vault's pending backlog
|
|
245
|
+
* @param ageMs - Age of its oldest pending item
|
|
246
|
+
* @param orphan - True when discovery does not return the vault
|
|
247
|
+
*/
|
|
248
|
+
private alertStaleQueue;
|
|
249
|
+
/**
|
|
250
|
+
* Fill in placeholders a WI brief carries, since the claimant reads the
|
|
251
|
+
* brief raw. See {@link WikiWorkItemBridgeOptions.orchestratorSkillsPath}.
|
|
252
|
+
*
|
|
253
|
+
* @param brief - Brief markdown with `{{ORCHESTRATOR_SKILLS_PATH}}`
|
|
254
|
+
* @returns The brief with the path filled in, or unchanged when unknown
|
|
255
|
+
*/
|
|
256
|
+
private resolveBrief;
|
|
197
257
|
/**
|
|
198
258
|
* The session that should do a vault's wiki work: the resolver's answer
|
|
199
259
|
* (a team leader) or the fallback target.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wiki-workitem-bridge.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-workitem-bridge.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"wiki-workitem-bridge.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-workitem-bridge.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ import path from 'path';
|
|
|
30
30
|
import { existsSync, promises as fs } from 'fs';
|
|
31
31
|
import { LoggerService } from '../core/logger.service.js';
|
|
32
32
|
import { TaskPoolService } from '../task-pool/task-pool.service.js';
|
|
33
|
-
import { WikiQueueService } from './wiki-queue.service.js';
|
|
33
|
+
import { WikiQueueService, normalizeVaultPath } from './wiki-queue.service.js';
|
|
34
34
|
import { WikiMigrateService } from './wiki-migrate.service.js';
|
|
35
35
|
import { WikiCleanupService } from './wiki-cleanup.service.js';
|
|
36
36
|
import { discoverWikiVaults } from './wiki-bookkeep-trigger.service.js';
|
|
@@ -38,7 +38,7 @@ import { isInsidePackageTree } from '../v3/mission-paths.js';
|
|
|
38
38
|
import { createWorkItem } from '../../types/v2/work-item.types.js';
|
|
39
39
|
import { atomicWriteJson, safeReadJson, ensureDir } from '../../utils/file-io.utils.js';
|
|
40
40
|
import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
|
|
41
|
-
import { WIKI_KB_CONSTANTS } from '../../constants.js';
|
|
41
|
+
import { WIKI_KB_CONSTANTS, WIKI_QUEUE_CONSTANTS } from '../../constants.js';
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
43
|
// Constants
|
|
44
44
|
// ---------------------------------------------------------------------------
|
|
@@ -157,6 +157,12 @@ export class WikiWorkItemBridgeService {
|
|
|
157
157
|
statePath;
|
|
158
158
|
/** True after `loadStateFromDisk` has either populated or no-op'd. */
|
|
159
159
|
stateLoaded = false;
|
|
160
|
+
orchestratorSkillsPath;
|
|
161
|
+
notifyOwner;
|
|
162
|
+
maxItemAgeMs;
|
|
163
|
+
staleAlertAgeMs;
|
|
164
|
+
/** vaultPath → epoch ms of the last stale-queue owner alert. */
|
|
165
|
+
lastStaleAlertAt = new Map();
|
|
160
166
|
constructor(opts = {}) {
|
|
161
167
|
this.logger = LoggerService.getInstance().createComponentLogger('WikiWorkItemBridge');
|
|
162
168
|
this.intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
@@ -171,6 +177,10 @@ export class WikiWorkItemBridgeService {
|
|
|
171
177
|
this.migrate = opts.migrateService ?? WikiMigrateService.getInstance();
|
|
172
178
|
this.cleanup = opts.cleanupService ?? WikiCleanupService.getInstance();
|
|
173
179
|
this.pool = opts.taskPool ?? TaskPoolService.getInstance();
|
|
180
|
+
this.orchestratorSkillsPath = opts.orchestratorSkillsPath ?? null;
|
|
181
|
+
this.notifyOwner = opts.notifyOwner ?? null;
|
|
182
|
+
this.maxItemAgeMs = opts.maxItemAgeMs ?? WIKI_QUEUE_CONSTANTS.MAX_ITEM_AGE_MS;
|
|
183
|
+
this.staleAlertAgeMs = opts.staleAlertAgeMs ?? WIKI_QUEUE_CONSTANTS.STALE_ALERT_AGE_MS;
|
|
174
184
|
if (opts.statePath === null) {
|
|
175
185
|
this.statePath = null;
|
|
176
186
|
}
|
|
@@ -367,6 +377,10 @@ export class WikiWorkItemBridgeService {
|
|
|
367
377
|
deferredByThrottle: [],
|
|
368
378
|
skippedByCooldown: [],
|
|
369
379
|
createdCleanupForVault: [],
|
|
380
|
+
expiredQueueItems: 0,
|
|
381
|
+
releasedQueueClaims: 0,
|
|
382
|
+
orphanQueueVaults: [],
|
|
383
|
+
staleQueueVaults: [],
|
|
370
384
|
};
|
|
371
385
|
if (this.running) {
|
|
372
386
|
// Overlapping ticks would create duplicates; the dedupe pass below
|
|
@@ -381,6 +395,7 @@ export class WikiWorkItemBridgeService {
|
|
|
381
395
|
const { inflightVaults, inflightProjects, inflightCleanupVaults } = await this.snapshotInflight();
|
|
382
396
|
// Drains come first — they're cheap, fast, and the most common case.
|
|
383
397
|
const vaults = await this.discoverRoots();
|
|
398
|
+
await this.sweepQueue(vaults, result);
|
|
384
399
|
for (const vaultPath of vaults) {
|
|
385
400
|
result.scannedVaults.push(vaultPath);
|
|
386
401
|
if (inflightVaults.has(vaultPath)) {
|
|
@@ -393,10 +408,14 @@ export class WikiWorkItemBridgeService {
|
|
|
393
408
|
continue;
|
|
394
409
|
}
|
|
395
410
|
try {
|
|
411
|
+
// Uncapped (#914): with `limit: 200` a vault holding ≥ 200 pending
|
|
412
|
+
// items reported 200 every time, so every drain WI looked like
|
|
413
|
+
// "no progress" and the cooldown climbed to 24h even while the
|
|
414
|
+
// agent was draining.
|
|
396
415
|
const pending = await this.queue.list({
|
|
397
416
|
vaultPath,
|
|
398
417
|
status: 'pending',
|
|
399
|
-
limit:
|
|
418
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
400
419
|
});
|
|
401
420
|
if (pending.length === 0)
|
|
402
421
|
continue;
|
|
@@ -410,7 +429,7 @@ export class WikiWorkItemBridgeService {
|
|
|
410
429
|
createdThisTick++;
|
|
411
430
|
}
|
|
412
431
|
catch (err) {
|
|
413
|
-
this.logger.
|
|
432
|
+
this.logger.warn('queue.list / drain WI create failed (non-fatal)', {
|
|
414
433
|
vaultPath,
|
|
415
434
|
error: err.message,
|
|
416
435
|
});
|
|
@@ -569,6 +588,101 @@ export class WikiWorkItemBridgeService {
|
|
|
569
588
|
}
|
|
570
589
|
return { inflightVaults, inflightProjects, inflightCleanupVaults };
|
|
571
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* Queue housekeeping at the start of each tick (#914): release abandoned
|
|
593
|
+
* claims, dead-letter items past the max age, warn about pending items
|
|
594
|
+
* whose vault discovery does not return (nothing would ever drain them),
|
|
595
|
+
* and alert the owner when a vault's oldest pending item is older than
|
|
596
|
+
* the stale-alert age. Failures are logged and never abort the tick.
|
|
597
|
+
*
|
|
598
|
+
* @param vaults - Vault paths discovery returned this tick
|
|
599
|
+
* @param result - Tick result to fill in
|
|
600
|
+
*/
|
|
601
|
+
async sweepQueue(vaults, result) {
|
|
602
|
+
const now = this.nowFn();
|
|
603
|
+
let sweep;
|
|
604
|
+
try {
|
|
605
|
+
sweep = await this.queue.sweep({ now, maxItemAgeMs: this.maxItemAgeMs });
|
|
606
|
+
}
|
|
607
|
+
catch (err) {
|
|
608
|
+
this.logger.warn('Wiki queue sweep failed (non-fatal)', { error: err.message });
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
result.expiredQueueItems = sweep.expired.length;
|
|
612
|
+
result.releasedQueueClaims = sweep.releasedClaims.length;
|
|
613
|
+
const discovered = new Set(vaults.map(normalizeVaultPath));
|
|
614
|
+
for (const backlog of sweep.backlog) {
|
|
615
|
+
if (!discovered.has(backlog.vaultPath)) {
|
|
616
|
+
result.orphanQueueVaults.push(backlog.vaultPath);
|
|
617
|
+
if (!this.exhaustedWarned.has(`orphan:${backlog.vaultPath}`)) {
|
|
618
|
+
this.exhaustedWarned.add(`orphan:${backlog.vaultPath}`);
|
|
619
|
+
this.logger.warn('Wiki queue has pending items for a vault the bridge does not discover — no drain WI will be created for them', {
|
|
620
|
+
vaultPath: backlog.vaultPath,
|
|
621
|
+
pending: backlog.pending,
|
|
622
|
+
oldestQueuedAt: backlog.oldestQueuedAt,
|
|
623
|
+
hint: 'the vault needs a SCHEMA.md and its project must be in ~/.crewly/projects.json; otherwise the items expire to the dead-letter folder',
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const ageMs = now - Date.parse(backlog.oldestQueuedAt);
|
|
628
|
+
if (!(ageMs > this.staleAlertAgeMs))
|
|
629
|
+
continue;
|
|
630
|
+
result.staleQueueVaults.push(backlog.vaultPath);
|
|
631
|
+
const last = this.lastStaleAlertAt.get(backlog.vaultPath);
|
|
632
|
+
if (last !== undefined && now - last < WIKI_QUEUE_CONSTANTS.STALE_ALERT_COOLDOWN_MS)
|
|
633
|
+
continue;
|
|
634
|
+
this.lastStaleAlertAt.set(backlog.vaultPath, now);
|
|
635
|
+
await this.alertStaleQueue(backlog, ageMs, !discovered.has(backlog.vaultPath));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Report one stale vault: a warn log line always, plus the owner
|
|
640
|
+
* notification when one is wired.
|
|
641
|
+
*
|
|
642
|
+
* @param backlog - The vault's pending backlog
|
|
643
|
+
* @param ageMs - Age of its oldest pending item
|
|
644
|
+
* @param orphan - True when discovery does not return the vault
|
|
645
|
+
*/
|
|
646
|
+
async alertStaleQueue(backlog, ageMs, orphan) {
|
|
647
|
+
const ageDays = Math.floor(ageMs / (24 * 60 * 60 * 1000));
|
|
648
|
+
const expireDays = Math.round(this.maxItemAgeMs / (24 * 60 * 60 * 1000));
|
|
649
|
+
const scope = describeVaultScope(backlog.vaultPath);
|
|
650
|
+
const message = `${backlog.pending} wiki queue item(s) for ${scope} are waiting; the oldest was queued ${ageDays} days ago (${backlog.oldestQueuedAt}). ` +
|
|
651
|
+
(orphan
|
|
652
|
+
? 'This vault is not discovered (no SCHEMA.md or project not registered), so nothing will process them. '
|
|
653
|
+
: 'The drain WorkItems are not keeping up — check that the vault owner is claiming and finishing them. ') +
|
|
654
|
+
`Items older than ${expireDays} days move to ~/.crewly/wiki-queue/${WIKI_QUEUE_CONSTANTS.DEAD_LETTER_DIR}/.`;
|
|
655
|
+
this.logger.warn('Wiki queue is stale', {
|
|
656
|
+
vaultPath: backlog.vaultPath,
|
|
657
|
+
pending: backlog.pending,
|
|
658
|
+
oldestQueuedAt: backlog.oldestQueuedAt,
|
|
659
|
+
ageDays,
|
|
660
|
+
orphan,
|
|
661
|
+
});
|
|
662
|
+
if (!this.notifyOwner)
|
|
663
|
+
return;
|
|
664
|
+
try {
|
|
665
|
+
await this.notifyOwner('Wiki queue backlog', message);
|
|
666
|
+
}
|
|
667
|
+
catch (err) {
|
|
668
|
+
this.logger.warn('Stale wiki queue notification failed (non-fatal)', {
|
|
669
|
+
vaultPath: backlog.vaultPath,
|
|
670
|
+
error: err.message,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Fill in placeholders a WI brief carries, since the claimant reads the
|
|
676
|
+
* brief raw. See {@link WikiWorkItemBridgeOptions.orchestratorSkillsPath}.
|
|
677
|
+
*
|
|
678
|
+
* @param brief - Brief markdown with `{{ORCHESTRATOR_SKILLS_PATH}}`
|
|
679
|
+
* @returns The brief with the path filled in, or unchanged when unknown
|
|
680
|
+
*/
|
|
681
|
+
resolveBrief(brief) {
|
|
682
|
+
if (!this.orchestratorSkillsPath)
|
|
683
|
+
return brief;
|
|
684
|
+
return brief.replace(/\{\{ORCHESTRATOR_SKILLS_PATH\}\}/g, this.orchestratorSkillsPath);
|
|
685
|
+
}
|
|
572
686
|
/**
|
|
573
687
|
* The session that should do a vault's wiki work: the resolver's answer
|
|
574
688
|
* (a team leader) or the fallback target.
|
|
@@ -595,7 +709,7 @@ export class WikiWorkItemBridgeService {
|
|
|
595
709
|
target,
|
|
596
710
|
title: `Drain ${pendingCount} wiki queue item(s) — ${scope}`,
|
|
597
711
|
description: `Process ${pendingCount} pending wiki queue items in ${vaultPath}.`,
|
|
598
|
-
briefMarkdown: drainBrief(vaultPath, pendingCount),
|
|
712
|
+
briefMarkdown: this.resolveBrief(drainBrief(vaultPath, pendingCount)),
|
|
599
713
|
maxRetries: 1,
|
|
600
714
|
metadata: {
|
|
601
715
|
kind: META_KIND_WIKI_DRAIN,
|
|
@@ -621,7 +735,7 @@ export class WikiWorkItemBridgeService {
|
|
|
621
735
|
target,
|
|
622
736
|
title: `Cleanup ${chunk.length} of ${totalCandidates} low-quality wiki page(s) — ${scope}`,
|
|
623
737
|
description: `Review ${chunk.length} cleanup candidates in ${vaultPath}; decide keep/delete; call wiki-cleanup --apply with the final list.`,
|
|
624
|
-
briefMarkdown: cleanupBrief(vaultPath, chunk, totalCandidates),
|
|
738
|
+
briefMarkdown: this.resolveBrief(cleanupBrief(vaultPath, chunk, totalCandidates)),
|
|
625
739
|
maxRetries: 1,
|
|
626
740
|
metadata: {
|
|
627
741
|
kind: META_KIND_WIKI_CLEANUP,
|
|
@@ -654,7 +768,7 @@ export class WikiWorkItemBridgeService {
|
|
|
654
768
|
target,
|
|
655
769
|
title: `Migrate ${proposedCount} legacy wiki item(s) — ${path.basename(projectRoot)}`,
|
|
656
770
|
description: `Apply wiki-migrate for ${projectRoot} (${proposedCount} new pages).`,
|
|
657
|
-
briefMarkdown: migrateBrief(projectRoot, proposedCount),
|
|
771
|
+
briefMarkdown: this.resolveBrief(migrateBrief(projectRoot, proposedCount)),
|
|
658
772
|
maxRetries: 1,
|
|
659
773
|
metadata: {
|
|
660
774
|
kind: META_KIND_WIKI_MIGRATE,
|