pi-harness-runtime 1.1.324 → 1.1.326

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 (125) hide show
  1. package/package.json +1 -1
  2. package/packages/a2a-adapter/package.json +1 -1
  3. package/packages/agent-policy/dist/policy-loader.d.ts +8 -1
  4. package/packages/agent-policy/dist/policy-loader.d.ts.map +1 -1
  5. package/packages/agent-policy/dist/policy-loader.js +23 -5
  6. package/packages/agent-policy/dist/policy-loader.js.map +1 -1
  7. package/packages/agent-policy/package.json +1 -1
  8. package/packages/agent-policy/src/policy-loader.ts +28 -7
  9. package/packages/agent-policy/test/policy-retention.test.ts +43 -1
  10. package/packages/agent-policy/test/policy.test.ts +7 -3
  11. package/packages/architecture-generator/package.json +1 -1
  12. package/packages/auth/package.json +1 -1
  13. package/packages/autonomous-refactor/package.json +1 -1
  14. package/packages/autonomous-runtime/package.json +1 -1
  15. package/packages/cache-strategy/package.json +1 -1
  16. package/packages/capability-registry/package.json +1 -1
  17. package/packages/checkpoint/package.json +1 -1
  18. package/packages/cli-plugin-sdk/package.json +1 -1
  19. package/packages/clipboard/package.json +1 -1
  20. package/packages/clipboard-plugin/package.json +1 -1
  21. package/packages/code-generation/package.json +1 -1
  22. package/packages/code-review/package.json +1 -1
  23. package/packages/codex-adapter/package.json +1 -1
  24. package/packages/codex-watcher/package.json +1 -1
  25. package/packages/config-capture/package.json +1 -1
  26. package/packages/context-compiler/package.json +1 -1
  27. package/packages/context-discovery/package.json +1 -1
  28. package/packages/context-manager/package.json +1 -1
  29. package/packages/cookie-sanitizer/package.json +1 -1
  30. package/packages/cost-optimizer/package.json +1 -1
  31. package/packages/dependency-analyzer/package.json +1 -1
  32. package/packages/django-plugin/package.json +1 -1
  33. package/packages/doc-generator/package.json +1 -1
  34. package/packages/durable-review/package.json +1 -1
  35. package/packages/e2e-tester/package.json +1 -1
  36. package/packages/evaluation-engine/package.json +1 -1
  37. package/packages/evaluation-runner/package.json +1 -1
  38. package/packages/event-bus/package.json +1 -1
  39. package/packages/event-store/package.json +1 -1
  40. package/packages/experience-replay/package.json +1 -1
  41. package/packages/feedback-collector/package.json +1 -1
  42. package/packages/file-copy-helper/package.json +1 -1
  43. package/packages/framework-detector/package.json +1 -1
  44. package/packages/framework-plugin-sdk/package.json +1 -1
  45. package/packages/frappe-plugin/package.json +1 -1
  46. package/packages/generic-web-plugin/package.json +1 -1
  47. package/packages/health-monitor/package.json +1 -1
  48. package/packages/intent-analyzer/package.json +1 -1
  49. package/packages/jev-judge/package.json +1 -1
  50. package/packages/knowledge-graph/package.json +1 -1
  51. package/packages/knowledge-retrieval/package.json +1 -1
  52. package/packages/laravel-plugin/package.json +1 -1
  53. package/packages/learning-engine/package.json +1 -1
  54. package/packages/mcp-adapter/package.json +1 -1
  55. package/packages/memory-engine/package.json +1 -1
  56. package/packages/milestone-manager/package.json +1 -1
  57. package/packages/model-registry/package.json +1 -1
  58. package/packages/nextjs-plugin/package.json +1 -1
  59. package/packages/notification/package.json +1 -1
  60. package/packages/observability/package.json +1 -1
  61. package/packages/okf-indexer/package.json +1 -1
  62. package/packages/paperclip-integration/package.json +1 -1
  63. package/packages/performance-optimizer/package.json +1 -1
  64. package/packages/privilege-broker/package.json +1 -1
  65. package/packages/project-analyzer/package.json +1 -1
  66. package/packages/project-bootstrap/package.json +1 -1
  67. package/packages/projection-engine/package.json +1 -1
  68. package/packages/prompt-compiler/package.json +1 -1
  69. package/packages/prompt-versioning/package.json +1 -1
  70. package/packages/provider-adapter-sdk/package.json +1 -1
  71. package/packages/provider-router/package.json +1 -1
  72. package/packages/provider-selector/package.json +1 -1
  73. package/packages/providers/package.json +1 -1
  74. package/packages/qdrant-skills/package.json +1 -1
  75. package/packages/quota-manager/package.json +1 -1
  76. package/packages/rate-limiter/package.json +1 -1
  77. package/packages/react-vite-plugin/package.json +1 -1
  78. package/packages/release-manager/package.json +1 -1
  79. package/packages/requirement-compiler/package.json +1 -1
  80. package/packages/runtime/package.json +1 -1
  81. package/packages/scheduler/package.json +1 -1
  82. package/packages/scheduler-adapter/package.json +1 -1
  83. package/packages/session/package.json +1 -1
  84. package/packages/session-api/package.json +1 -1
  85. package/packages/session-export/package.json +1 -1
  86. package/packages/shared-context/package.json +1 -1
  87. package/packages/skill-mcp-client/package.json +1 -1
  88. package/packages/skill-registry/package.json +1 -1
  89. package/packages/skills/package.json +1 -1
  90. package/packages/sprint-planner/package.json +1 -1
  91. package/packages/subscription-engine/package.json +1 -1
  92. package/packages/task-compiler/package.json +1 -1
  93. package/packages/telegram/package.json +1 -1
  94. package/packages/tencentdb-memory/package.json +1 -1
  95. package/packages/tencentdb-sync/package.json +1 -1
  96. package/packages/test-data-generator/package.json +1 -1
  97. package/packages/test-generator/package.json +1 -1
  98. package/packages/todo-bd-sync/package.json +1 -1
  99. package/packages/token-estimation/package.json +1 -1
  100. package/packages/token-optimizer/package.json +1 -1
  101. package/packages/trajectory/package.json +1 -1
  102. package/packages/tui/package.json +1 -1
  103. package/packages/types/package.json +1 -1
  104. package/packages/webmcp-tester/package.json +1 -1
  105. package/packages/wiki/dist/index.d.ts +132 -0
  106. package/packages/wiki/dist/index.d.ts.map +1 -0
  107. package/packages/wiki/dist/index.js +448 -0
  108. package/packages/wiki/dist/index.js.map +1 -0
  109. package/packages/wiki/dist/storage.d.ts +142 -0
  110. package/packages/wiki/dist/storage.d.ts.map +1 -0
  111. package/packages/wiki/dist/storage.js +603 -0
  112. package/packages/wiki/dist/storage.js.map +1 -0
  113. package/packages/wiki/dist/types.d.ts +189 -0
  114. package/packages/wiki/dist/types.d.ts.map +1 -0
  115. package/packages/wiki/dist/types.js +30 -0
  116. package/packages/wiki/dist/types.js.map +1 -0
  117. package/packages/wiki/package.json +22 -0
  118. package/packages/wiki/src/index.ts +578 -0
  119. package/packages/wiki/src/storage.ts +696 -0
  120. package/packages/wiki/src/types.ts +263 -0
  121. package/packages/wiki/test/basic.test.ts +242 -0
  122. package/packages/workflow-events/package.json +1 -1
  123. package/packages/workspace-scanner/package.json +1 -1
  124. package/packages/worktree/package.json +1 -1
  125. package/packages/write-review/package.json +1 -1
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Wiki Package - Main API
3
+ *
4
+ * Implements LLM Wiki integration per wiki/llm-wiki-integration-minimax-plan.md
5
+ */
6
+
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { join, resolve, relative } from "node:path";
9
+ import { randomUUID } from "node:crypto";
10
+ import {
11
+ WikiStorage,
12
+ createWikiStorage,
13
+ computeHash,
14
+ now,
15
+ parseFrontmatter,
16
+ combinePage,
17
+ } from "./storage.js";
18
+ import type {
19
+ WikiConfig,
20
+ WikiPage,
21
+ WikiPageFrontmatter,
22
+ SourceSnapshot,
23
+ WikiOperation,
24
+ WikiSearchFilters,
25
+ WikiSearchResult,
26
+ LintFinding,
27
+ StagedChange,
28
+ WikiInitResult,
29
+ PageStatus,
30
+ PageKind,
31
+ } from "./types.js";
32
+ import { toSourceRef } from "./types.js";
33
+
34
+ // ============================================================================
35
+ // Feature Flag
36
+ // ============================================================================
37
+
38
+ /**
39
+ * Check if wiki feature is enabled
40
+ */
41
+ export function isWikiEnabled(): boolean {
42
+ return process.env.HARNESS_KNOWLEDGE_WIKI === "1";
43
+ }
44
+
45
+ /**
46
+ * Require wiki to be enabled
47
+ */
48
+ function requireWiki(): void {
49
+ if (!isWikiEnabled()) {
50
+ throw new Error("Wiki feature is disabled. Set HARNESS_KNOWLEDGE_WIKI=1 to enable.");
51
+ }
52
+ }
53
+
54
+ // ============================================================================
55
+ // Wiki Manager
56
+ // ============================================================================
57
+
58
+ /**
59
+ * Wiki manager - main API for wiki operations
60
+ */
61
+ export class WikiManager {
62
+ private storage: WikiStorage;
63
+ private config: WikiConfig;
64
+
65
+ constructor(storage: WikiStorage) {
66
+ this.storage = storage;
67
+ this.config = storage.getConfig();
68
+ }
69
+
70
+ /**
71
+ * Get wiki configuration
72
+ */
73
+ getConfig(): WikiConfig {
74
+ return this.config;
75
+ }
76
+
77
+ // ========================================================================
78
+ // Initialization
79
+ // ========================================================================
80
+
81
+ /**
82
+ * Initialize wiki structure
83
+ */
84
+ initialize(): WikiInitResult {
85
+ requireWiki();
86
+ return this.storage.initialize();
87
+ }
88
+
89
+ /**
90
+ * Check if wiki is initialized
91
+ */
92
+ isInitialized(): boolean {
93
+ return existsSync(this.config.knowledgeDir);
94
+ }
95
+
96
+ // ========================================================================
97
+ // Source Ingestion
98
+ // ========================================================================
99
+
100
+ /**
101
+ * Ingest a source file and create snapshot
102
+ */
103
+ ingestSource(
104
+ sourcePath: string,
105
+ requestId?: string
106
+ ): { snapshot: SourceSnapshot; operation: WikiOperation } {
107
+ requireWiki();
108
+
109
+ // Validate source path
110
+ const resolvedPath = resolve(sourcePath);
111
+ if (!existsSync(resolvedPath)) {
112
+ throw new Error(`Source file not found: ${sourcePath}`);
113
+ }
114
+
115
+ // Read content
116
+ const content = readFileSync(resolvedPath, "utf8");
117
+
118
+ // Log operation
119
+ const operation = this.storage.logOperation("ingest", { sourcePath }, requestId);
120
+
121
+ try {
122
+ // Create snapshot
123
+ const snapshot = this.storage.createSnapshot(resolvedPath, content, operation.id);
124
+
125
+ // Complete operation
126
+ this.storage.completeOperation(operation.id, "success");
127
+
128
+ return { snapshot, operation };
129
+ } catch (err) {
130
+ const error = err instanceof Error ? err.message : String(err);
131
+ this.storage.completeOperation(operation.id, "failed", error);
132
+ throw err;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Get source snapshot
138
+ */
139
+ getSnapshot(snapshotId: string): SourceSnapshot | null {
140
+ requireWiki();
141
+ return this.storage.getSnapshot(snapshotId);
142
+ }
143
+
144
+ // ========================================================================
145
+ // Page Operations
146
+ // ========================================================================
147
+
148
+ /**
149
+ * Create a new wiki page
150
+ */
151
+ createPage(params: {
152
+ title: string;
153
+ kind: PageKind;
154
+ body: string;
155
+ sources?: SourceSnapshot[];
156
+ relatedPages?: string[];
157
+ codeVersion?: string;
158
+ }): WikiPage {
159
+ requireWiki();
160
+
161
+ const id = `page-${randomUUID().slice(0, 8)}`;
162
+ const timestamp = now();
163
+
164
+ const frontmatter: WikiPageFrontmatter = {
165
+ id,
166
+ title: params.title,
167
+ kind: params.kind,
168
+ projectId: this.config.projectId,
169
+ status: "proposed",
170
+ createdAt: timestamp,
171
+ updatedAt: timestamp,
172
+ sources: (params.sources ?? []).map(toSourceRef),
173
+ relatedPages: params.relatedPages ?? [],
174
+ codeVersion: params.codeVersion,
175
+ };
176
+
177
+ const page: WikiPage = {
178
+ frontmatter,
179
+ body: params.body,
180
+ rawFrontmatter: "",
181
+ };
182
+
183
+ this.storage.savePage(page);
184
+ return page;
185
+ }
186
+
187
+ /**
188
+ * Update an existing page
189
+ */
190
+ updatePage(
191
+ pageId: string,
192
+ updates: Partial<{
193
+ title: string;
194
+ status: PageStatus;
195
+ body: string;
196
+ sources: SourceSnapshot[];
197
+ relatedPages: string[];
198
+ codeVersion: string;
199
+ verification: WikiPageFrontmatter["verification"];
200
+ }>
201
+ ): WikiPage {
202
+ requireWiki();
203
+
204
+ const existing = this.storage.loadPage(pageId);
205
+ if (!existing) {
206
+ throw new Error(`Page not found: ${pageId}`);
207
+ }
208
+
209
+ const updatedFrontmatter: WikiPageFrontmatter = {
210
+ ...existing.frontmatter,
211
+ ...updates,
212
+ sources: updates.sources ? updates.sources.map(toSourceRef) : existing.frontmatter.sources,
213
+ updatedAt: now(),
214
+ };
215
+
216
+ const page: WikiPage = {
217
+ frontmatter: updatedFrontmatter,
218
+ body: updates.body ?? existing.body,
219
+ rawFrontmatter: existing.rawFrontmatter,
220
+ };
221
+
222
+ this.storage.savePage(page);
223
+ return page;
224
+ }
225
+
226
+ /**
227
+ * Load a wiki page
228
+ */
229
+ loadPage(pageId: string): WikiPage | null {
230
+ requireWiki();
231
+ return this.storage.loadPage(pageId);
232
+ }
233
+
234
+ /**
235
+ * Delete a wiki page
236
+ */
237
+ deletePage(pageId: string): void {
238
+ requireWiki();
239
+ this.storage.deletePage(pageId);
240
+ }
241
+
242
+ /**
243
+ * Get all pages
244
+ */
245
+ getAllPages(): WikiPage[] {
246
+ requireWiki();
247
+ return this.storage.getAllPages();
248
+ }
249
+
250
+ // ========================================================================
251
+ // Search
252
+ // ========================================================================
253
+
254
+ /**
255
+ * Search wiki pages
256
+ */
257
+ search(query: string, filters?: WikiSearchFilters, limit = 10): WikiSearchResult[] {
258
+ requireWiki();
259
+ return this.storage.search(query, filters, limit);
260
+ }
261
+
262
+ /**
263
+ * Get page index
264
+ */
265
+ getIndex() {
266
+ requireWiki();
267
+ return this.storage.getIndex();
268
+ }
269
+
270
+ // ========================================================================
271
+ // Staged Changes
272
+ // ========================================================================
273
+
274
+ /**
275
+ * Stage a change for later application
276
+ */
277
+ stageChange(pageId: string, expectedRevision: string, newContent: string): StagedChange {
278
+ requireWiki();
279
+
280
+ const existing = this.storage.loadPage(pageId);
281
+ if (!existing) {
282
+ throw new Error(`Page not found: ${pageId}`);
283
+ }
284
+
285
+ const change: StagedChange = {
286
+ pageId,
287
+ expectedRevision,
288
+ newContent,
289
+ operationId: "",
290
+ };
291
+
292
+ this.storage.stageChange(change);
293
+ return change;
294
+ }
295
+
296
+ /**
297
+ * Get staged change for a page
298
+ */
299
+ getStagedChange(pageId: string): StagedChange | undefined {
300
+ requireWiki();
301
+ return this.storage.getStagedChange(pageId);
302
+ }
303
+
304
+ /**
305
+ * Clear staged change
306
+ */
307
+ clearStagedChange(pageId: string): void {
308
+ requireWiki();
309
+ this.storage.clearStagedChange(pageId);
310
+ }
311
+
312
+ // ========================================================================
313
+ // Apply Changes
314
+ // ========================================================================
315
+
316
+ /**
317
+ * Apply staged change with conflict detection
318
+ */
319
+ applyChange(pageId: string, requestId?: string): WikiPage {
320
+ requireWiki();
321
+
322
+ const staged = this.storage.getStagedChange(pageId);
323
+ if (!staged) {
324
+ throw new Error(`No staged change for page: ${pageId}`);
325
+ }
326
+
327
+ const existing = this.storage.loadPage(pageId);
328
+ if (!existing) {
329
+ throw new Error(`Page not found: ${pageId}`);
330
+ }
331
+
332
+ // Check for conflicts
333
+ const currentRevision = computeHash(existing.rawFrontmatter || "");
334
+ if (staged.expectedRevision !== currentRevision) {
335
+ throw new Error(
336
+ `Conflict: page was modified. Expected revision ${staged.expectedRevision}, found ${currentRevision}`
337
+ );
338
+ }
339
+
340
+ // Parse new content
341
+ const parsed = parseFrontmatter(staged.newContent);
342
+ if (!parsed.frontmatter) {
343
+ throw new Error("Invalid page content: missing frontmatter");
344
+ }
345
+
346
+ // Create updated page
347
+ const page: WikiPage = {
348
+ frontmatter: {
349
+ ...parsed.frontmatter,
350
+ id: pageId,
351
+ updatedAt: now(),
352
+ } as WikiPageFrontmatter,
353
+ body: parsed.body,
354
+ rawFrontmatter: parsed.raw,
355
+ };
356
+
357
+ this.storage.savePage(page);
358
+ this.storage.clearStagedChange(pageId);
359
+
360
+ return page;
361
+ }
362
+
363
+ // ========================================================================
364
+ // Lint
365
+ // ========================================================================
366
+
367
+ /**
368
+ * Run lint checks on wiki
369
+ */
370
+ lint(scope?: "all" | "pages" | "links" | "freshness"): LintFinding[] {
371
+ requireWiki();
372
+
373
+ const findings: LintFinding[] = [];
374
+
375
+ if (scope === undefined || scope === "all" || scope === "pages") {
376
+ findings.push(...this.lintPages());
377
+ }
378
+
379
+ if (scope === undefined || scope === "all" || scope === "links") {
380
+ findings.push(...this.lintLinks());
381
+ }
382
+
383
+ if (scope === undefined || scope === "all" || scope === "freshness") {
384
+ findings.push(...this.lintFreshness());
385
+ }
386
+
387
+ return findings;
388
+ }
389
+
390
+ /**
391
+ * Lint page structure
392
+ */
393
+ private lintPages(): LintFinding[] {
394
+ const findings: LintFinding[] = [];
395
+ const pages = this.storage.getAllPages();
396
+
397
+ for (const page of pages) {
398
+ // Check required frontmatter fields
399
+ if (!page.frontmatter.id) {
400
+ findings.push({
401
+ severity: "error",
402
+ category: "structure",
403
+ pageId: page.frontmatter.id,
404
+ message: "Missing id in frontmatter",
405
+ });
406
+ }
407
+
408
+ if (!page.frontmatter.title) {
409
+ findings.push({
410
+ severity: "error",
411
+ category: "structure",
412
+ pageId: page.frontmatter.id,
413
+ message: "Missing title in frontmatter",
414
+ });
415
+ }
416
+
417
+ if (!page.frontmatter.kind) {
418
+ findings.push({
419
+ severity: "error",
420
+ category: "structure",
421
+ pageId: page.frontmatter.id,
422
+ message: "Missing kind in frontmatter",
423
+ });
424
+ }
425
+
426
+ // Check for missing sources in non-reference pages
427
+ if (
428
+ page.frontmatter.kind !== "reference" &&
429
+ page.frontmatter.sources.length === 0
430
+ ) {
431
+ findings.push({
432
+ severity: "warning",
433
+ category: "evidence",
434
+ pageId: page.frontmatter.id,
435
+ message: "Page has no source citations",
436
+ });
437
+ }
438
+
439
+ // Check for verified status without evidence
440
+ if (page.frontmatter.status === "verified" && !page.frontmatter.verification) {
441
+ findings.push({
442
+ severity: "warning",
443
+ category: "evidence",
444
+ pageId: page.frontmatter.id,
445
+ message: "Page has 'verified' status but no verification evidence",
446
+ });
447
+ }
448
+ }
449
+
450
+ return findings;
451
+ }
452
+
453
+ /**
454
+ * Lint link validity
455
+ */
456
+ private lintLinks(): LintFinding[] {
457
+ const findings: LintFinding[] = [];
458
+ const pages = this.storage.getAllPages();
459
+ const pageIds = new Set(pages.map((p) => p.frontmatter.id));
460
+
461
+ for (const page of pages) {
462
+ // Check related pages exist
463
+ for (const relatedId of page.frontmatter.relatedPages) {
464
+ if (!pageIds.has(relatedId)) {
465
+ findings.push({
466
+ severity: "warning",
467
+ category: "links",
468
+ pageId: page.frontmatter.id,
469
+ message: `Related page not found: ${relatedId}`,
470
+ });
471
+ }
472
+ }
473
+
474
+ // Check source snapshots exist
475
+ for (const source of page.frontmatter.sources) {
476
+ if (!this.storage.getSnapshot(source.sourceId)) {
477
+ findings.push({
478
+ severity: "warning",
479
+ category: "links",
480
+ pageId: page.frontmatter.id,
481
+ message: `Source snapshot not found: ${source.sourceId}`,
482
+ });
483
+ }
484
+ }
485
+ }
486
+
487
+ return findings;
488
+ }
489
+
490
+ /**
491
+ * Lint freshness
492
+ */
493
+ private lintFreshness(): LintFinding[] {
494
+ const findings: LintFinding[] = [];
495
+ const pages = this.storage.getAllPages();
496
+ const nowTime = Date.now();
497
+ const staleThreshold = 30 * 24 * 60 * 60 * 1000; // 30 days
498
+
499
+ for (const page of pages) {
500
+ const updatedTime = new Date(page.frontmatter.updatedAt).getTime();
501
+ const age = nowTime - updatedTime;
502
+
503
+ // Flag old pages without verification
504
+ if (
505
+ page.frontmatter.status !== "verified" &&
506
+ page.frontmatter.status !== "superseded" &&
507
+ age > staleThreshold
508
+ ) {
509
+ findings.push({
510
+ severity: "info",
511
+ category: "freshness",
512
+ pageId: page.frontmatter.id,
513
+ message: `Page has not been updated in ${Math.floor(age / (24 * 60 * 60 * 1000))} days`,
514
+ });
515
+ }
516
+
517
+ // Check if sources have changed
518
+ for (const source of page.frontmatter.sources) {
519
+ const snapshot = this.storage.getSnapshot(source.sourceId);
520
+ if (snapshot) {
521
+ const snapTime = new Date(snapshot.capturedAt).getTime();
522
+ if (snapTime < updatedTime) {
523
+ findings.push({
524
+ severity: "warning",
525
+ category: "freshness",
526
+ pageId: page.frontmatter.id,
527
+ message: `Source ${source.sourceId} was captured before page was last updated`,
528
+ suggestion: "Consider re-ingesting source to verify content is current",
529
+ });
530
+ }
531
+ }
532
+ }
533
+ }
534
+
535
+ return findings;
536
+ }
537
+
538
+ // ========================================================================
539
+ // Operations
540
+ // ========================================================================
541
+
542
+ /**
543
+ * Get recent operations
544
+ */
545
+ getRecentOperations(limit = 50): WikiOperation[] {
546
+ requireWiki();
547
+ return this.storage.getRecentOperations(limit);
548
+ }
549
+ }
550
+
551
+ // ============================================================================
552
+ // Factory
553
+ // ============================================================================
554
+
555
+ /**
556
+ * Create wiki manager for a workspace
557
+ */
558
+ export function createWikiManager(workspaceRoot: string, projectId: string): WikiManager {
559
+ const storage = createWikiStorage(workspaceRoot, projectId);
560
+ return new WikiManager(storage);
561
+ }
562
+
563
+ // Re-export storage class
564
+ export { WikiStorage, createWikiStorage } from "./storage.js";
565
+
566
+ /**
567
+ * Check if wiki exists in workspace
568
+ */
569
+ export function wikiExists(workspaceRoot: string): boolean {
570
+ const wikiRoot = join(workspaceRoot, "wiki");
571
+ return existsSync(join(wikiRoot, "knowledge"));
572
+ }
573
+
574
+ // ============================================================================
575
+ // Exports
576
+ // ============================================================================
577
+
578
+ export * from "./types.js";