fluncle 0.200.0 → 0.202.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/bin/fluncle.mjs +142 -77
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -367,6 +367,55 @@ var require_main = __commonJS((exports, module) => {
|
|
|
367
367
|
module.exports = DotenvModule;
|
|
368
368
|
});
|
|
369
369
|
|
|
370
|
+
// src/env.ts
|
|
371
|
+
import { homedir } from "node:os";
|
|
372
|
+
import { join } from "node:path";
|
|
373
|
+
function loadEnv(keys) {
|
|
374
|
+
loadConfig();
|
|
375
|
+
const result = {};
|
|
376
|
+
const missing = [];
|
|
377
|
+
for (const key of keys) {
|
|
378
|
+
const value = process.env[key];
|
|
379
|
+
if (value === undefined) {
|
|
380
|
+
missing.push(key);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
result[key] = value;
|
|
384
|
+
}
|
|
385
|
+
if (missing.length > 0) {
|
|
386
|
+
throw new Error(`Missing required env vars: ${missing.join(", ")}`);
|
|
387
|
+
}
|
|
388
|
+
return result;
|
|
389
|
+
}
|
|
390
|
+
function getApiBaseUrl() {
|
|
391
|
+
loadConfig();
|
|
392
|
+
return (process.env.FLUNCLE_API_BASE_URL ?? "https://www.fluncle.com").replace(/\/+$/, "");
|
|
393
|
+
}
|
|
394
|
+
function loadConfig() {
|
|
395
|
+
const profile = getEnvProfile();
|
|
396
|
+
if (loadedProfile === profile) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
loadedProfile = profile;
|
|
400
|
+
if (false) {}
|
|
401
|
+
import_dotenv2.config({ path: join(homedir(), `.config/fluncle/.env.${profile}`), quiet: true });
|
|
402
|
+
}
|
|
403
|
+
function getEnvProfile() {
|
|
404
|
+
const profile = process.env.FLUNCLE_ENV ?? defaultEnvProfile;
|
|
405
|
+
if (!isEnvProfile2(profile)) {
|
|
406
|
+
throw new Error(`Unknown env profile: ${profile}. Expected local or production.`);
|
|
407
|
+
}
|
|
408
|
+
return profile;
|
|
409
|
+
}
|
|
410
|
+
function isEnvProfile2(value) {
|
|
411
|
+
return envProfiles2.includes(value);
|
|
412
|
+
}
|
|
413
|
+
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
|
|
414
|
+
var init_env = __esm(() => {
|
|
415
|
+
import_dotenv2 = __toESM(require_main(), 1);
|
|
416
|
+
envProfiles2 = ["local", "production"];
|
|
417
|
+
});
|
|
418
|
+
|
|
370
419
|
// ../../packages/contracts/src/util.ts
|
|
371
420
|
function formatDuration(durationMs) {
|
|
372
421
|
const totalSeconds = Math.round(durationMs / 1000);
|
|
@@ -561,7 +610,7 @@ function parseVersion(version) {
|
|
|
561
610
|
var currentVersion;
|
|
562
611
|
var init_version = __esm(() => {
|
|
563
612
|
init_output();
|
|
564
|
-
currentVersion = "0.
|
|
613
|
+
currentVersion = "0.202.0".trim() ? "0.202.0".trim() : "0.1.0";
|
|
565
614
|
});
|
|
566
615
|
|
|
567
616
|
// src/update-notifier.ts
|
|
@@ -573,8 +622,8 @@ __export(exports_update_notifier, {
|
|
|
573
622
|
detectInstallMethod: () => detectInstallMethod
|
|
574
623
|
});
|
|
575
624
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
576
|
-
import { homedir, platform } from "node:os";
|
|
577
|
-
import { dirname, join, sep } from "node:path";
|
|
625
|
+
import { homedir as homedir2, platform } from "node:os";
|
|
626
|
+
import { dirname, join as join2, sep } from "node:path";
|
|
578
627
|
import { fileURLToPath } from "node:url";
|
|
579
628
|
async function notifyIfUpdateAvailable(args) {
|
|
580
629
|
try {
|
|
@@ -686,8 +735,8 @@ async function writeCache(state) {
|
|
|
686
735
|
} catch {}
|
|
687
736
|
}
|
|
688
737
|
function cacheFilePath() {
|
|
689
|
-
const base = process.env.XDG_CACHE_HOME?.trim() || platform() === "win32" && process.env.LOCALAPPDATA?.trim() ||
|
|
690
|
-
return
|
|
738
|
+
const base = process.env.XDG_CACHE_HOME?.trim() || platform() === "win32" && process.env.LOCALAPPDATA?.trim() || join2(homedir2(), ".config");
|
|
739
|
+
return join2(base, "fluncle", "update-check.json");
|
|
691
740
|
}
|
|
692
741
|
function buildNotice(current, latest) {
|
|
693
742
|
const method = detectInstallMethod({ entry: entryPath(), execPath: process.execPath || "" });
|
|
@@ -747,55 +796,6 @@ var init_update_notifier = __esm(() => {
|
|
|
747
796
|
cacheTtlMs = 24 * 60 * 60 * 1000;
|
|
748
797
|
});
|
|
749
798
|
|
|
750
|
-
// src/env.ts
|
|
751
|
-
import { homedir as homedir2 } from "node:os";
|
|
752
|
-
import { join as join2 } from "node:path";
|
|
753
|
-
function loadEnv(keys) {
|
|
754
|
-
loadConfig();
|
|
755
|
-
const result = {};
|
|
756
|
-
const missing = [];
|
|
757
|
-
for (const key of keys) {
|
|
758
|
-
const value = process.env[key];
|
|
759
|
-
if (value === undefined) {
|
|
760
|
-
missing.push(key);
|
|
761
|
-
continue;
|
|
762
|
-
}
|
|
763
|
-
result[key] = value;
|
|
764
|
-
}
|
|
765
|
-
if (missing.length > 0) {
|
|
766
|
-
throw new Error(`Missing required env vars: ${missing.join(", ")}`);
|
|
767
|
-
}
|
|
768
|
-
return result;
|
|
769
|
-
}
|
|
770
|
-
function getApiBaseUrl() {
|
|
771
|
-
loadConfig();
|
|
772
|
-
return (process.env.FLUNCLE_API_BASE_URL ?? "https://www.fluncle.com").replace(/\/+$/, "");
|
|
773
|
-
}
|
|
774
|
-
function loadConfig() {
|
|
775
|
-
const profile = getEnvProfile();
|
|
776
|
-
if (loadedProfile === profile) {
|
|
777
|
-
return;
|
|
778
|
-
}
|
|
779
|
-
loadedProfile = profile;
|
|
780
|
-
if (false) {}
|
|
781
|
-
import_dotenv2.config({ path: join2(homedir2(), `.config/fluncle/.env.${profile}`), quiet: true });
|
|
782
|
-
}
|
|
783
|
-
function getEnvProfile() {
|
|
784
|
-
const profile = process.env.FLUNCLE_ENV ?? defaultEnvProfile;
|
|
785
|
-
if (!isEnvProfile2(profile)) {
|
|
786
|
-
throw new Error(`Unknown env profile: ${profile}. Expected local or production.`);
|
|
787
|
-
}
|
|
788
|
-
return profile;
|
|
789
|
-
}
|
|
790
|
-
function isEnvProfile2(value) {
|
|
791
|
-
return envProfiles2.includes(value);
|
|
792
|
-
}
|
|
793
|
-
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
|
|
794
|
-
var init_env = __esm(() => {
|
|
795
|
-
import_dotenv2 = __toESM(require_main(), 1);
|
|
796
|
-
envProfiles2 = ["local", "production"];
|
|
797
|
-
});
|
|
798
|
-
|
|
799
799
|
// src/user-token.ts
|
|
800
800
|
import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
801
801
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -1400,10 +1400,12 @@ async function resyncYoutube(mixtapeId) {
|
|
|
1400
1400
|
}
|
|
1401
1401
|
async function authYoutubeCommand() {
|
|
1402
1402
|
const response = await adminApiGet("/api/v1/admin/youtube/auth/start");
|
|
1403
|
-
console.log(`Open this
|
|
1403
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
1404
1404
|
|
|
1405
1405
|
${response.authUrl}
|
|
1406
1406
|
|
|
1407
|
+
It hands you off to Google. Signed out? Log in there and it resumes on its own.
|
|
1408
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
1407
1409
|
After approving access, Google returns to the Fluncle admin callback and stores the refresh token server-side.`);
|
|
1408
1410
|
}
|
|
1409
1411
|
async function initiate(mixtapeId, contentLength, contentType) {
|
|
@@ -1571,10 +1573,12 @@ async function resyncMixcloud(mixtapeId) {
|
|
|
1571
1573
|
}
|
|
1572
1574
|
async function authMixcloudCommand() {
|
|
1573
1575
|
const response = await adminApiGet("/api/v1/admin/mixcloud/auth/start");
|
|
1574
|
-
console.log(`Open this
|
|
1576
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
1575
1577
|
|
|
1576
1578
|
${response.authUrl}
|
|
1577
1579
|
|
|
1580
|
+
It hands you off to Mixcloud. Signed out? Log in there and it resumes on its own.
|
|
1581
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
1578
1582
|
After approving access, Mixcloud returns to the Fluncle admin callback and stores the access token server-side.`);
|
|
1579
1583
|
}
|
|
1580
1584
|
function mixtapeDescription(note, logId) {
|
|
@@ -2448,7 +2452,7 @@ function parseVersion2(version) {
|
|
|
2448
2452
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2449
2453
|
var init_version2 = __esm(() => {
|
|
2450
2454
|
init_output();
|
|
2451
|
-
currentVersion2 = "0.
|
|
2455
|
+
currentVersion2 = "0.202.0".trim() ? "0.202.0".trim() : "0.1.0";
|
|
2452
2456
|
});
|
|
2453
2457
|
|
|
2454
2458
|
// ../../packages/registry/src/index.ts
|
|
@@ -2517,18 +2521,6 @@ var init_src = __esm(() => {
|
|
|
2517
2521
|
url: `${SITE}/mix`,
|
|
2518
2522
|
weights: { web: "secondary" }
|
|
2519
2523
|
},
|
|
2520
|
-
{
|
|
2521
|
-
exposedContent: [
|
|
2522
|
-
"the feed-first Stories surface — full-bleed findings",
|
|
2523
|
-
"/stories/:logId — one finding as a Story"
|
|
2524
|
-
],
|
|
2525
|
-
kind: "web_route",
|
|
2526
|
-
name: "web.stories",
|
|
2527
|
-
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2528
|
-
route: "/stories",
|
|
2529
|
-
url: `${SITE}/stories`,
|
|
2530
|
-
weights: { web: "secondary" }
|
|
2531
|
-
},
|
|
2532
2524
|
{
|
|
2533
2525
|
exposedContent: ["who Fluncle is, what the Galaxy is, how to read a Log ID"],
|
|
2534
2526
|
kind: "web_route",
|
|
@@ -3113,7 +3105,7 @@ var init_src = __esm(() => {
|
|
|
3113
3105
|
exposedContent: ["the XML sitemap index of every public page"],
|
|
3114
3106
|
kind: "discovery",
|
|
3115
3107
|
name: "discovery.sitemap",
|
|
3116
|
-
operatorNotes: "A sitemap INDEX, not a flat urlset: the URLs live in children at /sitemap/<kind>-<n>.xml, ONE CHILD PER ENTITY TYPE (pages/findings/artists/labels/albums/galaxies/logbook), each auto-paged under Google's 50,000-URL ceiling so a breach cannot happen rather than merely not having happened yet. robots.txt still names this one URL — a crawler discovers the children from here. Splitting per entity type is also the diagnostic: Search Console reports coverage PER sitemap, so each entity type gets its own submitted/indexed count.",
|
|
3108
|
+
operatorNotes: "A sitemap INDEX, not a flat urlset: the URLs live in children at /sitemap/<kind>-<n>.xml, ONE CHILD PER ENTITY TYPE (pages/findings/artists/labels/albums/galaxies/logbook/docs), each auto-paged under Google's 50,000-URL ceiling so a breach cannot happen rather than merely not having happened yet. robots.txt still names this one URL — a crawler discovers the children from here. Splitting per entity type is also the diagnostic: Search Console reports coverage PER sitemap, so each entity type gets its own submitted/indexed count.",
|
|
3117
3109
|
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
3118
3110
|
route: "/sitemap.xml",
|
|
3119
3111
|
url: `${SITE}/sitemap.xml`,
|
|
@@ -3122,7 +3114,7 @@ var init_src = __esm(() => {
|
|
|
3122
3114
|
{
|
|
3123
3115
|
apiFormat: "application/xml",
|
|
3124
3116
|
exposedContent: [
|
|
3125
|
-
"one child sitemap, per entity type: the pages / findings / artists / labels / albums / galaxies / logbook URLs, auto-paged"
|
|
3117
|
+
"one child sitemap, per entity type: the pages / findings / artists / labels / albums / galaxies / logbook / docs URLs, auto-paged"
|
|
3126
3118
|
],
|
|
3127
3119
|
kind: "discovery",
|
|
3128
3120
|
name: "discovery.sitemap-shard",
|
|
@@ -3153,6 +3145,16 @@ var init_src = __esm(() => {
|
|
|
3153
3145
|
url: `${SITE}/llms.txt`,
|
|
3154
3146
|
weights: { web: "primary" }
|
|
3155
3147
|
},
|
|
3148
|
+
{
|
|
3149
|
+
apiFormat: "text/markdown",
|
|
3150
|
+
exposedContent: ["one developer-doc page as clean Markdown, at `/docs.md/<slug>`"],
|
|
3151
|
+
kind: "discovery",
|
|
3152
|
+
name: "discovery.docs-markdown",
|
|
3153
|
+
operatorNotes: 'The Markdown twin of every /docs page — front-matter-free, the title as the H1, the description as the lede, then the precompiled body (`includeProcessedMarkdown` in source.config.ts → `page.data.getText("processed")`). It is the endpoint behind the page-actions affordance ("View as Markdown", "Copy page", and the Open in ChatGPT/Claude/Cursor links, which carry this URL so the assistant pulls the clean Markdown), and each /docs page advertises it as `<link rel="alternate" type="text/markdown">` (routes/-docs-head.ts). A machine-FETCHED document rather than a page, so it is catalogued as `discovery` next to llms.txt. No probeConfig: the route is slug-parameterized, so there is no fixed URL to GET-probe (the `discovery.oembed` / `web.artist` precedent) — the post-deploy probe skips it for the same reason it skips /artist/:slug/fresh.xml. Source: apps/web/src/routes/docs[.]md.$.ts (a pure splat, mounted at /docs.md/$).',
|
|
3154
|
+
route: "/docs.md/:slug",
|
|
3155
|
+
url: `${SITE}/docs.md/cli`,
|
|
3156
|
+
weights: { web: "tertiary" }
|
|
3157
|
+
},
|
|
3156
3158
|
{
|
|
3157
3159
|
apiFormat: "text/markdown",
|
|
3158
3160
|
exposedContent: ["the entire archive in one ingestible markdown document, every finding"],
|
|
@@ -3256,7 +3258,7 @@ var init_src = __esm(() => {
|
|
|
3256
3258
|
{
|
|
3257
3259
|
command: "ssh rave.fluncle.com",
|
|
3258
3260
|
exposedContent: [
|
|
3259
|
-
"the rave terminal TUI: Latest
|
|
3261
|
+
"the rave terminal TUI: Latest findings, Fresh releases, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
|
|
3260
3262
|
"deep-register one-shots: `ssh rave.fluncle.com latest|fresh|random`"
|
|
3261
3263
|
],
|
|
3262
3264
|
kind: "ssh",
|
|
@@ -5054,10 +5056,12 @@ async function resyncYoutube2(mixtapeId) {
|
|
|
5054
5056
|
}
|
|
5055
5057
|
async function authYoutubeCommand2() {
|
|
5056
5058
|
const response = await adminApiGet("/api/v1/admin/youtube/auth/start");
|
|
5057
|
-
console.log(`Open this
|
|
5059
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
5058
5060
|
|
|
5059
5061
|
${response.authUrl}
|
|
5060
5062
|
|
|
5063
|
+
It hands you off to Google. Signed out? Log in there and it resumes on its own.
|
|
5064
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
5061
5065
|
After approving access, Google returns to the Fluncle admin callback and stores the refresh token server-side.`);
|
|
5062
5066
|
}
|
|
5063
5067
|
async function initiate2(mixtapeId, contentLength, contentType) {
|
|
@@ -6394,11 +6398,13 @@ __export(exports_auth, {
|
|
|
6394
6398
|
});
|
|
6395
6399
|
async function authSpotifyCommand() {
|
|
6396
6400
|
const response = await adminApiGet("/api/v1/admin/spotify/auth/start");
|
|
6397
|
-
console.log(`Open this
|
|
6401
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
6398
6402
|
|
|
6399
6403
|
${response.authUrl}
|
|
6400
6404
|
|
|
6401
|
-
|
|
6405
|
+
It hands you off to Spotify. Signed out? Log in there and it resumes on its own.
|
|
6406
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
6407
|
+
After approving access, Spotify returns to the Fluncle admin callback and stores auth server-side.`);
|
|
6402
6408
|
}
|
|
6403
6409
|
var init_auth = __esm(() => {
|
|
6404
6410
|
init_api();
|
|
@@ -6475,10 +6481,12 @@ async function resyncMixcloud2(mixtapeId) {
|
|
|
6475
6481
|
}
|
|
6476
6482
|
async function authMixcloudCommand2() {
|
|
6477
6483
|
const response = await adminApiGet("/api/v1/admin/mixcloud/auth/start");
|
|
6478
|
-
console.log(`Open this
|
|
6484
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
6479
6485
|
|
|
6480
6486
|
${response.authUrl}
|
|
6481
6487
|
|
|
6488
|
+
It hands you off to Mixcloud. Signed out? Log in there and it resumes on its own.
|
|
6489
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
6482
6490
|
After approving access, Mixcloud returns to the Fluncle admin callback and stores the access token server-side.`);
|
|
6483
6491
|
}
|
|
6484
6492
|
function mixtapeDescription2(note, logId) {
|
|
@@ -6554,10 +6562,12 @@ __export(exports_auth_tiktok, {
|
|
|
6554
6562
|
});
|
|
6555
6563
|
async function authTikTokCommand() {
|
|
6556
6564
|
const response = await adminApiGet("/api/v1/admin/tiktok/auth/start");
|
|
6557
|
-
console.log(`Open this
|
|
6565
|
+
console.log(`Open this link in the browser you're logged into /admin with:
|
|
6558
6566
|
|
|
6559
6567
|
${response.authUrl}
|
|
6560
6568
|
|
|
6569
|
+
It hands you off to TikTok. Signed out? Log in there and it resumes on its own.
|
|
6570
|
+
The link is good for 10 minutes; run this again if it expires.
|
|
6561
6571
|
After approving access, TikTok returns to the Fluncle admin callback and stores the refresh token server-side.`);
|
|
6562
6572
|
}
|
|
6563
6573
|
var init_auth_tiktok = __esm(() => {
|
|
@@ -9352,6 +9362,60 @@ function isEnvProfile(value) {
|
|
|
9352
9362
|
var spotifyPlaylistUrl = "https://open.spotify.com/playlist/1m5LADqpLjiBERdtqrIiL0";
|
|
9353
9363
|
var telegramUrl = "https://t.me/fluncle";
|
|
9354
9364
|
|
|
9365
|
+
// src/live.ts
|
|
9366
|
+
init_env();
|
|
9367
|
+
var NEBULA_VIOLET = "\x1B[38;2;171;123;255m";
|
|
9368
|
+
var RESET = "\x1B[0m";
|
|
9369
|
+
var TIMEOUT_MS = 1500;
|
|
9370
|
+
function shouldSkip(args) {
|
|
9371
|
+
if (process.env.FLUNCLE_NO_LIVE_CALLOUT === "1") {
|
|
9372
|
+
return true;
|
|
9373
|
+
}
|
|
9374
|
+
if (process.env.CI) {
|
|
9375
|
+
return true;
|
|
9376
|
+
}
|
|
9377
|
+
if (args.length === 0) {
|
|
9378
|
+
return true;
|
|
9379
|
+
}
|
|
9380
|
+
const first = args[0];
|
|
9381
|
+
if (first === "admin" || first === "help") {
|
|
9382
|
+
return true;
|
|
9383
|
+
}
|
|
9384
|
+
return args.some((arg) => arg === "--json" || arg === "--help" || arg === "-h" || arg === "--version" || arg === "-V");
|
|
9385
|
+
}
|
|
9386
|
+
function displayUrl(url) {
|
|
9387
|
+
return url.replace(/^https?:\/\/(www\.)?/, "");
|
|
9388
|
+
}
|
|
9389
|
+
async function maybePrintLiveCallout(args) {
|
|
9390
|
+
if (shouldSkip(args) || process.stdout.isTTY !== true) {
|
|
9391
|
+
return;
|
|
9392
|
+
}
|
|
9393
|
+
try {
|
|
9394
|
+
const controller = new AbortController;
|
|
9395
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
9396
|
+
let data;
|
|
9397
|
+
try {
|
|
9398
|
+
const response = await fetch(`${getApiBaseUrl()}/api/v1/status`, {
|
|
9399
|
+
signal: controller.signal
|
|
9400
|
+
});
|
|
9401
|
+
if (!response.ok) {
|
|
9402
|
+
return;
|
|
9403
|
+
}
|
|
9404
|
+
data = await response.json();
|
|
9405
|
+
} finally {
|
|
9406
|
+
clearTimeout(timer);
|
|
9407
|
+
}
|
|
9408
|
+
const live = data.live;
|
|
9409
|
+
if (!live?.on) {
|
|
9410
|
+
return;
|
|
9411
|
+
}
|
|
9412
|
+
const text = `On the decks, live now: ${displayUrl(live.url)}`;
|
|
9413
|
+
const line = process.env.NO_COLOR ? text : `${NEBULA_VIOLET}${text}${RESET}`;
|
|
9414
|
+
console.log(`${line}
|
|
9415
|
+
`);
|
|
9416
|
+
} catch {}
|
|
9417
|
+
}
|
|
9418
|
+
|
|
9355
9419
|
// src/output.ts
|
|
9356
9420
|
import { writeSync } from "node:fs";
|
|
9357
9421
|
var EAGAIN_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
@@ -9430,6 +9494,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
9430
9494
|
program2.outputHelp();
|
|
9431
9495
|
return;
|
|
9432
9496
|
}
|
|
9497
|
+
await maybePrintLiveCallout(args);
|
|
9433
9498
|
try {
|
|
9434
9499
|
assertParseArgsCompatiblePositionals(args);
|
|
9435
9500
|
assertParseArgsCompatibleOptionValues(args);
|
package/package.json
CHANGED