promptkaizen-agent 0.1.0 → 0.2.0

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 (43) hide show
  1. package/README.md +5 -3
  2. package/dist/cli/init.d.ts.map +1 -1
  3. package/dist/cli/init.js +4 -1
  4. package/dist/cli/init.js.map +1 -1
  5. package/dist/cli/install-systemd.d.ts +17 -0
  6. package/dist/cli/install-systemd.d.ts.map +1 -0
  7. package/dist/cli/install-systemd.js +96 -0
  8. package/dist/cli/install-systemd.js.map +1 -0
  9. package/dist/cli/start.d.ts.map +1 -1
  10. package/dist/cli/start.js +43 -2
  11. package/dist/cli/start.js.map +1 -1
  12. package/dist/cli/status.d.ts.map +1 -1
  13. package/dist/cli/status.js +24 -2
  14. package/dist/cli/status.js.map +1 -1
  15. package/dist/cli/uninstall-systemd.d.ts +8 -0
  16. package/dist/cli/uninstall-systemd.d.ts.map +1 -0
  17. package/dist/cli/uninstall-systemd.js +58 -0
  18. package/dist/cli/uninstall-systemd.js.map +1 -0
  19. package/dist/config.d.ts +61 -0
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +31 -1
  22. package/dist/config.js.map +1 -1
  23. package/dist/detection-secret.d.ts +8 -0
  24. package/dist/detection-secret.d.ts.map +1 -0
  25. package/dist/detection-secret.js +37 -0
  26. package/dist/detection-secret.js.map +1 -0
  27. package/dist/index.js +13 -5
  28. package/dist/index.js.map +1 -1
  29. package/dist/mask-rules-fetcher.d.ts +15 -0
  30. package/dist/mask-rules-fetcher.d.ts.map +1 -0
  31. package/dist/mask-rules-fetcher.js +67 -0
  32. package/dist/mask-rules-fetcher.js.map +1 -0
  33. package/dist/pii-masker.d.ts +48 -1
  34. package/dist/pii-masker.d.ts.map +1 -1
  35. package/dist/pii-masker.js +144 -41
  36. package/dist/pii-masker.js.map +1 -1
  37. package/dist/secret-detector.d.ts +82 -0
  38. package/dist/secret-detector.d.ts.map +1 -0
  39. package/dist/secret-detector.js +400 -0
  40. package/dist/secret-detector.js.map +1 -0
  41. package/dist/types.d.ts +12 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * HMAC 鍵を解決する。優先順:
3
+ * 1. agent 設定 `detection.hmacSecret`
4
+ * 2. 既存の鍵ファイル (~/.promptkaizen/detection-secret)
5
+ * 3. 初回起動時に生成して同ファイルへ保存 (mode 600)
6
+ */
7
+ export declare function loadOrCreateDetectionSecret(configSecret?: string, secretPath?: string): Promise<string>;
8
+ //# sourceMappingURL=detection-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection-secret.d.ts","sourceRoot":"","sources":["../src/detection-secret.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,YAAY,CAAC,EAAE,MAAM,EACrB,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadOrCreateDetectionSecret = loadOrCreateDetectionSecret;
7
+ const crypto_1 = require("crypto");
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const path_1 = __importDefault(require("path"));
11
+ // pii/pii_jp の matchHash (HMAC-SHA256) に使うローカルシークレット (Issue #42)。
12
+ // マイナンバー等の低エントロピー値を無塩ハッシュで送ると総当たりで復元できてしまう
13
+ // ため、鍵付きハッシュにする。鍵はローカルにのみ保持し、クラウドへは送らない。
14
+ const DEFAULT_SECRET_PATH = path_1.default.join(os_1.default.homedir(), '.promptkaizen', 'detection-secret');
15
+ /**
16
+ * HMAC 鍵を解決する。優先順:
17
+ * 1. agent 設定 `detection.hmacSecret`
18
+ * 2. 既存の鍵ファイル (~/.promptkaizen/detection-secret)
19
+ * 3. 初回起動時に生成して同ファイルへ保存 (mode 600)
20
+ */
21
+ async function loadOrCreateDetectionSecret(configSecret, secretPath = DEFAULT_SECRET_PATH) {
22
+ if (configSecret)
23
+ return configSecret;
24
+ try {
25
+ const existing = (await promises_1.default.readFile(secretPath, 'utf8')).trim();
26
+ if (existing.length >= 32)
27
+ return existing;
28
+ }
29
+ catch {
30
+ // ファイルなし (初回起動) → 下で生成する
31
+ }
32
+ const secret = (0, crypto_1.randomBytes)(32).toString('hex');
33
+ await promises_1.default.mkdir(path_1.default.dirname(secretPath), { recursive: true });
34
+ await promises_1.default.writeFile(secretPath, secret + '\n', { mode: 0o600 });
35
+ return secret;
36
+ }
37
+ //# sourceMappingURL=detection-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection-secret.js","sourceRoot":"","sources":["../src/detection-secret.ts"],"names":[],"mappings":";;;;;AAiBA,kEAeC;AAhCD,mCAAoC;AACpC,2DAA4B;AAC5B,4CAAmB;AACnB,gDAAuB;AAEvB,kEAAkE;AAClE,2CAA2C;AAC3C,yCAAyC;AAEzC,MAAM,mBAAmB,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAA;AAExF;;;;;GAKG;AACI,KAAK,UAAU,2BAA2B,CAC/C,YAAqB,EACrB,aAAqB,mBAAmB;IAExC,IAAI,YAAY;QAAE,OAAO,YAAY,CAAA;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,kBAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAC/D,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE;YAAE,OAAO,QAAQ,CAAA;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;IAC3B,CAAC;IACD,MAAM,MAAM,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC9C,MAAM,kBAAE,CAAC,KAAK,CAAC,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7D,MAAM,kBAAE,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC9D,OAAO,MAAM,CAAA;AACf,CAAC"}
package/dist/index.js CHANGED
@@ -3,9 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const init_1 = require("./cli/init");
5
5
  const install_launchd_1 = require("./cli/install-launchd");
