pi-harness-runtime 1.1.97 → 1.1.98

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 (100) hide show
  1. package/index.ts +12 -1
  2. package/package.json +1 -1
  3. package/packages/a2a-adapter/package.json +1 -1
  4. package/packages/architecture-generator/package.json +1 -1
  5. package/packages/auth/package.json +1 -1
  6. package/packages/autonomous-refactor/package.json +1 -1
  7. package/packages/autonomous-runtime/package.json +1 -1
  8. package/packages/cache-strategy/package.json +1 -1
  9. package/packages/capability-registry/package.json +1 -1
  10. package/packages/checkpoint/package.json +1 -1
  11. package/packages/cli-plugin-sdk/package.json +1 -1
  12. package/packages/clipboard/package.json +1 -1
  13. package/packages/clipboard-plugin/package.json +1 -1
  14. package/packages/code-generation/package.json +1 -1
  15. package/packages/code-review/package.json +1 -1
  16. package/packages/codex-adapter/package.json +1 -1
  17. package/packages/config-capture/package.json +1 -1
  18. package/packages/context-compiler/package.json +1 -1
  19. package/packages/context-discovery/package.json +1 -1
  20. package/packages/context-manager/package.json +1 -1
  21. package/packages/cookie-sanitizer/package.json +1 -1
  22. package/packages/cost-optimizer/package.json +1 -1
  23. package/packages/dependency-analyzer/package.json +1 -1
  24. package/packages/django-plugin/package.json +1 -1
  25. package/packages/doc-generator/package.json +1 -1
  26. package/packages/evaluation-engine/package.json +1 -1
  27. package/packages/evaluation-runner/package.json +1 -1
  28. package/packages/event-bus/package.json +1 -1
  29. package/packages/event-store/package.json +1 -1
  30. package/packages/experience-replay/package.json +1 -1
  31. package/packages/feedback-collector/package.json +1 -1
  32. package/packages/file-copy-helper/package.json +1 -1
  33. package/packages/framework-detector/package.json +1 -1
  34. package/packages/framework-plugin-sdk/package.json +1 -1
  35. package/packages/frappe-plugin/package.json +1 -1
  36. package/packages/generic-web-plugin/package.json +1 -1
  37. package/packages/health-monitor/package.json +1 -1
  38. package/packages/intent-analyzer/package.json +1 -1
  39. package/packages/jev-judge/package.json +1 -1
  40. package/packages/knowledge-graph/package.json +1 -1
  41. package/packages/knowledge-retrieval/package.json +1 -1
  42. package/packages/laravel-plugin/package.json +1 -1
  43. package/packages/learning-engine/package.json +1 -1
  44. package/packages/mcp-adapter/package.json +1 -1
  45. package/packages/memory-engine/package.json +1 -1
  46. package/packages/milestone-manager/package.json +1 -1
  47. package/packages/model-registry/package.json +1 -1
  48. package/packages/nextjs-plugin/package.json +1 -1
  49. package/packages/notification/package.json +1 -1
  50. package/packages/observability/package.json +1 -1
  51. package/packages/okf-indexer/package.json +1 -1
  52. package/packages/performance-optimizer/package.json +1 -1
  53. package/packages/privilege-broker/package.json +1 -1
  54. package/packages/project-analyzer/package.json +1 -1
  55. package/packages/project-bootstrap/package.json +1 -1
  56. package/packages/projection-engine/package.json +1 -1
  57. package/packages/prompt-compiler/package.json +1 -1
  58. package/packages/prompt-versioning/package.json +1 -1
  59. package/packages/provider-adapter-sdk/package.json +1 -1
  60. package/packages/provider-router/package.json +1 -1
  61. package/packages/provider-selector/package.json +1 -1
  62. package/packages/providers/package.json +1 -1
  63. package/packages/qdrant-skills/package.json +1 -1
  64. package/packages/quota-manager/package.json +1 -1
  65. package/packages/rate-limiter/package.json +1 -1
  66. package/packages/react-vite-plugin/package.json +1 -1
  67. package/packages/release-manager/package.json +1 -1
  68. package/packages/requirement-compiler/package.json +1 -1
  69. package/packages/runtime/package.json +1 -1
  70. package/packages/scheduler/package.json +1 -1
  71. package/packages/scheduler-adapter/package.json +1 -1
  72. package/packages/session/package.json +1 -1
  73. package/packages/session-api/package.json +1 -1
  74. package/packages/session-export/package.json +1 -1
  75. package/packages/shared-context/package.json +1 -1
  76. package/packages/skill-mcp-client/package.json +1 -1
  77. package/packages/skill-registry/package.json +1 -1
  78. package/packages/skills/dist/loader.d.ts +42 -1
  79. package/packages/skills/dist/loader.d.ts.map +1 -1
  80. package/packages/skills/dist/loader.js +185 -1
  81. package/packages/skills/dist/loader.js.map +1 -1
  82. package/packages/skills/package.json +1 -1
  83. package/packages/skills/src/loader.ts +238 -2
  84. package/packages/sprint-planner/package.json +1 -1
  85. package/packages/subscription-engine/package.json +1 -1
  86. package/packages/task-compiler/package.json +1 -1
  87. package/packages/tencentdb-memory/package.json +1 -1
  88. package/packages/tencentdb-sync/package.json +1 -1
  89. package/packages/test-data-generator/package.json +1 -1
  90. package/packages/test-generator/package.json +1 -1
  91. package/packages/todo-bd-sync/package.json +1 -1
  92. package/packages/token-estimation/package.json +1 -1
  93. package/packages/token-optimizer/package.json +1 -1
  94. package/packages/trajectory/package.json +1 -1
  95. package/packages/tui/package.json +1 -1
  96. package/packages/types/package.json +1 -1
  97. package/packages/workflow-events/package.json +1 -1
  98. package/packages/workspace-scanner/package.json +1 -1
  99. package/packages/worktree/package.json +1 -1
  100. package/packages/write-review/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Skill Registry
