pm-ops 2026.9.13 → 2026.9.18
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/CHANGELOG.md +29 -17
- package/README.md +100 -6
- package/dist/attestation.d.ts.map +1 -1
- package/dist/attestation.js +13 -23
- package/dist/attestation.js.map +1 -1
- package/dist/duplication.d.ts +75 -0
- package/dist/duplication.d.ts.map +1 -0
- package/dist/duplication.js +196 -0
- package/dist/duplication.js.map +1 -0
- package/dist/eslint.d.ts +41 -0
- package/dist/eslint.d.ts.map +1 -0
- package/dist/eslint.js +125 -0
- package/dist/eslint.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -121
- package/dist/index.js.map +1 -1
- package/dist/invocation-audit.d.ts +33 -0
- package/dist/invocation-audit.d.ts.map +1 -0
- package/dist/invocation-audit.js +47 -0
- package/dist/invocation-audit.js.map +1 -0
- package/dist/merge-driver.d.ts +57 -0
- package/dist/merge-driver.d.ts.map +1 -0
- package/dist/merge-driver.js +122 -0
- package/dist/merge-driver.js.map +1 -0
- package/manifest.json +1 -1
- package/package.json +50 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-driver.d.ts","sourceRoot":"","sources":["../merge-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,KAClE,OAAO,CAAC;AAEb;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,CASjF;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,GAAG,IAAI,CAuBjG;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,GAAE,MAAM,CAAC,UAAwB,EAC5C,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,OAAO,GAAE,cAA6B,GACrC,MAAM,CAgDR"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical installer for pm's field-aware Git merge drivers.
|
|
3
|
+
*
|
|
4
|
+
* Git never clones `.git/config`, so every fleet package has to run
|
|
5
|
+
* `pm merge install` from its npm `prepare` script or concurrent agents
|
|
6
|
+
* conflict on tracker files. Twelve repositories vendored a byte-identical
|
|
7
|
+
* untyped JavaScript hook for that step. This module is the typed, tested
|
|
8
|
+
* replacement those packages import as `pm-ops/merge-driver`.
|
|
9
|
+
*
|
|
10
|
+
* Absence of `pm` is a supported production-install state and skips with a
|
|
11
|
+
* one-line notice. A present but broken CLI fails loudly so an install cannot
|
|
12
|
+
* pretend it configured merge safety when it did not. Windows PATH quoting,
|
|
13
|
+
* PATHEXT shims, and the `execFile` `.cmd` limitation are honoured through an
|
|
14
|
+
* injectable process boundary so the POSIX path is never faked.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
import { execFileSync } from "node:child_process";
|
|
19
|
+
import { accessSync, constants, statSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
/**
|
|
22
|
+
* Return whether `path` is a regular file the current platform would execute.
|
|
23
|
+
*
|
|
24
|
+
* POSIX requires the executable bit. Windows keys executability off PATHEXT,
|
|
25
|
+
* so a regular file is enough; directories, missing paths, and (on POSIX)
|
|
26
|
+
* mode-000 files are rejected without turning an ordinary absent-CLI install
|
|
27
|
+
* into a failure.
|
|
28
|
+
*/
|
|
29
|
+
export function isExecutableFile(path, platform) {
|
|
30
|
+
try {
|
|
31
|
+
if (!statSync(path).isFile())
|
|
32
|
+
return false;
|
|
33
|
+
if (platform === "win32")
|
|
34
|
+
return true;
|
|
35
|
+
accessSync(path, constants.X_OK);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the exact `pm` launcher on the supplied PATH, or `null` if none.
|
|
44
|
+
*
|
|
45
|
+
* Inspection never executes a candidate, so a present-but-broken CLI is not
|
|
46
|
+
* mistaken for absence. Empty POSIX components mean the current directory;
|
|
47
|
+
* Windows ignores them, may quote directories that contain spaces, and appends
|
|
48
|
+
* each PATHEXT suffix (defaulting to `.COM;.EXE;.BAT;.CMD` when unset).
|
|
49
|
+
*/
|
|
50
|
+
export function pmOnPath(environment, platform) {
|
|
51
|
+
const directories = (environment.PATH ?? "")
|
|
52
|
+
.split(platform === "win32" ? ";" : ":")
|
|
53
|
+
.map((entry) => platform === "win32" && entry.startsWith('"') && entry.endsWith('"')
|
|
54
|
+
? entry.slice(1, -1)
|
|
55
|
+
: entry === "" && platform !== "win32"
|
|
56
|
+
? "."
|
|
57
|
+
: entry)
|
|
58
|
+
.filter((entry) => entry !== "");
|
|
59
|
+
const extensions = platform === "win32"
|
|
60
|
+
? (environment.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((entry) => entry.trim()).filter((entry) => entry.length > 0)
|
|
61
|
+
: [""];
|
|
62
|
+
for (const directory of directories) {
|
|
63
|
+
for (const extension of extensions) {
|
|
64
|
+
const candidate = join(directory, `pm${extension}`);
|
|
65
|
+
if (isExecutableFile(candidate, platform))
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Install clone-local merge drivers when `pm` is available.
|
|
73
|
+
*
|
|
74
|
+
* @returns `0` when installation ran or `pm` was absent (a one-line notice is
|
|
75
|
+
* printed on skip). A present CLI whose `pm merge install` fails returns that
|
|
76
|
+
* command's numeric status, or `1` when the failure has no status.
|
|
77
|
+
*/
|
|
78
|
+
export function runPrepareMergeDriver(environment = process.env, platform = process.platform, install = execFileSync) {
|
|
79
|
+
const executable = pmOnPath(environment, platform);
|
|
80
|
+
if (executable === null) {
|
|
81
|
+
console.error("pm is not on PATH; skipping merge-driver install");
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Node cannot execFile a Windows .cmd shim, so Windows has to go through
|
|
86
|
+
// cmd.exe. Only the constant command `pm merge install` may cross that
|
|
87
|
+
// boundary: interpolating the resolved path would let a PATH directory
|
|
88
|
+
// containing spaces split the command line, or one containing cmd
|
|
89
|
+
// metacharacters (`&`, `|`, `^`, `%`) inject into it. cmd resolves `pm`
|
|
90
|
+
// from the same PATH and PATHEXT that discovery just validated. POSIX
|
|
91
|
+
// executes the validated absolute path directly, with no shell at all.
|
|
92
|
+
//
|
|
93
|
+
// cmd.exe also searches the CURRENT directory before PATH, so a `pm.cmd`
|
|
94
|
+
// committed at the repository root (the prepare hook's cwd) would replace
|
|
95
|
+
// the validated launcher (CWE-426). NoDefaultCurrentDirectoryInExePath
|
|
96
|
+
// turns that search off for the child; any case variant already in the
|
|
97
|
+
// environment is dropped first, because Windows treats names
|
|
98
|
+
// case-insensitively and a stale `nodefaultcurrentdirectoryinexepath=`
|
|
99
|
+
// could otherwise shadow the one set here.
|
|
100
|
+
const windows = platform === "win32";
|
|
101
|
+
install(windows ? "pm" : executable, ["merge", "install"], {
|
|
102
|
+
stdio: "inherit",
|
|
103
|
+
env: windows
|
|
104
|
+
? {
|
|
105
|
+
...Object.fromEntries(Object.entries(environment).filter(([name]) => name.toLowerCase() !== "nodefaultcurrentdirectoryinexepath")),
|
|
106
|
+
NoDefaultCurrentDirectoryInExePath: "1",
|
|
107
|
+
}
|
|
108
|
+
: environment,
|
|
109
|
+
shell: windows,
|
|
110
|
+
});
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.error(error instanceof Error ? error.message : error);
|
|
115
|
+
if (typeof error === "object" && error !== null && "status" in error &&
|
|
116
|
+
typeof error.status === "number") {
|
|
117
|
+
return error.status;
|
|
118
|
+
}
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=merge-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-driver.js","sourceRoot":"","sources":["../merge-driver.ts"],"names":[],"mappings":"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"}
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-ops",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.18",
|
|
4
4
|
"description": "Multi-repo fleet operations for pm-cli",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,9 +34,21 @@
|
|
|
34
34
|
"types": "./dist/attestation.d.ts",
|
|
35
35
|
"default": "./dist/attestation.js"
|
|
36
36
|
},
|
|
37
|
+
"./merge-driver": {
|
|
38
|
+
"types": "./dist/merge-driver.d.ts",
|
|
39
|
+
"default": "./dist/merge-driver.js"
|
|
40
|
+
},
|
|
37
41
|
"./lifecycle-policy": {
|
|
38
42
|
"types": "./dist/lifecycle-policy.d.ts",
|
|
39
43
|
"default": "./dist/lifecycle-policy.js"
|
|
44
|
+
},
|
|
45
|
+
"./eslint": {
|
|
46
|
+
"types": "./dist/eslint.d.ts",
|
|
47
|
+
"default": "./dist/eslint.js"
|
|
48
|
+
},
|
|
49
|
+
"./duplication": {
|
|
50
|
+
"types": "./dist/duplication.d.ts",
|
|
51
|
+
"default": "./dist/duplication.js"
|
|
40
52
|
}
|
|
41
53
|
},
|
|
42
54
|
"files": [
|
|
@@ -58,7 +70,9 @@
|
|
|
58
70
|
"changelog:full": "pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-ops/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded",
|
|
59
71
|
"changelog:check": "pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-ops/blob/main/.agents/pm --respect-item-release --check --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded",
|
|
60
72
|
"docstring": "node scripts/docstring-gate.ts",
|
|
61
|
-
"
|
|
73
|
+
"lint": "node scripts/lint.ts",
|
|
74
|
+
"duplication": "node scripts/duplication-gate.ts",
|
|
75
|
+
"release:check": "npm run check && npm run lint && npm run duplication && npm run docstring && npm run coverage && npm run audit:prod && npm run pack:dry-run && npm run changelog:check && npm run verify:release-changelog-date && npm run verify:release-publish-attestation && npm run verify:lifecycle-policy",
|
|
62
76
|
"prepublishOnly": "npm run release:check",
|
|
63
77
|
"release:notes": "pm-changelog --pm-root .agents/pm --stdout --since-previous-tag --until-release-tag --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-ops/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --github-step-summary",
|
|
64
78
|
"prepare": "node scripts/prepare-merge-driver.ts",
|
|
@@ -74,13 +88,40 @@
|
|
|
74
88
|
"typescript": "7.0.2"
|
|
75
89
|
},
|
|
76
90
|
"peerDependencies": {
|
|
77
|
-
"@
|
|
91
|
+
"@babel/eslint-parser": "^8.0.5",
|
|
92
|
+
"@babel/plugin-syntax-typescript": "^8.0.3",
|
|
93
|
+
"@unbrained/pm-cli": ">=2026.8.20",
|
|
94
|
+
"eslint": "^10.10.0",
|
|
95
|
+
"fast-glob": "^3.3.3",
|
|
96
|
+
"jscpd": "^4.3.0"
|
|
97
|
+
},
|
|
98
|
+
"peerDependenciesMeta": {
|
|
99
|
+
"@babel/eslint-parser": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@babel/plugin-syntax-typescript": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"eslint": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"fast-glob": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"jscpd": {
|
|
112
|
+
"optional": true
|
|
113
|
+
}
|
|
78
114
|
},
|
|
79
115
|
"devDependencies": {
|
|
116
|
+
"@babel/eslint-parser": "^8.0.5",
|
|
117
|
+
"@babel/plugin-syntax-typescript": "^8.0.3",
|
|
80
118
|
"@types/node": "^26.2.0",
|
|
81
|
-
"@unbrained/pm-cli": "2026.9.
|
|
119
|
+
"@unbrained/pm-cli": "2026.9.17",
|
|
82
120
|
"c8": "^12.0.0",
|
|
83
|
-
"
|
|
121
|
+
"eslint": "^10.10.0",
|
|
122
|
+
"fast-glob": "^3.3.3",
|
|
123
|
+
"jscpd": "^4.3.0",
|
|
124
|
+
"pm-changelog": "^2026.9.16"
|
|
84
125
|
},
|
|
85
126
|
"keywords": [
|
|
86
127
|
"pm-cli",
|
|
@@ -145,5 +186,9 @@
|
|
|
145
186
|
"functions": 100
|
|
146
187
|
},
|
|
147
188
|
"ignore": []
|
|
189
|
+
},
|
|
190
|
+
"duplicationGate": {
|
|
191
|
+
"threshold": 0,
|
|
192
|
+
"minTokens": 50
|
|
148
193
|
}
|
|
149
194
|
}
|