@pagepocket/cli 0.11.0 → 0.12.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.
Files changed (48) hide show
  1. package/dist/commands/archive.js +80 -118
  2. package/dist/commands/plugin/add.js +19 -25
  3. package/dist/commands/plugin/doctor.js +22 -28
  4. package/dist/commands/plugin/ls.js +16 -22
  5. package/dist/commands/plugin/prune.js +13 -19
  6. package/dist/commands/plugin/remove.js +16 -22
  7. package/dist/commands/plugin/set.js +14 -22
  8. package/dist/commands/plugin/uninstall.js +29 -35
  9. package/dist/commands/plugin/update.js +22 -28
  10. package/dist/commands/strategy/add.js +14 -20
  11. package/dist/commands/strategy/doctor.js +15 -21
  12. package/dist/commands/strategy/ls.js +31 -17
  13. package/dist/commands/strategy/pin.js +10 -16
  14. package/dist/commands/strategy/remove.js +10 -16
  15. package/dist/commands/strategy/update.js +21 -27
  16. package/dist/commands/view.js +36 -42
  17. package/dist/index.js +9 -7
  18. package/dist/lib/filename.js +1 -5
  19. package/dist/services/config-service.js +30 -36
  20. package/dist/services/load-configured-plugins.js +8 -12
  21. package/dist/services/plugin-installer.js +14 -20
  22. package/dist/services/plugin-store.js +36 -79
  23. package/dist/services/strategy/builtin-strategy-registry.js +14 -32
  24. package/dist/services/strategy/strategy-analyze.js +14 -22
  25. package/dist/services/strategy/strategy-config.js +10 -17
  26. package/dist/services/strategy/strategy-fetch.js +12 -21
  27. package/dist/services/strategy/strategy-io.js +14 -30
  28. package/dist/services/strategy/strategy-normalize.js +9 -15
  29. package/dist/services/strategy/strategy-pack-read.js +12 -21
  30. package/dist/services/strategy/strategy-pack-store.js +12 -18
  31. package/dist/services/strategy/strategy-service.js +122 -117
  32. package/dist/services/strategy/types.js +1 -2
  33. package/dist/services/units/unit-store.js +16 -20
  34. package/dist/services/units/unit-validate.js +23 -11
  35. package/dist/services/user-packages/parse-pinned-spec.js +7 -17
  36. package/dist/services/user-packages/user-package-installer.js +8 -13
  37. package/dist/services/user-packages/user-package-store.js +27 -65
  38. package/dist/stages/prepare-output.js +6 -13
  39. package/dist/units/network-observer-unit.js +7 -10
  40. package/dist/utils/array.js +1 -7
  41. package/dist/utils/normalize-argv.js +3 -8
  42. package/dist/utils/parse-json.js +1 -5
  43. package/dist/utils/parse-plugin-options.js +1 -5
  44. package/dist/utils/parse-plugin-spec.js +5 -11
  45. package/dist/utils/validate-plugin-default-export.js +1 -5
  46. package/dist/utils/with-spinner.js +3 -10
  47. package/dist/view.js +14 -21
  48. package/package.json +16 -12