3
- *
3
+ *
4
4
  * Stores and manages skills with progressive disclosure.
5
5
  * Based on pi.dev Agent Skills specification.
6
6
  */
@@ -19,6 +19,100 @@ import type {
19
19
  } from "./types.js";
20
20
  import { parseSkillFile, scanSkillDirectory } from "./parser.js";
21
21
 
22
+ // --- Qdrant integration (optional) -----------------------------------------
23
+ // Loaded dynamically so skills work without Qdrant configured.
24
+ // At runtime, packages/ is resolved from the monorepo root or node_modules.
25
+
26
+ interface QdrantSkillPoint {
27
+ id: number;
28
+ name: string;
29
+ description: string;
30
+ body: string;
31
+ text: string;
32
+ }
33
+
34
+ interface QdrantClientLike {
35
+ upsert(collection: string, opts: { wait?: boolean; points: unknown[] }): Promise<void>;
36
+ query(collection: string, opts: {
37
+ query?: { text?: string; model?: string };
38
+ limit?: number;
39
+ with_payload?: boolean;
40
+ filter?: Record<string, unknown>;
41
+ }): Promise<unknown>;
42
+ }
43
+
44
+ interface QdrantEmbedderLike {
45
+ createEmbedding(text: string, apiKey?: string): Promise<{ embedding: number[]; tokens: number }>;
46
+ }
47
+
48
+ /** Resolve the Qdrant skill module path (monorepo sibling or npm package) */
49
+ async function resolveQdrantModules(): Promise<{
50
+ createQdrantClient: (cfg: unknown) => { upsert(c: string, o: unknown): Promise<void>; query(c: string, o: unknown): Promise<unknown>; };
51
+ createCollection: (client: unknown, name: string, dims: number) => Promise<void>;
52
+ createEmbedding: (text: string, apiKey?: string) => Promise<{ embedding: number[]; tokens: number }>;
53
+ } | null> {
54
+ // Try monorepo sibling first (resolved from packages/skills/src/loader.ts)
55
+ for (const base of ["../../../packages/qdrant-skills/src", "../../packages/qdrant-skills/src"]) {
56
+ try {
57
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
58
+ const mod = require(/* @vite-ignore */ base + "/index.js");
59
+ return mod as Awaited<ReturnType<typeof resolveQdrantModules>>;
60
+ } catch {
61
+ // Try next path
62
+ }
63
+ }
64
+ // Fall back to npm package
65
+ try {
66
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
67
+ const mod = require(/* @vite-ignore */ "@pi-harness/qdrant-skills") as { createQdrantClient: unknown; createCollection: unknown; createEmbedding: unknown };
68
+ return {
69
+ createQdrantClient: (cfg: unknown) => (mod.createQdrantClient as Function)(cfg) as { upsert(c: string, o: unknown): Promise<void>; query(c: string, o: unknown): Promise<unknown> },
70
+ createCollection: mod.createCollection as (client: unknown, name: string, dims: number) => Promise<void>,
71
+ createEmbedding: mod.createEmbedding as (text: string, apiKey?: string) => Promise<{ embedding: number[]; tokens: number }>,
72
+ };
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ /** Read a key file, returning null if missing or empty */
79
+ function readKeyFile(path: string): string | null {
80
+ try {
81
+ if (!existsSync(path)) return null;
82
+ const val = readFileSync(path, "utf8").trim();
83
+ return val.length > 5 ? val : null;
84
+ } catch {
85
+ return null;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Get Qdrant config from env or keys files.
91
+ * Returns null if not configured.
92
+ */
93
+ export function getQdrantConfig(): {
94
+ url: string;
95
+ apiKey: string;
96
+ collection: string;
97
+ } | null {
98
+ const homedir = process.env.HOME || process.env.USERPROFILE || "/home/frappe";
99
+ const keysDir = `${homedir}/.pi-harness-runtime/keys`;
100
+
101
+ const url =
102
+ process.env.QDRANT_CLUSTER_ENDPOINT ||
103
+ readKeyFile(`${keysDir}/qdrant-cluster-url.txt`);
104
+ const apiKey =
105
+ process.env.QDRANT_API_KEY ||
106
+ readKeyFile(`${keysDir}/qdrant-api-key.txt`);
107
+
108
+ if (!url || !apiKey) return null;
109
+ return {
110
+ url,
111
+ apiKey,
112
+ collection: process.env.QDRANT_COLLECTION || "pi-harness-skills",
113
+ };
114
+ }
115
+
22
116
  /**
23
117
  * Skill Registry - manages loaded and indexed skills
24
118
  */
@@ -27,12 +121,92 @@ export class SkillRegistry {
27
121
  private index: SkillIndex = { entries: [], loadedAt: 0 };
28
122
  private loading: Map<string, Promise<Skill>> = new Map();
29
123
 
124
+ // Qdrant state (lazily initialized on first register if configured)
125
+ private _qdrant: {
126
+ client: QdrantClientLike;
127
+ embedder: QdrantEmbedderLike;
128
+ collection: string;
129
+ ready: boolean;
130
+ } | null = null;
131
+ private _qdrantInitAttempted = false;
132
+
133
+ /**
134
+ * Initialize Qdrant client if configured.
135
+ * Called lazily on first skill registration.
136
+ */
137
+ private async _ensureQdrant(): Promise<void> {
138
+ if (this._qdrantInitAttempted) return;
139
+ this._qdrantInitAttempted = true;
140
+
141
+ const config = getQdrantConfig();
142
+ if (!config) return;
143
+
144
+ const mods = await resolveQdrantModules();
145
+ if (!mods) {
146
+ console.debug("[skills] Qdrant package not found — skipping vector indexing");
147
+ return;
148
+ }
149
+
150
+ try {
151
+ const client = mods.createQdrantClient({
152
+ url: config.url,
153
+ apiKey: config.apiKey,
154
+ });
155
+ await mods.createCollection(client, config.collection, 1536);
156
+ this._qdrant = {
157
+ client,
158
+ embedder: { createEmbedding: mods.createEmbedding },
159
+ collection: config.collection,
160
+ ready: true,
161
+ };
162
+ console.log(`[skills] Qdrant vector store ready (collection: ${config.collection})`);
163
+ } catch (err) {
164
+ console.error("[skills] Qdrant init failed:", err instanceof Error ? err.message : String(err));
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Index a single skill into Qdrant (non-blocking).
170
+ */
171
+ private async _indexSkillToQdrant(skill: Skill): Promise<void> {
172
+ if (!this._qdrant?.ready) return;
173
+
174
+ const point: QdrantSkillPoint = {
175
+ id: this._hashId(skill.id),
176
+ name: skill.id,
177
+ description: skill.frontmatter.description,
178
+ body: skill.body.slice(0, 2000),
179
+ text: [skill.id, skill.frontmatter.name, skill.frontmatter.description, skill.body.slice(0, 1500)].join(" "),
180
+ };
181
+
182
+ try {
183
+ const { embedding } = await this._qdrant.embedder.createEmbedding(point.text);
184
+ await this._qdrant.client.upsert(this._qdrant.collection, {
185
+ wait: false,
186
+ points: [{ id: point.id, vector: embedding, payload: point }],
187
+ });
188
+ } catch (err) {
189
+ console.error(`[skills] Failed to index "${skill.id}" to Qdrant:`, err instanceof Error ? err.message : String(err));
190
+ }
191
+ }
192
+
193
+ /** Simple deterministic ID for Qdrant (no bigints needed). */
194
+ private _hashId(id: string): number {
195
+ let h = 0;
196
+ for (let i = 0; i < id.length; i++) {
197
+ h = (Math.imul(31, h) + id.charCodeAt(i)) | 0;
198
+ }
199
+ return Math.abs(h);
200
+ }
201
+
30
202
  /**
31
- * Register a skill
203
+ * Register a skill (auto-indexes to Qdrant if configured).
32
204
  */
33
205
  register(skill: Skill): void {
34
206
  this.skills.set(skill.id, skill);
35
207
  this.updateIndex(skill);
208
+ // Trigger async Qdrant indexing without blocking registration
209
+ this._ensureQdrant().then(() => this._indexSkillToQdrant(skill)).catch(() => {});
36
210
  }
37
211
 
38
212
  /**
@@ -166,6 +340,68 @@ export class SkillRegistry {
166
340
  return results[0] ?? null;
167
341
  }
168
342
 
343
+ // --- Qdrant vector search --------------------------------------------------
344
+
345
+ /**
346
+ * Search skills by semantic similarity using Qdrant.
347
+ * Falls back to an empty result if Qdrant is not available.
348
+ *
349
+ * @param query Natural-language query
350
+ * @param limit Max results (default 5)
351
+ * @param threshold Minimum cosine score (default 0.5)
352
+ */
353
+ async findVector(
354
+ query: string,
355
+ limit = 5,
356
+ threshold = 0.5,
357
+ ): Promise<Array<{ skill: Skill; score: number }>> {
358
+ await this._ensureQdrant();
359
+ if (!this._qdrant?.ready) return [];
360
+
361
+ try {
362
+ const { embedding } = await this._qdrant.embedder.createEmbedding(query);
363
+ // SAFETY: Qdrant's query() accepts number[] for dense vector search via its internal
364
+ // OpenAPI spec — the float[] overload is not in the generated TypeScript types but
365
+ // the server handles it correctly at runtime.
366
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
+ const queryOpts: any = { query: embedding, limit, with_payload: true };
368
+ const raw = await this._qdrant.client.query(this._qdrant.collection, queryOpts) as {
369
+ result?: { points?: Array<{ id: number; score: number; payload?: Record<string, unknown> }> } };
370
+
371
+ const results: Array<{ skill: Skill; score: number }> = [];
372
+ for (const pt of raw.result?.points ?? []) {
373
+ if (pt.score < threshold) continue;
374
+ const name = pt.payload?.name as string | undefined;
375
+ const skill = name ? this.skills.get(name) : undefined;
376
+ if (skill) results.push({ skill, score: pt.score });
377
+ }
378
+ return results;
379
+ } catch (err) {
380
+ console.error("[skills] Qdrant vector search failed:", err instanceof Error ? err.message : String(err));
381
+ return [];
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Sync all registered skills to Qdrant.
387
+ * Useful after Qdrant becomes available or collection is rebuilt.
388
+ */
389
+ async syncAllToQdrant(onProgress?: (index: number, total: number) => void): Promise<void> {
390
+ await this._ensureQdrant();
391
+ if (!this._qdrant?.ready) return;
392
+
393
+ const skills = this.list();
394
+ for (let i = 0; i < skills.length; i++) {
395
+ await this._indexSkillToQdrant(skills[i]);
396
+ onProgress?.(i + 1, skills.length);
397
+ }
398
+ }
399
+
400
+ /** Whether Qdrant is available and ready. */
401
+ get isQdrantReady(): boolean {
402
+ return this._qdrant?.ready ?? false;
403
+ }
404
+
169
405
  /**
170
406
  * Load a skill's full content (progressive disclosure)
171
407
  */
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/sprint-planner",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "type": "module",
5
5
  "description": "Sprint planning engine for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/subscription-engine",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/task-compiler",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Task Compiler for pi-harness-runtime — produces deterministic task DAG from CompiledRequirement",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/tencentdb-memory",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "TencentDB Agent Memory client - sync skills to centralized knowledge base",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tencentdb-sync",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Sync SKILL.md skills to TencentDB-Agent-Memory server (RFC-0105/0106)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/test-data-generator",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Test data generation for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/test-generator",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Auto-Test Generator — generate unit and E2E tests from source code (RFC-0013)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/todo-bd-sync",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Two-way sync between rpiv-todo overlay and bd issue tracker",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/token-estimation",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "pi-harness-runtime — token-estimation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/token-optimizer",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Token Budget Optimizer — maximize prompt value within token limits (RFC-0011)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/trajectory",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Trajectory capture for the write-review loop — persists cycle records for learning",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tui",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "pi-harness-runtime — tui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/types",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Shared TypeScript types for pi-harness-runtime packages",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/workflow-events",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/workspace-scanner",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/worktree",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "pi-harness-runtime — worktree",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/write-review",
3
- "version": "1.1.97",
3
+ "version": "1.1.98",
4
4
  "description": "Two-agent write-review loop with blackboard coordination",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",