crewly 1.8.3 → 1.8.5
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/roles/_common/wiki-instructions.md +33 -0
- package/config/roles/orchestrator/prompt.md +121 -0
- package/config/roles/team-leader/prompt.md +38 -0
- package/config/skills/agent/core/wiki-query/SKILL.md +66 -0
- package/config/skills/agent/core/wiki-query/execute.sh +107 -0
- package/config/skills/orchestrator/wiki-bookkeep/SKILL.md +71 -0
- package/config/skills/orchestrator/wiki-bookkeep/execute.sh +72 -0
- package/config/skills/orchestrator/wiki-ingest/SKILL.md +63 -0
- package/config/skills/orchestrator/wiki-ingest/execute.sh +113 -0
- package/config/skills/orchestrator/wiki-process-queue/SKILL.md +71 -0
- package/config/skills/orchestrator/wiki-process-queue/execute.sh +93 -0
- package/config/skills/orchestrator/wiki-queue-add/SKILL.md +89 -0
- package/config/skills/orchestrator/wiki-queue-add/execute.sh +115 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +134 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +718 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts +23 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +43 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +39 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/core/system-health.util.d.ts +29 -4
- package/dist/backend/backend/src/services/core/system-health.util.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/system-health.util.js +105 -6
- package/dist/backend/backend/src/services/core/system-health.util.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +28 -0
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js +162 -4
- package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +20 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts +38 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.js +124 -0
- package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +19 -2
- package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/v3-data.service.js +64 -7
- package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts +69 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js +174 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js +183 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts +86 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js +187 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +116 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +299 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +74 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +154 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +212 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts +84 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js +138 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +115 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js +291 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts +115 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js +261 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts +84 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.js +10 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.js.map +1 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +20 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/frontend/dist/assets/{index-b279da34.js → index-cc115bb4.js} +246 -246
- package/frontend/dist/assets/{index-c07e04c0.css → index-db3f5041.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WikiBookkeepTriggerService — periodic vault scan that fires a
|
|
3
|
+
* notification to ORC when bookkeeping is due.
|
|
4
|
+
*
|
|
5
|
+
* Per Steve's 2026-05-22 design point #5: "还要时不时让 agent 针对自己的
|
|
6
|
+
* vault 进行 bookkeeping (可以根据存入的 md 数量来 trigger), 譬如过去
|
|
7
|
+
* N 天超过 X 个 md, 然后总结一下."
|
|
8
|
+
*
|
|
9
|
+
* Mechanism:
|
|
10
|
+
* - every `intervalMs` (default 30 min) tick
|
|
11
|
+
* - discover known vaults (project + team + global) by walking known
|
|
12
|
+
* filesystem roots for SCHEMA.md
|
|
13
|
+
* - call `WikiBookkeepService.generate` for each
|
|
14
|
+
* - if `report.shouldFire`, invoke the caller-injected `fireFn` (in
|
|
15
|
+
* production: enqueue a `[BOOKKEEP] vault=…` message to ORC)
|
|
16
|
+
* - debounce per-vault so we don't spam — only refire after
|
|
17
|
+
* `debounceMs` (default 6 h)
|
|
18
|
+
*
|
|
19
|
+
* The service intentionally does NOT do the consolidation itself — it
|
|
20
|
+
* notifies the agent, which then runs `wiki-bookkeep` + `wiki-ingest`
|
|
21
|
+
* (per the orchestrator system prompt rule).
|
|
22
|
+
*
|
|
23
|
+
* @module services/wiki/wiki-bookkeep-trigger.service
|
|
24
|
+
*/
|
|
25
|
+
import { WikiBookkeepService, WikiBookkeepReport } from './wiki-bookkeep.service.js';
|
|
26
|
+
export type WikiBookkeepFireFn = (vaultPath: string, report: WikiBookkeepReport) => Promise<void> | void;
|
|
27
|
+
export interface WikiBookkeepTriggerOptions {
|
|
28
|
+
/** Interval between scans, ms. Default 30 minutes. */
|
|
29
|
+
intervalMs?: number;
|
|
30
|
+
/** Minimum gap between fires for the same vault, ms. Default 6 hours. */
|
|
31
|
+
debounceMs?: number;
|
|
32
|
+
/** Caller-injected notifier. Production wires this to enqueue a message to ORC. */
|
|
33
|
+
fireFn: WikiBookkeepFireFn;
|
|
34
|
+
/** Optional override of the discovery roots (tests). */
|
|
35
|
+
discoverRoots?: () => Promise<string[]>;
|
|
36
|
+
/** Optional override of the bookkeep service (tests). */
|
|
37
|
+
bookkeepService?: WikiBookkeepService;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Discover absolute vault paths by walking the well-known Crewly roots:
|
|
41
|
+
* - `<env CREWLY_PROJECT_VAULT_PATH>` (single explicit override)
|
|
42
|
+
* - `<process.cwd>/.crewly/wiki` (current project vault)
|
|
43
|
+
* - `~/.crewly/teams/<uuid>/wiki` (every team vault)
|
|
44
|
+
* - `~/.crewly/global-wiki` (ORC cross-project vault, if present)
|
|
45
|
+
*
|
|
46
|
+
* A path is only included if `SCHEMA.md` exists inside it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function discoverWikiVaults(): Promise<string[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Periodic vault-bookkeep trigger. Start at boot, stop at shutdown.
|
|
51
|
+
*/
|
|
52
|
+
export declare class WikiBookkeepTriggerService {
|
|
53
|
+
private static instance;
|
|
54
|
+
private readonly logger;
|
|
55
|
+
private readonly intervalMs;
|
|
56
|
+
private readonly debounceMs;
|
|
57
|
+
private readonly fireFn;
|
|
58
|
+
private readonly discoverRoots;
|
|
59
|
+
private readonly bookkeepService;
|
|
60
|
+
private timer;
|
|
61
|
+
/** vaultPath → last fired timestamp (ms). */
|
|
62
|
+
private readonly lastFiredAt;
|
|
63
|
+
/** Per-vault locks so two overlapping ticks don't double-fire. */
|
|
64
|
+
private inflight;
|
|
65
|
+
constructor(opts: WikiBookkeepTriggerOptions);
|
|
66
|
+
static getInstance(): WikiBookkeepTriggerService | null;
|
|
67
|
+
/** Wire the production singleton. Pass null to detach (tests / shutdown). */
|
|
68
|
+
static setInstance(next: WikiBookkeepTriggerService | null): void;
|
|
69
|
+
/** Begin scanning. Idempotent. */
|
|
70
|
+
start(): void;
|
|
71
|
+
/** Stop scanning. Safe to call multiple times. */
|
|
72
|
+
stop(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Run one scan pass. Public for test + the manual
|
|
75
|
+
* `/api/wiki/bookkeep/trigger-now` endpoint.
|
|
76
|
+
*/
|
|
77
|
+
tick(): Promise<{
|
|
78
|
+
scanned: string[];
|
|
79
|
+
fired: string[];
|
|
80
|
+
skippedByDebounce: string[];
|
|
81
|
+
quietVaults: string[];
|
|
82
|
+
}>;
|
|
83
|
+
/** Test affordance: clear the debounce ledger. */
|
|
84
|
+
_resetDebounceForTesting(): void;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=wiki-bookkeep-trigger.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-bookkeep-trigger.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-bookkeep-trigger.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,CAC/B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,KACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,MAAM,WAAW,0BAA0B;IACzC,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,MAAM,EAAE,kBAAkB,CAAC;IAC3B,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,yDAAyD;IACzD,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AAKD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA4B5D;AAED;;GAEG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA2C;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;IACtD,OAAO,CAAC,KAAK,CAA+B;IAC5C,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,IAAI,EAAE,0BAA0B;IAS5C,MAAM,CAAC,WAAW,IAAI,0BAA0B,GAAG,IAAI;IAIvD,6EAA6E;IAC7E,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,0BAA0B,GAAG,IAAI,GAAG,IAAI;IAKjE,kCAAkC;IAClC,KAAK,IAAI,IAAI;IAWb,kDAAkD;IAClD,IAAI,IAAI,IAAI;IAQZ;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;QAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IAoDF,kDAAkD;IAClD,wBAAwB,IAAI,IAAI;CAGjC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WikiBookkeepTriggerService — periodic vault scan that fires a
|
|
3
|
+
* notification to ORC when bookkeeping is due.
|
|
4
|
+
*
|
|
5
|
+
* Per Steve's 2026-05-22 design point #5: "还要时不时让 agent 针对自己的
|
|
6
|
+
* vault 进行 bookkeeping (可以根据存入的 md 数量来 trigger), 譬如过去
|
|
7
|
+
* N 天超过 X 个 md, 然后总结一下."
|
|
8
|
+
*
|
|
9
|
+
* Mechanism:
|
|
10
|
+
* - every `intervalMs` (default 30 min) tick
|
|
11
|
+
* - discover known vaults (project + team + global) by walking known
|
|
12
|
+
* filesystem roots for SCHEMA.md
|
|
13
|
+
* - call `WikiBookkeepService.generate` for each
|
|
14
|
+
* - if `report.shouldFire`, invoke the caller-injected `fireFn` (in
|
|
15
|
+
* production: enqueue a `[BOOKKEEP] vault=…` message to ORC)
|
|
16
|
+
* - debounce per-vault so we don't spam — only refire after
|
|
17
|
+
* `debounceMs` (default 6 h)
|
|
18
|
+
*
|
|
19
|
+
* The service intentionally does NOT do the consolidation itself — it
|
|
20
|
+
* notifies the agent, which then runs `wiki-bookkeep` + `wiki-ingest`
|
|
21
|
+
* (per the orchestrator system prompt rule).
|
|
22
|
+
*
|
|
23
|
+
* @module services/wiki/wiki-bookkeep-trigger.service
|
|
24
|
+
*/
|
|
25
|
+
import * as path from 'path';
|
|
26
|
+
import * as os from 'os';
|
|
27
|
+
import * as fs from 'fs/promises';
|
|
28
|
+
import { existsSync } from 'fs';
|
|
29
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
30
|
+
import { WikiBookkeepService } from './wiki-bookkeep.service.js';
|
|
31
|
+
const DEFAULT_INTERVAL_MS = 30 * 60 * 1000;
|
|
32
|
+
const DEFAULT_DEBOUNCE_MS = 6 * 3600 * 1000;
|
|
33
|
+
/**
|
|
34
|
+
* Discover absolute vault paths by walking the well-known Crewly roots:
|
|
35
|
+
* - `<env CREWLY_PROJECT_VAULT_PATH>` (single explicit override)
|
|
36
|
+
* - `<process.cwd>/.crewly/wiki` (current project vault)
|
|
37
|
+
* - `~/.crewly/teams/<uuid>/wiki` (every team vault)
|
|
38
|
+
* - `~/.crewly/global-wiki` (ORC cross-project vault, if present)
|
|
39
|
+
*
|
|
40
|
+
* A path is only included if `SCHEMA.md` exists inside it.
|
|
41
|
+
*/
|
|
42
|
+
export async function discoverWikiVaults() {
|
|
43
|
+
const found = new Set();
|
|
44
|
+
const candidates = [];
|
|
45
|
+
const fromEnv = process.env['CREWLY_PROJECT_VAULT_PATH'];
|
|
46
|
+
if (fromEnv && path.isAbsolute(fromEnv))
|
|
47
|
+
candidates.push(fromEnv);
|
|
48
|
+
candidates.push(path.join(process.cwd(), '.crewly/wiki'));
|
|
49
|
+
candidates.push(path.join(os.homedir(), '.crewly/global-wiki'));
|
|
50
|
+
const teamsRoot = path.join(os.homedir(), '.crewly/teams');
|
|
51
|
+
if (existsSync(teamsRoot)) {
|
|
52
|
+
try {
|
|
53
|
+
const entries = await fs.readdir(teamsRoot, { withFileTypes: true });
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (!entry.isDirectory())
|
|
56
|
+
continue;
|
|
57
|
+
candidates.push(path.join(teamsRoot, entry.name, 'wiki'));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// ignore — partial discovery is fine
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const candidate of candidates) {
|
|
65
|
+
if (existsSync(path.join(candidate, 'SCHEMA.md'))) {
|
|
66
|
+
found.add(candidate);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return [...found].sort();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Periodic vault-bookkeep trigger. Start at boot, stop at shutdown.
|
|
73
|
+
*/
|
|
74
|
+
export class WikiBookkeepTriggerService {
|
|
75
|
+
static instance = null;
|
|
76
|
+
logger;
|
|
77
|
+
intervalMs;
|
|
78
|
+
debounceMs;
|
|
79
|
+
fireFn;
|
|
80
|
+
discoverRoots;
|
|
81
|
+
bookkeepService;
|
|
82
|
+
timer = null;
|
|
83
|
+
/** vaultPath → last fired timestamp (ms). */
|
|
84
|
+
lastFiredAt = new Map();
|
|
85
|
+
/** Per-vault locks so two overlapping ticks don't double-fire. */
|
|
86
|
+
inflight = new Set();
|
|
87
|
+
constructor(opts) {
|
|
88
|
+
this.logger = LoggerService.getInstance().createComponentLogger('WikiBookkeepTrigger');
|
|
89
|
+
this.intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
90
|
+
this.debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
91
|
+
this.fireFn = opts.fireFn;
|
|
92
|
+
this.discoverRoots = opts.discoverRoots ?? discoverWikiVaults;
|
|
93
|
+
this.bookkeepService = opts.bookkeepService ?? WikiBookkeepService.getInstance();
|
|
94
|
+
}
|
|
95
|
+
static getInstance() {
|
|
96
|
+
return this.instance;
|
|
97
|
+
}
|
|
98
|
+
/** Wire the production singleton. Pass null to detach (tests / shutdown). */
|
|
99
|
+
static setInstance(next) {
|
|
100
|
+
if (this.instance && this.instance !== next)
|
|
101
|
+
this.instance.stop();
|
|
102
|
+
this.instance = next;
|
|
103
|
+
}
|
|
104
|
+
/** Begin scanning. Idempotent. */
|
|
105
|
+
start() {
|
|
106
|
+
if (this.timer)
|
|
107
|
+
return;
|
|
108
|
+
this.timer = setInterval(() => void this.tick(), this.intervalMs);
|
|
109
|
+
// Don't keep the event loop alive just for bookkeeping.
|
|
110
|
+
this.timer.unref?.();
|
|
111
|
+
this.logger.info('WikiBookkeepTrigger started', {
|
|
112
|
+
intervalMs: this.intervalMs,
|
|
113
|
+
debounceMs: this.debounceMs,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Stop scanning. Safe to call multiple times. */
|
|
117
|
+
stop() {
|
|
118
|
+
if (this.timer) {
|
|
119
|
+
clearInterval(this.timer);
|
|
120
|
+
this.timer = null;
|
|
121
|
+
this.logger.info('WikiBookkeepTrigger stopped');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run one scan pass. Public for test + the manual
|
|
126
|
+
* `/api/wiki/bookkeep/trigger-now` endpoint.
|
|
127
|
+
*/
|
|
128
|
+
async tick() {
|
|
129
|
+
const vaults = await this.discoverRoots();
|
|
130
|
+
const result = {
|
|
131
|
+
scanned: [...vaults],
|
|
132
|
+
fired: [],
|
|
133
|
+
skippedByDebounce: [],
|
|
134
|
+
quietVaults: [],
|
|
135
|
+
};
|
|
136
|
+
for (const v of vaults) {
|
|
137
|
+
if (this.inflight.has(v))
|
|
138
|
+
continue;
|
|
139
|
+
this.inflight.add(v);
|
|
140
|
+
try {
|
|
141
|
+
const outcome = await this.bookkeepService.generate({ vaultPath: v });
|
|
142
|
+
if (!outcome.ok) {
|
|
143
|
+
this.logger.warn('WikiBookkeepTrigger: bookkeep failed for vault', {
|
|
144
|
+
vault: v,
|
|
145
|
+
reason: outcome.reason,
|
|
146
|
+
});
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (!outcome.report.shouldFire) {
|
|
150
|
+
result.quietVaults.push(v);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const last = this.lastFiredAt.get(v) ?? 0;
|
|
154
|
+
if (Date.now() - last < this.debounceMs) {
|
|
155
|
+
result.skippedByDebounce.push(v);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this.lastFiredAt.set(v, Date.now());
|
|
159
|
+
try {
|
|
160
|
+
await this.fireFn(v, outcome.report);
|
|
161
|
+
result.fired.push(v);
|
|
162
|
+
this.logger.info('WikiBookkeepTrigger fired', {
|
|
163
|
+
vault: v,
|
|
164
|
+
recentMd: outcome.report.recentMdCount,
|
|
165
|
+
threshold: outcome.report.threshold,
|
|
166
|
+
duplicates: outcome.report.duplicateCandidates.length,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
this.logger.warn('WikiBookkeepTrigger: fireFn threw (swallowed)', {
|
|
171
|
+
vault: v,
|
|
172
|
+
error: err.message,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
this.inflight.delete(v);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
/** Test affordance: clear the debounce ledger. */
|
|
183
|
+
_resetDebounceForTesting() {
|
|
184
|
+
this.lastFiredAt.clear();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=wiki-bookkeep-trigger.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-bookkeep-trigger.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-bookkeep-trigger.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WikiBookkeepService — vault health metrics + consolidation signals.
|
|
3
|
+
*
|
|
4
|
+
* Per Steve's 2026-05-22 design point #5: "还要时不时让 agent 针对自己的
|
|
5
|
+
* vault 进行 bookkeeping (可以根据存入的 md 数量来 trigger), 譬如过去 N
|
|
6
|
+
* 天超过 X 个 md, 然后总结一下."
|
|
7
|
+
*
|
|
8
|
+
* This service produces the report the bookkeeping agent reads:
|
|
9
|
+
* - md count per top-level llm-curated subfolder
|
|
10
|
+
* - new mds in the last N days
|
|
11
|
+
* - filename clusters (likely-duplicates by Jaccard of token sets)
|
|
12
|
+
* - queue stats (so the agent sees pending items too)
|
|
13
|
+
*
|
|
14
|
+
* The agent uses this report (+ its LLM) to decide:
|
|
15
|
+
* - which pages to consolidate / dedupe (calls wiki-ingest with a new
|
|
16
|
+
* consolidated body + deletes the originals via a separate skill —
|
|
17
|
+
* deletion is OUT of scope for Phase 1; surface as proposals).
|
|
18
|
+
* - which topics deserve a summary "rollup" page.
|
|
19
|
+
*
|
|
20
|
+
* The service does NOT delete or rewrite anything. It reports.
|
|
21
|
+
*
|
|
22
|
+
* @module services/wiki/wiki-bookkeep.service
|
|
23
|
+
*/
|
|
24
|
+
import { SchemaLoaderService } from './schema-loader.service.js';
|
|
25
|
+
import { WikiQueueService } from './wiki-queue.service.js';
|
|
26
|
+
export interface WikiBookkeepInput {
|
|
27
|
+
/** Absolute vault path. */
|
|
28
|
+
vaultPath: string;
|
|
29
|
+
/** Window for "recent activity" stats. Default 7 days. */
|
|
30
|
+
windowDays?: number;
|
|
31
|
+
/** Md-count threshold used by `shouldFire` (default 10). */
|
|
32
|
+
threshold?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface WikiPageRef {
|
|
35
|
+
path: string;
|
|
36
|
+
bytes: number;
|
|
37
|
+
modifiedAt: string;
|
|
38
|
+
}
|
|
39
|
+
export interface WikiDuplicateCluster {
|
|
40
|
+
/** Shared base — the longest filename prefix across the cluster. */
|
|
41
|
+
basis: string;
|
|
42
|
+
/** Member pages (relative paths). */
|
|
43
|
+
pages: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface WikiBookkeepReport {
|
|
46
|
+
vault: {
|
|
47
|
+
scope: string;
|
|
48
|
+
id: string;
|
|
49
|
+
path: string;
|
|
50
|
+
};
|
|
51
|
+
generatedAt: string;
|
|
52
|
+
windowDays: number;
|
|
53
|
+
threshold: number;
|
|
54
|
+
/** Did we cross the threshold for "trigger a consolidation pass"? */
|
|
55
|
+
shouldFire: boolean;
|
|
56
|
+
/** Total md files under the vault (recursive). */
|
|
57
|
+
totalMdCount: number;
|
|
58
|
+
/** Newly created/touched mds within `windowDays`. */
|
|
59
|
+
recentMdCount: number;
|
|
60
|
+
/** Per-folder counts under llm-curated/<x>/. */
|
|
61
|
+
countsByFolder: Record<string, number>;
|
|
62
|
+
/** Likely-duplicate clusters by filename Jaccard. */
|
|
63
|
+
duplicateCandidates: WikiDuplicateCluster[];
|
|
64
|
+
/** Mds that haven't been touched in 90 days — stale candidates. */
|
|
65
|
+
staleCount: number;
|
|
66
|
+
/** Queue snapshot for this vault. */
|
|
67
|
+
queue: {
|
|
68
|
+
pending: number;
|
|
69
|
+
claimed: number;
|
|
70
|
+
processed: number;
|
|
71
|
+
skipped: number;
|
|
72
|
+
total: number;
|
|
73
|
+
};
|
|
74
|
+
/** Recommendations the agent's LLM should act on. */
|
|
75
|
+
recommendations: string[];
|
|
76
|
+
}
|
|
77
|
+
export type WikiBookkeepOutcome = {
|
|
78
|
+
ok: true;
|
|
79
|
+
report: WikiBookkeepReport;
|
|
80
|
+
} | {
|
|
81
|
+
ok: false;
|
|
82
|
+
reason: 'invalid_input' | 'schema_missing' | 'vault_missing';
|
|
83
|
+
message: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Vault health + bookkeeping report generator. Stateless; uses the
|
|
87
|
+
* schema loader + queue services it composes.
|
|
88
|
+
*/
|
|
89
|
+
export declare class WikiBookkeepService {
|
|
90
|
+
private static instance;
|
|
91
|
+
private readonly logger;
|
|
92
|
+
private readonly schemaLoader;
|
|
93
|
+
private readonly queue;
|
|
94
|
+
constructor(schemaLoader?: SchemaLoaderService, queue?: WikiQueueService);
|
|
95
|
+
static getInstance(): WikiBookkeepService;
|
|
96
|
+
/** Test-only reset. */
|
|
97
|
+
static _resetForTesting(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Build the bookkeeping report. Caller (skill / cron / agent) decides
|
|
100
|
+
* whether to act on `shouldFire`. The service never writes; it reports.
|
|
101
|
+
*/
|
|
102
|
+
generate(input: WikiBookkeepInput): Promise<WikiBookkeepOutcome>;
|
|
103
|
+
private collectPages;
|
|
104
|
+
/**
|
|
105
|
+
* Find filename clusters by Jaccard over name tokens.
|
|
106
|
+
* Two pages with ≥ 0.6 overlap on their non-trivial filename tokens
|
|
107
|
+
* are flagged as potential duplicates. Token = anything ≥ 3 chars
|
|
108
|
+
* after splitting on `[-_./]`, lowercased, minus date prefix.
|
|
109
|
+
*/
|
|
110
|
+
private findDuplicateClusters;
|
|
111
|
+
private tokenizeFilename;
|
|
112
|
+
private jaccard;
|
|
113
|
+
private longestCommonPrefix;
|
|
114
|
+
private buildRecommendations;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=wiki-bookkeep.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-bookkeep.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-bookkeep.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAM3D,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,UAAU,EAAE,OAAO,CAAC;IACpB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,qDAAqD;IACrD,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IAC5C,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,qDAAqD;IACrD,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GACxC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,GAAG,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;gBAGvC,YAAY,CAAC,EAAE,mBAAmB,EAClC,KAAK,CAAC,EAAE,gBAAgB;IAO1B,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAKzC,uBAAuB;IACvB,MAAM,CAAC,gBAAgB,IAAI,IAAI;IAI/B;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAwGxD,YAAY;IA2C1B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IA6B7B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,oBAAoB;CA8C7B"}
|