crewly 1.11.3 → 1.11.4

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.
Files changed (171) hide show
  1. package/config/skills/agent/core/accept-task/SKILL.md +35 -7
  2. package/config/skills/agent/core/poll-tasks/execute.sh +44 -9
  3. package/config/skills/agent/core/poll-tasks/execute.test.sh +98 -0
  4. package/config/skills/agent/core/record-learning/execute.sh +92 -3
  5. package/config/skills/agent/core/register-self/SKILL.md +51 -8
  6. package/config/skills/agent/transcribe-audio/SKILL.md +110 -0
  7. package/config/skills/agent/transcribe-audio/execute.sh +223 -0
  8. package/config/skills/agent/transcribe-audio/instructions.md +92 -0
  9. package/config/skills/agent/transcribe-audio/skill.json +22 -0
  10. package/config/skills/orchestrator/assign-task/SKILL.md +40 -6
  11. package/config/skills/orchestrator/broadcast/SKILL.md +45 -8
  12. package/dist/backend/backend/src/constants.d.ts +0 -16
  13. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  14. package/dist/backend/backend/src/constants.js +0 -16
  15. package/dist/backend/backend/src/constants.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
  17. package/dist/backend/backend/src/controllers/memory/memory.controller.js +3 -10
  18. package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
  20. package/dist/backend/backend/src/controllers/system/system.controller.js +24 -5
  21. package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
  22. package/dist/backend/backend/src/index.d.ts +2 -0
  23. package/dist/backend/backend/src/index.d.ts.map +1 -1
  24. package/dist/backend/backend/src/index.js +124 -1
  25. package/dist/backend/backend/src/index.js.map +1 -1
  26. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  27. package/dist/backend/backend/src/routes/api.routes.js +0 -3
  28. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  29. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/agent/agent-registration.service.js +56 -20
  31. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  32. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
  33. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
  35. package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
  36. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
  38. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
  39. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  40. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  41. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  42. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  43. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +88 -0
  44. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts.map +1 -0
  45. package/dist/backend/backend/src/services/boot/boot-announce.service.js +119 -0
  46. package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -0
  47. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +14 -0
  49. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  50. package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/mcp-server.js +0 -6
  52. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  53. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  54. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  56. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  57. package/dist/backend/backend/src/services/memory/memory.service.d.ts +78 -41
  58. package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/memory/memory.service.js +209 -127
  60. package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/memory/project-memory.service.js +37 -9
  63. package/dist/backend/backend/src/services/memory/project-memory.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -0
  66. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
  67. package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
  68. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +9 -0
  69. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
  70. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
  71. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
  72. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js +214 -0
  73. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
  74. package/dist/backend/backend/src/services/sop/sop.service.d.ts +70 -2
  75. package/dist/backend/backend/src/services/sop/sop.service.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/sop/sop.service.js +93 -3
  77. package/dist/backend/backend/src/services/sop/sop.service.js.map +1 -1
  78. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts +41 -0
  79. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/task-pool/claim.service.js +72 -0
  81. package/dist/backend/backend/src/services/task-pool/claim.service.js.map +1 -1
  82. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  83. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +20 -0
  85. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  86. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +11 -0
  88. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -1
  89. package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/telegram/telegram.service.js +24 -2
  91. package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -1
  92. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
  93. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +18 -18
  94. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
  95. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +10 -0
  96. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
  97. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +20 -12
  98. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
  99. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
  100. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +12 -3
  101. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
  102. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +15 -5
  103. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +31 -50
  105. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
  106. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +16 -0
  107. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
  108. package/dist/backend/backend/src/services/wiki/wiki-search.service.js +20 -0
  109. package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
  110. package/dist/backend/backend/src/types/settings.types.d.ts +8 -0
  111. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  112. package/dist/backend/backend/src/types/settings.types.js +2 -0
  113. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  114. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
  115. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  116. package/dist/backend/backend/src/types/v2/work-item.types.js +29 -0
  117. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  118. package/dist/cli/backend/src/constants.d.ts +0 -16
  119. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  120. package/dist/cli/backend/src/constants.js +0 -16
  121. package/dist/cli/backend/src/constants.js.map +1 -1
  122. package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
  123. package/dist/cli/backend/src/services/mcp-server.js +0 -6
  124. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  125. package/dist/cli/backend/src/services/memory/memory.service.d.ts +78 -41
  126. package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
  127. package/dist/cli/backend/src/services/memory/memory.service.js +209 -127
  128. package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
  129. package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  130. package/dist/cli/backend/src/services/memory/project-memory.service.js +37 -9
  131. package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -1
  132. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts +41 -0
  133. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  134. package/dist/cli/backend/src/services/task-pool/claim.service.js +72 -0
  135. package/dist/cli/backend/src/services/task-pool/claim.service.js.map +1 -1
  136. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  137. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  138. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +20 -0
  139. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  140. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
  141. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
  142. package/dist/cli/backend/src/services/wiki/schema-loader.service.js +183 -0
  143. package/dist/cli/backend/src/services/wiki/schema-loader.service.js.map +1 -0
  144. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
  145. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
  146. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +212 -0
  147. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
  148. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts +43 -0
  149. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts.map +1 -0
  150. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js +67 -0
  151. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js.map +1 -0
  152. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +166 -0
  153. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -0
  154. package/dist/cli/backend/src/services/wiki/wiki-search.service.js +379 -0
  155. package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -0
  156. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts +84 -0
  157. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
  158. package/dist/cli/backend/src/services/wiki/wiki.types.js +10 -0
  159. package/dist/cli/backend/src/services/wiki/wiki.types.js.map +1 -0
  160. package/dist/cli/backend/src/types/settings.types.d.ts +8 -0
  161. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  162. package/dist/cli/backend/src/types/settings.types.js +2 -0
  163. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  164. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
  165. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  166. package/dist/cli/backend/src/types/v2/work-item.types.js +29 -0
  167. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  168. package/frontend/dist/assets/{index-44266b5d.css → index-8205ea5e.css} +1 -1
  169. package/frontend/dist/assets/{index-4099a91c.js → index-890d3f9d.js} +289 -289
  170. package/frontend/dist/index.html +2 -2
  171. package/package.json +1 -1