6
+ const install_systemd_1 = require("./cli/install-systemd");
6
7
  const start_1 = require("./cli/start");
7
8
  const status_1 = require("./cli/status");
8
9
  const uninstall_launchd_1 = require("./cli/uninstall-launchd");
10
+ const uninstall_systemd_1 = require("./cli/uninstall-systemd");
9
11
  const version_1 = require("./version");
10
12
  const HELP = `promptkaizen-agent v${version_1.AGENT_VERSION}
11
13
 
@@ -18,17 +20,19 @@ Usage:
18
20
 
19
21
  Subcommands:
20
22
  init Interactive setup — write ~/.promptkaizen/agent.config.json
21
- start Run the agent in the foreground (used by launchd too)
22
- status Health check: config, plist, process, offsets, endpoint
23
- install-launchd Register a macOS LaunchAgent — auto-start on login + auto-restart
24
- uninstall-launchd Remove the LaunchAgent (config/offsets preserved)
23
+ start Run the agent in the foreground (used by launchd/systemd too)
24
+ status Health check: config, autostart, process, offsets, endpoint
25
+ install-launchd [macOS] Register a LaunchAgent — auto-start on login + auto-restart
26
+ uninstall-launchd [macOS] Remove the LaunchAgent (config/offsets preserved)
27
+ install-systemd [Linux] Register a systemd user unit — auto-start + auto-restart
28
+ uninstall-systemd [Linux] Remove the systemd user unit (config/offsets preserved)
25
29
  version Print agent version
26
30
  help Print this message
27
31
 
28
32
  Examples:
29
33
  npm link # one-time, from repo root after build
30
34
  promptkaizen-agent init
31
- promptkaizen-agent install-launchd
35
+ promptkaizen-agent install-launchd # macOS (Linux: install-systemd)
32
36
  promptkaizen-agent status
33
37
  `;
