pm-ops 2026.10.6 → 2026.10.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm-ops",
3
- "version": "2026.10.6",
3
+ "version": "2026.10.13",
4
4
  "description": "Multi-repo fleet operations for pm-cli",
5
5
  "repository": {
6
6
  "type": "git",
@@ -53,6 +53,10 @@
53
53
  "./duplication": {
54
54
  "types": "./dist/duplication.d.ts",
55
55
  "default": "./dist/duplication.js"
56
+ },
57
+ "./release-repair": {
58
+ "types": "./dist/release-repair.d.ts",
59
+ "default": "./dist/release-repair.js"
56
60
  }
57
61
  },
58
62
  "files": [
@@ -86,7 +90,8 @@
86
90
  "verify:release-changelog-date": "node scripts/verify-release-changelog-date.ts",
87
91
  "verify:release-publish-attestation": "node scripts/verify-release-publish-attestation.ts",
88
92
  "verify:release-completeness": "node scripts/verify-release-completeness.ts",
89
- "verify:lifecycle-policy": "node scripts/verify-lifecycle-policy.ts"
93
+ "verify:lifecycle-policy": "node scripts/verify-lifecycle-policy.ts",
94
+ "accept:packed": "node test/packed-consumer.acceptance.ts"
90
95
  },
91
96
  "dependencies": {
92
97
  "@toon-format/toon": "^4.1.0",
@@ -118,16 +123,16 @@
118
123
  }
119
124
  },
120
125
  "devDependencies": {
121
- "@babel/eslint-parser": "8.0.6",
126
+ "@babel/eslint-parser": "8.0.7",
122
127
  "@babel/plugin-syntax-typescript": "8.0.3",
123
128
  "@types/node": "26.6.4",
124
- "@unbrained/pm-cli": "2026.10.4",
129
+ "@unbrained/pm-cli": "2026.10.10",
125
130
  "c8": "12.0.0",
126
131
  "eslint": "10.12.0",
127
132
  "fast-glob": "3.3.3",
128
- "jscpd": "5.4.0",
133
+ "jscpd": "5.4.1",
129
134
  "jscpd4": "npm:jscpd@4.3.0",
130
- "pm-changelog": "2026.10.4"
135
+ "pm-changelog": "2026.10.5"
131
136
  },