@@ -0,0 +1,212 @@
1
+ /**
2
+ * WikiIngestService — write canonical pages into a vault's `llm-curated/`.
3
+ *
4
+ * Phase A scope per v2.1 spec: append entries to `llm-curated/log.md` for
5
+ * every chat/spec/learning source. Decisions/pattern pages (separate files
6
+ * under `llm-curated/decisions/`) are gated behind the LLM routing layer
7
+ * which lands in Phase B.
8
+ *
9
+ * Frozen-path contract (§2): refuses ANY write whose target lives under a
10
+ * `hardcoded:` folder. SchemaLoaderService.isFrozenPath() is the gate.
11
+ *
12
+ * @module services/wiki/wiki-ingest.service
13
+ */
14
+ import * as path from 'path';
15
+ import * as fs from 'fs/promises';
16
+ import { existsSync } from 'fs';
17
+ import { LoggerService } from '../core/logger.service.js';
18
+ import { SchemaLoaderService } from './schema-loader.service.js';
19
+ const DEFAULT_LOG_RELATIVE_PATH = 'llm-curated/log.md';
20
+ const MAX_BODY_BYTES = 64 * 1024;
21
+ // Spec note (Steve, 2026-05-22): the earlier keyword-based
22
+ // `detectMessageShape` heuristic + `buildDecisionSlug` + `ingestDecision`
23
+ // dual-write were REMOVED. Routing into `llm-curated/<folder>/<page>.md`
24
+ // is now agent-driven via `wiki-process-queue` + the agent's own LLM gate
25
+ // — see WikiQueueService for the queue + the orchestrator system prompt
26
+ // for the rule that says "queue worth-saving content as you see it." This
27
+ // service stays low-level: it only writes the path the caller (skill,
28
+ // route, queue processor) specifies, after the frozen-path gate.
29
+ /**
30
+ * Writes ingest pages to a vault. Construct one per process; stateless.
31
+ */
32
+ export class WikiIngestService {
33
+ static instance = null;
34
+ logger;
35
+ schemaLoader;
36
+ constructor(schemaLoader) {
37
+ this.logger = LoggerService.getInstance().createComponentLogger('WikiIngest');
38
+ this.schemaLoader = schemaLoader ?? new SchemaLoaderService();
39
+ }
40
+ static getInstance() {
41
+ if (!this.instance) {
42
+ this.instance = new WikiIngestService();
43
+ }
44
+ return this.instance;
45
+ }
46
+ /** Test-only reset. */
47
+ static _resetForTesting() {
48
+ this.instance = null;
49
+ }
50
+ /**
51
+ * Ingest a single source into the vault.
52
+ *
53
+ * Errors are returned as structured outcomes — this method never throws
54
+ * on legitimate refusals (frozen path, missing schema, empty body) so
55
+ * callers can fold the result into their normal control flow.
56
+ */
57
+ async ingest(input) {
58
+ const validation = this.validateInput(input);
59
+ if (validation) {
60
+ return validation;
61
+ }
62
+ let schema;
63
+ try {
64
+ schema = await this.schemaLoader.load(input.vaultPath);
65
+ }
66
+ catch (err) {
67
+ return {
68
+ ok: false,
69
+ reason: 'schema_missing',
70
+ message: err.message,
71
+ };
72
+ }
73
+ const target = input.targetRelativePath ?? DEFAULT_LOG_RELATIVE_PATH;
74
+ if (this.schemaLoader.isFrozenPath(schema, target)) {
75
+ return {
76
+ ok: false,
77
+ reason: 'frozen_path',
78
+ attemptedPath: target,
79
+ frozenFolders: this.schemaLoader.getFrozenPaths(schema),
80
+ };
81
+ }
82
+ const absoluteTarget = path.join(input.vaultPath, target);
83
+ await fs.mkdir(path.dirname(absoluteTarget), { recursive: true });
84
+ const logEntry = this.formatLogEntry(input);
85
+ await this.appendOrCreate(absoluteTarget, logEntry, input);
86
+ this.logger.info('WikiIngest wrote log entry', {
87
+ vault: input.vaultPath,
88
+ target,
89
+ sourceType: input.sourceType,
90
+ sourceRef: input.sourceRef,
91
+ bodyBytes: input.sourceBody.length,
92
+ });
93
+ return {
94
+ ok: true,
95
+ pagesWritten: [target],
96
+ logEntry,
97
+ frozenPathsTouched: [],
98
+ };
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Internals
102
+ // ---------------------------------------------------------------------------
103
+ validateInput(input) {
104
+ if (!input.vaultPath || !path.isAbsolute(input.vaultPath)) {
105
+ return {
106
+ ok: false,
107
+ reason: 'invalid_input',
108
+ message: `vaultPath must be an absolute path, got "${input.vaultPath ?? ''}"`,
109
+ };
110
+ }
111
+ if (!input.sourceType) {
112
+ return { ok: false, reason: 'invalid_input', message: 'sourceType is required' };
113
+ }
114
+ if (!input.sourceRef) {
115
+ return { ok: false, reason: 'invalid_input', message: 'sourceRef is required' };
116
+ }
117
+ const body = input.sourceBody ?? '';
118
+ if (body.trim().length === 0) {
119
+ return {
120
+ ok: false,
121
+ reason: 'empty_body',
122
+ message: 'sourceBody is empty after trimming whitespace',
123
+ };
124
+ }
125
+ if (Buffer.byteLength(body, 'utf8') > MAX_BODY_BYTES) {
126
+ return {
127
+ ok: false,
128
+ reason: 'invalid_input',
129
+ message: `sourceBody exceeds ${MAX_BODY_BYTES} bytes`,
130
+ };
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * Build the markdown entry. Format is chosen to be safely append-only
136
+ * (no preceding section to rewrite) and grep-friendly:
137
+ *
138
+ * ## [<ISO>] <sourceType> | <callerSession or sourceRef>
139
+ *
140
+ * ref: <sourceRef>
141
+ *
142
+ * <body>
143
+ */
144
+ formatLogEntry(input) {
145
+ const ts = new Date().toISOString();
146
+ const header = this.sanitizeOneLine(input.callerSession ?? input.sourceRef, 80);
147
+ const body = this.sanitizeBody(input.sourceBody);
148
+ const ref = this.sanitizeOneLine(input.sourceRef, 200);
149
+ return [
150
+ '',
151
+ `## [${ts}] ${input.sourceType} | ${header}`,
152
+ '',
153
+ `ref: ${ref}`,
154
+ '',
155
+ body,
156
+ '',
157
+ ].join('\n');
158
+ }
159
+ async appendOrCreate(absolutePath, entry, input) {
160
+ if (!existsSync(absolutePath)) {
161
+ const header = this.buildPageHeader(absolutePath, input);
162
+ await fs.writeFile(absolutePath, header + entry, 'utf8');
163
+ return;
164
+ }
165
+ await fs.appendFile(absolutePath, entry, 'utf8');
166
+ }
167
+ /**
168
+ * Pick the right header for a freshly-created page:
169
+ * - `log.md` → audit-log preamble (append-only)
170
+ * - `decisions/*.md` → decision-page title + provenance block
171
+ * - anything else → minimal title block from the source ref
172
+ */
173
+ buildPageHeader(absolutePath, input) {
174
+ const basename = absolutePath.split(/[/\\]/).pop() ?? '';
175
+ if (basename === 'log.md') {
176
+ return '# Activity log\n\nAppend-only log of ingested sources. Each entry: `## [<ISO>] <sourceType> | <caller>`.\n';
177
+ }
178
+ if (absolutePath.includes('/decisions/')) {
179
+ const title = this.sanitizeOneLine(input.sourceBody, 80);
180
+ const caller = input.callerSession ?? input.sourceRef;
181
+ return [
182
+ `# ${title}`,
183
+ '',
184
+ `> **source:** \`${this.sanitizeOneLine(input.sourceRef, 200)}\` `,
185
+ `> **caller:** \`${this.sanitizeOneLine(caller, 80)}\` `,
186
+ `> **recorded:** ${new Date().toISOString()}`,
187
+ '',
188
+ '---',
189
+ '',
190
+ ].join('\n');
191
+ }
192
+ // Generic non-log target: minimal title block.
193
+ return `# ${this.sanitizeOneLine(input.sourceRef, 80)}\n\n`;
194
+ }
195
+ /**
196
+ * Defuse markers a future skill might mis-route on: `[CHAT]`, `[NOTIFY]`,
197
+ * `[EVENT]`, `[ESCALATION]` get a zero-width space inserted so they're
198
+ * still human-readable but don't trigger regex matchers downstream.
199
+ * (Mirrors the escalation-router sanitizer from PR #606.)
200
+ */
201
+ sanitizeBody(body) {
202
+ const trimmed = body.replace(/\r\n/g, '\n').trim();
203
+ return trimmed.replace(/\[(CHAT|NOTIFY|EVENT|ESCALATION)\]/g, (_match, tag) => `[​${tag}]`);
204
+ }
205
+ sanitizeOneLine(value, maxLen) {
206
+ const flat = value.replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').trim();
207
+ if (flat.length <= maxLen)
208
+ return flat;
209
+ return flat.slice(0, maxLen - 1) + '…';
210
+ }
211
+ }
212
+ //# sourceMappingURL=wiki-ingest.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-ingest.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-ingest.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,aAAa,EAAmB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAuDjE,MAAM,yBAAyB,GAAG,oBAAoB,CAAC;AACvD,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjC,2DAA2D;AAC3D,0EAA0E;AAC1E,yEAAyE;AACzE,0EAA0E;AAC1E,wEAAwE;AACxE,0EAA0E;AAC1E,sEAAsE;AACtE,iEAAiE;AAEjE;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAC,QAAQ,GAA6B,IAAI,CAAC;IACxC,MAAM,CAAkB;IACxB,YAAY,CAAsB;IAEnD,YAAY,YAAkC;QAC5C,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC;QAC9E,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,IAAI,mBAAmB,EAAE,CAAC;IAChE,CAAC;IAED,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAC1C,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,uBAAuB;IACvB,MAAM,CAAC,gBAAgB;QACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,KAAsB;QACjC,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,IAAI,MAAmB,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,gBAAgB;gBACxB,OAAO,EAAG,GAAa,CAAC,OAAO;aAChC,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,kBAAkB,IAAI,yBAAyB,CAAC;QACrE,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YACnD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,aAAa;gBACrB,aAAa,EAAE,MAAM;gBACrB,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC;aACxD,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAElE,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE3D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE;YAC7C,KAAK,EAAE,KAAK,CAAC,SAAS;YACtB,MAAM;YACN,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM;SACnC,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,IAAI;YACR,YAAY,EAAE,CAAC,MAAM,CAAC;YACtB,QAAQ;YACR,kBAAkB,EAAE,EAAE;SACvB,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,YAAY;IACZ,8EAA8E;IAEtE,aAAa,CAAC,KAAsB;QAC1C,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1D,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,eAAe;gBACvB,OAAO,EAAE,4CAA4C,KAAK,CAAC,SAAS,IAAI,EAAE,GAAG;aAC9E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;QACnF,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;QAClF,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,YAAY;gBACpB,OAAO,EAAE,+CAA+C;aACzD,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,cAAc,EAAE,CAAC;YACrD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,eAAe;gBACvB,OAAO,EAAE,sBAAsB,cAAc,QAAQ;aACtD,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;OASG;IACK,cAAc,CAAC,KAAsB;QAC3C,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAChF,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO;YACL,EAAE;YACF,OAAO,EAAE,KAAK,KAAK,CAAC,UAAU,MAAM,MAAM,EAAE;YAC5C,EAAE;YACF,QAAQ,GAAG,EAAE;YACb,EAAE;YACF,IAAI;YACJ,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,YAAoB,EACpB,KAAa,EACb,KAAsB;QAEtB,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QACD,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED;;;;;OAKG;IACK,eAAe,CAAC,YAAoB,EAAE,KAAsB;QAClE,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACzD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,4GAA4G,CAAC;QACtH,CAAC;QACD,IAAI,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS,CAAC;YACtD,OAAO;gBACL,KAAK,KAAK,EAAE;gBACZ,EAAE;gBACF,mBAAmB,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM;gBACnE,mBAAmB,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;gBACzD,mBAAmB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;gBAC7C,EAAE;gBACF,KAAK;gBACL,EAAE;aACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;QACD,+CAA+C;QAC/C,OAAO,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC;IAC9D,CAAC;IAED;;;;;OAKG;IACK,YAAY,CAAC,IAAY;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,OAAO,CACpB,qCAAqC,EACrC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,GAAG,CAC7B,CAAC;IACJ,CAAC;IAEO,eAAe,CAAC,KAAa,EAAE,MAAc;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACxE,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACzC,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Wiki canonical-folder overlay resolver.
3
+ *
4
+ * Some schema-frozen folders in a team vault (`sop/`, `team-norm/`) are
5
+ * reserved canonical homes whose content actually lives elsewhere on disk and
6
+ * is read directly by the engine — they were never wired to receive wiki
7
+ * writes, so they always render empty. Rather than copy/migrate that content
8
+ * (which would drift), the wiki tree + page endpoints read THROUGH to the real
9
+ * source so the folders always reflect live content.
10
+ *
11
+ * Overlay sources (both PER-TEAM siblings of the vault, so the wiki shows only
12
+ * what the team actually owns — config/sops/ is a catalog you install FROM,
13
+ * never shown directly in a team folder):
14
+ * - `sop/` → `<vault>/../sops/` (SOPs the team has installed from the catalog)
15
+ * - `team-norm/` → `<vault>/../norms/` (per-team norms written by update-team-norm)
16
+ *
17
+ * @module services/wiki/wiki-overlay.resolver
18
+ */
19
+ /** Top-level vault folders that read through to a live external source. */
20
+ export type OverlayFolder = 'sop' | 'team-norm';
21
+ /**
22
+ * Return the real on-disk directory backing a top-level canonical folder, or
23
+ * null when the folder is not overlayed (the vault's own directory is used).
24
+ * Both overlay folders resolve to a per-team sibling of the vault.
25
+ *
26
+ * @param vaultPath - Absolute path to the vault root (e.g. `.../teams/<id>/wiki`).
27
+ * @param topFolder - The top-level folder name (e.g. `sop`, `team-norm`, `llm-curated`).
28
+ * @returns Absolute source directory for read-through, or null.
29
+ */
30
+ export declare function overlayRootFor(vaultPath: string, topFolder: string): string | null;
31
+ /**
32
+ * Resolve the absolute file path to read for an overlayed page request, with a
33
+ * traversal guard against escaping the overlay source root. Returns null when
34
+ * the relativePath is not under an overlay folder; callers then fall back to
35
+ * the normal in-vault resolution.
36
+ *
37
+ * @param vaultPath - Absolute path to the vault root.
38
+ * @param relativePath - Vault-relative page path, e.g. `sop/pm/progress-tracking.md`.
39
+ * @returns Absolute real file path, or null if not overlayed.
40
+ * @throws Error tagged `overlay_escape` when the path would escape the source root.
41
+ */
42
+ export declare function resolveOverlayFilePath(vaultPath: string, relativePath: string): string | null;
43
+ //# sourceMappingURL=wiki-overlay.resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-overlay.resolver.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-overlay.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,WAAW,CAAC;AAIhD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,IAAI,CAgBf"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Wiki canonical-folder overlay resolver.
3
+ *
4
+ * Some schema-frozen folders in a team vault (`sop/`, `team-norm/`) are
5
+ * reserved canonical homes whose content actually lives elsewhere on disk and
6
+ * is read directly by the engine — they were never wired to receive wiki
7
+ * writes, so they always render empty. Rather than copy/migrate that content
8
+ * (which would drift), the wiki tree + page endpoints read THROUGH to the real
9
+ * source so the folders always reflect live content.
10
+ *
11
+ * Overlay sources (both PER-TEAM siblings of the vault, so the wiki shows only
12
+ * what the team actually owns — config/sops/ is a catalog you install FROM,
13
+ * never shown directly in a team folder):
14
+ * - `sop/` → `<vault>/../sops/` (SOPs the team has installed from the catalog)
15
+ * - `team-norm/` → `<vault>/../norms/` (per-team norms written by update-team-norm)
16
+ *
17
+ * @module services/wiki/wiki-overlay.resolver
18
+ */
19
+ import * as path from 'path';
20
+ const OVERLAY_FOLDERS = new Set(['sop', 'team-norm']);
21
+ /**
22
+ * Return the real on-disk directory backing a top-level canonical folder, or
23
+ * null when the folder is not overlayed (the vault's own directory is used).
24
+ * Both overlay folders resolve to a per-team sibling of the vault.
25
+ *
26
+ * @param vaultPath - Absolute path to the vault root (e.g. `.../teams/<id>/wiki`).
27
+ * @param topFolder - The top-level folder name (e.g. `sop`, `team-norm`, `llm-curated`).
28
+ * @returns Absolute source directory for read-through, or null.
29
+ */
30
+ export function overlayRootFor(vaultPath, topFolder) {
31
+ if (!OVERLAY_FOLDERS.has(topFolder))
32
+ return null;
33
+ // sop → installed SOPs sibling dir; team-norm → norms sibling dir.
34
+ const sibling = topFolder === 'sop' ? 'sops' : 'norms';
35
+ return path.resolve(vaultPath, '..', sibling);
36
+ }
37
+ /**
38
+ * Resolve the absolute file path to read for an overlayed page request, with a
39
+ * traversal guard against escaping the overlay source root. Returns null when
40
+ * the relativePath is not under an overlay folder; callers then fall back to
41
+ * the normal in-vault resolution.
42
+ *
43
+ * @param vaultPath - Absolute path to the vault root.
44
+ * @param relativePath - Vault-relative page path, e.g. `sop/pm/progress-tracking.md`.
45
+ * @returns Absolute real file path, or null if not overlayed.
46
+ * @throws Error tagged `overlay_escape` when the path would escape the source root.
47
+ */
48
+ export function resolveOverlayFilePath(vaultPath, relativePath) {
49
+ const normalized = relativePath.replace(/\\/g, '/').replace(/^\/+/, '');
50
+ const slash = normalized.indexOf('/');
51
+ if (slash <= 0)
52
+ return null;
53
+ const topFolder = normalized.slice(0, slash);
54
+ const root = overlayRootFor(vaultPath, topFolder);
55
+ if (!root)
56
+ return null;
57
+ const subPath = normalized.slice(slash + 1);
58
+ const resolved = path.resolve(root, subPath);
59
+ const rootResolved = path.resolve(root);
60
+ if (resolved !== rootResolved && !resolved.startsWith(rootResolved + path.sep)) {
61
+ const err = new Error('overlay path escapes source root');
62
+ err.name = 'overlay_escape';
63
+ throw err;
64
+ }
65
+ return resolved;
66
+ }
67
+ //# sourceMappingURL=wiki-overlay.resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-overlay.resolver.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-overlay.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAK7B,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;AAE1F;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,SAAiB;IACjE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,mEAAmE;IACnE,MAAM,OAAO,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACvD,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAAiB,EACjB,YAAoB;IAEpB,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,QAAQ,KAAK,YAAY,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/E,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1D,GAAG,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC5B,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Wiki Search Service
3
+ *
4
+ * In-process full-text search across a wiki vault's `.md` files. Returns
5
+ * per-file matches with line numbers + short snippets so the UI can render
6
+ * a result list and let the user jump straight to a page.
7
+ *
8
+ * Ranking: Okapi **BM25** (term-frequency saturation via `k1`, length
9
+ * normalisation via `b`, inverse-document-frequency weighting) computed
10
+ * per request. No external index — the vaults here are O(100s) of pages so
11
+ * a per-request scan + score is fine; revisit with a persisted index when
12
+ * volumes justify it. Tokenisation is Unicode-aware: Latin word tokens plus
13
+ * individual CJK characters, so Chinese/Japanese content is searchable.
14
+ *
15
+ * Scope: walks the vault directory AND the per-team overlay sources
16
+ * (`sop/` → installed/custom SOPs, `team-norm/` → team norms) so SOP and
17
+ * norm content is searchable even though it lives outside the vault.
18
+ *
19
+ * @module services/wiki/wiki-search.service
20
+ */
21
+ /** Cap on how many .md files are inspected per search. */
22
+ export declare const WIKI_SEARCH_MAX_FILES = 500;
23
+ /** Cap on how many results returned to the caller. */
24
+ export declare const WIKI_SEARCH_MAX_RESULTS = 50;
25
+ /** Cap on how many snippets surfaced per matching file. */
26
+ export declare const WIKI_SEARCH_MAX_SNIPPETS_PER_FILE = 3;
27
+ /** Maximum query length — guards against pathological input. */
28
+ export declare const WIKI_SEARCH_MAX_QUERY_LENGTH = 200;
29
+ /** Cap on per-file size we will read; larger files are skipped. */
30
+ export declare const WIKI_SEARCH_MAX_FILE_BYTES: number;
31
+ export interface WikiSearchSnippet {
32
+ /** 1-based line number where the match was found. */
33
+ lineNumber: number;
34
+ /** The matching line (trimmed for display). */
35
+ text: string;
36
+ }
37
+ export interface WikiSearchHit {
38
+ /** Relative path inside the vault, with forward slashes. */
39
+ relativePath: string;
40
+ /** True when the filename itself contains the query. */
41
+ filenameMatch: boolean;
42
+ /** Number of total content matches across the file. */
43
+ matchCount: number;
44
+ /** BM25 relevance score (higher = better). */
45
+ score: number;
46
+ /** Up to `WIKI_SEARCH_MAX_SNIPPETS_PER_FILE` matching lines. */
47
+ snippets: WikiSearchSnippet[];
48
+ /** Owning vault path (set for all-vault search; absent for single-vault). */
49
+ vaultPath?: string;
50
+ /** Human label for the owning vault (all-vault search only). */
51
+ vaultLabel?: string;
52
+ }
53
+ export interface WikiSearchResult {
54
+ ok: true;
55
+ /** Searched vault path, or '' for an all-vault search. */
56
+ vaultPath: string;
57
+ query: string;
58
+ hits: WikiSearchHit[];
59
+ /** True when the file/result cap was hit; UI should hint "narrow your search". */
60
+ truncated: boolean;
61
+ }
62
+ export interface WikiSearchFailure {
63
+ ok: false;
64
+ reason: 'vault_missing' | 'invalid_input' | 'invalid_query';
65
+ message: string;
66
+ }
67
+ export interface WikiSearchInput {
68
+ vaultPath: string;
69
+ query: string;
70
+ }
71
+ /** A vault to include in an all-vault search. */
72
+ export interface VaultRef {
73
+ vaultPath: string;
74
+ label?: string;
75
+ }
76
+ export interface WikiMultiSearchInput {
77
+ vaults: VaultRef[];
78
+ query: string;
79
+ }
80
+ /**
81
+ * Tokenise text into searchable terms: lowercase Latin word runs
82
+ * (`[a-z0-9]+`) plus individual CJK characters (Han, Hiragana, Katakana),
83
+ * so both English and Chinese/Japanese content is matched.
84
+ *
85
+ * @param text - Raw text to tokenise.
86
+ * @returns Array of lowercase tokens (order preserved, duplicates kept).
87
+ */
88
+ export declare function tokenize(text: string): string[];
89
+ /**
90
+ * Service exposing `search()`. Stateless singleton — matches the pattern of
91
+ * the other wiki services (`WikiBookkeepService.getInstance()`, etc.).
92
+ */
93
+ export declare class WikiSearchService {
94
+ private static instance;
95
+ /** Singleton accessor. */
96
+ static getInstance(): WikiSearchService;
97
+ /** Reset for tests. */
98
+ static resetInstance(): void;
99
+ /** Validate + normalise a query, or return a structured failure. */
100
+ private validateQuery;
101
+ /**
102
+ * Search a single vault and rank results with BM25. Returns either
103
+ * `{ok:true, hits}` or a structured failure. Filesystem read errors are
104
+ * silently skipped so one bad file doesn't blank the whole result.
105
+ */
106
+ search(input: WikiSearchInput): Promise<WikiSearchResult | WikiSearchFailure>;
107
+ /**
108
+ * Search across MANY vaults and return one merged BM25-ranked list. IDF is
109
+ * computed over the combined corpus so scores are comparable across vaults.
110
+ * Each hit carries its owning `vaultPath` (+ `vaultLabel` when provided).
111
+ */
112
+ searchAllVaults(input: WikiMultiSearchInput): Promise<WikiSearchResult | WikiSearchFailure>;
113
+ /**
114
+ * BM25-rank an explicit list of documents (rather than auto-collecting the
115
+ * whole vault). Lets callers that need their own eligibility rules — e.g. the
116
+ * `wiki-query` skill, which ranks only `llm-curated/` pages and skips
117
+ * `log.md` — reuse the exact same Okapi BM25 scoring with IDF computed over
118
+ * precisely the documents they supply.
119
+ *
120
+ * @param vaultPath - Owning vault (stamped on each hit's `vaultPath`).
121
+ * @param docs - Candidate documents as `{ relativePath, absPath }`.
122
+ * @param query - Raw query string (validated/normalised here).
123
+ * @returns BM25-ranked hits, or an empty array for an invalid/empty query.
124
+ */
125
+ searchCorpus(vaultPath: string, docs: Array<{
126
+ relativePath: string;
127
+ absPath: string;
128
+ }>, query: string): Promise<WikiSearchHit[]>;
129
+ /**
130
+ * Core BM25 search over an arbitrary corpus of doc refs (one or many vaults).
131
+ * Builds the combined corpus statistics, scores, ranks, and attaches snippets
132
+ * for the top results. Each hit carries its owning `vaultPath`.
133
+ */
134
+ private _searchCorpus;
135
+ /**
136
+ * Collect candidate `.md` documents: the vault tree plus the per-team
137
+ * overlay sources (`sop/`, `team-norm/`). Overlay paths are prefixed with
138
+ * the folder name so they resolve back through the page endpoint.
139
+ *
140
+ * @param vaultPath - Absolute vault root.
141
+ * @returns Deduped list of `{ relativePath, absPath }`, capped at the limit.
142
+ */
143
+ private collectDocs;
144
+ /**
145
+ * Recursively collect `.md` files under `root`, returned as root-relative
146
+ * POSIX paths. Skips dotfile dirs (`.git`, `.queue`) and stops at the cap.
147
+ */
148
+ private walkMd;
149
+ /**
150
+ * Read a doc and compute its length + per-query-term frequencies. Filename
151
+ * tokens are folded in (weighted) so title relevance contributes to BM25.
152
+ * Returns null only on unreadable/oversize files with no filename match.
153
+ */
154
+ private statDoc;
155
+ /**
156
+ * Standard Okapi BM25 score for a doc against the query terms.
157
+ */
158
+ private bm25Score;
159
+ /**
160
+ * Re-read a top-ranked file and extract matching-line snippets (a line
161
+ * matches when it contains any query term as a substring). Returns the
162
+ * total content match count + up to the snippet cap.
163
+ */
164
+ private buildSnippets;
165
+ }
166
+ //# sourceMappingURL=wiki-search.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-search.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-search.service.ts"],"names":[],"mappings":"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"}