@planu/cli 5.3.20 → 5.3.22

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 (26) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/config/runtime-policy.json +3 -3
  3. package/dist/engine/framework-detector.js +4 -2
  4. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  5. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +4 -4
  6. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  7. package/dist/engine/planu-core.darwin-x64.node.sbom.json +4 -4
  8. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  9. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +4 -4
  10. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  11. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +4 -4
  12. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  13. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +4 -4
  14. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  15. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +4 -4
  16. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  17. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +4 -4
  18. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  19. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +4 -4
  20. package/dist/engine/universal-rules/rules/planu-release-policy.js +2 -1
  21. package/dist/resources/process.js +1 -1
  22. package/dist/tools/create-spec.js +21 -9
  23. package/package.json +15 -12
  24. package/planu-native.json +1 -1
  25. package/planu-plugin.json +1 -1
  26. package/scripts/lib/portable-paths.mjs +54 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [5.3.22] - 2026-08-13
2
+
3
+ ### Bug Fixes
4
+ - fix(spec-1523): bind isolated rebuild sidecar provenance to the build-source commit
5
+ - fix(spec-1521): pin native provenance across the lockfile-integrity amend
6
+ - fix(spec-1519): bound acknowledgement latency at a tail ceiling, not a bare SLO constant
7
+ - fix(spec-1518): scope PLANU_RELEASE_MODE out of the source-quality phase
8
+ - fix(spec-1518): scope release-build env out of the source-quality phase
9
+ - fix(deps): drop vulnerable extract-zip by forcing puppeteer-core 25
10
+ - fix(spec-1506,spec-1507): align release invariant and lint budget with shipped behaviour
11
+ - fix(spec-1506,spec-1507): correct native lockfile integrity and uncache every gate
12
+
13
+
14
+ ## [5.3.21] - 2026-08-12
15
+
16
+ ### Bug Fixes
17
+ - fix(spec-1499,spec-1500): portable path redaction and a cheap pre-flight gate
18
+
19
+ ### Chores
20
+ - chore(planu): refresh session context after SPEC-1505 intake
21
+
22
+
1
23
  ## [5.3.20] - 2026-08-12
2
24
 
3
25
  ### Bug Fixes
@@ -14,7 +14,7 @@
14
14
  "maximumOutputBufferBytes": 67108864
15
15
  },
16
16
  "lintValidation": {
17
- "defaultTimeoutMs": 180000,
17
+ "defaultTimeoutMs": 420000,
18
18
  "minimumTimeoutMs": 1000,
19
19
  "maximumTimeoutMs": 1800000
20
20
  },
@@ -28,8 +28,8 @@
28
28
  },
29
29
  "validation": {
30
30
  "defaultDeadlineMs": 1800000,
31
- "durableLintTimeoutMs": 170000,
32
- "perGateTimeoutMs": 180000,
31
+ "durableLintTimeoutMs": 420000,
32
+ "perGateTimeoutMs": 450000,
33
33
  "complianceCommandTimeoutMs": 900000,
34
34
  "noProgressTimeoutMs": 960000,
35
35
  "submissionLockWaitMs": 180,
@@ -221,6 +221,7 @@ export async function detectTestCommand(projectPath, packageManager) {
221
221
  }
222
222
  return null;
223
223
  }
224
+ const LINT_SCRIPT_PREFERENCE = ['lint:gate', 'lint:ci', 'lint'];
224
225
  /**
225
226
  * Detect lint command from project config files.
226
227
  */
