pi-harness-runtime 1.1.422 → 1.1.424
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/README.md +1 -1
- package/harness/skills-plan/2026-07-12-herdr-moo-skills-adaptation-plan.md +9 -6
- package/index.ts +32 -1
- package/package.json +2 -6
- 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/package.json +1 -1
- 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 +174 -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 +219 -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/plugins/herdr-clipboard/paste.sh +28 -0
- package/scripts/copy-plugins.js +9 -5
- package/scripts/sync-to-qdrant.ts +5 -9
- package/scripts/verify-package-contents.ts +124 -1
- package/skills/harness-runtime/SKILL.md +0 -300
- /package/{.pi/plugins → plugins}/herdr-clipboard/herdr-plugin.toml +0 -0
- /package/{.pi/plugins → plugins}/herdr-clipboard/start-bridge.sh +0 -0
- /package/{.pi/plugins → plugins}/herdr-clipboard/tmux-watch.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/provider-router",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.424",
|
|
4
4
|
"description": "Enhanced Provider Router for pi-harness-runtime — intelligent routing with capabilities, costs, and quotas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/provider-router.js",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAExE,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAExE,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAKzE;;;;;;GAMG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,kDAAkD;IAClD,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,MAAM,CAAC,EAAE,OAAO,CACd,YAAY,GAAG;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CACF,GACA,gBAAgB,CA+BlB;AA8BD;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;EAyB/B;AAGD,eAAO,MAAM,oBAAoB,EAAE,YAYlC,CAAC"}
|
|
@@ -21,6 +21,9 @@ export * from "./skill-versioning.js";
|
|
|
21
21
|
export * from "./linter.js";
|
|
22
22
|
import { scanForSkillsSync } from "./scanner.js";
|
|
23
23
|
import { getGlobalSkillRegistry } from "./loader.js";
|
|
24
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
25
|
+
import { homedir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
24
27
|
/**
|
|
25
28
|
* Initialize skills system
|
|
26
29
|
*
|
|
@@ -46,14 +49,19 @@ export function initSkills(config) {
|
|
|
46
49
|
}
|
|
47
50
|
// Hint: if ~/.pi-harness-runtime/skills/ is empty, suggest the sync script
|
|
48
51
|
checkEmptySkillsDir();
|
|
49
|
-
|
|
52
|
+
// The scan can find the same skill twice: a symlinked directory is
|
|
53
|
+
// scanned twice, because the scanner follows the path it is given. The
|
|
54
|
+
// registry keeps one entry per id, so the count of the local skills is
|
|
55
|
+
// the count of the DISTINCT skills - and not the count of the files
|
|
56
|
+
// that were read.
|
|
57
|
+
const distinct = new Map();
|
|
58
|
+
for (const skill of result.skills)
|
|
59
|
+
distinct.set(skill.id, skill);
|
|
60
|
+
return { ...result, skills: [...distinct.values()], registry };
|
|
50
61
|
}
|
|
51
62
|
/** Show sync hint if the harness skills dir is empty. */
|
|
52
63
|
function checkEmptySkillsDir() {
|
|
53
64
|
try {
|
|
54
|
-
const { readdirSync, existsSync } = require("node:fs");
|
|
55
|
-
const { join } = require("node:path");
|
|
56
|
-
const { homedir } = require("node:os");
|
|
57
65
|
const harnessDir = join(homedir(), ".pi-harness-runtime", "skills");
|
|
58
66
|
if (!existsSync(harnessDir))
|
|
59
67
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wBAAwB;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAsB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rules that keep a client name out of the shared collection.
|
|
3
|
+
*
|
|
4
|
+
* The names of the clients of the users of the harness are **not** in this
|
|
5
|
+
* repository. The repository is public, and a list of client names in it
|
|
6
|
+
* is a list of client names in the world - the names of the projects and
|
|
7
|
+
* of the clients of every person who installs the package.
|
|
8
|
+
*
|
|
9
|
+
* The rules therefore live in a local file:
|
|
10
|
+
*
|
|
11
|
+
* ~/.pi-harness-runtime/skill-sanitization.json
|
|
12
|
+
*
|
|
13
|
+
* and this module is the mechanism that reads them and applies them. The
|
|
14
|
+
* file is per installation, so a machine holds the rules of its own
|
|
15
|
+
* clients and nobody else's.
|
|
16
|
+
*
|
|
17
|
+
* The file is optional. Without it only the generic rules apply, and the
|
|
18
|
+
* name of a client would travel into the collection of that installation.
|
|
19
|
+
* `sanitizationStatus()` tells the caller which of the two is the case,
|
|
20
|
+
* so a missing file is a visible state and not a silent one.
|
|
21
|
+
*
|
|
22
|
+
* The format of the file:
|
|
23
|
+
*
|
|
24
|
+
* ```json
|
|
25
|
+
* {
|
|
26
|
+
* "rules": [
|
|
27
|
+
* { "pattern": "acme", "replacement": "[Client A]", "flags": "gi" }
|
|
28
|
+
* ],
|
|
29
|
+
* "nameMap": {
|
|
30
|
+
* "acme-approval-workflow": "client-a-approval-workflow"
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The pattern is the source of a regular expression and the flags default
|
|
36
|
+
* to "gi". The rules match a plain fragment, without a word boundary: a
|
|
37
|
+
* client name rarely stands alone, it appears inside a directory name
|
|
38
|
+
* (`erp_report_2024.json`), inside a module name (`acme_pharma`) or in a
|
|
39
|
+
* sentence ("integrated with Acme"). A word boundary would miss all of
|
|
40
|
+
* them - and `_` is a word character, so a boundary never follows an
|
|
41
|
+
* underscore.
|
|
42
|
+
*/
|
|
43
|
+
/** A rule as it is written in the local file. */
|
|
44
|
+
export interface SanitizationRuleSpec {
|
|
45
|
+
/** The source of a regular expression. */
|
|
46
|
+
pattern: string;
|
|
47
|
+
/** What a match becomes. */
|
|
48
|
+
replacement: string;
|
|
49
|
+
/** The flags of the regular expression. Defaults to "gi". */
|
|
50
|
+
flags?: string;
|
|
51
|
+
}
|
|
52
|
+
/** A compiled rule. */
|
|
53
|
+
export interface SanitizationRule {
|
|
54
|
+
pattern: RegExp;
|
|
55
|
+
replacement: string;
|
|
56
|
+
}
|
|
57
|
+
/** The whole rule set of one installation. */
|
|
58
|
+
export interface SanitizationRuleSet {
|
|
59
|
+
/** The rules, in the order they are applied. */
|
|
60
|
+
rules: SanitizationRule[];
|
|
61
|
+
/** The names that are renamed as a whole. */
|
|
62
|
+
nameMap: Record<string, string>;
|
|
63
|
+
/** Where the rules came from. */
|
|
64
|
+
source: "local-file" | "generic-only";
|
|
65
|
+
/** Why the local file did not contribute its rules. */
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Where the rules of this installation live. */
|
|
69
|
+
export declare function sanitizationFilePath(): string;
|
|
70
|
+
/**
|
|
71
|
+
* The state of the rules of this installation.
|
|
72
|
+
*
|
|
73
|
+
* `configured` is false when the local file is missing or unreadable. The
|
|
74
|
+
* caller shows it, because a missing file is a weaker privacy guarantee
|
|
75
|
+
* and not a detail.
|
|
76
|
+
*/
|
|
77
|
+
export declare function sanitizationStatus(): {
|
|
78
|
+
configured: boolean;
|
|
79
|
+
path: string;
|
|
80
|
+
ruleCount: number;
|
|
81
|
+
error?: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The rules of this installation.
|
|
85
|
+
*
|
|
86
|
+
* The file is read once per process: the rules do not change while the
|
|
87
|
+
* harness runs, and a skill that is indexed a hundred times must not read
|
|
88
|
+
* a file a hundred times.
|
|
89
|
+
*/
|
|
90
|
+
export declare function loadSanitizationRules(path?: string): SanitizationRuleSet;
|
|
91
|
+
/** Forget the cached rules. A test needs it, a new file needs it. */
|
|
92
|
+
export declare function resetSanitizationRulesCache(): void;
|
|
93
|
+
//# sourceMappingURL=sanitize-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-rules.d.ts","sourceRoot":"","sources":["../src/sanitize-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAMH,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uBAAuB;AACvB,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iCAAiC;IACjC,MAAM,EAAE,YAAY,GAAG,cAAc,CAAC;IACtC,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2BD,iDAAiD;AACjD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CASA;AAID;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,SAAyB,GAAG,mBAAmB,CAMxF;AAED,qEAAqE;AACrE,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rules that keep a client name out of the shared collection.
|
|
3
|
+
*
|
|
4
|
+
* The names of the clients of the users of the harness are **not** in this
|
|
5
|
+
* repository. The repository is public, and a list of client names in it
|
|
6
|
+
* is a list of client names in the world - the names of the projects and
|
|
7
|
+
* of the clients of every person who installs the package.
|
|
8
|
+
*
|
|
9
|
+
* The rules therefore live in a local file:
|
|
10
|
+
*
|
|
11
|
+
* ~/.pi-harness-runtime/skill-sanitization.json
|
|
12
|
+
*
|
|
13
|
+
* and this module is the mechanism that reads them and applies them. The
|
|
14
|
+
* file is per installation, so a machine holds the rules of its own
|
|
15
|
+
* clients and nobody else's.
|
|
16
|
+
*
|
|
17
|
+
* The file is optional. Without it only the generic rules apply, and the
|
|
18
|
+
* name of a client would travel into the collection of that installation.
|
|
19
|
+
* `sanitizationStatus()` tells the caller which of the two is the case,
|
|
20
|
+
* so a missing file is a visible state and not a silent one.
|
|
21
|
+
*
|
|
22
|
+
* The format of the file:
|
|
23
|
+
*
|
|
24
|
+
* ```json
|
|
25
|
+
* {
|
|
26
|
+
* "rules": [
|
|
27
|
+
* { "pattern": "acme", "replacement": "[Client A]", "flags": "gi" }
|
|
28
|
+
* ],
|
|
29
|
+
* "nameMap": {
|
|
30
|
+
* "acme-approval-workflow": "client-a-approval-workflow"
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The pattern is the source of a regular expression and the flags default
|
|
36
|
+
* to "gi". The rules match a plain fragment, without a word boundary: a
|
|
37
|
+
* client name rarely stands alone, it appears inside a directory name
|
|
38
|
+
* (`erp_report_2024.json`), inside a module name (`acme_pharma`) or in a
|
|
39
|
+
* sentence ("integrated with Acme"). A word boundary would miss all of
|
|
40
|
+
* them - and `_` is a word character, so a boundary never follows an
|
|
41
|
+
* underscore.
|
|
42
|
+
*/
|
|
43
|
+
import { readFileSync } from "node:fs";
|
|
44
|
+
import { homedir } from "node:os";
|
|
45
|
+
import { join } from "node:path";
|
|
46
|
+
/**
|
|
47
|
+
* The rules that hold for every installation.
|
|
48
|
+
*
|
|
49
|
+
* They are about the way a text talks about a client, not about the name
|
|
50
|
+
* of a client: "Company Name" is a placeholder in a template, and it
|
|
51
|
+
* must not become a client name in the collection.
|
|
52
|
+
*/
|
|
53
|
+
const GENERIC_RULES = [
|
|
54
|
+
{ pattern: /Company Name/gi, replacement: "[Client Name]" },
|
|
55
|
+
{ pattern: /your company/gi, replacement: "[Client]" },
|
|
56
|
+
{ pattern: /our client/gi, replacement: "[Client]" },
|
|
57
|
+
{ pattern: /client-specific/gi, replacement: "[Project-specific]" },
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* The names that are renamed as a whole, for every installation.
|
|
61
|
+
*
|
|
62
|
+
* A name that would be unreadable after the pattern rules - a name that
|
|
63
|
+
* carries the client name in its middle - is renamed here.
|
|
64
|
+
*
|
|
65
|
+
* The map is empty: a name that belongs to a client is that client's, so it
|
|
66
|
+
* lives in the local file next to the other rules of the installation.
|
|
67
|
+
*/
|
|
68
|
+
const GENERIC_NAME_MAP = {};
|
|
69
|
+
/** Where the rules of this installation live. */
|
|
70
|
+
export function sanitizationFilePath() {
|
|
71
|
+
const override = process.env.PI_SKILL_SANITIZATION_FILE;
|
|
72
|
+
if (override && override.trim())
|
|
73
|
+
return override.trim();
|
|
74
|
+
const home = process.env.HOME || process.env.USERPROFILE || homedir();
|
|
75
|
+
return join(home, ".pi-harness-runtime", "skill-sanitization.json");
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The state of the rules of this installation.
|
|
79
|
+
*
|
|
80
|
+
* `configured` is false when the local file is missing or unreadable. The
|
|
81
|
+
* caller shows it, because a missing file is a weaker privacy guarantee
|
|
82
|
+
* and not a detail.
|
|
83
|
+
*/
|
|
84
|
+
export function sanitizationStatus() {
|
|
85
|
+
const path = sanitizationFilePath();
|
|
86
|
+
const set = loadSanitizationRules(path);
|
|
87
|
+
return {
|
|
88
|
+
configured: set.source === "local-file",
|
|
89
|
+
path,
|
|
90
|
+
ruleCount: set.rules.length,
|
|
91
|
+
...(set.error ? { error: set.error } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
let cached;
|
|
95
|
+
/**
|
|
96
|
+
* The rules of this installation.
|
|
97
|
+
*
|
|
98
|
+
* The file is read once per process: the rules do not change while the
|
|
99
|
+
* harness runs, and a skill that is indexed a hundred times must not read
|
|
100
|
+
* a file a hundred times.
|
|
101
|
+
*/
|
|
102
|
+
export function loadSanitizationRules(path = sanitizationFilePath()) {
|
|
103
|
+
if (cached && cached.path === path)
|
|
104
|
+
return cached.set;
|
|
105
|
+
const set = readSanitizationRules(path);
|
|
106
|
+
cached = { path, set };
|
|
107
|
+
return set;
|
|
108
|
+
}
|
|
109
|
+
/** Forget the cached rules. A test needs it, a new file needs it. */
|
|
110
|
+
export function resetSanitizationRulesCache() {
|
|
111
|
+
cached = undefined;
|
|
112
|
+
}
|
|
113
|
+
function readSanitizationRules(path) {
|
|
114
|
+
let raw;
|
|
115
|
+
try {
|
|
116
|
+
raw = readFileSync(path, "utf8");
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
const code = err?.code;
|
|
120
|
+
if (code !== "ENOENT") {
|
|
121
|
+
return {
|
|
122
|
+
rules: [...GENERIC_RULES],
|
|
123
|
+
nameMap: { ...GENERIC_NAME_MAP },
|
|
124
|
+
source: "generic-only",
|
|
125
|
+
error: `The sanitization rules at ${path} could not be read: ${err instanceof Error ? err.message : String(err)}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
rules: [...GENERIC_RULES],
|
|
130
|
+
nameMap: { ...GENERIC_NAME_MAP },
|
|
131
|
+
source: "generic-only",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(raw);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
return {
|
|
140
|
+
rules: [...GENERIC_RULES],
|
|
141
|
+
nameMap: { ...GENERIC_NAME_MAP },
|
|
142
|
+
source: "generic-only",
|
|
143
|
+
error: `The sanitization rules at ${path} are not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const rules = [...GENERIC_RULES];
|
|
147
|
+
const nameMap = { ...GENERIC_NAME_MAP };
|
|
148
|
+
const file = parsed;
|
|
149
|
+
for (const spec of file.rules ?? []) {
|
|
150
|
+
if (!spec || typeof spec.pattern !== "string" || typeof spec.replacement !== "string") {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
rules.push({
|
|
155
|
+
pattern: new RegExp(spec.pattern, spec.flags ?? "gi"),
|
|
156
|
+
replacement: spec.replacement,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// A broken pattern must not take the whole rule set down: the other
|
|
161
|
+
// rules still hold, and the broken one is reported below.
|
|
162
|
+
rules.push({
|
|
163
|
+
pattern: /$^/,
|
|
164
|
+
replacement: spec.replacement,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const [from, to] of Object.entries(file.nameMap ?? {})) {
|
|
169
|
+
if (typeof from === "string" && typeof to === "string")
|
|
170
|
+
nameMap[from] = to;
|
|
171
|
+
}
|
|
172
|
+
return { rules, nameMap, source: "local-file" };
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=sanitize-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-rules.js","sourceRoot":"","sources":["../src/sanitize-rules.ts"],"names":[],"mappings":"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"}
|