@@ -1,42 +1,39 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StrategyService = void 0;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const config_service_1 = require("../config-service");
9
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
10
- const unit_store_1 = require("../units/unit-store");
11
- const array_1 = require("../../utils/array");
12
- const strategy_analyze_1 = require("./strategy-analyze");
13
- const strategy_config_1 = require("./strategy-config");
14
- const strategy_fetch_1 = require("./strategy-fetch");
15
- const strategy_io_1 = require("./strategy-io");
16
- const strategy_normalize_1 = require("./strategy-normalize");
17
- const strategy_pack_read_1 = require("./strategy-pack-read");
18
- const strategy_pack_store_1 = require("./strategy-pack-store");
19
- class StrategyService {
20
- constructor(configService = new config_service_1.ConfigService()) {
1
+ import fs from "node:fs";
2
+ import { uniq } from "../../utils/array.js";
3
+ import { ConfigService } from "../config-service.js";
4
+ import { UnitStore } from "../units/unit-store.js";
5
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
6
+ import { collectWantedVersions, computeConflicts, computeDrift, ensureNoInstalledVersionConflicts } from "./strategy-analyze.js";
7
+ import { listStrategyNamesFromConfig, requireStrategyInstalled, withStrategyInConfig, withoutStrategyInConfig } from "./strategy-config.js";
8
+ import { fetchStrategyFile } from "./strategy-fetch.js";
9
+ import { getStrategyPath, getStrategiesDir, readStrategyFile, writeJsonAtomic } from "./strategy-io.js";
10
+ import { normalizeStrategyUnits } from "./strategy-normalize.js";
11
+ import { readStrategiesFromPackRoot } from "./strategy-pack-read.js";
12
+ import { StrategyPackStore } from "./strategy-pack-store.js";
13
+ export class StrategyService {
14
+ configService;
15
+ unitStore;
16
+ packStore;
17
+ constructor(configService = new ConfigService()) {
21
18
  this.configService = configService;
22
- this.unitStore = new unit_store_1.UnitStore(configService);
23
- this.packStore = new strategy_pack_store_1.StrategyPackStore(configService);
19
+ this.unitStore = new UnitStore(configService);
20
+ this.packStore = new StrategyPackStore(configService);
24
21
  }
25
22
  ensureConfigFileExists() {
26
23
  return this.configService.ensureConfigFileExists();
27
24
  }
28
25
  getStrategiesDir() {
29
- return (0, strategy_io_1.getStrategiesDir)(this.configService);
26
+ return getStrategiesDir(this.configService);
30
27
  }
31
28
  getStrategyPath(name) {
32
- return (0, strategy_io_1.getStrategyPath)(this.configService, name);
29
+ return getStrategyPath(this.configService, name);
33
30
  }
34
31
  readStrategy(name) {
35
- return (0, strategy_io_1.readStrategyFile)(this.getStrategyPath(name));
32
+ return readStrategyFile(this.getStrategyPath(name));
36
33
  }
37
34
  listInstalledStrategyNames() {
38
35
  const config = this.configService.readConfigOrDefault();
39
- return (0, strategy_config_1.listStrategyNamesFromConfig)(config);
36
+ return listStrategyNamesFromConfig(config);
40
37
  }
41
38
  async addStrategy(input) {
42
39
  this.configService.ensureConfigFileExists();
@@ -44,7 +41,7 @@ class StrategyService {
44
41
  const sourceTrimmed = input.source.trim();
45
42
  const isPinnedNpm = (() => {
46
43
  try {
47
- (0, parse_pinned_spec_1.parsePinnedSpec)(sourceTrimmed);
44
+ parsePinnedSpec(sourceTrimmed);
48
45
  return true;
49
46
  }
50
47
  catch {
@@ -54,35 +51,35 @@ class StrategyService {
54
51
  if (isPinnedNpm) {
55
52
  const pinned = this.packStore.installPinned(sourceTrimmed);
56
53
  const packRoot = this.packStore.resolvePackRoot(pinned.name);
57
- const strategies = (0, strategy_pack_read_1.readStrategiesFromPackRoot)(packRoot);
54
+ const strategies = readStrategiesFromPackRoot(packRoot);
58
55
  if (strategies.length === 0) {
59
56
  throw new Error(`No *.strategy.json found in package: ${pinned.spec}`);
60
57
  }
61
- const allUnits = strategies.flatMap((s) => (0, strategy_normalize_1.normalizeStrategyUnits)(s));
62
- const refs = (0, array_1.uniq)(allUnits.map((u) => u.ref));
63
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(this.unitStore.readInstalledDependencyVersions(), refs);
58
+ const allUnits = strategies.flatMap((strategy) => normalizeStrategyUnits(strategy));
59
+ const refs = uniq(allUnits.map((unit) => unit.ref));
60
+ ensureNoInstalledVersionConflicts(this.unitStore.readInstalledDependencyVersions(), refs);
64
61
  refs.forEach((ref) => this.unitStore.installPinned(ref));
65
62
  const installedStrategies = [];
66
63
  strategies.forEach((strategy) => {
67
64
  const name = strategy.name;
68
65
  const strategyPath = this.getStrategyPath(name);
69
- if (!input.force && node_fs_1.default.existsSync(strategyPath)) {
66
+ if (!input.force && fs.existsSync(strategyPath)) {
70
67
  return;
71
68
  }
72
69
  const toWrite = {
73
70
  ...strategy,
74
71
  source: { type: "npm", value: pinned.spec }
75
72
  };
76
- (0, strategy_io_1.writeJsonAtomic)(strategyPath, toWrite);
73
+ writeJsonAtomic(strategyPath, toWrite);
77
74
  installedStrategies.push(name);
78
75
  });
79
- const nextConfig = installedStrategies.reduce((acc, s) => (0, strategy_config_1.withStrategyInConfig)(acc, s), config);
76
+ const nextConfig = installedStrategies.reduce((configAccumulator, strategyName) => withStrategyInConfig(configAccumulator, strategyName), config);
80
77
  const existing = nextConfig.strategyPacks ?? [];
81
- const filtered = existing.filter((x) => {
82
- if (typeof x === "string") {
83
- return x.trim().length > 0;
78
+ const filtered = existing.filter((packEntry) => {
79
+ if (typeof packEntry === "string") {
80
+ return packEntry.trim().length > 0;
84
81
  }
85
- return x.name !== pinned.name;
82
+ return packEntry.name !== pinned.name;
86
83
  });
87
84
  const strategyPacks = [
88
85
  ...filtered,
@@ -94,61 +91,65 @@ class StrategyService {
94
91
  this.configService.writeConfig({ ...nextConfig, strategyPacks });
95
92
  return { installedRefs: refs, installedStrategies };
96
93
  }
97
- const { strategy, source } = await (0, strategy_fetch_1.fetchStrategyFile)(sourceTrimmed);
98
- const normalizedUnits = (0, strategy_normalize_1.normalizeStrategyUnits)(strategy);
99
- const refs = (0, array_1.uniq)(normalizedUnits.map((u) => u.ref));
94
+ const { strategy, source } = await fetchStrategyFile(sourceTrimmed);
95
+ const normalizedUnits = normalizeStrategyUnits(strategy);
96
+ const refs = uniq(normalizedUnits.map((unit) => unit.ref));
100
97
  const strategyPath = this.getStrategyPath(strategy.name);
101
- if (!input.force && node_fs_1.default.existsSync(strategyPath)) {
98
+ if (!input.force && fs.existsSync(strategyPath)) {
102
99
  throw new Error(`Strategy already exists: ${strategy.name}`);
103
100
  }
104
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(this.unitStore.readInstalledDependencyVersions(), refs);
101
+ ensureNoInstalledVersionConflicts(this.unitStore.readInstalledDependencyVersions(), refs);
105
102
  refs.forEach((ref) => this.unitStore.installPinned(ref));
106
103
  const toWrite = {
107
104
  ...strategy,
108
105
  source
109
106
  };
110
- (0, strategy_io_1.writeJsonAtomic)(strategyPath, toWrite);
111
- this.configService.writeConfig((0, strategy_config_1.withStrategyInConfig)(config, strategy.name));
107
+ writeJsonAtomic(strategyPath, toWrite);
108
+ this.configService.writeConfig(withStrategyInConfig(config, strategy.name));
112
109
  return { installedRefs: refs, installedStrategies: [strategy.name] };
113
110
  }
114
111
  removeStrategy(name) {
115
112
  this.configService.ensureConfigFileExists();
116
113
  const config = this.configService.readConfigOrDefault();
117
- (0, strategy_config_1.requireStrategyInstalled)(config, name);
114
+ requireStrategyInstalled(config, name);
118
115
  const strategyPath = this.getStrategyPath(name);
119
- if (node_fs_1.default.existsSync(strategyPath)) {
120
- node_fs_1.default.rmSync(strategyPath);
116
+ if (fs.existsSync(strategyPath)) {
117
+ fs.rmSync(strategyPath);
121
118
  }
122
- this.configService.writeConfig((0, strategy_config_1.withoutStrategyInConfig)(config, name));
119
+ this.configService.writeConfig(withoutStrategyInConfig(config, name));
123
120
  }
124
121
  async updateStrategy(name, opts) {
125
122
  this.configService.ensureConfigFileExists();
126
123
  const config = this.configService.readConfigOrDefault();
127
- const names = name ? [name] : (0, strategy_config_1.listStrategyNamesFromConfig)(config);
124
+ const names = name ? [name] : listStrategyNamesFromConfig(config);
128
125
  if (names.length === 0) {
129
126
  return;
130
127
  }
131
128
  const installed = this.unitStore.readInstalledDependencyVersions();
132
129
  if (opts?.packageOnly) {
133
- const packageNames = (0, array_1.uniq)(names
134
- .flatMap((n) => (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n)).map((u) => (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref).name))
135
- .filter((x) => x.trim().length > 0));
130
+ const packageNames = uniq(names
131
+ .flatMap((strategyName) => normalizeStrategyUnits(this.readStrategy(strategyName)).map((unit) => parsePinnedSpec(unit.ref).name))
132
+ .filter((packageName) => packageName.trim().length > 0));
136
133
  packageNames.forEach((pkg) => {
137
134
  this.unitStore.updateToLatest(pkg);
138
135
  });
139
136
  const afterInstalled = this.unitStore.readInstalledDependencyVersions();
140
- const afterStrategies = (0, strategy_config_1.listStrategyNamesFromConfig)(config).map((n) => ({
141
- name: n,
142
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
137
+ const afterStrategies = listStrategyNamesFromConfig(config).map((strategyName) => ({
138
+ name: strategyName,
139
+ units: normalizeStrategyUnits(this.readStrategy(strategyName))
143
140
  }));
144
- const wanted = (0, strategy_analyze_1.collectWantedVersions)(afterStrategies);
145
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
141
+ const wanted = collectWantedVersions(afterStrategies);
142
+ const conflicts = computeConflicts(wanted);
146
143
  if (conflicts.length > 0) {
147
144
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
148
145
  }
149
146
  const drift = afterStrategies
150
- .map((s) => (0, strategy_analyze_1.computeDrift)({ strategyName: s.name, units: s.units, installed: afterInstalled }))
151
- .filter((d) => d.items.length > 0);
147
+ .map((strategy) => computeDrift({
148
+ strategyName: strategy.name,
149
+ units: strategy.units,
150
+ installed: afterInstalled
151
+ }))
152
+ .filter((drift) => drift.items.length > 0);
152
153
  if (drift.length > 0) {
153
154
  throw new Error("Strategy drift detected after --package-only update. Run 'pp strategy doctor'.");
154
155
  }
@@ -156,119 +157,124 @@ class StrategyService {
156
157
  }
157
158
  const nextStrategies = [];
158
159
  const npmPacksToUpdate = new Set();
159
- for (const n of names) {
160
- const current = this.readStrategy(n);
160
+ for (const strategyName of names) {
161
+ const current = this.readStrategy(strategyName);
161
162
  const src = current.source;
162
163
  if (!src) {
163
- throw new Error(`Strategy ${n} has no source. Re-add it with a URL/path source to enable update.`);
164
+ throw new Error(`Strategy ${strategyName} has no source. Re-add it with a URL/path source to enable update.`);
164
165
  }
165
166
  if (src.type === "npm") {
166
167
  npmPacksToUpdate.add(src.value);
167
168
  continue;
168
169
  }
169
- const fetched = await (0, strategy_fetch_1.fetchStrategyFile)(src.value);
170
- if (fetched.strategy.name !== n) {
171
- throw new Error(`Strategy name mismatch while updating ${n}: got ${fetched.strategy.name}`);
170
+ const fetched = await fetchStrategyFile(src.value);
171
+ if (fetched.strategy.name !== strategyName) {
172
+ throw new Error(`Strategy name mismatch while updating ${strategyName}: got ${fetched.strategy.name}`);
172
173
  }
173
174
  const file = { ...fetched.strategy, source: fetched.source };
174
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
175
- nextStrategies.push({ name: n, file, units });
175
+ const units = normalizeStrategyUnits(file);
176
+ nextStrategies.push({ name: strategyName, file, units });
176
177
  }
177
178
  if (npmPacksToUpdate.size > 0) {
178
179
  const specs = [...npmPacksToUpdate];
179
180
  specs.forEach((spec) => {
180
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
181
+ const pinned = parsePinnedSpec(spec);
181
182
  this.packStore.updateToLatest(pinned.name);
182
183
  });
183
184
  const installedPackVersions = this.packStore.readInstalledDependencyVersions();
184
185
  const updatedSpecs = specs.map((spec) => {
185
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
186
- const v = installedPackVersions[pinned.name];
187
- if (!v) {
186
+ const pinned = parsePinnedSpec(spec);
187
+ const installedVersion = installedPackVersions[pinned.name];
188
+ if (!installedVersion) {
188
189
  throw new Error(`Strategy pack not installed after update: ${pinned.name}`);
189
190
  }
190
- return `${pinned.name}@${v}`;
191
+ return `${pinned.name}@${installedVersion}`;
191
192
  });
192
193
  const updatedFiles = [];
193
194
  updatedSpecs.forEach((spec) => {
194
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
195
+ const pinned = parsePinnedSpec(spec);
195
196
  const root = this.packStore.resolvePackRoot(pinned.name);
196
- const files = (0, strategy_pack_read_1.readStrategiesFromPackRoot)(root).map((f) => ({
197
- ...f,
197
+ const files = readStrategiesFromPackRoot(root).map((strategyFile) => ({
198
+ ...strategyFile,
198
199
  source: { type: "npm", value: spec }
199
200
  }));
200
201
  updatedFiles.push(...files);
201
202
  });
202
203
  updatedFiles.forEach((file) => {
203
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
204
+ const units = normalizeStrategyUnits(file);
204
205
  nextStrategies.push({ name: file.name, file, units });
205
206
  });
206
207
  const nextConfig = this.configService.readConfigOrDefault();
207
208
  const existing = nextConfig.strategyPacks ?? [];
208
- const filtered = existing.filter((x) => {
209
- if (typeof x === "string") {
210
- return x.trim().length > 0;
209
+ const filtered = existing.filter((packEntry) => {
210
+ if (typeof packEntry === "string") {
211
+ return packEntry.trim().length > 0;
211
212
  }
212
- return !updatedSpecs.some((spec) => (0, parse_pinned_spec_1.parsePinnedSpec)(spec).name === x.name);
213
+ return !updatedSpecs.some((spec) => parsePinnedSpec(spec).name === packEntry.name);
213
214
  });
214
215
  const packsNext = [
215
216
  ...filtered,
216
217
  ...updatedSpecs.map((spec) => {
217
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
218
+ const pinned = parsePinnedSpec(spec);
218
219
  return { name: pinned.name, spec: pinned.spec };
219
220
  })
220
221
  ];
221
222
  this.configService.writeConfig({ ...nextConfig, strategyPacks: packsNext });
222
223
  }
223
- const allOtherNames = (0, strategy_config_1.listStrategyNamesFromConfig)(config).filter((n) => !names.includes(n));
224
- const otherStrategies = allOtherNames.map((n) => ({
225
- name: n,
226
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
224
+ const allOtherNames = listStrategyNamesFromConfig(config).filter((strategyName) => !names.includes(strategyName));
225
+ const otherStrategies = allOtherNames.map((strategyName) => ({
226
+ name: strategyName,
227
+ units: normalizeStrategyUnits(this.readStrategy(strategyName))
227
228
  }));
228
- const wanted = (0, strategy_analyze_1.collectWantedVersions)([
229
+ const wanted = collectWantedVersions([
229
230
  ...otherStrategies,
230
- ...nextStrategies.map((s) => ({ name: s.name, units: s.units }))
231
+ ...nextStrategies.map((strategy) => ({ name: strategy.name, units: strategy.units }))
231
232
  ]);
232
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
233
+ const conflicts = computeConflicts(wanted);
233
234
  if (conflicts.length > 0) {
234
235
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
235
236
  }
236
- const refs = (0, array_1.uniq)(nextStrategies.flatMap((s) => s.units.map((u) => u.ref)));
237
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(installed, refs);
237
+ const refs = uniq(nextStrategies.flatMap((strategy) => strategy.units.map((unit) => unit.ref)));
238
+ ensureNoInstalledVersionConflicts(installed, refs);
238
239
  refs.forEach((ref) => {
239
240
  this.unitStore.installPinned(ref);
240
241
  });
241
- nextStrategies.forEach((s) => {
242
- (0, strategy_io_1.writeJsonAtomic)(this.getStrategyPath(s.name), s.file);
242
+ nextStrategies.forEach((strategy) => {
243
+ writeJsonAtomic(this.getStrategyPath(strategy.name), strategy.file);
243
244
  });
244
245
  }
245
246
  pinStrategy(name) {
246
247
  this.configService.ensureConfigFileExists();
247
248
  const config = this.configService.readConfigOrDefault();
248
- (0, strategy_config_1.requireStrategyInstalled)(config, name);
249
+ requireStrategyInstalled(config, name);
249
250
  const file = this.readStrategy(name);
250
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
251
+ const units = normalizeStrategyUnits(file);
251
252
  const installed = this.unitStore.readInstalledDependencyVersions();
252
- const pinnedUnits = units.map((u) => {
253
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref);
254
- const v = installed[pinned.name];
255
- if (!v) {
253
+ const pinnedUnits = units.map((unit) => {
254
+ const pinned = parsePinnedSpec(unit.ref);
255
+ const installedVersion = installed[pinned.name];
256
+ if (!installedVersion) {
256
257
  throw new Error(`Unit package is not installed: ${pinned.name}`);
257
258
  }
258
- const nextRef = `${pinned.name}@${v}`;
259
- return u.args.length === 0 ? nextRef : { ref: nextRef, args: u.args };
259
+ const nextRef = `${pinned.name}@${installedVersion}`;
260
+ return unit.args.length === 0 ? nextRef : { ref: nextRef, args: unit.args };
260
261
  });
261
- const others = (0, strategy_config_1.listStrategyNamesFromConfig)(config)
262
- .filter((n) => n !== name)
263
- .map((n) => ({ name: n, units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n)) }));
264
- const nextWanted = (0, strategy_analyze_1.collectWantedVersions)([
262
+ const others = listStrategyNamesFromConfig(config)
263
+ .filter((strategyName) => strategyName !== name)
264
+ .map((strategyName) => ({
265
+ name: strategyName,
266
+ units: normalizeStrategyUnits(this.readStrategy(strategyName))
267
+ }));
268
+ const nextWanted = collectWantedVersions([
265
269
  ...others,
266
270
  {
267
271
  name,
268
- units: pinnedUnits.map((x) => typeof x === "string" ? { ref: x, args: [] } : { ref: x.ref, args: x.args ?? [] })
272
+ units: pinnedUnits.map((pinnedUnit) => typeof pinnedUnit === "string"
273
+ ? { ref: pinnedUnit, args: [] }
274
+ : { ref: pinnedUnit.ref, args: pinnedUnit.args ?? [] })
269
275
  }
270
276
  ]);
271
- const conflicts = (0, strategy_analyze_1.computeConflicts)(nextWanted);
277
+ const conflicts = computeConflicts(nextWanted);
272
278
  if (conflicts.length > 0) {
273
279
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
274
280
  }
@@ -279,23 +285,22 @@ class StrategyService {
279
285
  units: pinnedUnits
280
286
  }
281
287
  };
282
- (0, strategy_io_1.writeJsonAtomic)(this.getStrategyPath(name), nextFile);
288
+ writeJsonAtomic(this.getStrategyPath(name), nextFile);
283
289
  }
284
290
  doctor() {
285
291
  this.configService.ensureConfigFileExists();
286
292
  const config = this.configService.readConfigOrDefault();
287
- const names = (0, strategy_config_1.listStrategyNamesFromConfig)(config);
293
+ const names = listStrategyNamesFromConfig(config);
288
294
  const installed = this.unitStore.readInstalledDependencyVersions();
289
- const strategies = names.map((n) => ({
290
- name: n,
291
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
295
+ const strategies = names.map((strategyName) => ({
296
+ name: strategyName,
297
+ units: normalizeStrategyUnits(this.readStrategy(strategyName))
292
298
  }));
293
- const wanted = (0, strategy_analyze_1.collectWantedVersions)(strategies);
294
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
299
+ const wanted = collectWantedVersions(strategies);
300
+ const conflicts = computeConflicts(wanted);
295
301
  const drift = strategies
296
- .map((s) => (0, strategy_analyze_1.computeDrift)({ strategyName: s.name, units: s.units, installed }))
297
- .filter((d) => d.items.length > 0);
302
+ .map((strategy) => computeDrift({ strategyName: strategy.name, units: strategy.units, installed }))
303
+ .filter((drift) => drift.items.length > 0);
298
304
  return { conflicts, drift };
299
305
  }
300
306
  }
301
- exports.StrategyService = StrategyService;
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -1,15 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnitStore = void 0;
4
- const user_package_installer_1 = require("../user-packages/user-package-installer");
5
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
6
- const user_package_store_1 = require("../user-packages/user-package-store");
7
- const unit_validate_1 = require("./unit-validate");
1
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
2
+ import { installPinnedPackage, updatePackageToLatest } from "../user-packages/user-package-installer.js";
3
+ import { UserPackageStore } from "../user-packages/user-package-store.js";
4
+ import { isUnitLike, resolveUnitConstructor } from "./unit-validate.js";
8
5
  const UNITS_KIND = "units";
9
6
  const UNITS_PACKAGE_JSON_NAME = "pagepocket-user-units";
10
- class UnitStore {
7
+ export class UnitStore {
8
+ store;
11
9
  constructor(configService) {
12
- this.store = new user_package_store_1.UserPackageStore(configService, UNITS_KIND);
10
+ this.store = new UserPackageStore(configService, UNITS_KIND);
13
11
  }
14
12
  getInstallDir() {
15
13
  return this.store.getInstallDir();
@@ -21,14 +19,14 @@ class UnitStore {
21
19
  return this.store.readInstalledPackageMeta(UNITS_PACKAGE_JSON_NAME, packageName);
22
20
  }
23
21
  installPinned(ref) {
24
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(ref);
25
- (0, user_package_installer_1.installPinnedPackage)(this.store, {
22
+ const pinned = parsePinnedSpec(ref);
23
+ installPinnedPackage(this.store, {
26
24
  packageJsonName: UNITS_PACKAGE_JSON_NAME,
27
25
  packageSpec: pinned.spec
28
26
  });
29
27
  }
30
28
  updateToLatest(packageName) {
31
- (0, user_package_installer_1.updatePackageToLatest)(this.store, {
29
+ updatePackageToLatest(this.store, {
32
30
  packageJsonName: UNITS_PACKAGE_JSON_NAME,
33
31
  packageName
34
32
  });
@@ -37,18 +35,16 @@ class UnitStore {
37
35
  return this.store.importModule(UNITS_PACKAGE_JSON_NAME, packageName);
38
36
  }
39
37
  async instantiateFromRef(ref, args) {
40
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(ref);
38
+ const pinned = parsePinnedSpec(ref);
41
39
  const mod = await this.importUnitModule(pinned.name);
42
- const def = mod.default;
43
- if (typeof def !== "function") {
44
- throw new Error(`Unit ${pinned.name} must default export a constructor.`);
40
+ const ctor = resolveUnitConstructor(mod);
41
+ if (!ctor) {
42
+ throw new Error(`Unit ${pinned.name} does not export a Unit constructor.`);
45
43
  }
46
- const ctor = def;
47
44
  const instance = new ctor(...args);
48
- if (!(0, unit_validate_1.isUnitLike)(instance)) {
49
- throw new Error(`Unit ${pinned.name} default export did not construct a Unit.`);
45
+ if (!isUnitLike(instance)) {
46
+ throw new Error(`Unit ${pinned.name} exported constructor did not produce a Unit.`);
50
47
  }
51
48
  return instance;
52
49
  }
53
50
  }
54
- exports.UnitStore = UnitStore;
@@ -1,13 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUnitLike = void 0;
4
- const isRecord = (value) => {
5
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
- };
7
- const isCallable = (value) => {
8
- return typeof value === "function";
9
- };
10
- const isUnitLike = (value) => {
1
+ const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
2
+ const isCallable = (value) => typeof value === "function";
3
+ export const isUnitLike = (value) => {
11
4
  if (!isRecord(value)) {
12
5
  return false;
13
6
  }
@@ -25,4 +18,23 @@ const isUnitLike = (value) => {
25
18
  }
26
19
  return true;
27
20
  };
28
- exports.isUnitLike = isUnitLike;
21
+ /**
22
+ * Resolve a Unit constructor from an imported ESM module.
23
+ *
24
+ * Checks `mod.default` first. If it is not a function (e.g. older packages
25
+ * that only use named exports), falls back to the first exported function
26
+ * whose name ends with "Unit".
27
+ *
28
+ * @returns The constructor function, or `undefined` when none is found.
29
+ */
30
+ export const resolveUnitConstructor = (mod) => {
31
+ if (typeof mod.default === "function") {
32
+ return mod.default;
33
+ }
34
+ const fallback = Object.values(mod).find((exportedValue) => typeof exportedValue === "function" &&
35
+ exportedValue.name?.endsWith("Unit"));
36
+ if (typeof fallback === "function") {
37
+ return fallback;
38
+ }
39
+ return undefined;
40
+ };
@@ -1,23 +1,14 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parsePinnedSpec = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const node_module_1 = require("node:module");
9
- const isRecord = (value) => {
10
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
11
- };
12
- const isExactSemver = (value) => {
13
- return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(value);
14
- };
15
- const parsePinnedSpec = (input) => {
1
+ import { createRequire } from "node:module";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
5
+ const isExactSemver = (value) => /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(value);
6
+ export const parsePinnedSpec = (input) => {
16
7
  const trimmed = input.trim();
17
8
  if (!trimmed) {
18
9
  throw new Error("package spec is empty");
19
10
  }
20
- const req = (0, node_module_1.createRequire)(typeof __filename === "string" ? __filename : node_path_1.default.join(process.cwd(), "package.json"));
11
+ const req = createRequire(import.meta.url ? fileURLToPath(import.meta.url) : path.join(process.cwd(), "package.json"));
21
12
  const npa = req("npm-package-arg");
22
13
  const parsed = npa(trimmed);
23
14
  if (!isRecord(parsed)) {
@@ -40,4 +31,3 @@ const parsePinnedSpec = (input) => {
40
31
  }
41
32
  return { name, version: rawSpec, spec: `${name}@${rawSpec}` };
42
33
  };
43
- exports.parsePinnedSpec = parsePinnedSpec;
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updatePackageToLatest = exports.installPinnedPackage = void 0;
4
- const node_child_process_1 = require("node:child_process");
1
+ import { spawnSync } from "node:child_process";
5
2
  const toError = (value) => {
6
3
  if (value instanceof Error) {
7
4
  return value;
@@ -9,16 +6,16 @@ const toError = (value) => {
9
6
  return new Error(String(value));
10
7
  };
11
8
  const tryRun = (cwd, cmd, args) => {
12
- const r = (0, node_child_process_1.spawnSync)(cmd, args, {
9
+ const result = spawnSync(cmd, args, {
13
10
  cwd,
14
11
  stdio: "inherit",
15
12
  shell: false
16
13
  });
17
- if (r.error) {
18
- return { ok: false, error: toError(r.error) };
14
+ if (result.error) {
15
+ return { ok: false, error: toError(result.error) };
19
16
  }
20
- if (typeof r.status === "number" && r.status !== 0) {
21
- return { ok: false, error: new Error(`${cmd} exited with code ${r.status}`) };
17
+ if (typeof result.status === "number" && result.status !== 0) {
18
+ return { ok: false, error: new Error(`${cmd} exited with code ${result.status}`) };
22
19
  }
23
20
  return { ok: true };
24
21
  };
@@ -33,15 +30,13 @@ const installWithFallback = (installDir, packageSpec) => {
33
30
  }
34
31
  throw new Error(`Failed to install ${packageSpec}. Ensure pnpm or npm is available.`);
35
32
  };
36
- const installPinnedPackage = (store, input) => {
33
+ export const installPinnedPackage = (store, input) => {
37
34
  store.ensureInstallDirPackageJson(input.packageJsonName);
38
35
  const installDir = store.getInstallDir();
39
36
  installWithFallback(installDir, input.packageSpec);
40
37
  };
41
- exports.installPinnedPackage = installPinnedPackage;
42
- const updatePackageToLatest = (store, input) => {
38
+ export const updatePackageToLatest = (store, input) => {
43
39
  store.ensureInstallDirPackageJson(input.packageJsonName);
44
40
  const installDir = store.getInstallDir();
45
41
  installWithFallback(installDir, `${input.packageName}@latest`);
46
42
  };
47
- exports.updatePackageToLatest = updatePackageToLatest;