pubz 0.7.3 → 0.7.4
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/dist/cli.js +126 -90
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -47,24 +47,92 @@ function frameLine(text = "") {
|
|
|
47
47
|
|
|
48
48
|
// src/discovery.ts
|
|
49
49
|
import { readFile, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
50
|
-
import { join as
|
|
50
|
+
import { join as join3, resolve } from "node:path";
|
|
51
|
+
|
|
52
|
+
// src/config.ts
|
|
53
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
54
|
+
import { join } from "node:path";
|
|
55
|
+
|
|
56
|
+
// src/log.ts
|
|
57
|
+
var verboseEnabled = false;
|
|
58
|
+
function setVerbose(enabled) {
|
|
59
|
+
verboseEnabled = enabled;
|
|
60
|
+
}
|
|
61
|
+
function debug(...args) {
|
|
62
|
+
if (verboseEnabled) {
|
|
63
|
+
console.error("[debug]", ...args);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/config.ts
|
|
68
|
+
var CONFIG_FILENAME = ".pubz";
|
|
69
|
+
var VALID_KEYS = new Set(["skip-build", "skip-publish", "always-publish", "registry"]);
|
|
70
|
+
function loadConfig(cwd) {
|
|
71
|
+
const configPath = join(cwd, CONFIG_FILENAME);
|
|
72
|
+
if (!existsSync(configPath)) {
|
|
73
|
+
debug(`No ${CONFIG_FILENAME} found at ${configPath}`);
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
const content = readFileSync(configPath, "utf-8");
|
|
77
|
+
const config = {};
|
|
78
|
+
for (const rawLine of content.split(`
|
|
79
|
+
`)) {
|
|
80
|
+
const line = rawLine.trim();
|
|
81
|
+
if (!line || line.startsWith("#"))
|
|
82
|
+
continue;
|
|
83
|
+
const eqIndex = line.indexOf("=");
|
|
84
|
+
let key;
|
|
85
|
+
let value;
|
|
86
|
+
if (eqIndex === -1) {
|
|
87
|
+
key = line;
|
|
88
|
+
} else {
|
|
89
|
+
key = line.slice(0, eqIndex).trim();
|
|
90
|
+
value = line.slice(eqIndex + 1).trim();
|
|
91
|
+
}
|
|
92
|
+
if (!VALID_KEYS.has(key)) {
|
|
93
|
+
debug(`Ignoring unknown config key: ${key}`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (key === "registry") {
|
|
97
|
+
config.registry = value ?? "";
|
|
98
|
+
} else {
|
|
99
|
+
const boolKey = key;
|
|
100
|
+
if (value === undefined || value === "true") {
|
|
101
|
+
config[boolKey] = true;
|
|
102
|
+
} else if (value === "false") {
|
|
103
|
+
config[boolKey] = false;
|
|
104
|
+
} else {
|
|
105
|
+
debug(`Invalid boolean value for ${key}: ${value}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
debug(`Loaded ${CONFIG_FILENAME}: ${JSON.stringify(config)}`);
|
|
110
|
+
return config;
|
|
111
|
+
}
|
|
51
112
|
|
|
52
113
|
// src/glob.ts
|
|
53
114
|
import { readdir, stat } from "node:fs/promises";
|
|
54
|
-
import { join } from "node:path";
|
|
115
|
+
import { join as join2 } from "node:path";
|
|
55
116
|
async function glob(pattern, cwd) {
|
|
56
117
|
const results = [];
|
|
118
|
+
const isGlob = /\/\*\*?$/.test(pattern);
|
|
57
119
|
const basePattern = pattern.replace(/\/\*\*?$/, "");
|
|
58
120
|
const isRecursive = pattern.endsWith("/**");
|
|
59
|
-
const basePath =
|
|
121
|
+
const basePath = join2(cwd, basePattern);
|
|
122
|
+
if (!isGlob) {
|
|
123
|
+
try {
|
|
124
|
+
await stat(join2(basePath, "package.json"));
|
|
125
|
+
return [basePattern];
|
|
126
|
+
} catch {}
|
|
127
|
+
}
|
|
60
128
|
try {
|
|
61
129
|
const entries = await readdir(basePath, { withFileTypes: true });
|
|
62
130
|
for (const entry of entries) {
|
|
63
131
|
if (entry.isDirectory()) {
|
|
64
|
-
const entryPath =
|
|
65
|
-
const fullPath =
|
|
132
|
+
const entryPath = join2(basePattern, entry.name);
|
|
133
|
+
const fullPath = join2(cwd, entryPath);
|
|
66
134
|
try {
|
|
67
|
-
await stat(
|
|
135
|
+
await stat(join2(fullPath, "package.json"));
|
|
68
136
|
results.push(entryPath);
|
|
69
137
|
} catch {
|
|
70
138
|
if (isRecursive) {
|
|
@@ -80,7 +148,7 @@ async function glob(pattern, cwd) {
|
|
|
80
148
|
|
|
81
149
|
// src/discovery.ts
|
|
82
150
|
async function findRootPackageJson(cwd) {
|
|
83
|
-
const packageJsonPath =
|
|
151
|
+
const packageJsonPath = join3(cwd, "package.json");
|
|
84
152
|
try {
|
|
85
153
|
await stat2(packageJsonPath);
|
|
86
154
|
return packageJsonPath;
|
|
@@ -116,10 +184,10 @@ async function discoverPackages(cwd) {
|
|
|
116
184
|
packageDirs.push(...matches);
|
|
117
185
|
}
|
|
118
186
|
} else {
|
|
119
|
-
const packagesDir =
|
|
187
|
+
const packagesDir = join3(cwd, "packages");
|
|
120
188
|
try {
|
|
121
189
|
const entries = await readdir2(packagesDir, { withFileTypes: true });
|
|
122
|
-
packageDirs = entries.filter((entry) => entry.isDirectory()).map((entry) =>
|
|
190
|
+
packageDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => join3("packages", entry.name));
|
|
123
191
|
} catch {
|
|
124
192
|
if (!rootPackageJson.private) {
|
|
125
193
|
return [
|
|
@@ -137,7 +205,7 @@ async function discoverPackages(cwd) {
|
|
|
137
205
|
}
|
|
138
206
|
for (const dir of packageDirs) {
|
|
139
207
|
const pkgPath = resolve(cwd, dir);
|
|
140
|
-
const pkgJsonPath =
|
|
208
|
+
const pkgJsonPath = join3(pkgPath, "package.json");
|
|
141
209
|
try {
|
|
142
210
|
const pkgJson = await readPackageJson(pkgJsonPath);
|
|
143
211
|
packageNames.add(pkgJson.name);
|
|
@@ -150,13 +218,16 @@ async function discoverPackages(cwd) {
|
|
|
150
218
|
return packages;
|
|
151
219
|
}
|
|
152
220
|
async function packageFromPath(path, packageJsonPath, packageJson, localDependencies) {
|
|
221
|
+
const pkgConfig = loadConfig(path);
|
|
153
222
|
return {
|
|
154
223
|
name: packageJson.name,
|
|
155
224
|
version: packageJson.version,
|
|
156
225
|
path,
|
|
157
226
|
packageJsonPath,
|
|
158
227
|
isPrivate: packageJson.private === true,
|
|
159
|
-
localDependencies
|
|
228
|
+
localDependencies,
|
|
229
|
+
skipPublish: pkgConfig["skip-publish"],
|
|
230
|
+
alwaysPublish: pkgConfig["always-publish"]
|
|
160
231
|
};
|
|
161
232
|
}
|
|
162
233
|
function findLocalDependencies(pkg, packageNames) {
|
|
@@ -338,19 +409,6 @@ async function multiSelect(message, options, allSelectedByDefault = true) {
|
|
|
338
409
|
// src/auth.ts
|
|
339
410
|
import { spawn } from "node:child_process";
|
|
340
411
|
import { homedir } from "node:os";
|
|
341
|
-
|
|
342
|
-
// src/log.ts
|
|
343
|
-
var verboseEnabled = false;
|
|
344
|
-
function setVerbose(enabled) {
|
|
345
|
-
verboseEnabled = enabled;
|
|
346
|
-
}
|
|
347
|
-
function debug(...args) {
|
|
348
|
-
if (verboseEnabled) {
|
|
349
|
-
console.error("[debug]", ...args);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// src/auth.ts
|
|
354
412
|
async function checkNpmAuth(registry) {
|
|
355
413
|
return new Promise((resolve2) => {
|
|
356
414
|
const proc = spawn("npm", ["whoami", "--registry", registry], {
|
|
@@ -397,10 +455,10 @@ async function npmLogin(registry) {
|
|
|
397
455
|
import { spawn as spawn2 } from "node:child_process";
|
|
398
456
|
import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
|
|
399
457
|
import { homedir as homedir2 } from "node:os";
|
|
400
|
-
import { join as
|
|
458
|
+
import { join as join4 } from "node:path";
|
|
401
459
|
var DIM_ON = "\x1B[90m";
|
|
402
460
|
var DIM_OFF = "\x1B[39m";
|
|
403
|
-
function run(command, args, cwd) {
|
|
461
|
+
function run(command, args, cwd, options) {
|
|
404
462
|
return new Promise((resolve2) => {
|
|
405
463
|
const proc = spawn2(command, args, {
|
|
406
464
|
cwd,
|
|
@@ -409,17 +467,29 @@ function run(command, args, cwd) {
|
|
|
409
467
|
let output = "";
|
|
410
468
|
proc.stdout?.on("data", (data) => {
|
|
411
469
|
output += data.toString();
|
|
412
|
-
|
|
470
|
+
if (!options?.silent)
|
|
471
|
+
process.stdout.write(DIM_ON + data.toString() + DIM_OFF);
|
|
413
472
|
});
|
|
414
473
|
proc.stderr?.on("data", (data) => {
|
|
415
474
|
output += data.toString();
|
|
416
|
-
|
|
475
|
+
if (!options?.silent)
|
|
476
|
+
process.stderr.write(DIM_ON + data.toString() + DIM_OFF);
|
|
417
477
|
});
|
|
418
478
|
proc.on("close", (code) => {
|
|
419
479
|
resolve2({ code: code ?? 1, output });
|
|
420
480
|
});
|
|
421
481
|
});
|
|
422
482
|
}
|
|
483
|
+
function runStdout(command, args, cwd) {
|
|
484
|
+
return new Promise((resolve2) => {
|
|
485
|
+
const proc = spawn2(command, args, { cwd, stdio: ["inherit", "pipe", "ignore"] });
|
|
486
|
+
let stdout = "";
|
|
487
|
+
proc.stdout?.on("data", (data) => {
|
|
488
|
+
stdout += data.toString();
|
|
489
|
+
});
|
|
490
|
+
proc.on("close", () => resolve2(stdout));
|
|
491
|
+
});
|
|
492
|
+
}
|
|
423
493
|
function runInteractive(command, args, cwd) {
|
|
424
494
|
return new Promise((resolve2) => {
|
|
425
495
|
const proc = spawn2(command, args, {
|
|
@@ -466,7 +536,7 @@ async function verifyBuild(pkg) {
|
|
|
466
536
|
filesToCheck.push("./dist/index.js");
|
|
467
537
|
}
|
|
468
538
|
for (const file of filesToCheck) {
|
|
469
|
-
const filePath =
|
|
539
|
+
const filePath = join4(pkg.path, file);
|
|
470
540
|
try {
|
|
471
541
|
await stat3(filePath);
|
|
472
542
|
} catch {
|
|
@@ -510,8 +580,8 @@ async function publishPackage(pkg, registry, context, dryRun) {
|
|
|
510
580
|
return { success: true };
|
|
511
581
|
}
|
|
512
582
|
async function hasUncommittedChanges(cwd) {
|
|
513
|
-
const
|
|
514
|
-
const output =
|
|
583
|
+
const stdout = await runStdout("git", ["status", "--porcelain"], cwd);
|
|
584
|
+
const output = stdout.trim();
|
|
515
585
|
if (!output) {
|
|
516
586
|
return { hasChanges: false, files: [] };
|
|
517
587
|
}
|
|
@@ -524,8 +594,8 @@ async function commitVersionBump(version, cwd, dryRun) {
|
|
|
524
594
|
if (dryRun) {
|
|
525
595
|
return { success: true };
|
|
526
596
|
}
|
|
527
|
-
const
|
|
528
|
-
if (!
|
|
597
|
+
const statusOutput = await runStdout("git", ["status", "--porcelain"], cwd);
|
|
598
|
+
if (!statusOutput.trim()) {
|
|
529
599
|
return { success: true };
|
|
530
600
|
}
|
|
531
601
|
const addResult = await run("git", ["add", "-A"], cwd);
|
|
@@ -574,12 +644,12 @@ import { spawn as spawn4 } from "node:child_process";
|
|
|
574
644
|
// src/claude.ts
|
|
575
645
|
import { spawn as spawn3 } from "node:child_process";
|
|
576
646
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
577
|
-
import { join as
|
|
647
|
+
import { join as join5 } from "node:path";
|
|
578
648
|
async function resolveCredentials() {
|
|
579
649
|
const home = process.env.HOME ?? "";
|
|
580
650
|
if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
581
651
|
try {
|
|
582
|
-
const tokenFile =
|
|
652
|
+
const tokenFile = join5(home, ".claude", "agent-oauth-token");
|
|
583
653
|
const token = (await readFile3(tokenFile, "utf-8")).trim();
|
|
584
654
|
if (token) {
|
|
585
655
|
process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
|
|
@@ -619,7 +689,7 @@ async function resolveCredentials() {
|
|
|
619
689
|
}
|
|
620
690
|
if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
621
691
|
try {
|
|
622
|
-
const raw = await readFile3(
|
|
692
|
+
const raw = await readFile3(join5(home, ".claude.json"), "utf-8");
|
|
623
693
|
const creds = JSON.parse(raw);
|
|
624
694
|
const accessToken = creds?.claudeAiOauth?.accessToken;
|
|
625
695
|
if (typeof accessToken === "string" && accessToken.length > 0) {
|
|
@@ -805,54 +875,6 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
|
|
|
805
875
|
return { success: true, url };
|
|
806
876
|
}
|
|
807
877
|
|
|
808
|
-
// src/config.ts
|
|
809
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
810
|
-
import { join as join5 } from "node:path";
|
|
811
|
-
var CONFIG_FILENAME = ".pubz";
|
|
812
|
-
var VALID_KEYS = new Set(["skip-build", "skip-publish", "registry"]);
|
|
813
|
-
function loadConfig(cwd) {
|
|
814
|
-
const configPath = join5(cwd, CONFIG_FILENAME);
|
|
815
|
-
if (!existsSync(configPath)) {
|
|
816
|
-
debug(`No ${CONFIG_FILENAME} found at ${configPath}`);
|
|
817
|
-
return {};
|
|
818
|
-
}
|
|
819
|
-
const content = readFileSync(configPath, "utf-8");
|
|
820
|
-
const config = {};
|
|
821
|
-
for (const rawLine of content.split(`
|
|
822
|
-
`)) {
|
|
823
|
-
const line = rawLine.trim();
|
|
824
|
-
if (!line || line.startsWith("#"))
|
|
825
|
-
continue;
|
|
826
|
-
const eqIndex = line.indexOf("=");
|
|
827
|
-
let key;
|
|
828
|
-
let value;
|
|
829
|
-
if (eqIndex === -1) {
|
|
830
|
-
key = line;
|
|
831
|
-
} else {
|
|
832
|
-
key = line.slice(0, eqIndex).trim();
|
|
833
|
-
value = line.slice(eqIndex + 1).trim();
|
|
834
|
-
}
|
|
835
|
-
if (!VALID_KEYS.has(key)) {
|
|
836
|
-
debug(`Ignoring unknown config key: ${key}`);
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
if (key === "registry") {
|
|
840
|
-
config.registry = value ?? "";
|
|
841
|
-
} else {
|
|
842
|
-
const boolKey = key;
|
|
843
|
-
if (value === undefined || value === "true") {
|
|
844
|
-
config[boolKey] = true;
|
|
845
|
-
} else if (value === "false") {
|
|
846
|
-
config[boolKey] = false;
|
|
847
|
-
} else {
|
|
848
|
-
debug(`Invalid boolean value for ${key}: ${value}`);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
debug(`Loaded ${CONFIG_FILENAME}: ${JSON.stringify(config)}`);
|
|
853
|
-
return config;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
878
|
// src/version.ts
|
|
857
879
|
import { readFile as readFile4, writeFile } from "node:fs/promises";
|
|
858
880
|
async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
|
|
@@ -1149,13 +1171,20 @@ async function main() {
|
|
|
1149
1171
|
process.exit(1);
|
|
1150
1172
|
}
|
|
1151
1173
|
let packages = await discoverPackages(cwd);
|
|
1152
|
-
const publishablePackages = packages.filter((p) =>
|
|
1174
|
+
const publishablePackages = packages.filter((p) => {
|
|
1175
|
+
if (p.alwaysPublish)
|
|
1176
|
+
return true;
|
|
1177
|
+
if (p.isPrivate)
|
|
1178
|
+
return p.skipPublish || options.skipPublish;
|
|
1179
|
+
return true;
|
|
1180
|
+
});
|
|
1153
1181
|
if (publishablePackages.length === 0) {
|
|
1154
1182
|
console.log(yellow("No publishable packages found."));
|
|
1155
1183
|
console.log("");
|
|
1156
1184
|
console.log(muted("Make sure your packages:"));
|
|
1157
1185
|
console.log(muted(' - Have a package.json with a "name" field'));
|
|
1158
1186
|
console.log(muted(' - Do not have "private": true (or use --skip-publish for private packages)'));
|
|
1187
|
+
console.log(muted(' - Do not have "skip-publish" in a per-package .pubz file'));
|
|
1159
1188
|
console.log("");
|
|
1160
1189
|
process.exit(1);
|
|
1161
1190
|
}
|
|
@@ -1283,7 +1312,14 @@ async function main() {
|
|
|
1283
1312
|
process.exit(1);
|
|
1284
1313
|
}
|
|
1285
1314
|
}
|
|
1286
|
-
|
|
1315
|
+
const packagesToPublish = packages.filter((p) => {
|
|
1316
|
+
if (p.alwaysPublish)
|
|
1317
|
+
return true;
|
|
1318
|
+
if (p.skipPublish || options.skipPublish)
|
|
1319
|
+
return false;
|
|
1320
|
+
return true;
|
|
1321
|
+
});
|
|
1322
|
+
if (packagesToPublish.length === 0) {
|
|
1287
1323
|
console.log(yellow(bold("⏭️ Skipping npm publish")) + dim(" — use without --skip-publish to publish to npm"));
|
|
1288
1324
|
console.log("");
|
|
1289
1325
|
} else {
|
|
@@ -1308,7 +1344,7 @@ async function main() {
|
|
|
1308
1344
|
console.log(`Publishing to ${cyan(registry)}:`);
|
|
1309
1345
|
}
|
|
1310
1346
|
console.log("");
|
|
1311
|
-
for (const pkg of
|
|
1347
|
+
for (const pkg of packagesToPublish) {
|
|
1312
1348
|
console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1313
1349
|
}
|
|
1314
1350
|
console.log("");
|
|
@@ -1352,7 +1388,7 @@ async function main() {
|
|
|
1352
1388
|
}
|
|
1353
1389
|
}
|
|
1354
1390
|
frameLine(dim("Preparing packages..."));
|
|
1355
|
-
const workspaceTransforms = await transformWorkspaceProtocolForPublish(
|
|
1391
|
+
const workspaceTransforms = await transformWorkspaceProtocolForPublish(packagesToPublish, newVersion, options.dryRun);
|
|
1356
1392
|
const publishContext = {
|
|
1357
1393
|
otp: options.otp,
|
|
1358
1394
|
useBrowserAuth: !options.ci,
|
|
@@ -1363,7 +1399,7 @@ async function main() {
|
|
|
1363
1399
|
let failedPackageName = "";
|
|
1364
1400
|
let failedError = "";
|
|
1365
1401
|
try {
|
|
1366
|
-
for (const pkg of
|
|
1402
|
+
for (const pkg of packagesToPublish) {
|
|
1367
1403
|
if (options.dryRun) {
|
|
1368
1404
|
frameLine(` ${dim("[dry run]")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1369
1405
|
} else {
|
|
@@ -1400,7 +1436,7 @@ async function main() {
|
|
|
1400
1436
|
console.log("");
|
|
1401
1437
|
}
|
|
1402
1438
|
}
|
|
1403
|
-
if (
|
|
1439
|
+
if (packagesToPublish.length > 0) {
|
|
1404
1440
|
console.log("✅ " + green(bold(`Published v${newVersion}!`)));
|
|
1405
1441
|
console.log("");
|
|
1406
1442
|
}
|