@kici-dev/shared 0.1.9 → 0.1.11

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.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Package-manager identity — the enum and pure helpers, with no filesystem
3
+ * dependency. Kept separate from `package-manager.ts` (which reads the disk to
4
+ * detect the manager) so browser-safe consumers — the engine protocol schemas
5
+ * and lock-file types the dashboard transitively imports — can reference the
6
+ * enum without pulling `node:fs` into a browser bundle.
7
+ */
8
+ /** Supported package managers. */
9
+ export declare enum PackageManager {
10
+ Npm = "npm",
11
+ Pnpm = "pnpm",
12
+ Yarn = "yarn"
13
+ }
14
+ /** All package-manager identifiers, for flag/schema validation. */
15
+ export declare const PACKAGE_MANAGERS: readonly PackageManager[];
16
+ /**
17
+ * Parse a raw string into a {@link PackageManager}, or `null` when it does not
18
+ * name a supported manager. Accepts bare names (`pnpm`) used by the CLI flag
19
+ * and the env-var / packageManager-field tiers.
20
+ */
21
+ export declare function parsePackageManager(value: string): PackageManager | null;
22
+ //# sourceMappingURL=package-manager-types.d.ts.map
@@ -0,0 +1,35 @@
1
+ import "./chunk-gOLHoazu.js";
2
+ //#region src/package-manager-types.ts
3
+ /**
4
+ * Package-manager identity — the enum and pure helpers, with no filesystem
5
+ * dependency. Kept separate from `package-manager.ts` (which reads the disk to
6
+ * detect the manager) so browser-safe consumers — the engine protocol schemas
7
+ * and lock-file types the dashboard transitively imports — can reference the
8
+ * enum without pulling `node:fs` into a browser bundle.
9
+ */
10
+ /** Supported package managers. */
11
+ let PackageManager = /* @__PURE__ */ function(PackageManager) {
12
+ PackageManager["Npm"] = "npm";
13
+ PackageManager["Pnpm"] = "pnpm";
14
+ PackageManager["Yarn"] = "yarn";
15
+ return PackageManager;
16
+ }({});
17
+ /** All package-manager identifiers, for flag/schema validation. */
18
+ const PACKAGE_MANAGERS = Object.values(PackageManager);
19
+ /**
20
+ * Parse a raw string into a {@link PackageManager}, or `null` when it does not
21
+ * name a supported manager. Accepts bare names (`pnpm`) used by the CLI flag
22
+ * and the env-var / packageManager-field tiers.
23
+ */
24
+ function parsePackageManager(value) {
25
+ switch (value) {
26
+ case "npm": return "npm";
27
+ case "pnpm": return "pnpm";
28
+ case "yarn": return "yarn";
29
+ default: return null;
30
+ }
31
+ }
32
+ //#endregion
33
+ export { PACKAGE_MANAGERS, PackageManager, parsePackageManager };
34
+
35
+ //# sourceMappingURL=package-manager-types.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Package-manager detection.
3
+ *
4
+ * Determines which package manager (npm / pnpm / yarn) a project relies on, so
5
+ * dependency operations use the manager that matches the rest of the user's
6
+ * repository instead of always assuming npm. Used by `kici init` (to generate a
7
+ * lockfile that matches the user's repo) and by the agent (to install `.kici/`
8
+ * dependencies with the manager that can resolve the repo's dependency graph,
9
+ * including pnpm/yarn `workspace:` siblings).
10
+ *
11
+ * The {@link PackageManager} enum + pure helpers live in the node-free
12
+ * `./package-manager-types.js` module and are re-exported here so existing
13
+ * `@kici-dev/shared/package-manager` consumers keep one import site.
14
+ */
15
+ import { PackageManager } from './package-manager-types.js';
16
+ export { PackageManager, PACKAGE_MANAGERS, parsePackageManager } from './package-manager-types.js';
17
+ /** Map a detected manager to its install command argv (binary + args). */
18
+ export declare function installCommand(pm: PackageManager): [string, 'install'];
19
+ /**
20
+ * Detect the package manager the user's project relies on.
21
+ *
22
+ * Priority order (first match wins):
23
+ * 1. `packageManager` field in `<projectDir>/package.json` (Corepack
24
+ * convention, e.g. `"packageManager": "pnpm@9.x"`). Only the name before
25
+ * `@` is parsed; an unrecognized name falls through.
26
+ * 2. A lockfile in the project root (`pnpm-lock.yaml` > `yarn.lock` >
27
+ * `package-lock.json`).
28
+ * 3. The `npm_config_user_agent` env var (set by `pnpm dlx` / `yarn dlx` /
29
+ * `npx`); the leading `<name>/` segment names the manager.
30
+ * 4. Default to npm when nothing matches, so we never guess wrong and emit a
31
+ * lockfile the user did not ask for.
32
+ *
33
+ * @param projectDir - The project root to inspect.
34
+ */
35
+ export declare function detectPackageManager(projectDir: string): Promise<PackageManager>;
36
+ /**
37
+ * Detect the package manager from a directory's **committed manifests only** —
38
+ * tiers 1 (`packageManager` field) and 2 (lockfile). Returns `null` when the
39
+ * directory carries no package-manager signal, so callers can distinguish
40
+ * "explicitly npm" from "no signal".
41
+ *
42
+ * This deliberately excludes the `npm_config_user_agent` tier: a consumer
43
+ * inspecting a cloned repository (the agent) must key off the repo's own files,
44
+ * not the ambient env of the process that happens to be reading them.
45
+ */
46
+ export declare function detectPackageManagerFromManifests(projectDir: string): Promise<PackageManager | null>;
47
+ /**
48
+ * Synchronous {@link detectPackageManager}. Used by the compiler's lock-file
49
+ * generation, which is synchronous; identical tiering and precedence.
50
+ */
51
+ export declare function detectPackageManagerSync(projectDir: string): PackageManager;
52
+ //# sourceMappingURL=package-manager.d.ts.map
@@ -0,0 +1,131 @@
1
+ import "./chunk-gOLHoazu.js";
2
+ import { PACKAGE_MANAGERS, PackageManager, parsePackageManager } from "./package-manager-types.js";
3
+ import { access, readFile } from "node:fs/promises";
4
+ import { accessSync, readFileSync } from "node:fs";
5
+ import path from "node:path";
6
+ //#region src/package-manager.ts
7
+ /**
8
+ * Package-manager detection.
9
+ *
10
+ * Determines which package manager (npm / pnpm / yarn) a project relies on, so
11
+ * dependency operations use the manager that matches the rest of the user's
12
+ * repository instead of always assuming npm. Used by `kici init` (to generate a
13
+ * lockfile that matches the user's repo) and by the agent (to install `.kici/`
14
+ * dependencies with the manager that can resolve the repo's dependency graph,
15
+ * including pnpm/yarn `workspace:` siblings).
16
+ *
17
+ * The {@link PackageManager} enum + pure helpers live in the node-free
18
+ * `./package-manager-types.js` module and are re-exported here so existing
19
+ * `@kici-dev/shared/package-manager` consumers keep one import site.
20
+ */
21
+ /** Map a detected manager to its install command argv (binary + args). */
22
+ function installCommand(pm) {
23
+ return [pm, "install"];
24
+ }
25
+ /** Lockfile basenames mapped to the manager that produces them, in priority order. */
26
+ const LOCKFILES = [
27
+ ["pnpm-lock.yaml", "pnpm"],
28
+ ["yarn.lock", "yarn"],
29
+ ["package-lock.json", "npm"]
30
+ ];
31
+ /**
32
+ * Detect the package manager the user's project relies on.
33
+ *
34
+ * Priority order (first match wins):
35
+ * 1. `packageManager` field in `<projectDir>/package.json` (Corepack
36
+ * convention, e.g. `"packageManager": "pnpm@9.x"`). Only the name before
37
+ * `@` is parsed; an unrecognized name falls through.
38
+ * 2. A lockfile in the project root (`pnpm-lock.yaml` > `yarn.lock` >
39
+ * `package-lock.json`).
40
+ * 3. The `npm_config_user_agent` env var (set by `pnpm dlx` / `yarn dlx` /
41
+ * `npx`); the leading `<name>/` segment names the manager.
42
+ * 4. Default to npm when nothing matches, so we never guess wrong and emit a
43
+ * lockfile the user did not ask for.
44
+ *
45
+ * @param projectDir - The project root to inspect.
46
+ */
47
+ async function detectPackageManager(projectDir) {
48
+ const fromManifests = await detectPackageManagerFromManifests(projectDir);
49
+ if (fromManifests) return fromManifests;
50
+ const fromUserAgent = parseUserAgent(process.env.npm_config_user_agent);
51
+ if (fromUserAgent) return fromUserAgent;
52
+ return "npm";
53
+ }
54
+ /**
55
+ * Detect the package manager from a directory's **committed manifests only** —
56
+ * tiers 1 (`packageManager` field) and 2 (lockfile). Returns `null` when the
57
+ * directory carries no package-manager signal, so callers can distinguish
58
+ * "explicitly npm" from "no signal".
59
+ *
60
+ * This deliberately excludes the `npm_config_user_agent` tier: a consumer
61
+ * inspecting a cloned repository (the agent) must key off the repo's own files,
62
+ * not the ambient env of the process that happens to be reading them.
63
+ */
64
+ async function detectPackageManagerFromManifests(projectDir) {
65
+ const fromField = parsePackageManagerField(await readPackageJson(projectDir));
66
+ if (fromField) return fromField;
67
+ for (const [file, pm] of LOCKFILES) if (await fileExists(path.join(projectDir, file))) return pm;
68
+ return null;
69
+ }
70
+ /**
71
+ * Synchronous {@link detectPackageManager}. Used by the compiler's lock-file
72
+ * generation, which is synchronous; identical tiering and precedence.
73
+ */
74
+ function detectPackageManagerSync(projectDir) {
75
+ const fromField = parsePackageManagerField(readPackageJsonSync(projectDir));
76
+ if (fromField) return fromField;
77
+ for (const [file, pm] of LOCKFILES) if (fileExistsSync(path.join(projectDir, file))) return pm;
78
+ const fromUserAgent = parseUserAgent(process.env.npm_config_user_agent);
79
+ if (fromUserAgent) return fromUserAgent;
80
+ return "npm";
81
+ }
82
+ /** Tier 1: parse the Corepack `packageManager` field, if present. */
83
+ function parsePackageManagerField(content) {
84
+ if (content === null) return null;
85
+ try {
86
+ const pkg = JSON.parse(content);
87
+ if (typeof pkg.packageManager !== "string") return null;
88
+ return parsePackageManager(pkg.packageManager.split("@", 1)[0]);
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+ /** Tier 3: the `npm_config_user_agent` env var, whose leading segment names the manager. */
94
+ function parseUserAgent(userAgent) {
95
+ if (!userAgent) return null;
96
+ return parsePackageManager(userAgent.split("/", 1)[0]);
97
+ }
98
+ async function readPackageJson(projectDir) {
99
+ try {
100
+ return await readFile(path.join(projectDir, "package.json"), "utf-8");
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ function readPackageJsonSync(projectDir) {
106
+ try {
107
+ return readFileSync(path.join(projectDir, "package.json"), "utf-8");
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+ async function fileExists(target) {
113
+ try {
114
+ await access(target);
115
+ return true;
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+ function fileExistsSync(target) {
121
+ try {
122
+ accessSync(target);
123
+ return true;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+ //#endregion
129
+ export { PACKAGE_MANAGERS, PackageManager, detectPackageManager, detectPackageManagerFromManifests, detectPackageManagerSync, installCommand, parsePackageManager };
130
+
131
+ //# sourceMappingURL=package-manager.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=package-manager.test.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/shared",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
5
5
  "keywords": [
6
6
  "kici",
@@ -65,6 +65,14 @@
65
65
  "./db-collation": {
66
66
  "import": "./dist/db-collation.js",
67
67
  "types": "./dist/db-collation.d.ts"
68
+ },
69
+ "./package-manager": {
70
+ "import": "./dist/package-manager.js",
71
+ "types": "./dist/package-manager.d.ts"
72
+ },
73
+ "./package-manager-types": {
74
+ "import": "./dist/package-manager-types.js",
75
+ "types": "./dist/package-manager-types.d.ts"
68
76
  }
69
77
  },
70
78
  "dependencies": {
package/sbom.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@kici-dev/shared@0.1.9",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.9/2a0fe48d-9ace-447e-bf38-52dc8ec9bacf",
5
+ "name": "@kici-dev/shared@0.1.11",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.11/93edde48-354c-4bb9-91a7-77d0ffd95743",
7
7
  "creationInfo": {
8
- "created": "2026-05-26T16:48:53Z",
8
+ "created": "2026-05-27T16:18:10Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -947,7 +947,7 @@
947
947
  {
948
948
  "SPDXID": "SPDXRef-RootPackage",
949
949
  "name": "@kici-dev/shared",
950
- "versionInfo": "0.1.9",
950
+ "versionInfo": "0.1.11",
951
951
  "downloadLocation": "NOASSERTION",
952
952
  "filesAnalyzed": false,
953
953
  "licenseConcluded": "NOASSERTION",
@@ -958,7 +958,7 @@
958
958
  {
959
959
  "referenceCategory": "PACKAGE-MANAGER",
960
960
  "referenceType": "purl",
961
- "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.9"
961
+ "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.11"
962
962
  }
963
963
  ],
964
964
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",