pi-harness-runtime 1.1.414 → 1.1.416

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 (135) hide show
  1. package/package.json +1 -1
  2. package/packages/a2a-adapter/package.json +1 -1
  3. package/packages/agent-policy/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/codex-watcher/package.json +1 -1
  18. package/packages/config-capture/package.json +1 -1
  19. package/packages/connection-runtime/package.json +1 -1
  20. package/packages/context-compiler/package.json +1 -1
  21. package/packages/context-discovery/package.json +1 -1
  22. package/packages/context-manager/package.json +1 -1
  23. package/packages/contracts/package.json +1 -1
  24. package/packages/cookie-sanitizer/package.json +1 -1
  25. package/packages/cost-optimizer/package.json +1 -1
  26. package/packages/dependency-analyzer/package.json +1 -1
  27. package/packages/django-plugin/package.json +1 -1
  28. package/packages/doc-generator/package.json +1 -1
  29. package/packages/durable-review/package.json +1 -1
  30. package/packages/e2e-tester/package.json +1 -1
  31. package/packages/evaluation-engine/package.json +1 -1
  32. package/packages/evaluation-runner/package.json +1 -1
  33. package/packages/event-bus/package.json +1 -1
  34. package/packages/event-sink/package.json +1 -1
  35. package/packages/event-store/package.json +1 -1
  36. package/packages/experience-replay/package.json +1 -1
  37. package/packages/feedback-collector/package.json +1 -1
  38. package/packages/file-copy-helper/package.json +1 -1
  39. package/packages/framework-detector/package.json +1 -1
  40. package/packages/framework-plugin-sdk/package.json +1 -1
  41. package/packages/frappe-plugin/package.json +1 -1
  42. package/packages/generic-web-plugin/package.json +1 -1
  43. package/packages/health-monitor/package.json +1 -1
  44. package/packages/intent-analyzer/package.json +1 -1
  45. package/packages/jev-judge/package.json +1 -1
  46. package/packages/knowledge-graph/package.json +1 -1
  47. package/packages/knowledge-retrieval/package.json +1 -1
  48. package/packages/laravel-plugin/package.json +1 -1
  49. package/packages/learning-engine/package.json +1 -1
  50. package/packages/logging/package.json +1 -1
  51. package/packages/mcp-adapter/package.json +1 -1
  52. package/packages/memory-engine/package.json +1 -1
  53. package/packages/milestone-manager/package.json +1 -1
  54. package/packages/model-registry/package.json +1 -1
  55. package/packages/nextjs-plugin/package.json +1 -1
  56. package/packages/notification/package.json +1 -1
  57. package/packages/observability/package.json +1 -1
  58. package/packages/okf-indexer/package.json +1 -1
  59. package/packages/paperclip-integration/package.json +1 -1
  60. package/packages/performance-optimizer/package.json +1 -1
  61. package/packages/permission-mode/package.json +1 -1
  62. package/packages/privilege-broker/package.json +1 -1
  63. package/packages/project-analyzer/package.json +1 -1
  64. package/packages/project-bootstrap/package.json +1 -1
  65. package/packages/projection-engine/package.json +1 -1
  66. package/packages/prompt-compiler/package.json +1 -1
  67. package/packages/prompt-versioning/package.json +1 -1
  68. package/packages/provider-adapter-sdk/package.json +1 -1
  69. package/packages/provider-router/package.json +1 -1
  70. package/packages/provider-selector/package.json +1 -1
  71. package/packages/providers/package.json +1 -1
  72. package/packages/qdrant-skills/package.json +1 -1
  73. package/packages/quota-manager/package.json +1 -1
  74. package/packages/rate-limiter/package.json +1 -1
  75. package/packages/react-vite-plugin/package.json +1 -1
  76. package/packages/relay/package.json +1 -1
  77. package/packages/release-manager/package.json +1 -1
  78. package/packages/requirement-compiler/package.json +1 -1
  79. package/packages/runtime/package.json +1 -1
  80. package/packages/scheduler/package.json +1 -1
  81. package/packages/scheduler-adapter/package.json +1 -1
  82. package/packages/session/package.json +1 -1
  83. package/packages/session-api/package.json +1 -1
  84. package/packages/session-export/package.json +1 -1
  85. package/packages/shared-context/package.json +1 -1
  86. package/packages/skill-mcp-client/package.json +1 -1
  87. package/packages/skill-registry/package.json +1 -1
  88. package/packages/skills/dist/index.d.ts +1 -0
  89. package/packages/skills/dist/index.d.ts.map +1 -1
  90. package/packages/skills/dist/index.js +1 -0
  91. package/packages/skills/dist/index.js.map +1 -1
  92. package/packages/skills/dist/loader.d.ts +9 -0
  93. package/packages/skills/dist/loader.d.ts.map +1 -1
  94. package/packages/skills/dist/loader.js +24 -3
  95. package/packages/skills/dist/loader.js.map +1 -1
  96. package/packages/skills/dist/sanitize.d.ts +32 -0
  97. package/packages/skills/dist/sanitize.d.ts.map +1 -0
  98. package/packages/skills/dist/sanitize.js +100 -0
  99. package/packages/skills/dist/sanitize.js.map +1 -0
  100. package/packages/skills/dist/vector-schema.d.ts +4 -0
  101. package/packages/skills/dist/vector-schema.d.ts.map +1 -1
  102. package/packages/skills/dist/vector-schema.js +13 -4
  103. package/packages/skills/dist/vector-schema.js.map +1 -1
  104. package/packages/skills/package.json +1 -1
  105. package/packages/skills/src/index.ts +1 -0
  106. package/packages/skills/src/loader.ts +26 -3
  107. package/packages/skills/src/sanitize.ts +111 -0
  108. package/packages/skills/src/vector-schema.ts +14 -4
  109. package/packages/skills/test/remote-skills.test.ts +41 -0
  110. package/packages/skills/test/sanitize.test.ts +131 -0
  111. package/packages/skills/test/vector-schema.test.ts +15 -2
  112. package/packages/sprint-planner/package.json +1 -1
  113. package/packages/subscription-engine/package.json +1 -1
  114. package/packages/task-compiler/package.json +1 -1
  115. package/packages/telegram/package.json +1 -1
  116. package/packages/tencentdb-memory/package.json +1 -1
  117. package/packages/tencentdb-sync/package.json +1 -1
  118. package/packages/test-data-generator/package.json +1 -1
  119. package/packages/test-generator/package.json +1 -1
  120. package/packages/todo-bd-sync/package.json +1 -1
  121. package/packages/token-estimation/package.json +1 -1
  122. package/packages/token-optimizer/package.json +1 -1
  123. package/packages/tooling-preference/package.json +1 -1
  124. package/packages/trajectory/package.json +1 -1
  125. package/packages/tui/package.json +1 -1
  126. package/packages/two-phase-review/package.json +1 -1
  127. package/packages/types/package.json +1 -1
  128. package/packages/voice-api/package.json +1 -1
  129. package/packages/webmcp-tester/package.json +1 -1
  130. package/packages/wiki/package.json +1 -1
  131. package/packages/workflow-events/package.json +1 -1
  132. package/packages/workspace-scanner/package.json +1 -1
  133. package/packages/worktree/package.json +1 -1
  134. package/packages/write-review/package.json +1 -1
  135. package/scripts/sync-to-qdrant.ts +18 -83