132
137
  "keywords": [
133
138
  "pm-cli",
@@ -9,6 +9,8 @@
9
9
  * notice; any other resolution failure (for example a pm-ops too old to export
10
10
  * the entry, or a `pm-ops` directory whose package.json is gone) and any
11
11
  * installer failure fail the install.
12
+ * Artifact-time prepare (`npm pack` or `npm publish`) instead exits with one
13
+ * notice before resolving pm-ops, preserving the packing clone's Git config.
12
14
  *
13
15
  * Canonical copy: `pm-ops/templates/prepare-merge-driver.ts`. Copy it
14
16
  * unchanged to `scripts/prepare-merge-driver.ts`.
@@ -19,47 +21,54 @@ import { lstatSync } from "node:fs";
19
21
  import { createRequire } from "node:module";
20
22
  import { join } from "node:path";
21
23
 
22
- // npm runs `prepare` from the package root, so pm-ops is resolved from there.
23
- const resolver = createRequire(join(process.cwd(), "package.json"));
24
- let installer: string | undefined;
25
- try {
26
- installer = resolver.resolve("pm-ops/merge-driver/prepare");
27
- } catch (error) {
28
- // Only an absent pm-ops package may skip. Probing its package.json tells that
29
- // apart from an installed pm-ops that cannot serve the entry (exports without
30
- // it, no exports map, a missing file): those resolve or fail differently, and
31
- // the original error is rethrown. A probe that finds no package.json is not
32
- // yet proof of absence: a broken install can leave `node_modules/pm-ops` (a
33
- // directory or a dangling link) with no package.json in any ancestor Node
34
- // searches. Such an entry also counts as present. Keep Node's global paths
35
- // too: the installer resolution above can use them, so an absent local
36
- // package alone cannot prove absence. An unreadable or malformed lookup path
37
- // leaves presence uncertain and must fail closed with the original error.
38
- // Node returns null paths only for built-in modules; pm-ops/package.json is
39
- // a package specifier.
40
- let packagePresent = true;
24
+ // npm also runs prepare while creating artifacts. Git configuration belongs
25
+ // to clone installation, so artifact creation must stop before resolution or
26
+ // spawning the installer. Keep the install/ci broken-package checks intact.
27
+ if (process.env.npm_command === "pack" || process.env.npm_command === "publish") {
28
+ console.error(`npm ${process.env.npm_command}: skipping merge-driver install during artifact creation`);
29
+ } else {
30
+ // npm runs `prepare` from the package root, so pm-ops is resolved from there.
31
+ const resolver = createRequire(join(process.cwd(), "package.json"));
32
+ let installer: string | undefined;
41
33
  try {
42
- resolver.resolve("pm-ops/package.json");
43
- } catch (probe) {
44
- packagePresent =
45
- !(probe instanceof Error && "code" in probe && probe.code === "MODULE_NOT_FOUND") ||
46
- resolver.resolve.paths("pm-ops/package.json")!.some(
47
- (directory) => {
48
- try {
49
- return lstatSync(join(directory, "pm-ops"), { throwIfNoEntry: false }) !== undefined;
50
- } catch {
51
- // throwIfNoEntry:false only suppresses ENOENT, not EACCES, EPERM,
52
- // ENOTDIR, or ELOOP. Do not replace the installer diagnostic or
53
- // treat an inconclusive presence check as an omit-dev install.
54
- return true;
55
- }
56
- },
57
- );
34
+ installer = resolver.resolve("pm-ops/merge-driver/prepare");
35
+ } catch (error) {
36
+ // Only an absent pm-ops package may skip. Probing its package.json tells that
37
+ // apart from an installed pm-ops that cannot serve the entry (exports without
38
+ // it, no exports map, a missing file): those resolve or fail differently, and
39
+ // the original error is rethrown. A probe that finds no package.json is not
40
+ // yet proof of absence: a broken install can leave `node_modules/pm-ops` (a
41
+ // directory or a dangling link) with no package.json in any ancestor Node
42
+ // searches. Such an entry also counts as present. Keep Node's global paths
43
+ // too: the installer resolution above can use them, so an absent local
44
+ // package alone cannot prove absence. An unreadable or malformed lookup path
45
+ // leaves presence uncertain and must fail closed with the original error.
46
+ // Node returns null paths only for built-in modules; pm-ops/package.json is
47
+ // a package specifier.
48
+ let packagePresent = true;
49
+ try {
50
+ resolver.resolve("pm-ops/package.json");
51
+ } catch (probe) {
52
+ packagePresent =
53
+ !(probe instanceof Error && "code" in probe && probe.code === "MODULE_NOT_FOUND") ||
54
+ resolver.resolve.paths("pm-ops/package.json")!.some(
55
+ (directory) => {
56
+ try {
57
+ return lstatSync(join(directory, "pm-ops"), { throwIfNoEntry: false }) !== undefined;
58
+ } catch {
59
+ // throwIfNoEntry:false only suppresses ENOENT, not EACCES, EPERM,
60
+ // ENOTDIR, or ELOOP. Do not replace the installer diagnostic or
61
+ // treat an inconclusive presence check as an omit-dev install.
62
+ return true;
63
+ }
64
+ },
65
+ );
66
+ }
67
+ if (packagePresent) throw error;
68
+ }
69
+ if (installer === undefined) {
70
+ console.error("pm-ops is not installed (omit-dev install); skipping merge-driver install");
71
+ } else {
72
+ process.exitCode = spawnSync(process.execPath, [installer], { stdio: "inherit" }).status ?? 1;
58
73
  }
59
- if (packagePresent) throw error;
60
- }
61
- if (installer === undefined) {
62
- console.error("pm-ops is not installed (omit-dev install); skipping merge-driver install");
63
- } else {
64
- process.exitCode = spawnSync(process.execPath, [installer], { stdio: "inherit" }).status ?? 1;
65
74
  }