34
38
  async function main() {
@@ -44,6 +48,10 @@ async function main() {
44
48
  return (0, install_launchd_1.runInstallLaunchd)(rest);
45
49
  case 'uninstall-launchd':
46
50
  return (0, uninstall_launchd_1.runUninstallLaunchd)(rest);
51
+ case 'install-systemd':
52
+ return (0, install_systemd_1.runInstallSystemd)(rest);
53
+ case 'uninstall-systemd':
54
+ return (0, uninstall_systemd_1.runUninstallSystemd)(rest);
47
55
  case 'version':
48
56
  case '--version':
49
57
  case '-v':
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,qCAAoC;AACpC,2DAAyD;AACzD,uCAAsC;AACtC,yCAAwC;AACxC,+DAA6D;AAC7D,uCAAyC;AAEzC,MAAM,IAAI,GAAG,uBAAuB,uBAAa;;;;;;;;;;;;;;;;;;;;;;;CAuBhD,CAAA;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC5C,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,IAAA,cAAO,EAAC,IAAI,CAAC,CAAA;QACtB,KAAK,OAAO;YACV,OAAO,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAA;QACvB,KAAK,QAAQ;YACX,OAAO,IAAA,kBAAS,EAAC,IAAI,CAAC,CAAA;QACxB,KAAK,iBAAiB;YACpB,OAAO,IAAA,mCAAiB,EAAC,IAAI,CAAC,CAAA;QAChC,KAAK,mBAAmB;YACtB,OAAO,IAAA,uCAAmB,EAAC,IAAI,CAAC,CAAA;QAClC,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,uBAAa,CAAC,CAAA;YAC1B,OAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjB,OAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAA;YAC7C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACtC,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC9D,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,qCAAoC;AACpC,2DAAyD;AACzD,2DAAyD;AACzD,uCAAsC;AACtC,yCAAwC;AACxC,+DAA6D;AAC7D,+DAA6D;AAC7D,uCAAyC;AAEzC,MAAM,IAAI,GAAG,uBAAuB,uBAAa;;;;;;;;;;;;;;;;;;;;;;;;;CAyBhD,CAAA;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC5C,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,IAAA,cAAO,EAAC,IAAI,CAAC,CAAA;QACtB,KAAK,OAAO;YACV,OAAO,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAA;QACvB,KAAK,QAAQ;YACX,OAAO,IAAA,kBAAS,EAAC,IAAI,CAAC,CAAA;QACxB,KAAK,iBAAiB;YACpB,OAAO,IAAA,mCAAiB,EAAC,IAAI,CAAC,CAAA;QAChC,KAAK,mBAAmB;YACtB,OAAO,IAAA,uCAAmB,EAAC,IAAI,CAAC,CAAA;QAClC,KAAK,iBAAiB;YACpB,OAAO,IAAA,mCAAiB,EAAC,IAAI,CAAC,CAAA;QAChC,KAAK,mBAAmB;YACtB,OAAO,IAAA,uCAAmB,EAAC,IAAI,CAAC,CAAA;QAClC,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,uBAAa,CAAC,CAAA;YAC1B,OAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjB,OAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAA;YAC7C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACtC,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC9D,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ import type { MaskRulesConfig } from './pii-masker';
2
+ /** receiveObservations と同じ apiKey/endpoint pattern で /getAgentMaskRules を導出。 */
3
+ export declare function maskRulesUrl(apiEndpoint: string): string;
4
+ export interface FetchMaskRulesOptions {
5
+ apiEndpoint: string;
6
+ apiKey: string;
7
+ fetchImpl?: typeof fetch;
8
+ }
9
+ /**
10
+ * 組織/ユーザーのマスクルールを取得する。
11
+ * - 未設定 (cloud に doc がない) → null (ローカル設定のみで動作)
12
+ * - 通信エラー / 不正レスポンス → null + warn log (検知・送信は止めない)
13
+ */
14
+ export declare function fetchMaskRules(opts: FetchMaskRulesOptions): Promise<MaskRulesConfig | null>;
15
+ //# sourceMappingURL=mask-rules-fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-rules-fetcher.d.ts","sourceRoot":"","sources":["../src/mask-rules-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWnD,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAsBD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAuBjG"}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maskRulesUrl = maskRulesUrl;
4
+ exports.fetchMaskRules = fetchMaskRules;
5
+ const zod_1 = require("zod");
6
+ const logger_1 = require("./logger");
7
+ // =============================================
8
+ // 組織マスクルールの取得 (Issue #43)
9
+ // =============================================
10
+ //
11
+ // cloud (functions/src/agent/maskRules.ts getAgentMaskRules) から組織/ユーザーの
12
+ // マスクルールを取得する。認証は receiveObservations / agentHeartbeat と同じ
13
+ // Bearer apiKey。取得できない場合は null を返し、agent はローカル設定のみで
14
+ // 動作する (マスキング適用自体はローカル完結を維持)。
15
+ /** receiveObservations と同じ apiKey/endpoint pattern で /getAgentMaskRules を導出。 */
16
+ function maskRulesUrl(apiEndpoint) {
17
+ return apiEndpoint.replace(/\/receiveObservations\/?$/, '/getAgentMaskRules');
18
+ }
19
+ // cloud 側 (functions/src/agent/maskRules.ts) の schema と整合させること。
20
+ const MaskRulesSchema = zod_1.z.object({
21
+ builtin: zod_1.z.object({
22
+ maskApiKeys: zod_1.z.boolean(),
23
+ maskFilePaths: zod_1.z.boolean(),
24
+ maskEmails: zod_1.z.boolean(),
25
+ }),
26
+ customRules: zod_1.z
27
+ .array(zod_1.z.object({
28
+ ruleId: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,50}$/),
29
+ pattern: zod_1.z.string().min(1).max(500),
30
+ replacement: zod_1.z.string().max(100),
31
+ enabled: zod_1.z.boolean(),
32
+ }))
33
+ .max(100),
34
+ updatedAt: zod_1.z.number().optional(),
35
+ });
36
+ /**
37
+ * 組織/ユーザーのマスクルールを取得する。
38
+ * - 未設定 (cloud に doc がない) → null (ローカル設定のみで動作)
39
+ * - 通信エラー / 不正レスポンス → null + warn log (検知・送信は止めない)
40
+ */
41
+ async function fetchMaskRules(opts) {
42
+ const doFetch = opts.fetchImpl ?? fetch;
43
+ try {
44
+ const res = await doFetch(maskRulesUrl(opts.apiEndpoint), {
45
+ method: 'GET',
46
+ headers: { Authorization: `Bearer ${opts.apiKey}` },
47
+ });
48
+ if (!res.ok) {
49
+ logger_1.logger.warn('fetchMaskRules: non-OK response', { status: res.status });
50
+ return null;
51
+ }
52
+ const body = (await res.json());
53
+ if (!body.success || body.rules == null)
54
+ return null;
55
+ const parsed = MaskRulesSchema.safeParse(body.rules);
56
+ if (!parsed.success) {
57
+ logger_1.logger.warn('fetchMaskRules: invalid rules payload', { error: parsed.error.message });
58
+ return null;
59
+ }
60
+ return parsed.data;
61
+ }
62
+ catch (e) {
63
+ logger_1.logger.warn('fetchMaskRules failed', { error: e.message });
64
+ return null;
65
+ }
66
+ }
67
+ //# sourceMappingURL=mask-rules-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-rules-fetcher.js","sourceRoot":"","sources":["../src/mask-rules-fetcher.ts"],"names":[],"mappings":";;AAcA,oCAEC;AAiCD,wCAuBC;AAxED,6BAAuB;AACvB,qCAAiC;AAGjC,gDAAgD;AAChD,0BAA0B;AAC1B,gDAAgD;AAChD,EAAE;AACF,wEAAwE;AACxE,2DAA2D;AAC3D,oDAAoD;AACpD,8BAA8B;AAE9B,gFAAgF;AAChF,SAAgB,YAAY,CAAC,WAAmB;IAC9C,OAAO,WAAW,CAAC,OAAO,CAAC,2BAA2B,EAAE,oBAAoB,CAAC,CAAA;AAC/E,CAAC;AAED,gEAAgE;AAChE,MAAM,eAAe,GAAG,OAAC,CAAC,MAAM,CAAC;IAC/B,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC;QAChB,WAAW,EAAE,OAAC,CAAC,OAAO,EAAE;QACxB,aAAa,EAAE,OAAC,CAAC,OAAO,EAAE;QAC1B,UAAU,EAAE,OAAC,CAAC,OAAO,EAAE;KACxB,CAAC;IACF,WAAW,EAAE,OAAC;SACX,KAAK,CACJ,OAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,uBAAuB,CAAC;QACjD,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACnC,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;QAChC,OAAO,EAAE,OAAC,CAAC,OAAO,EAAE;KACrB,CAAC,CACH;SACA,GAAG,CAAC,GAAG,CAAC;IACX,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAA;AAQF;;;;GAIG;AACI,KAAK,UAAU,cAAc,CAAC,IAA2B;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;YACxD,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE;SACpD,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,eAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;YACtE,OAAO,IAAI,CAAA;QACb,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA2C,CAAA;QACzE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;QACpD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,eAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;YACrF,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAA;IACpB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,eAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;QACrE,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -1,10 +1,55 @@
1
1
  import type { AgentConfig } from './config';
