pi-harness-runtime 1.1.421 → 1.1.423
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +32 -1
- package/package.json +2 -2
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/dist/approvals.d.ts +70 -183
- package/packages/contracts/dist/events.d.ts +83 -57
- package/packages/contracts/dist/jobs.d.ts +77 -156
- package/packages/contracts/dist/notifications.d.ts +68 -230
- package/packages/contracts/dist/projects.d.ts +31 -109
- package/packages/contracts/dist/sessions.d.ts +66 -150
- package/packages/contracts/package.json +2 -2
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/logging/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/dist/index.d.ts.map +1 -1
- package/packages/skills/dist/index.js +12 -4
- package/packages/skills/dist/index.js.map +1 -1
- package/packages/skills/dist/sanitize-rules.d.ts +93 -0
- package/packages/skills/dist/sanitize-rules.d.ts.map +1 -0
- package/packages/skills/dist/sanitize-rules.js +173 -0
- package/packages/skills/dist/sanitize-rules.js.map +1 -0
- package/packages/skills/dist/sanitize.d.ts +13 -2
- package/packages/skills/dist/sanitize.d.ts.map +1 -1
- package/packages/skills/dist/sanitize.js +14 -48
- package/packages/skills/dist/sanitize.js.map +1 -1
- package/packages/skills/dist/vector-schema.d.ts +7 -1
- package/packages/skills/dist/vector-schema.d.ts.map +1 -1
- package/packages/skills/dist/vector-schema.js +10 -5
- package/packages/skills/dist/vector-schema.js.map +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/skills/src/index.ts +12 -5
- package/packages/skills/src/sanitize-rules.ts +218 -0
- package/packages/skills/src/sanitize.ts +26 -56
- package/packages/skills/src/vector-schema.ts +22 -14
- package/packages/skills/test/remote-skills.test.ts +33 -6
- package/packages/skills/test/sanitize.test.ts +163 -44
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tooling-preference/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/two-phase-review/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
- package/scripts/sync-to-qdrant.ts +5 -9
|
@@ -13,15 +13,40 @@
|
|
|
13
13
|
* network nor replaces a process-global module.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { describe, expect, it } from "bun:test";
|
|
16
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
20
|
createSkillRegistry,
|
|
20
21
|
type QdrantClientLike,
|
|
21
22
|
type QdrantEmbedderLike,
|
|
22
23
|
} from "../src/loader.js";
|
|
24
|
+
import { resetSanitizationRulesCache } from "../src/sanitize-rules.js";
|
|
23
25
|
import type { Skill } from "../src/types.js";
|
|
24
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The rules of the test.
|
|
29
|
+
*
|
|
30
|
+
* The rules of a client live in a local file, outside the repository. The
|
|
31
|
+
* test uses a fixture with made up names, so that the result of the test
|
|
32
|
+
* does not depend on the machine it runs on.
|
|
33
|
+
*/
|
|
34
|
+
const FIXTURE = fileURLToPath(
|
|
35
|
+
new URL("./fixtures/sanitization.json", import.meta.url),
|
|
36
|
+
);
|
|
37
|
+
const originalEnv = process.env.PI_SKILL_SANITIZATION_FILE;
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
process.env.PI_SKILL_SANITIZATION_FILE = FIXTURE;
|
|
41
|
+
resetSanitizationRulesCache();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
resetSanitizationRulesCache();
|
|
46
|
+
if (originalEnv === undefined) delete process.env.PI_SKILL_SANITIZATION_FILE;
|
|
47
|
+
else process.env.PI_SKILL_SANITIZATION_FILE = originalEnv;
|
|
48
|
+
});
|
|
49
|
+
|
|
25
50
|
/** A point of the vector store. */
|
|
26
51
|
interface VectorPoint {
|
|
27
52
|
id: number;
|
|
@@ -188,7 +213,7 @@ describe("a hit that carries the shared name of a local skill", () => {
|
|
|
188
213
|
embedder: fakeEmbedder,
|
|
189
214
|
collection: "pi-harness-skills-test",
|
|
190
215
|
});
|
|
191
|
-
registry.register(localSkill("
|
|
216
|
+
registry.register(localSkill("acmecorp-pe-approval-workflow"));
|
|
192
217
|
|
|
193
218
|
const results = await registry.findVector("workflow");
|
|
194
219
|
|
|
@@ -196,16 +221,18 @@ describe("a hit that carries the shared name of a local skill", () => {
|
|
|
196
221
|
// The skill of this machine stays a local skill - with its own
|
|
197
222
|
// name and its own body, not the sanitized copy.
|
|
198
223
|
expect(results[0].source).toBe("local");
|
|
199
|
-
expect(results[0].skill.id).toBe("
|
|
200
|
-
expect(results[0].skill.body).toBe(
|
|
224
|
+
expect(results[0].skill.id).toBe("acmecorp-pe-approval-workflow");
|
|
225
|
+
expect(results[0].skill.body).toBe(
|
|
226
|
+
"the local body of acmecorp-pe-approval-workflow",
|
|
227
|
+
);
|
|
201
228
|
});
|
|
202
229
|
|
|
203
230
|
it("resolves the shared name of a local skill in a lookup", () => {
|
|
204
231
|
const registry = createSkillRegistry({ indexer: null });
|
|
205
|
-
registry.register(localSkill("
|
|
232
|
+
registry.register(localSkill("acmecorp-pe-approval-workflow"));
|
|
206
233
|
|
|
207
234
|
expect(registry.get("client-a-pe-approval-workflow")?.id).toBe(
|
|
208
|
-
"
|
|
235
|
+
"acmecorp-pe-approval-workflow",
|
|
209
236
|
);
|
|
210
237
|
});
|
|
211
238
|
});
|
|
@@ -5,29 +5,81 @@
|
|
|
5
5
|
* into it. The rules used to live in `scripts/sync-to-qdrant.ts` - the
|
|
6
6
|
* only writer that could reach them. The runtime registry writes into the
|
|
7
7
|
* same collection, so it needs them too.
|
|
8
|
+
*
|
|
9
|
+
* The rules of the clients are **not** in this repository: it is public,
|
|
10
|
+
* and a list of client names in it is a list of client names in the world.
|
|
11
|
+
* They live in a local file, so the tests use a fixture with made up
|
|
12
|
+
* names and pass the rules in. A test must never read the rules of the
|
|
13
|
+
* machine it runs on - that would make the result of the test depend on
|
|
14
|
+
* the machine.
|
|
8
15
|
*/
|
|
9
16
|
|
|
10
|
-
import { describe, expect, test } from "bun:test";
|
|
17
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
18
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
11
22
|
|
|
12
23
|
import { sanitizeText, skillPointName } from "../src/sanitize.js";
|
|
24
|
+
import {
|
|
25
|
+
loadSanitizationRules,
|
|
26
|
+
resetSanitizationRulesCache,
|
|
27
|
+
sanitizationStatus,
|
|
28
|
+
} from "../src/sanitize-rules.js";
|
|
13
29
|
import { skillPointPayload } from "../src/vector-schema.js";
|
|
14
30
|
|
|
31
|
+
const FIXTURE = fileURLToPath(new URL("./fixtures/sanitization.json", import.meta.url));
|
|
32
|
+
const MISSING = join(tmpdir(), "pi-harness-no-such-sanitization-file.json");
|
|
33
|
+
|
|
34
|
+
const originalEnv = process.env.PI_SKILL_SANITIZATION_FILE;
|
|
35
|
+
|
|
36
|
+
/** The rules of the fixture, as the mechanism reads them. */
|
|
37
|
+
function fixtureRules() {
|
|
38
|
+
resetSanitizationRulesCache();
|
|
39
|
+
process.env.PI_SKILL_SANITIZATION_FILE = FIXTURE;
|
|
40
|
+
const set = loadSanitizationRules();
|
|
41
|
+
resetSanitizationRulesCache();
|
|
42
|
+
return set;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
resetSanitizationRulesCache();
|
|
47
|
+
process.env.PI_SKILL_SANITIZATION_FILE = FIXTURE;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
resetSanitizationRulesCache();
|
|
52
|
+
if (originalEnv === undefined) delete process.env.PI_SKILL_SANITIZATION_FILE;
|
|
53
|
+
else process.env.PI_SKILL_SANITIZATION_FILE = originalEnv;
|
|
54
|
+
});
|
|
55
|
+
|
|
15
56
|
describe("the sanitization of a text", () => {
|
|
16
57
|
test("the name of a client is replaced", () => {
|
|
17
|
-
|
|
18
|
-
expect(sanitizeText("
|
|
19
|
-
|
|
58
|
+
const rules = fixtureRules();
|
|
59
|
+
expect(sanitizeText("the acmecorp workflow", rules)).toBe(
|
|
60
|
+
"the [Client A] workflow",
|
|
61
|
+
);
|
|
62
|
+
expect(sanitizeText("for globex", rules)).toBe("for [Client B]");
|
|
63
|
+
expect(sanitizeText("initech step", rules)).toBe("[Insurance Project] step");
|
|
20
64
|
});
|
|
21
65
|
|
|
22
66
|
test("the name of a client is replaced in any case", () => {
|
|
23
|
-
|
|
67
|
+
const rules = fixtureRules();
|
|
68
|
+
expect(sanitizeText("ACMEcorp and Acmecorp", rules)).toBe(
|
|
69
|
+
"[Client A] and [Client A]",
|
|
70
|
+
);
|
|
24
71
|
});
|
|
25
72
|
|
|
26
73
|
test("a text without a client name stays the same", () => {
|
|
27
|
-
|
|
74
|
+
const rules = fixtureRules();
|
|
75
|
+
expect(sanitizeText("a plain skill", rules)).toBe("a plain skill");
|
|
28
76
|
});
|
|
29
77
|
|
|
30
78
|
test("the generic phrases are replaced", () => {
|
|
79
|
+
// The generic rules hold for every installation, so they work
|
|
80
|
+
// without a local file.
|
|
81
|
+
process.env.PI_SKILL_SANITIZATION_FILE = MISSING;
|
|
82
|
+
resetSanitizationRulesCache();
|
|
31
83
|
expect(sanitizeText("Company Name")).toBe("[Client Name]");
|
|
32
84
|
expect(sanitizeText("your company")).toBe("[Client]");
|
|
33
85
|
expect(sanitizeText("our client")).toBe("[Client]");
|
|
@@ -37,46 +89,53 @@ describe("the sanitization of a text", () => {
|
|
|
37
89
|
// The name of a client rarely stands alone. A word boundary would
|
|
38
90
|
// miss every one of these - and an underscore is a word character,
|
|
39
91
|
// so a boundary never follows one.
|
|
40
|
-
|
|
41
|
-
expect(sanitizeText("
|
|
92
|
+
const rules = fixtureRules();
|
|
93
|
+
expect(sanitizeText("acmecorp_pharma", rules)).toBe("[Client A]_pharma");
|
|
94
|
+
expect(sanitizeText("th_globex_erp_chart.json", rules)).toBe(
|
|
42
95
|
"th_[Client B]_erp_chart.json",
|
|
43
96
|
);
|
|
44
|
-
expect(sanitizeText("apps/
|
|
97
|
+
expect(sanitizeText("apps/acmecorp_pharma/setup", rules)).toBe(
|
|
45
98
|
"apps/[Client A]_pharma/setup",
|
|
46
99
|
);
|
|
47
100
|
});
|
|
48
101
|
|
|
49
102
|
test("a client name in a sentence is replaced", () => {
|
|
50
|
-
|
|
51
|
-
|
|
103
|
+
const rules = fixtureRules();
|
|
104
|
+
expect(sanitizeText("integrated with Globex", rules)).toBe(
|
|
105
|
+
"integrated with [Client B]",
|
|
106
|
+
);
|
|
107
|
+
expect(sanitizeText("Initech secrets", rules)).toBe(
|
|
108
|
+
"[Insurance Project] secrets",
|
|
52
109
|
);
|
|
53
|
-
expect(sanitizeText("OpenClaw secrets")).toBe("[Client F] secrets");
|
|
54
110
|
});
|
|
55
111
|
});
|
|
56
112
|
|
|
57
113
|
describe("the name of a skill in the shared collection", () => {
|
|
58
114
|
test("a name of the map is renamed", () => {
|
|
59
|
-
|
|
115
|
+
const rules = fixtureRules();
|
|
116
|
+
expect(skillPointName("acmecorp-pe-approval-workflow", rules)).toBe(
|
|
60
117
|
"client-a-pe-approval-workflow",
|
|
61
118
|
);
|
|
62
|
-
expect(skillPointName("
|
|
63
|
-
"
|
|
119
|
+
expect(skillPointName("initech-step5-slot-filter", rules)).toBe(
|
|
120
|
+
"insurance-project-step-filter",
|
|
64
121
|
);
|
|
65
|
-
expect(skillPointName("whispertool")).toBe("whisper-tool");
|
|
66
122
|
});
|
|
67
123
|
|
|
68
124
|
test("a name without a client name stays the same", () => {
|
|
69
|
-
|
|
125
|
+
const rules = fixtureRules();
|
|
126
|
+
expect(skillPointName("code-review", rules)).toBe("code-review");
|
|
70
127
|
});
|
|
71
128
|
|
|
72
129
|
test("the name never carries a client name", () => {
|
|
130
|
+
const rules = fixtureRules();
|
|
73
131
|
for (const name of [
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"whispertool",
|
|
132
|
+
"acmecorp-pe-approval-workflow",
|
|
133
|
+
"initech-step5-slot-filter",
|
|
134
|
+
"globex-channel",
|
|
78
135
|
]) {
|
|
79
|
-
expect(skillPointName(name)).not.toMatch(
|
|
136
|
+
expect(skillPointName(name, rules)).not.toMatch(
|
|
137
|
+
/acmecorp|initech|globex/i,
|
|
138
|
+
);
|
|
80
139
|
}
|
|
81
140
|
});
|
|
82
141
|
|
|
@@ -84,48 +143,108 @@ describe("the name of a skill in the shared collection", () => {
|
|
|
84
143
|
// The name of a point is the id of the skill that a search returns,
|
|
85
144
|
// so it has to be a name that a skill may carry.
|
|
86
145
|
const NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
146
|
+
const rules = fixtureRules();
|
|
87
147
|
for (const name of [
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"tbs-import-clearance-lcv",
|
|
92
|
-
"whispertool",
|
|
148
|
+
"acmecorp-pe-approval-workflow",
|
|
149
|
+
"globex-channel",
|
|
150
|
+
"initech-step5-slot-filter",
|
|
93
151
|
"code-review",
|
|
94
152
|
]) {
|
|
95
|
-
expect(skillPointName(name)).toMatch(NAME);
|
|
153
|
+
expect(skillPointName(name, rules)).toMatch(NAME);
|
|
96
154
|
}
|
|
97
155
|
});
|
|
98
156
|
|
|
99
157
|
test("a name that needs no sanitization stays the same", () => {
|
|
100
|
-
|
|
101
|
-
expect(skillPointName("
|
|
158
|
+
const rules = fixtureRules();
|
|
159
|
+
expect(skillPointName("code-review", rules)).toBe("code-review");
|
|
160
|
+
expect(skillPointName("frappe-doctype-field-order", rules)).toBe(
|
|
102
161
|
"frappe-doctype-field-order",
|
|
103
162
|
);
|
|
104
163
|
});
|
|
105
164
|
});
|
|
106
165
|
|
|
166
|
+
describe("the rules of the installation", () => {
|
|
167
|
+
test("a missing file leaves the generic rules", () => {
|
|
168
|
+
process.env.PI_SKILL_SANITIZATION_FILE = MISSING;
|
|
169
|
+
resetSanitizationRulesCache();
|
|
170
|
+
const status = sanitizationStatus();
|
|
171
|
+
expect(status.configured).toBe(false);
|
|
172
|
+
expect(status.ruleCount).toBeGreaterThan(0);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("a broken file is reported and does not take the rules down", () => {
|
|
176
|
+
const dir = mkdtempSync(join(tmpdir(), "pi-harness-sanitization-"));
|
|
177
|
+
const path = join(dir, "rules.json");
|
|
178
|
+
writeFileSync(path, "{ not json");
|
|
179
|
+
process.env.PI_SKILL_SANITIZATION_FILE = path;
|
|
180
|
+
resetSanitizationRulesCache();
|
|
181
|
+
const status = sanitizationStatus();
|
|
182
|
+
expect(status.configured).toBe(false);
|
|
183
|
+
expect(status.error).toContain("not valid JSON");
|
|
184
|
+
// The generic rules still hold.
|
|
185
|
+
expect(sanitizeText("Company Name")).toBe("[Client Name]");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("a broken pattern does not take the other rules down", () => {
|
|
189
|
+
const dir = mkdtempSync(join(tmpdir(), "pi-harness-sanitization-"));
|
|
190
|
+
const path = join(dir, "rules.json");
|
|
191
|
+
writeFileSync(
|
|
192
|
+
path,
|
|
193
|
+
JSON.stringify({
|
|
194
|
+
rules: [
|
|
195
|
+
{ pattern: "acmecorp", replacement: "[Client A]" },
|
|
196
|
+
{ pattern: "([unclosed", replacement: "[Broken]" },
|
|
197
|
+
{ pattern: "globex", replacement: "[Client B]" },
|
|
198
|
+
],
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
process.env.PI_SKILL_SANITIZATION_FILE = path;
|
|
202
|
+
resetSanitizationRulesCache();
|
|
203
|
+
const rules = loadSanitizationRules();
|
|
204
|
+
expect(sanitizeText("acmecorp and globex", rules)).toBe(
|
|
205
|
+
"[Client A] and [Client B]",
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("the local file is read once", () => {
|
|
210
|
+
process.env.PI_SKILL_SANITIZATION_FILE = FIXTURE;
|
|
211
|
+
resetSanitizationRulesCache();
|
|
212
|
+
const first = loadSanitizationRules();
|
|
213
|
+
const second = loadSanitizationRules();
|
|
214
|
+
expect(second).toBe(first);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
107
218
|
describe("the payload of a point is sanitized", () => {
|
|
108
219
|
test("the client names of the body do not travel into the collection", () => {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
220
|
+
const rules = fixtureRules();
|
|
221
|
+
const payload = skillPointPayload(
|
|
222
|
+
{
|
|
223
|
+
name: "acmecorp-pe-approval-workflow",
|
|
224
|
+
description: "the workflow of acmecorp",
|
|
225
|
+
body: "the approval of acmecorp for the client",
|
|
226
|
+
},
|
|
227
|
+
rules,
|
|
228
|
+
);
|
|
114
229
|
|
|
115
230
|
expect(payload.name).toBe("client-a-pe-approval-workflow");
|
|
116
|
-
expect(payload.description).not.toMatch(/
|
|
117
|
-
expect(payload.body).not.toMatch(/
|
|
118
|
-
expect(payload.text).not.toMatch(/
|
|
231
|
+
expect(payload.description).not.toMatch(/acmecorp/i);
|
|
232
|
+
expect(payload.body).not.toMatch(/acmecorp/i);
|
|
233
|
+
expect(payload.text).not.toMatch(/acmecorp/i);
|
|
119
234
|
});
|
|
120
235
|
|
|
121
236
|
test("the text is built from the sanitized parts", () => {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
237
|
+
const rules = fixtureRules();
|
|
238
|
+
const payload = skillPointPayload(
|
|
239
|
+
{
|
|
240
|
+
name: "acmecorp-pe-approval-workflow",
|
|
241
|
+
description: "the workflow",
|
|
242
|
+
body: "the body",
|
|
243
|
+
},
|
|
244
|
+
rules,
|
|
245
|
+
);
|
|
127
246
|
|
|
128
247
|
expect(payload.text).toContain("client-a-pe-approval-workflow");
|
|
129
|
-
expect(payload.text).not.toContain("
|
|
248
|
+
expect(payload.text).not.toContain("acmecorp-pe-approval-workflow");
|
|
130
249
|
});
|
|
131
250
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/two-phase-review",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.423",
|
|
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",
|
|
@@ -352,15 +352,11 @@ Sync Skills to Qdrant (Sanitized)
|
|
|
352
352
|
Upload skills to Qdrant for team sharing.
|
|
353
353
|
Client-specific names are REPLACED with placeholders.
|
|
354
354
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
paperclip → [Client D]
|
|
361
|
-
teamw → [Client E]
|
|
362
|
-
openclaw → [Client F]
|
|
363
|
-
autoresearch → [Internal Tool]
|
|
355
|
+
The rules live in the local file of the installation:
|
|
356
|
+
~/.pi-harness-runtime/skill-sanitization.json
|
|
357
|
+
They are not in this repository - it is public, and a list of client names
|
|
358
|
+
in it is a list of client names in the world. Set
|
|
359
|
+
PI_SKILL_SANITIZATION_FILE to use another file.
|
|
364
360
|
|
|
365
361
|
Usage:
|
|
366
362
|
bun scripts/sync-to-qdrant.ts --from <dir> Sync skills from directory
|