@@ -1 +1 @@
1
- {"version":3,"file":"vector-schema.d.ts","sourceRoot":"","sources":["../src/vector-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,0CAA0C;AAC1C,eAAO,MAAM,6BAA6B,2CAA2C,CAAC;AAEtF,gDAAgD;AAChD,eAAO,MAAM,kCAAkC,MAAM,CAAC;AAEtD,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IACjC,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,kDAAkD;AAClD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,CAMT;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAE7E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,iBAAiB,CAOpB;AACD,wBAAgB,2BAA2B,CAC1C,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,QAAQ,EAAE,iBAAiB,GACzB,MAAM,GAAG,IAAI,CASf"}
1
+ {"version":3,"file":"vector-schema.d.ts","sourceRoot":"","sources":["../src/vector-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,0CAA0C;AAC1C,eAAO,MAAM,6BAA6B,2CAA2C,CAAC;AAEtF,gDAAgD;AAChD,eAAO,MAAM,kCAAkC,MAAM,CAAC;AAEtD,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IACjC,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,kDAAkD;AAClD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,CAMT;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAE7E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,iBAAiB,CAWpB;AACD,wBAAgB,2BAA2B,CAC1C,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,QAAQ,EAAE,iBAAiB,GACzB,MAAM,GAAG,IAAI,CASf"}
@@ -15,6 +15,7 @@
15
15
  * module owns the collection - that is a decision of the skills domain, not
16
16
  * of the vector store.
17
17
  */
18
+ import { sanitizeText, skillPointName } from "./sanitize.js";
18
19
  /**
19
20
  * The collection the runtime indexes into and searches.
20
21
  *
@@ -91,13 +92,21 @@ export function skillQdrantPoint(payload) {
91
92
  }
92
93
  /**
93
94
  * The payload of a skill point.
95
+ *
96
+ * The payload is sanitized: the collection is shared, so the client names
97
+ * of a user must not travel into it. Both writers use this function, so
98
+ * both write the same sanitized payload for the same skill.
94
99
  */
95
100
  export function skillPointPayload(input) {
101
+ const name = skillPointName(input.name);
102
+ const title = input.title ? skillPointName(input.title) : undefined;
103
+ const description = sanitizeText(input.description);
104
+ const body = sanitizeText(input.body).slice(0, SKILL_PAYLOAD_BODY_LIMIT);
96
105
  return {
97
- name: input.name,
98
- description: input.description,
99
- body: input.body.slice(0, SKILL_PAYLOAD_BODY_LIMIT),
100
- text: skillPointText(input),
106
+ name,
107
+ description,
108
+ body,
109
+ text: skillPointText({ name, title, description, body }),
101
110
  };
102
111
  }
103
112
  export function describeSkillSchemaMismatch(actual, expected) {
@@ -1 +1 @@
1
- {"version":3,"file":"vector-schema.js","sourceRoot":"","sources":["../src/vector-schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vector-schema.js","sourceRoot":"","sources":["../src/vector-schema.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/skills",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
4
4
  "description": "File-based skill system with pi.dev compatibility and Hermes self-improvement",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -14,6 +14,7 @@ export * from "./parser.js";
14
14
  export * from "./scanner.js";
15
15
  export * from "./loader.js";
16
16
  export * from "./vector-schema.js";
17
+ export * from "./sanitize.js";
17
18
  export * from "./remote-source.js";
18
19
  export * from "./skill-commands.js";
19
20
  export * from "./skill-tool.js";
@@ -28,6 +28,7 @@ import {
28
28
  type SkillPointPayload,
29
29
  type SkillVectorSchema,
30
30
  } from "./vector-schema.js";
31
+ import { skillPointName } from "./sanitize.js";
31
32
  import {
32
33
  describeRemoteFailure,
33
34
  isStale,
@@ -339,6 +340,15 @@ export class SkillRegistry {
339
340
  * disk and how many it can reach through the vector store.
340
341
  */
341
342
  private remoteSkills: Map<string, Skill> = new Map();
343
+ /**
344
+ * The local skills by their name in the shared collection.
345
+ *
346
+ * The name of a point is the SANITIZED name of the skill, because the
347
+ * collection is shared. A hit of the collection therefore carries a name
348
+ * that this machine does not use - the registry is keyed by the name on
349
+ * this machine. This map bridges the two.
350
+ */
351
+ private _skillsByPointName: Map<string, Skill> = new Map();
342
352
  /**
343
353
  * The remote skills whose content is COMPLETE.
344
354
  *
@@ -766,6 +776,8 @@ export class SkillRegistry {
766
776
  */
767
777
  register(skill: Skill): void {
768
778
  this.skills.set(skill.id, skill);
779
+ // The shared collection knows the skill by its sanitized name.
780
+ this._skillsByPointName.set(skillPointName(skill.id), skill);
769
781
  this.updateIndex(skill);
770
782
  // Queue the skill for the vector index without blocking registration.
771
783
  this._scheduleIndex(skill);
@@ -778,6 +790,12 @@ export class SkillRegistry {
778
790
  const skill = this.skills.get(skillId);
779
791
  if (skill) {
780
792
  this.skills.delete(skillId);
793
+ // Only drop the shared name when it still points at this skill: two
794
+ // skills may share a sanitized name.
795
+ const pointName = skillPointName(skill.id);
796
+ if (this._skillsByPointName.get(pointName) === skill) {
797
+ this._skillsByPointName.delete(pointName);
798
+ }
781
799
  this.index.entries = this.index.entries.filter(
782
800
  (e) => e.id !== skillId
783
801
  );
@@ -791,8 +809,13 @@ export class SkillRegistry {
791
809
  */
792
810
  get(skillId: string): Skill | undefined {
793
811
  // A server skill is only known after a vector search found it, so it is
794
- // looked up second - the local skill always wins.
795
- return this.skills.get(skillId) ?? this.remoteSkills.get(skillId);
812
+ // looked up second - the local skill always wins. The shared name of a
813
+ // skill resolves to the local skill as well.
814
+ return (
815
+ this.skills.get(skillId) ??
816
+ this._skillsByPointName.get(skillId) ??
817
+ this.remoteSkills.get(skillId)
818
+ );
796
819
  }
797
820
 
798
821
  /**
@@ -1054,7 +1077,7 @@ export class SkillRegistry {
1054
1077
  const payload = pt.payload ?? {};
1055
1078
  const name = typeof payload.name === "string" ? payload.name : undefined;
1056
1079
  if (!name) continue;
1057
- const local = this.skills.get(name);
1080
+ const local = this._skillsByPointName.get(name) ?? this.skills.get(name);
1058
1081
  if (local) {
1059
1082
  results.push({ skill: local, score: pt.score, source: "local" });
1060
1083
  continue;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The sanitization of a skill for the shared collection.
3
+ *
4
+ * The collection is shared, so a client name must not travel into it. The
5
+ * rules lived in `scripts/sync-to-qdrant.ts` - the only writer that could
6
+ * reach them. The runtime registry writes into the same collection, so it
7
+ * needs them too: a writer that skipped the rules would leave the raw
8
+ * name and the raw body of a client skill in a shared cluster.
9
+ *
10
+ * Both writers therefore build their points with the same rules, and the
11
+ * name of a point is the sanitized name. One skill, one point.
12
+ */
13
+
14
+ /** A rule that replaces a client specific text. */
15
+ interface SanitizationRule {
16
+ pattern: RegExp;
17
+ replacement: string;
18
+ }
19
+
20
+ /**
21
+ * The patterns of the client specific names.
22
+ *
23
+ * The list is about the names of the clients and the projects of the
24
+ * users of the harness - not about the skills themselves.
25
+ *
26
+ * The patterns match a plain fragment, without a word boundary. A client
27
+ * name rarely stands alone: it appears inside a directory name
28
+ * (`th_digisoft_erp_chart.json`), inside a Python module (`inpac_pharma`)
29
+ * or in a sentence ("integrated with Paperclip"). A word boundary would
30
+ * miss all of them - and `_` is a word character, so a boundary never
31
+ * follows an underscore.
32
+ */
33
+ const SANITIZATION_RULES: SanitizationRule[] = [
34
+ // Client company names (case-insensitive)
35
+ { pattern: /inpac/gi, replacement: "[Client A]" },
36
+ { pattern: /m-capital/gi, replacement: "[Client A]" },
37
+ { pattern: /mcapital/gi, replacement: "[Client A]" },
38
+ { pattern: /digisoft/gi, replacement: "[Client B]" },
39
+
40
+ // Project/app specific names
41
+ { pattern: /gse-insurance/gi, replacement: "[Insurance Project]" },
42
+ { pattern: /tbs-import/gi, replacement: "[Import Project]" },
43
+ { pattern: /paperclip/gi, replacement: "[Client D]" },
44
+ { pattern: /openclaw/gi, replacement: "[Client F]" },
45
+
46
+ // Generic replacements
47
+ { pattern: /Company Name/gi, replacement: "[Client Name]" },
48
+ { pattern: /your company/gi, replacement: "[Client]" },
49
+ { pattern: /our client/gi, replacement: "[Client]" },
50
+ { pattern: /client-specific/gi, replacement: "[Project-specific]" },
51
+ ];
52
+
53
+ /**
54
+ * The names that are renamed as a whole.
55
+ *
56
+ * A name that would be unreadable after the pattern rules - a name that
57
+ * carries the client name in its middle - is renamed here.
58
+ */
59
+ const SKILL_NAME_MAP: Record<string, string> = {
60
+ "gse-insurance-step5-slot-filter": "insurance-project-step-filter",
61
+ "inpac-pe-approval-workflow": "client-a-pe-approval-workflow",
62
+ "inpac-po-approval-workflow": "client-a-po-approval-workflow",
63
+ "inpac-pr-approval-workflow": "client-a-pr-approval-workflow",
64
+ "tbs-import-clearance-lcv": "import-project-clearance",
65
+ whispertool: "whisper-tool",
66
+ };
67
+
68
+ /**
69
+ * Replace the client specific names of a text.
70
+ *
71
+ * The text stays the same length, so a vector that was built from it
72
+ * keeps its shape.
73
+ */
74
+ export function sanitizeText(text: string): string {
75
+ let result = text;
76
+ for (const rule of SANITIZATION_RULES) {
77
+ result = result.replace(rule.pattern, rule.replacement);
78
+ }
79
+ return result;
80
+ }
81
+
82
+ /**
83
+ * The name of a skill in the shared collection.
84
+ *
85
+ * The name is the identity of the point, so it has to be the same for
86
+ * every writer: the map first, then the pattern rules.
87
+ *
88
+ * The result is a skill name - lower case, words separated by a dash -
89
+ * because the name of a point is also the id of the skill that a search
90
+ * returns. The replacements of the rules carry a space and brackets,
91
+ * which no skill name may hold.
92
+ */
93
+ export function skillPointName(name: string): string {
94
+ const mapped = SKILL_NAME_MAP[name];
95
+ if (mapped) return mapped;
96
+ return kebabName(sanitizeText(name));
97
+ }
98
+
99
+ /**
100
+ * Bring a name into the shape of a skill name.
101
+ *
102
+ * The name of a skill is lower case and its words are separated by a
103
+ * dash: `^[a-z0-9]+(-[a-z0-9]+)*$`.
104
+ */
105
+ function kebabName(name: string): string {
106
+ return name
107
+ .toLowerCase()
108
+ .replace(/[^a-z0-9]+/g, "-")
109
+ .replace(/-{2,}/g, "-")
110
+ .replace(/^-+|-+$/g, "");
111
+ }
@@ -16,6 +16,8 @@
16
16
  * of the vector store.
17
17
  */
18
18
 
19
+ import { sanitizeText, skillPointName } from "./sanitize.js";
20
+
19
21
  /**
20
22
  * The collection the runtime indexes into and searches.
21
23
  *
@@ -152,6 +154,10 @@ export function skillQdrantPoint(payload: SkillPointPayload): SkillQdrantPoint {
152
154
 
153
155
  /**
154
156
  * The payload of a skill point.
157
+ *
158
+ * The payload is sanitized: the collection is shared, so the client names
159
+ * of a user must not travel into it. Both writers use this function, so
160
+ * both write the same sanitized payload for the same skill.
155
161
  */
156
162
  export function skillPointPayload(input: {
157
163
  /** The name the payload carries - the identity of the skill. */
@@ -163,11 +169,15 @@ export function skillPointPayload(input: {
163
169
  /** The body of the skill. */
164
170
  body: string;
165
171
  }): SkillPointPayload {
172
+ const name = skillPointName(input.name);
173
+ const title = input.title ? skillPointName(input.title) : undefined;
174
+ const description = sanitizeText(input.description);
175
+ const body = sanitizeText(input.body).slice(0, SKILL_PAYLOAD_BODY_LIMIT);
166
176
  return {
167
- name: input.name,
168
- description: input.description,
169
- body: input.body.slice(0, SKILL_PAYLOAD_BODY_LIMIT),
170
- text: skillPointText(input),
177
+ name,
178
+ description,
179
+ body,
180
+ text: skillPointText({ name, title, description, body }),
171
181
  };
172
182
  }
173
183
  export function describeSkillSchemaMismatch(
@@ -169,6 +169,47 @@ describe("a skill that only exists in the vector store", () => {
169
169
  });
170
170
  });
171
171
 
172
+ describe("a hit that carries the shared name of a local skill", () => {
173
+ it("resolves to the local skill", async () => {
174
+ // The collection is shared, so the point carries the SANITIZED name.
175
+ const client = fakeClient([
176
+ {
177
+ id: 1,
178
+ score: 0.9,
179
+ payload: {
180
+ name: "client-a-pe-approval-workflow",
181
+ description: "the workflow",
182
+ body: "the body",
183
+ },
184
+ },
185
+ ]);
186
+ const registry = createSkillRegistry({
187
+ qdrantClient: client,
188
+ embedder: fakeEmbedder,
189
+ collection: "pi-harness-skills-test",
190
+ });
191
+ registry.register(localSkill("inpac-pe-approval-workflow"));
192
+
193
+ const results = await registry.findVector("workflow");
194
+
195
+ expect(results).toHaveLength(1);
196
+ // The skill of this machine stays a local skill - with its own
197
+ // name and its own body, not the sanitized copy.
198
+ expect(results[0].source).toBe("local");
199
+ expect(results[0].skill.id).toBe("inpac-pe-approval-workflow");
200
+ expect(results[0].skill.body).toBe("the local body of inpac-pe-approval-workflow");
201
+ });
202
+
203
+ it("resolves the shared name of a local skill in a lookup", () => {
204
+ const registry = createSkillRegistry({ indexer: null });
205
+ registry.register(localSkill("inpac-pe-approval-workflow"));
206
+
207
+ expect(registry.get("client-a-pe-approval-workflow")?.id).toBe(
208
+ "inpac-pe-approval-workflow",
209
+ );
210
+ });
211
+ });
212
+
172
213
  describe("the state of the vector store", () => {
173
214
  it("reports the number of skills", async () => {
174
215
  const client = fakeClient([], {
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Tests for the sanitization of a skill for the shared collection.
3
+ *
4
+ * The collection is shared, so the client names of a user must not travel
5
+ * into it. The rules used to live in `scripts/sync-to-qdrant.ts` - the
6
+ * only writer that could reach them. The runtime registry writes into the
7
+ * same collection, so it needs them too.
8
+ */
9
+
10
+ import { describe, expect, test } from "bun:test";
11
+
12
+ import { sanitizeText, skillPointName } from "../src/sanitize.js";
13
+ import { skillPointPayload } from "../src/vector-schema.js";
14
+
15
+ describe("the sanitization of a text", () => {
16
+ test("the name of a client is replaced", () => {
17
+ expect(sanitizeText("the inpac workflow")).toBe("the [Client A] workflow");
18
+ expect(sanitizeText("for digisoft")).toBe("for [Client B]");
19
+ expect(sanitizeText("gse-insurance step")).toBe("[Insurance Project] step");
20
+ });
21
+
22
+ test("the name of a client is replaced in any case", () => {
23
+ expect(sanitizeText("INPAC and Inpac")).toBe("[Client A] and [Client A]");
24
+ });
25
+
26
+ test("a text without a client name stays the same", () => {
27
+ expect(sanitizeText("a plain skill")).toBe("a plain skill");
28
+ });
29
+
30
+ test("the generic phrases are replaced", () => {
31
+ expect(sanitizeText("Company Name")).toBe("[Client Name]");
32
+ expect(sanitizeText("your company")).toBe("[Client]");
33
+ expect(sanitizeText("our client")).toBe("[Client]");
34
+ });
35
+
36
+ test("a client name inside an identifier is replaced", () => {
37
+ // The name of a client rarely stands alone. A word boundary would
38
+ // miss every one of these - and an underscore is a word character,
39
+ // so a boundary never follows one.
40
+ expect(sanitizeText("inpac_pharma")).toBe("[Client A]_pharma");
41
+ expect(sanitizeText("th_digisoft_erp_chart.json")).toBe(
42
+ "th_[Client B]_erp_chart.json",
43
+ );
44
+ expect(sanitizeText("apps/inpac_pharma/setup")).toBe(
45
+ "apps/[Client A]_pharma/setup",
46
+ );
47
+ });
48
+
49
+ test("a client name in a sentence is replaced", () => {
50
+ expect(sanitizeText("integrated with Paperclip")).toBe(
51
+ "integrated with [Client D]",
52
+ );
53
+ expect(sanitizeText("OpenClaw secrets")).toBe("[Client F] secrets");
54
+ });
55
+ });
56
+
57
+ describe("the name of a skill in the shared collection", () => {
58
+ test("a name of the map is renamed", () => {
59
+ expect(skillPointName("inpac-pe-approval-workflow")).toBe(
60
+ "client-a-pe-approval-workflow",
61
+ );
62
+ expect(skillPointName("tbs-import-clearance-lcv")).toBe(
63
+ "import-project-clearance",
64
+ );
65
+ expect(skillPointName("whispertool")).toBe("whisper-tool");
66
+ });
67
+
68
+ test("a name without a client name stays the same", () => {
69
+ expect(skillPointName("code-review")).toBe("code-review");
70
+ });
71
+
72
+ test("the name never carries a client name", () => {
73
+ for (const name of [
74
+ "inpac-pe-approval-workflow",
75
+ "gse-insurance-step5-slot-filter",
76
+ "tbs-import-clearance-lcv",
77
+ "whispertool",
78
+ ]) {
79
+ expect(skillPointName(name)).not.toMatch(/inpac|gse-insurance|tbs-import/i);
80
+ }
81
+ });
82
+
83
+ test("the name is a valid skill name", () => {
84
+ // The name of a point is the id of the skill that a search returns,
85
+ // so it has to be a name that a skill may carry.
86
+ const NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
87
+ for (const name of [
88
+ "inpac-pe-approval-workflow",
89
+ "openclaw-channel",
90
+ "gse-insurance-step5-slot-filter",
91
+ "tbs-import-clearance-lcv",
92
+ "whispertool",
93
+ "code-review",
94
+ ]) {
95
+ expect(skillPointName(name)).toMatch(NAME);
96
+ }
97
+ });
98
+
99
+ test("a name that needs no sanitization stays the same", () => {
100
+ expect(skillPointName("code-review")).toBe("code-review");
101
+ expect(skillPointName("frappe-doctype-field-order")).toBe(
102
+ "frappe-doctype-field-order",
103
+ );
104
+ });
105
+ });
106
+
107
+ describe("the payload of a point is sanitized", () => {
108
+ test("the client names of the body do not travel into the collection", () => {
109
+ const payload = skillPointPayload({
110
+ name: "inpac-pe-approval-workflow",
111
+ description: "the workflow of inpac",
112
+ body: "the approval of inpac for the client",
113
+ });
114
+
115
+ expect(payload.name).toBe("client-a-pe-approval-workflow");
116
+ expect(payload.description).not.toMatch(/inpac/i);
117
+ expect(payload.body).not.toMatch(/inpac/i);
118
+ expect(payload.text).not.toMatch(/inpac/i);
119
+ });
120
+
121
+ test("the text is built from the sanitized parts", () => {
122
+ const payload = skillPointPayload({
123
+ name: "inpac-pe-approval-workflow",
124
+ description: "the workflow",
125
+ body: "the body",
126
+ });
127
+
128
+ expect(payload.text).toContain("client-a-pe-approval-workflow");
129
+ expect(payload.text).not.toContain("inpac-pe-approval-workflow");
130
+ });
131
+ });
@@ -138,8 +138,21 @@ describe("the identity of a skill point", () => {
138
138
  body: "b",
139
139
  });
140
140
 
141
- expect(withTitle.text).toContain("A Human Title");
142
- expect(withoutTitle.text).not.toContain("A Human Title");
141
+ // The title is treated like the name: it is sanitized and it is
142
+ // brought into the shape of a skill name.
143
+ expect(withTitle.text).toContain("a-human-title");
144
+ expect(withoutTitle.text).not.toContain("a-human-title");
145
+ });
146
+
147
+ test("a title that is the name is not repeated in the text", () => {
148
+ const payload = skillPointPayload({
149
+ name: "a-skill",
150
+ title: "a-skill",
151
+ description: "d",
152
+ body: "b",
153
+ });
154
+
155
+ expect(payload.text.match(/a-skill/g)?.length).toBe(1);
143
156
  });
144
157
  });
145
158
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/sprint-planner",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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": "@pi-harness/telegram",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
4
4
  "description": "pi-harness-runtime — Telegram inbound/outbound",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/tencentdb-memory",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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/tooling-preference",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
4
4
  "description": "pi-harness-runtime — JS/TS tooling preference (Biome vs ESLint/Prettier) proposal",
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.414",
3
+ "version": "1.1.416",
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.414",
3
+ "version": "1.1.416",
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/two-phase-review",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
4
4
  "description": "pi-harness-runtime — two-phase implementation and review workflow (queue review signals, gate the phase, scope the diff)",
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.414",
3
+ "version": "1.1.416",
4
4
  "description": "Shared TypeScript types for pi-harness-runtime packages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/voice-api",
3
- "version": "1.1.414",
3
+ "version": "1.1.416",
4
4
  "type": "module",
5
5
  "description": "Voice-to-text API using Whisper for Telegram and LINE integration",
6
6
  "main": "./dist/index.js",