@savvy-web/silk-effects 10.0.0 → 10.1.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.
package/index.d.ts CHANGED
@@ -6939,6 +6939,9 @@ declare class Command {
6939
6939
  private static cachedPackageManager;
6940
6940
  /** Cached project root path */
6941
6941
  private static cachedRoot;
6942
+ /** Memoizing tool discovery, created lazily and dropped by `clearCache` */
6943
+ private static discovery;
6944
+ private static getDiscovery;
6942
6945
  /**
6943
6946
  * Find the project root directory by walking up from `cwd`.
6944
6947
  *
@@ -6963,9 +6966,8 @@ declare class Command {
6963
6966
  /**
6964
6967
  * Detect the package manager declared by the root package.json.
6965
6968
  *
6966
- * Reads `devEngines.packageManager.name` (the first entry when it is an array), then the
6967
- * legacy `packageManager` field (e.g., `pnpm\@9.0.0`), then lockfile presence in priority
6968
- * order pnpm, yarn, bun. Falls back to "npm" when none of them names a manager.
6969
+ * Delegates to the kit's `detectPackageManagerSync` (manifest fields, then workspace and
6970
+ * lockfile markers) at `cwd` without walking up. Falls back to "npm" when none names a manager.
6969
6971
  *
6970
6972
  * @param cwd - Directory to search for package.json (defaults to `Command.findRoot()`)
6971
6973
  * @returns The detected package manager
@@ -6986,7 +6988,7 @@ declare class Command {
6986
6988
  * @example
6987
6989
  * ```typescript
6988
6990
  * Command.getExecPrefix('pnpm'); // ['pnpm', 'exec']
6989
- * Command.getExecPrefix('npm'); // ['npx', '--no']
6991
+ * Command.getExecPrefix('npm'); // ['npx', '--no', '--']
6990
6992
  * Command.getExecPrefix('yarn'); // ['yarn', 'exec']
6991
6993
  * Command.getExecPrefix('bun'); // ['bun', 'x', "--no-install"]
6992
6994
  * ```
@@ -7061,6 +7063,8 @@ declare class Command {
7061
7063
  /**
7062
7064
  * Execute a command and return its output.
7063
7065
  *
7066
+ * @deprecated No in-repo consumers; will be removed in a future major.
7067
+ *
7064
7068
  * @param command - The command to execute
7065
7069
  * @returns The command output as a string (trimmed)
7066
7070
  * @throws If the command fails
@@ -7075,6 +7079,8 @@ declare class Command {
7075
7079
  /**
7076
7080
  * Execute a command silently (ignore output).
7077
7081
  *
7082
+ * @deprecated No in-repo consumers; will be removed in a future major.
7083
+ *
7078
7084
  * @param command - The command to execute
7079
7085
  * @returns `true` if successful, `false` if failed
7080
7086
  */
@@ -1,7 +1,11 @@
1
- import { detectFromLockfiles, parsePackageManagerField } from "../../commitlint/hook/diagnostics/package-manager.js";
2
- import { existsSync, readFileSync } from "node:fs";
1
+ import { Result } from "effect";
2
+ import { existsSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
+ import { detectPackageManagerSync } from "@effected/workspaces";
4
5
  import { execSync } from "node:child_process";
6
+ import { LocalExec, Tool, makeToolDiscoverySync } from "@effected/commands";
7
+ import { nodeSpawnSync } from "@effected/commands/node-sync";
8
+ import { nodeSyncOps } from "@effected/workspaces/node-sync";
5
9
 
6
10
  // src/lint/utils/Command.ts
7
11
  /**
@@ -46,6 +50,18 @@ var Command = class Command {
46
50
  static cachedPackageManager = null;
47
51
  /** Cached project root path */
48
52
  static cachedRoot = null;
53
+ /** Memoizing tool discovery, created lazily and dropped by `clearCache` */
54
+ static discovery = null;
55
+ static getDiscovery() {
56
+ if (Command.discovery === null) {
57
+ const context = LocalExec.contextFor(Command.detectPackageManager(), { directory: Command.findRoot() });
58
+ Command.discovery = makeToolDiscoverySync({
59
+ spawn: nodeSpawnSync,
60
+ context
61
+ });
62
+ }
63
+ return Command.discovery;
64
+ }
49
65
  /**
50
66
  * Find the project root directory by walking up from `cwd`.
51
67
  *
@@ -84,9 +100,8 @@ var Command = class Command {
84
100
  /**
85
101
  * Detect the package manager declared by the root package.json.
86
102
  *
87
- * Reads `devEngines.packageManager.name` (the first entry when it is an array), then the
88
- * legacy `packageManager` field (e.g., `pnpm\@9.0.0`), then lockfile presence in priority
89
- * order pnpm, yarn, bun. Falls back to "npm" when none of them names a manager.
103
+ * Delegates to the kit's `detectPackageManagerSync` (manifest fields, then workspace and
104
+ * lockfile markers) at `cwd` without walking up. Falls back to "npm" when none names a manager.
90
105
  *
91
106
  * @param cwd - Directory to search for package.json (defaults to `Command.findRoot()`)
92
107
  * @returns The detected package manager
@@ -99,16 +114,8 @@ var Command = class Command {
99
114
  */
100
115
  static detectPackageManager(cwd = Command.findRoot()) {
101
116
  if (Command.cachedPackageManager !== null) return Command.cachedPackageManager;
102
- const packageJsonPath = join(cwd, "package.json");
103
- let declared = null;
104
- try {
105
- declared = parsePackageManagerField(readFileSync(packageJsonPath, "utf-8"));
106
- } catch {}
107
- Command.cachedPackageManager = declared ?? detectFromLockfiles({
108
- pnpm: existsSync(join(cwd, "pnpm-lock.yaml")),
109
- yarn: existsSync(join(cwd, "yarn.lock")),
110
- bun: existsSync(join(cwd, "bun.lock"))
111
- });
117
+ const detected = detectPackageManagerSync(cwd, nodeSyncOps);
118
+ Command.cachedPackageManager = Result.isSuccess(detected) ? detected.success.name : "npm";
112
119
  return Command.cachedPackageManager;
113
120
  }
114
121
  /**
@@ -120,22 +127,13 @@ var Command = class Command {
120
127
  * @example
121
128
  * ```typescript
122
129
  * Command.getExecPrefix('pnpm'); // ['pnpm', 'exec']
123
- * Command.getExecPrefix('npm'); // ['npx', '--no']
130
+ * Command.getExecPrefix('npm'); // ['npx', '--no', '--']
124
131
  * Command.getExecPrefix('yarn'); // ['yarn', 'exec']
125
132
  * Command.getExecPrefix('bun'); // ['bun', 'x', "--no-install"]
126
133
  * ```
127
134
  */
128
135
  static getExecPrefix(packageManager) {
129
- switch (packageManager) {
130
- case "pnpm": return ["pnpm", "exec"];
131
- case "yarn": return ["yarn", "exec"];
132
- case "bun": return [
133
- "bun",
134
- "x",
135
- "--no-install"
136
- ];
137
- default: return ["npx", "--no"];
138
- }
136
+ return [...LocalExec.contextFor(packageManager).prefix];
139
137
  }
140
138
  /**
141
139
  * Clear the cached package manager and project root detection.
@@ -144,6 +142,8 @@ var Command = class Command {
144
142
  static clearCache() {
145
143
  Command.cachedPackageManager = null;
146
144
  Command.cachedRoot = null;
145
+ Command.discovery?.invalidateAll();
146
+ Command.discovery = null;
147
147
  }
148
148
  /**
149
149
  * Check if a command is available in the system PATH.
@@ -160,12 +160,7 @@ var Command = class Command {
160
160
  */
161
161
  static isAvailable(command) {
162
162
  validateCommandName(command);
163
- try {
164
- execSync(`command -v ${command}`, { stdio: "ignore" });
165
- return true;
166
- } catch {
167
- return false;
168
- }
163
+ return Command.getDiscovery().isAvailable(Tool.named(command, { source: "global" }));
169
164
  }
170
165
  /**
171
166
  * Find a tool, checking global installation first, then the project's package manager.
@@ -188,26 +183,18 @@ var Command = class Command {
188
183
  */
189
184
  static findTool(tool) {
190
185
  validateCommandName(tool);
191
- if (Command.isAvailable(tool)) return {
192
- available: true,
193
- command: tool,
194
- source: "global"
195
- };
196
- const pm = Command.detectPackageManager();
197
- const execCmd = [...Command.getExecPrefix(pm), tool].join(" ");
198
- try {
199
- execSync(`${execCmd} --version`, { stdio: "ignore" });
200
- return {
201
- available: true,
202
- command: execCmd,
203
- source: pm
204
- };
205
- } catch {}
206
- return {
186
+ const resolved = Command.getDiscovery().resolve(Tool.named(tool, { prefer: "global" }));
187
+ if (Result.isFailure(resolved)) return {
207
188
  available: false,
208
189
  command: void 0,
209
190
  source: void 0
210
191
  };
192
+ const found = resolved.success;
193
+ return {
194
+ available: true,
195
+ command: found.argv().join(" "),
196
+ source: found.source === "global" ? "global" : Command.detectPackageManager()
197
+ };
211
198
  }
212
199
  /**
213
200
  * Find a tool or throw an error if not available.
@@ -247,6 +234,8 @@ var Command = class Command {
247
234
  /**
248
235
  * Execute a command and return its output.
249
236
  *
237
+ * @deprecated No in-repo consumers; will be removed in a future major.
238
+ *
250
239
  * @param command - The command to execute
251
240
  * @returns The command output as a string (trimmed)
252
241
  * @throws If the command fails
@@ -263,6 +252,8 @@ var Command = class Command {
263
252
  /**
264
253
  * Execute a command silently (ignore output).
265
254
  *
255
+ * @deprecated No in-repo consumers; will be removed in a future major.
256
+ *
266
257
  * @param command - The command to execute
267
258
  * @returns `true` if successful, `false` if failed
268
259
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk-effects",
3
- "version": "10.0.0",
3
+ "version": "10.1.0",
4
4
  "private": false,
5
5
  "description": "Shared Effect library for Silk Suite conventions",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
@@ -40,20 +40,20 @@
40
40
  "@effected/github-references": "^0.11.0",
41
41
  "@effected/glob": "^0.14.0",
42
42
  "@effected/jsonc": "^0.20.0",
43
- "@effected/markdown": "^0.22.0",
44
- "@effected/package-json": "^0.25.1",
43
+ "@effected/markdown": "^0.23.0",
44
+ "@effected/package-json": "^0.26.0",
45
45
  "@effected/toml": "^0.16.0",
46
- "@effected/walker": "^0.19.0",
47
- "@effected/yaml": "^0.25.0",
46
+ "@effected/walker": "^0.20.1",
47
+ "@effected/yaml": "^0.25.1",
48
48
  "@manypkg/get-packages": "^3.1.0",
49
- "@savvy-web/silk-core": "^0.5.1",
49
+ "@savvy-web/silk-core": "^0.5.2",
50
50
  "shell-quote": "^1.12.0"
51
51
  },
52
52
  "peerDependencies": {
53
- "@effected/commands": "^0.15.0",
53
+ "@effected/commands": "^0.16.0",
54
54
  "@effected/git": "^0.25.0",
55
55
  "@effected/templates": "^0.14.0",
56
- "@effected/workspaces": "^0.38.0",
56
+ "@effected/workspaces": "^0.39.0",
57
57
  "effect": "^4.0.0"
58
58
  }
59
59
  }
@@ -1,10 +1,35 @@
1
1
  import { ChangesetConfig } from "./ChangesetConfig.js";
2
2
  import { PublishTargetBindingError, ReleaseChannelError, trimTrailingSlashes } from "@savvy-web/silk-core";
3
- import { Effect, FileSystem, Layer } from "effect";
3
+ import { Effect, FileSystem, Layer, Schema } from "effect";
4
4
  import { isAbsolute, join, relative } from "node:path";
5
5
  import { PublishTarget, PublishabilityDetector, WorkspaceDiscovery } from "@effected/workspaces";
6
6
 
7
7
  // src/services/SilkPublishability.ts
8
+ /**
9
+ * Structural decoder for {@link TargetsBinding}.
10
+ *
11
+ * @remarks
12
+ * `releases` is decoded as `unknown` on purpose: an unrecognised channel must surface as a typed
13
+ * `ReleaseChannelError` from `releaseChannelOf` (which names the package and target), not collapse
14
+ * into a missing binding here. Every other field is validated structurally.
15
+ */
16
+ const TargetsBindingSchema = Schema.Struct({
17
+ groups: Schema.Array(Schema.Struct({
18
+ id: Schema.String,
19
+ name: Schema.String,
20
+ dir: Schema.String
21
+ })),
22
+ targets: Schema.Array(Schema.Struct({
23
+ id: Schema.String,
24
+ group: Schema.String,
25
+ name: Schema.String,
26
+ registry: Schema.String,
27
+ releases: Schema.optionalKey(Schema.Unknown),
28
+ provenance: Schema.optionalKey(Schema.Boolean)
29
+ }))
30
+ });
31
+ /** `targets.json` file contents (a JSON string) decoded to a {@link TargetsBinding}. */
32
+ const TargetsBindingFromJson = Schema.fromJsonString(TargetsBindingSchema);
8
33
  const NPM_DEFAULT = "https://registry.npmjs.org/";
9
34
  /**
10
35
  * Default registry endpoints for the well-known target keys. Kept in sync with the
@@ -413,9 +438,6 @@ const readRaw = (fs, packageJsonPath) => fs.readFileString(packageJsonPath).pipe
413
438
  * @since 1.0.0
414
439
  * @public
415
440
  */
416
- const readTargetsBinding = (fs, pkgPath) => fs.readFileString(join(pkgPath, "dist", "prod", "targets.json")).pipe(Effect.flatMap((content) => Effect.try({
417
- try: () => JSON.parse(content),
418
- catch: () => /* @__PURE__ */ new Error("invalid targets.json")
419
- })), Effect.orElseSucceed(() => null));
441
+ const readTargetsBinding = (fs, pkgPath) => fs.readFileString(join(pkgPath, "dist", "prod", "targets.json")).pipe(Effect.flatMap(Schema.decodeUnknownEffect(TargetsBindingFromJson)), Effect.map((binding) => binding), Effect.orElseSucceed(() => null));
420
442
 
421
443
  export { SilkPublishability, readTargetsBinding };
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.59.1"
8
+ "packageVersion": "7.59.4"
9
9
  }
10
10
  ]
11
11
  }