2
2
  import type { ParsedEntry } from './types';
3
+ /** ファイルパス / 画像など、正規表現グループ外の構造的ルールの ruleId。 */
4
+ export declare const RULE_ID_FILE_PATH = "file_path";
5
+ export declare const RULE_ID_EMAIL = "email";
6
+ export declare const RULE_ID_IMAGE = "image_base64";
7
+ /** 1 entry あたりの MaskStat 上限 (detections の MAX_DETECTIONS_PER_ENTRY と同思想)。 */
8
+ export declare const MAX_MASK_STATS_PER_ENTRY = 50;
9
+ /** ルールごとのマスク実績 (生値は持たない。件数のみ)。 */
10
+ export interface MaskStat {
11
+ ruleId: string;
12
+ count: number;
13
+ }
14
+ export interface CustomMaskRule {
15
+ /** 英数字・ハイフン・アンダースコアのみ (Firestore field path 安全性のため)。 */
16
+ ruleId: string;
17
+ /** 正規表現文字列 (global flag は自動付与)。 */
18
+ pattern: string;
19
+ /** マスク後の文字列 (literal 置換。$1 等のグループ参照は使えない)。 */
20
+ replacement: string;
21
+ enabled: boolean;
22
+ }
23
+ export interface MaskRulesConfig {
24
+ builtin: {
25
+ maskApiKeys: boolean;
26
+ maskFilePaths: boolean;
27
+ maskEmails: boolean;
28
+ };
29
+ customRules: CustomMaskRule[];
30
+ updatedAt?: number;
31
+ }
32
+ /** 適用時の実効設定。ローカル設定と組織ルール (remote) をマージした結果。 */
33
+ export interface EffectiveMaskConfig {
34
+ maskApiKeys: boolean;
35
+ maskFilePaths: boolean;
36
+ maskEmails: boolean;
37
+ customRules: CustomMaskRule[];
38
+ }
39
+ /**
40
+ * ローカル設定 (agent.config.json の pii) と組織ルール (cloud 配信) をマージする。
41
+ * - builtin トグルは組織ルールがあればそちらを正とする (組織統制を優先)。
42
+ * - カスタムルールは両方の和集合 (多くマスクする方向は常に安全側)。
43
+ * ローカル customPatterns は ruleId を持たないため custom_local_N を自動付与する。
44
+ */
45
+ export declare function resolveMaskConfig(local: AgentConfig['pii'], remote?: MaskRulesConfig | null): EffectiveMaskConfig;
3
46
  export interface PiiMaskerOptions {
4
47
  homeDir?: string;
48
+ /** 組織のマスクルール (cloud 配信)。null/未指定ならローカル設定のみで動作する。 */
49
+ remoteRules?: MaskRulesConfig | null;
5
50
  }