@@ -228,8 +229,9 @@ export async function detectLintCommand(projectPath, packageManager) {
228
229
  const pkgJson = await readJsonFile(join(projectPath, 'package.json'));
229
230
  if (pkgJson) {
230
231
  const scripts = pkgJson.scripts;
231
- if (scripts?.lint) {
232
- return `${pmRunner(packageManager)} run lint`;
232
+ const scriptName = LINT_SCRIPT_PREFERENCE.find((name) => typeof scripts?.[name] === 'string' && scripts[name] !== '');
233
+ if (scriptName) {
234
+ return `${pmRunner(packageManager)} run ${scriptName}`;
233
235
  }
234
236
  }
235
237
  if (await hasAnyFile(projectPath, ['.eslintrc*', 'eslint.config.*'])) {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-aarch64-apple-darwin",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-aarch64-apple-darwin",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -17,15 +17,15 @@
17
17
  "platform": "darwin",
18
18
  "arch": "arm64",
19
19
  "libc": null,
20
- "artifactSha256": "e55efda88d366c03c6dedb2c606e5e085f9cb7b4b41950d0a59de891ca8e6e3e",
20
+ "artifactSha256": "4730c8bca1ecd506f9332cfd7754a3b2705272b7cfead67ed8a4a857ea51af47",
21
21
  "sbom": {
22
22
  "format": "CycloneDX-1.5",
23
23
  "path": "planu-core.darwin-arm64.node.sbom.json",
24
- "sha256": "c6865313d06acb32d6999c0b56796fbb7f36a6160c9a7f42ad2c9c25e354cfda"
24
+ "sha256": "379172a509801b9bb9072e03b95da643218c75c02a8cc7e11719193f37f028aa"
25
25
  },
26
26
  "provenance": {
27
27
  "builder": "scripts/build-rust-local.sh",
28
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
28
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
29
29
  "sourceTreeDirty": false,
30
30
  "sourceDateEpoch": 1,
31
31
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -34,6 +34,6 @@
34
34
  "signature": {
35
35
  "algorithm": "Ed25519",
36
36
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
37
- "value": "RUWNdjH6OhhIcCfdfPKR4jrxVbIgSynmnWCV8TAUP8OjP61pcXYBJ3Atoi3dFUbFKe5K5/PdXp0YR+2ypHmoDw=="
37
+ "value": "a6pf9ANIEnE+aYR1QZVf9LJOna7hPvbCmKSUoAYas2JtKtY5HkBvE/9FyN7j3PaG7P8SGXgCPNbAhZ4umyq2Dg=="
38
38
  }
39
39
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "e55efda88d366c03c6dedb2c606e5e085f9cb7b4b41950d0a59de891ca8e6e3e"
14
+ "content": "4730c8bca1ecd506f9332cfd7754a3b2705272b7cfead67ed8a4a857ea51af47"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-x86_64-apple-darwin",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-x86_64-apple-darwin",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -17,15 +17,15 @@
17
17
  "platform": "darwin",
18
18
  "arch": "x64",
19
19
  "libc": null,
20
- "artifactSha256": "f5b0bc55a024310b90e4273fee8302401e2ec83006a4410c95dadf087262ef87",
20
+ "artifactSha256": "9204816afcda7990a7caa85991ced38335301a2db840a58d7c1017f72ad7fb44",
21
21
  "sbom": {
22
22
  "format": "CycloneDX-1.5",
23
23
  "path": "planu-core.darwin-x64.node.sbom.json",
24
- "sha256": "eed96de149c1340631b052fe4561bd8a768e39ae29ffca54d715183c2e4756da"
24
+ "sha256": "ba853b859c2a9a22ff223d48566f616d05ab8479b3656c8912dd8cbee8617f53"
25
25
  },
26
26
  "provenance": {
27
27
  "builder": "scripts/build-rust-local.sh",
28
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
28
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
29
29
  "sourceTreeDirty": false,
30
30
  "sourceDateEpoch": 1,
31
31
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -34,6 +34,6 @@
34
34
  "signature": {
35
35
  "algorithm": "Ed25519",
36
36
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
37
- "value": "47S1SX1cvHc/E2jHlD7Mhagd3CiGdWbCdLiJmCFsCqP9yEWYBCkgw/jZoT3qUgTmExse+Hvzx8LDBc9fZl3RAA=="
37
+ "value": "n8UTXIAzGoISDWY5vDfDxlQBqP5oso3K37jRE5+kTUnedRmCvVUwPlTedlxMKXI+JWaE/gyq5tOl5V8BNOtXBg=="
38
38
  }
39
39
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "f5b0bc55a024310b90e4273fee8302401e2ec83006a4410c95dadf087262ef87"
14
+ "content": "9204816afcda7990a7caa85991ced38335301a2db840a58d7c1017f72ad7fb44"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-aarch64-unknown-linux-gnu",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-aarch64-unknown-linux-gnu",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "linux",
17
17
  "arch": "arm64",
18
18
  "libc": "glibc",
19
- "artifactSha256": "2ea9228381585e0867fa1744ce15a50a1406217925c18d61ca86ef46045ab341",
19
+ "artifactSha256": "acfa6ff4ed2e68598b779cd84eeac69900fd6911893d2ff26414a47304b2ccde",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.linux-arm64-gnu.node.sbom.json",
23
- "sha256": "8dfab3a92f1a20f69d26ab5bcd73cd218b622a82ed02c7bc6cc9c800937b9696"
23
+ "sha256": "cebfe96400b95cf97111e7f04e1992a9c7fbbd4071b44154d33ec10f1d3046ed"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "yOcMzbe+aaTbIFqSbUKv5azScjk4Fs/e2th78DhaQdP287O5UOsGxxhv5w54gmwB//Lm6tXdzgbWK77g37SbAg=="
36
+ "value": "Xyq0s76WcCzbKEu0nFqrYE0lzt5+UWllzUqcKnpFuXXSJhrvtEyTIW4N37ldPqEeZ4tTsfVAcWooxqpMT8aECA=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "2ea9228381585e0867fa1744ce15a50a1406217925c18d61ca86ef46045ab341"
14
+ "content": "acfa6ff4ed2e68598b779cd84eeac69900fd6911893d2ff26414a47304b2ccde"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-aarch64-unknown-linux-musl",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-aarch64-unknown-linux-musl",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "linux",
17
17
  "arch": "arm64",
18
18
  "libc": "musl",
19
- "artifactSha256": "820652ed60481ecf6291c64f2a2720d52410bd06b27268b24881e95f45ac4fb5",
19
+ "artifactSha256": "b102c6bec361271c98c9940b50a37c2110fd0a4e7c8e96f7b12e904e1162e2a2",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.linux-arm64-musl.node.sbom.json",
23
- "sha256": "709feb9088507693ac37ea745921e1f93ff3e1d342fb376ba3f7bb7e900d7799"
23
+ "sha256": "6d912c7181d379ae613ffb00e2e70af7beade6da0890b892b801e31ed77074c7"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "Clj0B7s1KmADZoERbK4C9DcJX3Y7B4572h/Key3t6oDNEdqIbaff4XJ47TIBTuDW1RICr5myVcQJQlOL1m+oDA=="
36
+ "value": "rdhGtK396/2ZwQtLhz9D+o6VvucindJmLidQT3Yjy+A0dXp8IyT1MJm7g+KzVD6b+SfqWu6HgubuEgGfhyH9CQ=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "820652ed60481ecf6291c64f2a2720d52410bd06b27268b24881e95f45ac4fb5"
14
+ "content": "b102c6bec361271c98c9940b50a37c2110fd0a4e7c8e96f7b12e904e1162e2a2"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-x86_64-unknown-linux-gnu",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-x86_64-unknown-linux-gnu",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "linux",
17
17
  "arch": "x64",
18
18
  "libc": "glibc",
19
- "artifactSha256": "480558ee13c36ac1382a265cb156eb9f966ded72e144a209052e7098ee61af47",
19
+ "artifactSha256": "5d2c48ac0de6d60629345143648c78e291a4cba707756face2957f27afb7d36b",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.linux-x64-gnu.node.sbom.json",
23
- "sha256": "4ad75195c8a05b860c309208c7ad45361c0eea7cc107d85500805e93ce04e687"
23
+ "sha256": "d6125400832c0bdee2823af553d4e6b717b15cba47133ca88aaf91e2183ef6e1"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "j6srf3XwnCHHrmF00S8IerExJd/Pov1K9oInF/jL/PkhGnknti6GYgm73GxfryUBK5FrsT7nTWXqXrmY2GHQDw=="
36
+ "value": "Cb1ueFKWd9mC0uzyo/kPIexFGBTxuVsJTk8knsTODmsR2ooH4rG/fqCqN2M1ZCO1kC7Zrpn5LwiifEcbUhUQBw=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "480558ee13c36ac1382a265cb156eb9f966ded72e144a209052e7098ee61af47"
14
+ "content": "5d2c48ac0de6d60629345143648c78e291a4cba707756face2957f27afb7d36b"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-x86_64-unknown-linux-musl",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-x86_64-unknown-linux-musl",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "linux",
17
17
  "arch": "x64",
18
18
  "libc": "musl",
19
- "artifactSha256": "4d49cab5c5a4acd877e594cab33c0aa0c2a1e3cc153598d500491c7980415d8e",
19
+ "artifactSha256": "43926c2400637b9670c3c869da140fedfa85dd786da4de04122c8f5022d3c5cc",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.linux-x64-musl.node.sbom.json",
23
- "sha256": "0df31770a702f024c54991719dc402e0c581652cac146a389fb03d1322d40456"
23
+ "sha256": "5db161ed910755ad5fe11ebc10d190f81fdf6b69779f21c048819f3be7bcb34e"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "KYrdMvuUvSOezgBWK84rqhv4NstKjCq4f0iEoe2E6h3iV2e2uDhXT5WQyXeeV+9/fNKLKfTcSkepeSW1347YDg=="
36
+ "value": "0NDYIwRlP6yJ/LWIt3in/B9XD367mRJM0WRoX5H4eERYz4/jtuyKA9yPXUh0sYnnY3roOFctTkbd4eLtFmtqBQ=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "4d49cab5c5a4acd877e594cab33c0aa0c2a1e3cc153598d500491c7980415d8e"
14
+ "content": "43926c2400637b9670c3c869da140fedfa85dd786da4de04122c8f5022d3c5cc"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-aarch64-pc-windows-msvc",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-aarch64-pc-windows-msvc",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "win32",
17
17
  "arch": "arm64",
18
18
  "libc": null,
19
- "artifactSha256": "af8d4bc6ff629838c2dc4ec1585fddb34ff746c7a655d17f330d1f948a9f88fa",
19
+ "artifactSha256": "2895b0fa8aad3dd46ad59f9b1e8a327dcbbaffe7357ea78830e232a292944920",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.win32-arm64-msvc.node.sbom.json",
23
- "sha256": "cb68d92f6c73d1a1761d6bf3dca51cd2d7ed4c777eaf21bbabaa10bd860c5bb1"
23
+ "sha256": "2e14b8772ac8aa9ec07793b8e1db4e72dd23541ed338a1fbe728884082fbe796"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "Es/39B5KADPs6wEf4GX2YjN5WA+nqJzGHtltz8VoVS6dsSJKFVKX3RfHiVSldTAv7Lw1k+A+MfmVbarQX3yYBA=="
36
+ "value": "r0Wa9w/3KI0OAHWMTjGqerm90i5pEtHM8VWAKrEb4oqqtxjUQaYhPhKubZfTE4YOdrvn+1RXdoVaU8jMScdSAA=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "af8d4bc6ff629838c2dc4ec1585fddb34ff746c7a655d17f330d1f948a9f88fa"
14
+ "content": "2895b0fa8aad3dd46ad59f9b1e8a327dcbbaffe7357ea78830e232a292944920"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.20",
4
- "engineVersion": "5.3.20",
5
- "buildId": "1-5.3.20-x86_64-pc-windows-msvc",
3
+ "cliVersion": "5.3.22",
4
+ "engineVersion": "5.3.22",
5
+ "buildId": "1-5.3.22-x86_64-pc-windows-msvc",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "win32",
17
17
  "arch": "x64",
18
18
  "libc": null,
19
- "artifactSha256": "662110578e520cfda4c20f3e99b3ae02f12b62fe4af3df0ddca993137144ec4c",
19
+ "artifactSha256": "832a639657313dad460661ba34672d01ac1fc5674a655362f7d936e48353c0e5",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.win32-x64-msvc.node.sbom.json",
23
- "sha256": "2a840b84b97ba7dcce0240fb82033dd2a88d4d9db4698ac7a0e75802f0093154"
23
+ "sha256": "2fac480bb810bb3201adc6a82859ace5aeb0b46e62da7cd257fb8089d1ade10f"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "b17b7f7133a1b83eacb1140de5138aa89c00f267",
27
+ "sourceCommit": "faabf932259a10c5cabfeedf510c23d686b45e83",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "RzsxC6qOLporNXgL8gFU0tSNJPRYuKZE4N5Afi7vixhyzHtW5e96Afpv608/uvuEaPXiFBwbQPSVa7Ev9jlDAg=="
36
+ "value": "MudkeMsYJwviSCoe775V8V4/N8d1dgRiQNRBlaGGrozpQb/cavJjNWpL8CoQEVsjX9n1CwjOeTVPu45gDzqqDQ=="
37
37
  }
38
38
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.20",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.22",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.20",
10
+ "version": "5.3.22",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "662110578e520cfda4c20f3e99b3ae02f12b62fe4af3df0ddca993137144ec4c"
14
+ "content": "832a639657313dad460661ba34672d01ac1fc5674a655362f7d936e48353c0e5"
15
15
  }
16
16
  ]
17
17
  }
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.20",
1109
+ "ref": "pkg:cargo/planu-core@5.3.22",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -7,7 +7,8 @@ Auto-generated by \`init_project\`. Do not edit manually.
7
7
 
8
8
  When implementation changes are complete and validated, always address release explicitly with a local-first flow:
9
9
 
10
- - canonical local gates: \`pnpm validate\` then \`pnpm check:strict\`
10
+ - canonical local gate: \`pnpm check:preflight\`
11
+ - source-quality evidence binds the exact release commit, so a pre-bump run can never produce a receipt the release will accept; the full source-quality plan runs inside the release, against the bump commit, and reruns whenever a later step rewrites that commit (for example the native-lockfile-integrity amend), since the prior receipt no longer binds the new sha
11
12
  - canonical local release command: \`pnpm release:local\`
12
13
  - publish externally only when the user has explicitly requested shipping/publishing
13
14
  - use \`main\` as the default release branch; treat \`develop\` as optional gitflow compatibility only when the repository actively uses it
@@ -94,7 +94,7 @@ function getSddProcess() {
94
94
  name: '8. Document & Ship',
95
95
  tools: ['generate_docs', 'generate_docs_site', 'integrate_pm', 'learn_pattern'],
96
96
  description: 'Generate documentation, run the local-first release contract ' +
97
- '(`pnpm validate`, `pnpm check:strict`, `pnpm release:local` when shipping), ' +
97
+ '(`pnpm check:preflight`, `pnpm release:local` when shipping), ' +
98
98
  'sync with project management tools, and learn patterns for future estimations.',
99
99
  },
100
100
  ],
@@ -41,6 +41,7 @@ import { OperationJournal, recoverOperationJournal, } from '../engine/execution/
41
41
  import { assertExecutionCanCommit } from '../engine/execution/context.js';
42
42
  import { cleanupExecutionArtifact, executionLink, executionMkdir, executionRemove, executionRename, executionWriteFileExclusive, } from '../engine/execution/deadline-io.js';
43
43
  import { atomicWriteFile } from '../engine/safety/atomic-write-file.js';
44
+ import { redactPortablePaths } from '../../scripts/lib/portable-paths.mjs';
44
45
  /** SPEC-584: Persist a clarification token when interactive questions are emitted. Best-effort. */
45
46
  async function persistClarificationToken(earlyReturn, projectId, toolName) {
46
47
  try {
@@ -199,6 +200,20 @@ function resolveOutOfScope(provided, source = '') {
199
200
  ? Array.from(section.matchAll(/^[-*]\s+(.+)$/gm), (match) => match[1]?.trim() ?? '').filter(Boolean)
200
201
  : [];
201
202
  }
203
+ /** Redact absolute repo/home paths from every free-text field before it enters the store. */
204
+ function redactCreateSpecInput(params, root) {
205
+ const options = { root };
206
+ return {
207
+ ...params,
208
+ title: redactPortablePaths(params.title, options),
209
+ description: redactPortablePaths(params.description, options),
210
+ outOfScope: params.outOfScope?.map((item) => redactPortablePaths(item, options)),
211
+ agentTeamFindings: params.agentTeamFindings?.map((entry) => ({
212
+ ...entry,
213
+ findings: redactPortablePaths(entry.findings, options),
214
+ })),
215
+ };
216
+ }
202
217
  /** SPEC-783: Synthesize agent team findings into unified spec.md ## Technical section. */
203
218
  async function handleAgentTeamSynthesis(specId, projectPath, findings) {
204
219
  try {
@@ -976,7 +991,7 @@ export async function resolveGroundedVerificationCommands(projectPath, testPaths
976
991
  }
977
992
  }
978
993
  async function prepareCreateSpecCandidate(initialParams, server) {
979
- let params = initialParams;
994
+ let params = { ...initialParams };
980
995
  const buildResult = await measureStep('buildSpecContext', () => buildSpecContext(params));
981
996
  if (!buildResult.ok) {
982
997
  return earlyPreparation({
@@ -1238,15 +1253,12 @@ export async function handleCreateSpec(inputParams, server) {
1238
1253
  isError: true,
1239
1254
  };
1240
1255
  }
1241
- const resolvedInputParams = {
1242
- ...inputParams,
1243
- projectPath: resolvedPath,
1244
- };
1256
+ const resolvedInputParams = redactCreateSpecInput({ ...inputParams, projectPath: resolvedPath }, resolvedPath);
1245
1257
  // SPEC-697: Agent team findings synthesis path — early return before full spec creation
1246
- if (inputParams.agentTeamFindings &&
1247
- inputParams.agentTeamFindings.length > 0 &&
1248
- inputParams.specId) {
1249
- return handleAgentTeamSynthesis(inputParams.specId, resolvedPath, inputParams.agentTeamFindings);
1258
+ if (resolvedInputParams.agentTeamFindings &&
1259
+ resolvedInputParams.agentTeamFindings.length > 0 &&
1260
+ resolvedInputParams.specId) {
1261
+ return handleAgentTeamSynthesis(resolvedInputParams.specId, resolvedPath, resolvedInputParams.agentTeamFindings);
1250
1262
  }
1251
1263
  // SPEC-584: Gate check — block if pending clarification token exists and no answers provided.
1252
1264
  // Runs before the English-only gate so a second call with no translation answer hits the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planu/cli",
3
- "version": "5.3.20",
3
+ "version": "5.3.22",
4
4
  "description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,6 +13,7 @@
13
13
  "!dist/**/*.map",
14
14
  "!dist/engine/*.node",
15
15
  "scripts/lib/pending-release-file.mjs",
16
+ "scripts/lib/portable-paths.mjs",
16
17
  "src/i18n/messages/",
17
18
  "planu-native.json",
18
19
  "planu-plugin.json",
@@ -35,14 +36,14 @@
35
36
  "packageName": "@planu/core"
36
37
  },
37
38
  "optionalDependencies": {
38
- "@planu/core-darwin-arm64": "5.3.20",
39
- "@planu/core-darwin-x64": "5.3.20",
40
- "@planu/core-linux-arm64-gnu": "5.3.20",
41
- "@planu/core-linux-arm64-musl": "5.3.20",
42
- "@planu/core-linux-x64-gnu": "5.3.20",
43
- "@planu/core-linux-x64-musl": "5.3.20",
44
- "@planu/core-win32-arm64-msvc": "5.3.20",
45
- "@planu/core-win32-x64-msvc": "5.3.20"
39
+ "@planu/core-darwin-arm64": "5.3.22",
40
+ "@planu/core-darwin-x64": "5.3.22",
41
+ "@planu/core-linux-arm64-gnu": "5.3.22",
42
+ "@planu/core-linux-arm64-musl": "5.3.22",
43
+ "@planu/core-linux-x64-gnu": "5.3.22",
44
+ "@planu/core-linux-x64-musl": "5.3.22",
45
+ "@planu/core-win32-arm64-msvc": "5.3.22",
46
+ "@planu/core-win32-x64-msvc": "5.3.22"
46
47
  },
47
48
  "engines": {
48
49
  "node": ">=24.0.0"
@@ -67,7 +68,8 @@
67
68
  "start": "node dist/index.js",
68
69
  "postpublish": "pnpm build",
69
70
  "clean": "rm -rf dist",
70
- "lint": "eslint src/ tests/ --max-warnings 0",
71
+ "lint": "eslint src/ tests/ --max-warnings 0 --cache --cache-strategy content --cache-location node_modules/.cache/eslint/",
72
+ "lint:gate": "eslint src/ tests/ --max-warnings 0",
71
73
  "lint:fix": "eslint src/ tests/ --fix --max-warnings 0",
72
74
  "format": "prettier --write 'src/**/*.ts' 'tests/**/*.test.ts'",
73
75
  "format:check": "prettier --check 'src/**/*.ts' 'tests/**/*.test.ts'",
@@ -86,9 +88,10 @@
86
88
  "native:project-graph:e2e": "PLANU_NATIVE_E2E=1 vitest run tests/integration/native-project-graph-e2e.test.ts",
87
89
  "native:project-graph:benchmark": "node scripts/benchmark-native-performance.mjs --operation project_graph_query --samples 30 --warmups 5 --project-path . --spec-id SPEC-1119 --json",
88
90
  "benchmark:execution-kernel": "pnpm build && node scripts/benchmark-execution-kernel.mjs",
89
- "check": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm check:destructive-ops && pnpm check:release-authorities && pnpm check:commercial-surfaces && pnpm check:tool-registration && pnpm check:public-privacy && pnpm check:website-proof && pnpm check:donation-assets && pnpm check:website-public-assets",
91
+ "check": "pnpm typecheck && pnpm lint:gate && pnpm format:check && pnpm check:destructive-ops && pnpm check:release-authorities && pnpm check:commercial-surfaces && pnpm check:tool-registration && pnpm check:public-privacy && pnpm check:website-proof && pnpm check:donation-assets && pnpm check:website-public-assets",
90
92
  "check:destructive-ops": "bash scripts/check-no-automatic-destructive-ops.sh",
91
93
  "check:strict": "pnpm check && pnpm generate:host-tool-registry -- --check && pnpm check:native-version-parity && pnpm check:environment-schema && pnpm audit:hardcodes && pnpm audit:deadcode && pnpm audit:circular && pnpm audit:types && pnpm audit:security && pnpm audit:i18n",
94
+ "check:preflight": "pnpm typecheck && pnpm lint:gate && pnpm format:check && node scripts/check-public-privacy.mjs && node scripts/check-preflight.mjs",
92
95
  "check:reliability": "node scripts/check-reliability-policies.mjs",
93
96
  "check:environment-schema": "node scripts/check-environment-schema.mjs",
94
97
  "test:contracts": "vitest run tests/contracts tests/integration/package-consumer-hono.test.ts",
@@ -118,7 +121,7 @@
118
121
  "prepublishOnly": "bash scripts/prepublish-guard.sh",
119
122
  "prepack": "pnpm build:ts && pnpm package:size",
120
123
  "test:debug": "vitest run --inspect-brk --single-thread",
121
- "validate": "pnpm build && pnpm typecheck && pnpm verify:typescript-migration && pnpm lint && pnpm format:check && pnpm test:release-gate",
124
+ "validate": "pnpm build && pnpm typecheck && pnpm verify:typescript-migration && pnpm lint:gate && pnpm format:check && pnpm test:release-gate",
122
125
  "docker:build": "docker build -t planu .",
123
126
  "docker:run": "docker compose up",
124
127
  "publish:blog": "node scripts/publish-blog.mjs",
package/planu-native.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dev.planu.native",
3
3
  "displayName": "Planu Native Lightweight Surface",
4
- "version": "5.3.20",
4
+ "version": "5.3.22",
5
5
  "packageName": "@planu/cli",
6
6
  "modes": {
7
7
  "lightweight": {
package/planu-plugin.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dev.planu.cli",
3
3
  "displayName": "Planu — Spec Driven Development",
4
4
  "description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
5
- "version": "5.3.20",
5
+ "version": "5.3.22",
6
6
  "icon": "assets/plugin/icon.svg",
7
7
  "command": ["npx", "@planu/cli@latest"],
8
8
  "packageName": "@planu/cli",
@@ -0,0 +1,54 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+
4
+ function escapeRegExp(value) {
5
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
6
+ }
7
+
8
+ function pathExpression(path) {
9
+ return escapeRegExp(path).replaceAll('/', '[\\\\/]');
10
+ }
11
+
12
+ function pathSegmentCount(path) {
13
+ return path.split(/[\\/]/u).filter(Boolean).length;
14
+ }
15
+
16
+ function planuDataDirectory(home, env, platform) {
17
+ if (platform === 'win32') {
18
+ const local = env.LOCALAPPDATA?.trim() || join(home, 'AppData', 'Local');
19
+ return join(local, 'Planu', 'data');
20
+ }
21
+ if (platform === 'darwin') {
22
+ return join(home, 'Library', 'Application Support', 'Planu', 'data');
23
+ }
24
+ const dataHome = env.XDG_DATA_HOME?.trim() || join(home, '.local', 'share');
25
+ return join(dataHome, 'planu');
26
+ }
27
+
28
+ export function portablePathPatterns({
29
+ root,
30
+ homeDirectory = homedir(),
31
+ env = process.env,
32
+ platform = process.platform,
33
+ } = {}) {
34
+ const home = homeDirectory.replace(/[\\/]$/u, '');
35
+ const candidates = [
36
+ { path: planuDataDirectory(home, env, platform), replacement: '<planu-data-dir>' },
37
+ { path: root, replacement: '<repo-root>' },
38
+ { path: home, replacement: '<home>' },
39
+ ].filter(
40
+ (candidate) => typeof candidate.path === 'string' && pathSegmentCount(candidate.path) >= 2,
41
+ );
42
+ candidates.sort((left, right) => right.path.length - left.path.length);
43
+ return candidates.map(({ path, replacement }) => ({
44
+ pattern: new RegExp(`(?:file:)?${pathExpression(path)}(?![A-Za-z0-9._-])`, 'giu'),
45
+ replacement,
46
+ }));
47
+ }
48
+
49
+ export function redactPortablePaths(text, options = {}) {
50
+ return portablePathPatterns(options).reduce(
51
+ (redacted, { pattern, replacement }) => redacted.replace(pattern, replacement),
52
+ text,
53
+ );
54
+ }