6
51
  export declare class PiiMasker {
7
- private readonly config;
52
+ private readonly effective;
8
53
  private readonly homeDir;
9
54
  private readonly customPatterns;
10
55
  constructor(config: AgentConfig['pii'], opts?: PiiMaskerOptions);
@@ -13,6 +58,8 @@ export declare class PiiMasker {
13
58
  /** 任意の値を再帰的に処理。string は pattern 置換、object は structural な特別処理あり */
14
59
  private maskValue;
15
60
  private maskString;
61
+ /** ファイルパス内のユーザー名を匿名化 */
62
+ private maskFilePathsInString;
16
63
  private isBase64ImageBlock;
17
64
  private summarizeImage;
18
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pii-masker.d.ts","sourceRoot":"","sources":["../src/pii-masker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AA4C1C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,GAAE,gBAAqB;IAUnE,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAIrC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE;IAI9C,kEAAkE;IAClE,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,cAAc;CAevB"}
1
+ {"version":3,"file":"pii-masker.d.ts","sourceRoot":"","sources":["../src/pii-masker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAmE1C,8CAA8C;AAC9C,eAAO,MAAM,iBAAiB,cAAc,CAAA;AAC5C,eAAO,MAAM,aAAa,UAAU,CAAA;AACpC,eAAO,MAAM,aAAa,iBAAiB,CAAA;AAE3C,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,kCAAkC;AAClC,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAQD,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QACP,WAAW,EAAE,OAAO,CAAA;QACpB,aAAa,EAAE,OAAO,CAAA;QACtB,UAAU,EAAE,OAAO,CAAA;KACpB,CAAA;IACD,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,EAAE,cAAc,EAAE,CAAA;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EACzB,MAAM,CAAC,EAAE,eAAe,GAAG,IAAI,GAC9B,mBAAmB,CAqBrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oDAAoD;IACpD,WAAW,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;CACrC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+D;gBAElF,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,GAAE,gBAAqB;IAenE,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAYrC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE;IAI9C,kEAAkE;IAClE,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,UAAU;IAmBlB,wBAAwB;IACxB,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,cAAc;CAevB"}
@@ -3,110 +3,198 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PiiMasker = void 0;
6
+ exports.PiiMasker = exports.MAX_MASK_STATS_PER_ENTRY = exports.RULE_ID_IMAGE = exports.RULE_ID_EMAIL = exports.RULE_ID_FILE_PATH = void 0;
7
+ exports.resolveMaskConfig = resolveMaskConfig;
7
8
  const crypto_1 = require("crypto");
8
9
  const os_1 = __importDefault(require("os"));
10
+ // =============================================
11
+ // PII マスキング (送信前に伏せる) — Issue #43 でルール駆動化
12
+ // =============================================
13
+ //
14
+ // secret-detector.ts (検出・記録) と同じ前処理パイプラインの別レイヤ。
15
+ // Issue #43 で「何がどうマスクされるか」を顧客が定義・確認・監査できるよう、
16
+ // 1. 既定ルールの ON/OFF とカスタムルール (正規表現 + マスク文字列) を設定可能に
17
+ // 2. ルールごとのマスク件数 (MaskStat) を entry に付与 → cloud が日次集計
18
+ // 3. 組織ルール (cloud 配信) とローカル設定をマージして適用
19
+ // した。マスク文字列のみが残り、元の値は entry に保持されない。
9
20
  /**
10
21
  * Built-in PII patterns. Phase B 観測 (`agent/docs/claude-log-structure.md` 第 7 節)
11
22
  * で実際に conversation に出現することが確認されたものを優先実装。
12
23
  *
13
24
  * 注: 検出粒度は false negative より false positive を許容する方針
14
25
  * (key 漏洩リスク > 文字列を過剰にマスクするリスク)。
26
+ * ruleId は secret-detector.ts の同種ルールと揃える (監査表示で対応が取れるように)。
15
27
  */
16
28
  const SECRET_PATTERNS = [
17
29
  // Anthropic API key (sk-ant-api... / sk-ant-oat... / sk-ant-ort...)
18
- [/sk-ant-(api|oat|ort)\d+-[A-Za-z0-9_-]{40,}/g, '[MASKED_ANTHROPIC_KEY]'],
30
+ {
31
+ ruleId: 'anthropic_key',
32
+ regex: /sk-ant-(api|oat|ort)\d+-[A-Za-z0-9_-]{40,}/g,
33
+ replacement: '[MASKED_ANTHROPIC_KEY]',
34
+ },
19
35
  // OpenAI key (sk-proj-... or legacy sk-...) — 40+ 文字に絞って誤検出抑制
20
- [/sk-(proj-)?[A-Za-z0-9]{40,}/g, '[MASKED_OPENAI_KEY]'],
36
+ {
37
+ ruleId: 'openai_key',
38
+ regex: /sk-(proj-)?[A-Za-z0-9]{40,}/g,
39
+ replacement: '[MASKED_OPENAI_KEY]',
40
+ },
21
41
  // GitHub token (ghp_, gho_, ghu_, ghs_, ghr_)
22
- [/gh[pousr]_[A-Za-z0-9]{36}/g, '[MASKED_GITHUB_TOKEN]'],
42
+ {
43
+ ruleId: 'github_token',
44
+ regex: /gh[pousr]_[A-Za-z0-9]{36}/g,
45
+ replacement: '[MASKED_GITHUB_TOKEN]',
46
+ },
23
47
  // Slack token (xoxb-, xoxp-, xoxa-, xoxr-, xoxs-)
24
- [/xox[baprs]-[A-Za-z0-9-]{10,}/g, '[MASKED_SLACK_TOKEN]'],
48
+ {
49
+ ruleId: 'slack_token',
50
+ regex: /xox[baprs]-[A-Za-z0-9-]{10,}/g,
51
+ replacement: '[MASKED_SLACK_TOKEN]',
52
+ },
25
53
  // AWS access key
26
- [/\bAKIA[0-9A-Z]{16}\b/g, '[MASKED_AWS_KEY]'],
54
+ { ruleId: 'aws_access_key', regex: /\bAKIA[0-9A-Z]{16}\b/g, replacement: '[MASKED_AWS_KEY]' },
27
55
  // GCP API key
28
- [/\bAIza[0-9A-Za-z_-]{35}\b/g, '[MASKED_GCP_KEY]'],
56
+ {
57
+ ruleId: 'gcp_api_key',
58
+ regex: /\bAIza[0-9A-Za-z_-]{35}\b/g,
59
+ replacement: '[MASKED_GCP_KEY]',
60
+ },
29
61
  // Generic Bearer token (短すぎる文字列は誤検出するので 20+ 文字に絞る)
30
- [/Bearer\s+[A-Za-z0-9._-]{20,}/g, 'Bearer [MASKED_TOKEN]'],
62
+ {
63
+ ruleId: 'bearer_token',
64
+ regex: /Bearer\s+[A-Za-z0-9._-]{20,}/g,
65
+ replacement: 'Bearer [MASKED_TOKEN]',
66
+ },
31
67
  ];
32
68
  // local-part を 2 文字以上にして Flask デコレータ等 (例: `t@app.context_processor`,
33
69
  // `n@app.after_request`) の false positive をブロック。1 文字 local-part の実 email は
34
70
  // RFC 上 valid だが実運用ではほぼ存在しない (acceptable trade-off)。
35
71
  const EMAIL_PATTERN = /[a-zA-Z0-9._%+-]{2,}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
36
- /** ファイルパス内のユーザー名を匿名化 */
37
- function maskFilePathsInString(str, homeDir) {
38
- let result = str;
39
- // 自分のホーム → ~
40
- if (homeDir) {
41
- result = result.split(homeDir).join('~');
72
+ /** ファイルパス / 画像など、正規表現グループ外の構造的ルールの ruleId。 */
73
+ exports.RULE_ID_FILE_PATH = 'file_path';
74
+ exports.RULE_ID_EMAIL = 'email';
75
+ exports.RULE_ID_IMAGE = 'image_base64';
76
+ /** 1 entry あたりの MaskStat 上限 (detections の MAX_DETECTIONS_PER_ENTRY と同思想)。 */
77
+ exports.MAX_MASK_STATS_PER_ENTRY = 50;
78
+ /**
79
+ * ローカル設定 (agent.config.json の pii) と組織ルール (cloud 配信) をマージする。
80
+ * - builtin トグルは組織ルールがあればそちらを正とする (組織統制を優先)。
81
+ * - カスタムルールは両方の和集合 (多くマスクする方向は常に安全側)。
82
+ * ローカル customPatterns は ruleId を持たないため custom_local_N を自動付与する。
83
+ */
84
+ function resolveMaskConfig(local, remote) {
85
+ const localCustom = (local.customPatterns ?? []).map((p, i) => ({
86
+ ruleId: `custom_local_${i + 1}`,
87
+ pattern: p.pattern,
88
+ replacement: p.replacement,
89
+ enabled: true,
90
+ }));
91
+ if (!remote) {
92
+ return {
93
+ maskApiKeys: local.maskApiKeys,
94
+ maskFilePaths: local.maskFilePaths,
95
+ maskEmails: local.maskEmails,
96
+ customRules: localCustom,
97
+ };
42
98
  }
43
- // 他ユーザー (チーム共有時に他のユーザー名が漏れないように)
44
- result = result.replace(/\/Users\/[^/\s"'`]+/g, '/Users/[USER]');
45
- result = result.replace(/\/home\/[^/\s"'`]+/g, '/home/[USER]');
46
- return result;
99
+ return {
100
+ maskApiKeys: remote.builtin.maskApiKeys,
101
+ maskFilePaths: remote.builtin.maskFilePaths,
102
+ maskEmails: remote.builtin.maskEmails,
103
+ customRules: [...remote.customRules.filter((r) => r.enabled), ...localCustom],
104
+ };
47
105
  }
48
106
  class PiiMasker {
49
- config;
107
+ effective;
50
108
  homeDir;
51
109
  customPatterns;
52
110
  constructor(config, opts = {}) {
53
- this.config = config;
111
+ this.effective = resolveMaskConfig(config, opts.remoteRules);
54
112
  this.homeDir = opts.homeDir ?? os_1.default.homedir();
55
- this.customPatterns = (config.customPatterns ?? []).map(({ pattern, replacement }) => {
56
- // ユーザー指定 regex は flag を付けて global にする
57
- const flags = pattern.startsWith('/') ? '' : 'g';
58
- return [new RegExp(pattern, flags), replacement];
59
- });
113
+ this.customPatterns = this.effective.customRules
114
+ .map((rule) => {
115
+ try {
116
+ return { ruleId: rule.ruleId, regex: new RegExp(rule.pattern, 'g'), replacement: rule.replacement };
117
+ }
118
+ catch {
119
+ // 不正な正規表現は無視 (1 ルールのせいでマスキング全体を落とさない)。
120
+ return null;
121
+ }
122
+ })
123
+ .filter((r) => r !== null);
60
124
  }
61
125
  mask(entry) {
62
- return { ...entry, raw: this.maskValue(entry.raw) };
126
+ const counts = new Map();
127
+ const raw = this.maskValue(entry.raw, counts);
128
+ if (counts.size === 0)
129
+ return { ...entry, raw };
130
+ // 件数降順で上限へ切り詰める (cloud 側 schema の上限と整合)。
131
+ const masks = [...counts.entries()]
132
+ .map(([ruleId, count]) => ({ ruleId, count }))
133
+ .sort((a, b) => b.count - a.count)
134
+ .slice(0, exports.MAX_MASK_STATS_PER_ENTRY);
135
+ return { ...entry, raw, masks };
63
136
  }
64
137
  maskAll(entries) {
65
138
  return entries.map((e) => this.mask(e));
66
139
  }
67
140
  /** 任意の値を再帰的に処理。string は pattern 置換、object は structural な特別処理あり */
68
- maskValue(v) {
141
+ maskValue(v, counts) {
69
142
  if (typeof v === 'string') {
70
- return this.maskString(v);
143
+ return this.maskString(v, counts);
71
144
  }
72
145
  if (Array.isArray(v)) {
73
- return v.map((x) => this.maskValue(x));
146
+ return v.map((x) => this.maskValue(x, counts));
74
147
  }
75
148
  if (v !== null && typeof v === 'object') {
76
149
  const obj = v;
77
150
  // 画像 base64 は構造的に検出して省略 (帯域節約 + 二次的 PII 流出防止)
78
151
  if (this.isBase64ImageBlock(obj)) {
152
+ bump(counts, exports.RULE_ID_IMAGE, 1);
79
153
  return this.summarizeImage(obj);
80
154
  }
81
155
  const result = {};
82
156
  for (const [k, val] of Object.entries(obj)) {
83
157
  // key 自体に絶対パス等が入るケース (例: file-history-snapshot の
84
158
  // trackedFileBackups は file path を key にする) があるので key も maskString
85
- const newKey = this.maskString(k);
86
- result[newKey] = this.maskValue(val);
159
+ const newKey = this.maskString(k, counts);
160
+ result[newKey] = this.maskValue(val, counts);
87
161
  }
88
162
  return result;
89
163
  }
90
164
  return v;
91
165
  }
92
- maskString(str) {
166
+ maskString(str, counts) {
93
167
  let result = str;
94
- if (this.config.maskApiKeys) {
95
- for (const [re, repl] of SECRET_PATTERNS) {
96
- result = result.replace(re, repl);
168
+ if (this.effective.maskApiKeys) {
169
+ for (const { ruleId, regex, replacement } of SECRET_PATTERNS) {
170
+ result = replaceCounted(result, regex, replacement, counts, ruleId);
97
171
  }
98
172
  }
99
- if (this.config.maskFilePaths) {
100
- result = maskFilePathsInString(result, this.homeDir);
173
+ if (this.effective.maskFilePaths) {
174
+ result = this.maskFilePathsInString(result, counts);
101
175
  }
102
- if (this.config.maskEmails) {
103
- result = result.replace(EMAIL_PATTERN, '[MASKED_EMAIL]');
176
+ if (this.effective.maskEmails) {
177
+ result = replaceCounted(result, EMAIL_PATTERN, '[MASKED_EMAIL]', counts, exports.RULE_ID_EMAIL);
104
178
  }
105
- for (const [re, repl] of this.customPatterns) {
106
- result = result.replace(re, repl);
179
+ for (const { ruleId, regex, replacement } of this.customPatterns) {
180
+ result = replaceCounted(result, regex, replacement, counts, ruleId);
107
181
  }
108
182
  return result;
109
183
  }
184
+ /** ファイルパス内のユーザー名を匿名化 */
185
+ maskFilePathsInString(str, counts) {
186
+ let result = str;
187
+ // 自分のホーム → ~
188
+ if (this.homeDir && result.includes(this.homeDir)) {
189
+ const parts = result.split(this.homeDir);
190
+ bump(counts, exports.RULE_ID_FILE_PATH, parts.length - 1);
191
+ result = parts.join('~');
192
+ }
193
+ // 他ユーザー (チーム共有時に他のユーザー名が漏れないように)
194
+ result = replaceCounted(result, /\/Users\/[^/\s"'`]+/g, '/Users/[USER]', counts, exports.RULE_ID_FILE_PATH);
195
+ result = replaceCounted(result, /\/home\/[^/\s"'`]+/g, '/home/[USER]', counts, exports.RULE_ID_FILE_PATH);
196
+ return result;
197
+ }
110
198
  isBase64ImageBlock(obj) {
111
199
  if (obj.type !== 'image')
112
200
  return false;
@@ -133,4 +221,19 @@ class PiiMasker {
133
221
  }
134
222
  }
135
223
  exports.PiiMasker = PiiMasker;
224
+ function bump(counts, ruleId, n) {
225
+ if (n <= 0)
226
+ return;
227
+ counts.set(ruleId, (counts.get(ruleId) ?? 0) + n);
228
+ }
229
+ /** literal 置換 + 置換回数のカウント。replacement 内の $& 等は解釈しない。 */
230
+ function replaceCounted(str, regex, replacement, counts, ruleId) {
231
+ let n = 0;
232
+ const result = str.replace(regex, () => {
233
+ n++;
234
+ return replacement;
235
+ });
236
+ bump(counts, ruleId, n);
237
+ return result;
238
+ }
136
239
  //# sourceMappingURL=pii-masker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pii-masker.js","sourceRoot":"","sources":["../src/pii-masker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pii-masker.js","sourceRoot":"","sources":["../src/pii-masker.ts"],"names":[],"mappings":"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"}