@joycostudio/scripts 0.0.3 → 0.0.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +201 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -10,6 +10,7 @@ pnpx @joycostudio/scripts compress ./images ./output --quality 80
10
10
  pnpx @joycostudio/scripts resize ./images ./output --width 1920 --height 1080
11
11
  pnpx @joycostudio/scripts sequence -z 4 ./frames ./output/frame_%n.png
12
12
  pnpx @joycostudio/scripts fix-svg src --dry --print
13
+ pnpx @joycostudio/scripts agents -s codex
13
14
  ```
14
15
 
15
16
  For local development, build the CLI before running it directly:
package/dist/cli.js CHANGED
@@ -502,10 +502,10 @@ var require_help = __commonJS({
502
502
  function formatList(textArray) {
503
503
  return textArray.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth));
504
504
  }
505
- let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
505
+ let output2 = [`Usage: ${helper.commandUsage(cmd)}`, ""];
506
506
  const commandDescription = helper.commandDescription(cmd);
507
507
  if (commandDescription.length > 0) {
508
- output = output.concat([
508
+ output2 = output2.concat([
509
509
  helper.wrap(commandDescription, helpWidth, 0),
510
510
  ""
511
511
  ]);
@@ -517,7 +517,7 @@ var require_help = __commonJS({
517
517
  );
518
518
  });
519
519
  if (argumentList.length > 0) {
520
- output = output.concat(["Arguments:", formatList(argumentList), ""]);
520
+ output2 = output2.concat(["Arguments:", formatList(argumentList), ""]);
521
521
  }
522
522
  const optionList = helper.visibleOptions(cmd).map((option) => {
523
523
  return formatItem(
@@ -526,7 +526,7 @@ var require_help = __commonJS({
526
526
  );
527
527
  });
528
528
  if (optionList.length > 0) {
529
- output = output.concat(["Options:", formatList(optionList), ""]);
529
+ output2 = output2.concat(["Options:", formatList(optionList), ""]);
530
530
  }
531
531
  if (this.showGlobalOptions) {
532
532
  const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
@@ -536,7 +536,7 @@ var require_help = __commonJS({
536
536
  );
537
537
  });
538
538
  if (globalOptionList.length > 0) {
539
- output = output.concat([
539
+ output2 = output2.concat([
540
540
  "Global Options:",
541
541
  formatList(globalOptionList),
542
542
  ""
@@ -550,9 +550,9 @@ var require_help = __commonJS({
550
550
  );
551
551
  });
552
552
  if (commandList.length > 0) {
553
- output = output.concat(["Commands:", formatList(commandList), ""]);
553
+ output2 = output2.concat(["Commands:", formatList(commandList), ""]);
554
554
  }
555
- return output.join("\n");
555
+ return output2.join("\n");
556
556
  }
557
557
  /**
558
558
  * Calculate the pad width from the maximum term length.
@@ -964,8 +964,8 @@ var require_command = __commonJS({
964
964
  "../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports2) {
965
965
  var EventEmitter = require("node:events").EventEmitter;
966
966
  var childProcess = require("node:child_process");
967
- var path6 = require("node:path");
968
- var fs5 = require("node:fs");
967
+ var path8 = require("node:path");
968
+ var fs7 = require("node:fs");
969
969
  var process2 = require("node:process");
970
970
  var { Argument: Argument2, humanReadableArgName } = require_argument();
971
971
  var { CommanderError: CommanderError2 } = require_error();
@@ -1897,11 +1897,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1897
1897
  let launchWithNode = false;
1898
1898
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1899
1899
  function findFile(baseDir, baseName) {
1900
- const localBin = path6.resolve(baseDir, baseName);
1901
- if (fs5.existsSync(localBin)) return localBin;
1902
- if (sourceExt.includes(path6.extname(baseName))) return void 0;
1900
+ const localBin = path8.resolve(baseDir, baseName);
1901
+ if (fs7.existsSync(localBin)) return localBin;
1902
+ if (sourceExt.includes(path8.extname(baseName))) return void 0;
1903
1903
  const foundExt = sourceExt.find(
1904
- (ext) => fs5.existsSync(`${localBin}${ext}`)
1904
+ (ext) => fs7.existsSync(`${localBin}${ext}`)
1905
1905
  );
1906
1906
  if (foundExt) return `${localBin}${foundExt}`;
1907
1907
  return void 0;
@@ -1913,21 +1913,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1913
1913
  if (this._scriptPath) {
1914
1914
  let resolvedScriptPath;
1915
1915
  try {
1916
- resolvedScriptPath = fs5.realpathSync(this._scriptPath);
1916
+ resolvedScriptPath = fs7.realpathSync(this._scriptPath);
1917
1917
  } catch (err) {
1918
1918
  resolvedScriptPath = this._scriptPath;
1919
1919
  }
1920
- executableDir = path6.resolve(
1921
- path6.dirname(resolvedScriptPath),
1920
+ executableDir = path8.resolve(
1921
+ path8.dirname(resolvedScriptPath),
1922
1922
  executableDir
1923
1923
  );
1924
1924
  }
1925
1925
  if (executableDir) {
1926
1926
  let localFile = findFile(executableDir, executableFile);
1927
1927
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1928
- const legacyName = path6.basename(
1928
+ const legacyName = path8.basename(
1929
1929
  this._scriptPath,
1930
- path6.extname(this._scriptPath)
1930
+ path8.extname(this._scriptPath)
1931
1931
  );
1932
1932
  if (legacyName !== this._name) {
1933
1933
  localFile = findFile(
@@ -1938,7 +1938,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1938
1938
  }
1939
1939
  executableFile = localFile || executableFile;
1940
1940
  }
1941
- launchWithNode = sourceExt.includes(path6.extname(executableFile));
1941
+ launchWithNode = sourceExt.includes(path8.extname(executableFile));
1942
1942
  let proc;
1943
1943
  if (process2.platform !== "win32") {
1944
1944
  if (launchWithNode) {
@@ -2778,7 +2778,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2778
2778
  * @return {Command}
2779
2779
  */
2780
2780
  nameFromFilename(filename) {
2781
- this._name = path6.basename(filename, path6.extname(filename));
2781
+ this._name = path8.basename(filename, path8.extname(filename));
2782
2782
  return this;
2783
2783
  }
2784
2784
  /**
@@ -2792,9 +2792,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2792
2792
  * @param {string} [path]
2793
2793
  * @return {(string|null|Command)}
2794
2794
  */
2795
- executableDir(path7) {
2796
- if (path7 === void 0) return this._executableDir;
2797
- this._executableDir = path7;
2795
+ executableDir(path9) {
2796
+ if (path9 === void 0) return this._executableDir;
2797
+ this._executableDir = path9;
2798
2798
  return this;
2799
2799
  }
2800
2800
  /**
@@ -3052,7 +3052,7 @@ var {
3052
3052
  // package.json
3053
3053
  var package_default = {
3054
3054
  name: "@joycostudio/scripts",
3055
- version: "0.0.3",
3055
+ version: "0.0.4",
3056
3056
  description: "Joyco utility scripts as a pnpx CLI",
3057
3057
  bin: {
3058
3058
  scripts: "dist/cli.js"
@@ -3503,6 +3503,179 @@ function register4(program2) {
3503
3503
  addExamples(command, ["scripts fix-svg src", "scripts fix-svg src --dry --print"]);
3504
3504
  }
3505
3505
 
3506
+ // src/commands/agents.ts
3507
+ var import_path7 = __toESM(require("path"));
3508
+ var import_promises5 = __toESM(require("fs/promises"));
3509
+ var import_promises6 = require("node:readline/promises");
3510
+ var import_node_process = require("node:process");
3511
+
3512
+ // src/core/agents.ts
3513
+ var import_promises4 = __toESM(require("fs/promises"));
3514
+ var import_path6 = __toESM(require("path"));
3515
+ var AGENTS_URL = "https://registry.joyco.studio/AGENTS.md";
3516
+ var agentStrategies = {
3517
+ codex: {
3518
+ defaultPath: "AGENTS.md",
3519
+ description: "Codex reads AGENTS.md from the project root."
3520
+ },
3521
+ claude: {
3522
+ defaultPath: "CLAUDE.md",
3523
+ description: "Claude Code reads CLAUDE.md from the project root."
3524
+ },
3525
+ cursor: {
3526
+ defaultPath: import_path6.default.join(".cursor", "rules", "AGENTS.md"),
3527
+ description: "Cursor reads Markdown rules from .cursor/rules/."
3528
+ }
3529
+ };
3530
+ function parseAgentStrategy(value) {
3531
+ const normalized = value.trim().toLowerCase();
3532
+ if (normalized in agentStrategies) {
3533
+ return normalized;
3534
+ }
3535
+ const choices = Object.keys(agentStrategies).join(", ");
3536
+ throw new Error(`Unknown strategy "${value}". Choose one of: ${choices}.`);
3537
+ }
3538
+ function getDefaultAgentsPath(strategy) {
3539
+ return agentStrategies[strategy].defaultPath;
3540
+ }
3541
+ function resolveAgentsPath({
3542
+ strategy,
3543
+ outputPath,
3544
+ cwd = process.cwd()
3545
+ }) {
3546
+ return import_path6.default.resolve(cwd, outputPath ?? getDefaultAgentsPath(strategy));
3547
+ }
3548
+ async function fetchAgentsMd(url = AGENTS_URL) {
3549
+ const response = await fetch(url, {
3550
+ headers: {
3551
+ "Cache-Control": "no-cache"
3552
+ }
3553
+ });
3554
+ if (!response.ok) {
3555
+ throw new Error(
3556
+ `Failed to fetch ${url} (${response.status} ${response.statusText}).`
3557
+ );
3558
+ }
3559
+ return response.text();
3560
+ }
3561
+ async function writeAgentsFile(outputPath, contents, mode) {
3562
+ await import_promises4.default.mkdir(import_path6.default.dirname(outputPath), { recursive: true });
3563
+ if (mode === "append") {
3564
+ const needsNewline = !contents.startsWith("\n") && contents.length > 0;
3565
+ await import_promises4.default.appendFile(outputPath, needsNewline ? `
3566
+ ${contents}` : contents, "utf8");
3567
+ return;
3568
+ }
3569
+ const flag = mode === "create" ? "wx" : "w";
3570
+ await import_promises4.default.writeFile(outputPath, contents, { encoding: "utf8", flag });
3571
+ }
3572
+ async function pullAgents({
3573
+ strategy,
3574
+ outputPath,
3575
+ writeMode = "create",
3576
+ cwd = process.cwd()
3577
+ }) {
3578
+ const resolvedPath = resolveAgentsPath({ strategy, outputPath, cwd });
3579
+ const contents = await fetchAgentsMd();
3580
+ await writeAgentsFile(resolvedPath, contents, writeMode);
3581
+ return {
3582
+ outputPath: resolvedPath,
3583
+ bytes: Buffer.byteLength(contents, "utf8")
3584
+ };
3585
+ }
3586
+
3587
+ // src/commands/agents.ts
3588
+ var strategyChoices = Object.entries(agentStrategies).map(([key, value]) => `${key}=${value.defaultPath}`).join(", ");
3589
+ async function fileExists(filePath) {
3590
+ try {
3591
+ await import_promises5.default.access(filePath);
3592
+ return true;
3593
+ } catch (error) {
3594
+ if (error && typeof error === "object" && "code" in error) {
3595
+ const errorCode = error.code;
3596
+ if (errorCode === "ENOENT") {
3597
+ return false;
3598
+ }
3599
+ }
3600
+ throw error;
3601
+ }
3602
+ }
3603
+ async function promptExistingFile(outputPath) {
3604
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
3605
+ throw new Error(
3606
+ "Output file already exists. Re-run in an interactive terminal to choose overwrite, append, or cancel."
3607
+ );
3608
+ }
3609
+ const rl = (0, import_promises6.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
3610
+ try {
3611
+ while (true) {
3612
+ const answer = await rl.question(
3613
+ `
3614
+ File already exists at ${outputPath}. Overwrite (o), append (a), or cancel (c)? `
3615
+ );
3616
+ const normalized = answer.trim().toLowerCase();
3617
+ if (normalized === "o" || normalized === "overwrite") {
3618
+ return "overwrite";
3619
+ }
3620
+ if (normalized === "a" || normalized === "append") {
3621
+ return "append";
3622
+ }
3623
+ if (normalized === "c" || normalized === "cancel") {
3624
+ return "cancel";
3625
+ }
3626
+ }
3627
+ } finally {
3628
+ rl.close();
3629
+ }
3630
+ }
3631
+ function register5(program2) {
3632
+ const command = program2.command("agents").description("Download the latest AGENTS.md for a selected agent tool strategy.").usage("[dest_path] [-s <strategy>]").argument(
3633
+ "[dest_path]",
3634
+ "Output path (defaults to the strategy's standard location)."
3635
+ ).option(
3636
+ "-s, --strategy <strategy>",
3637
+ `Agent tool strategy (${strategyChoices}).`,
3638
+ parseAgentStrategy,
3639
+ "codex"
3640
+ ).action(async (destPath, options, cmd) => {
3641
+ try {
3642
+ const strategySource = cmd.getOptionValueSource?.("strategy");
3643
+ if (destPath && strategySource === "cli") {
3644
+ throw new Error("Choose either an output path or -s/--strategy, not both.");
3645
+ }
3646
+ const resolvedPath = resolveAgentsPath({
3647
+ strategy: options.strategy,
3648
+ outputPath: destPath,
3649
+ cwd: process.cwd()
3650
+ });
3651
+ const displayPath = import_path7.default.relative(process.cwd(), resolvedPath);
3652
+ let writeMode = "create";
3653
+ if (await fileExists(resolvedPath)) {
3654
+ const choice = await promptExistingFile(displayPath);
3655
+ if (choice === "cancel") {
3656
+ console.log("Canceled.");
3657
+ process.exit(1);
3658
+ }
3659
+ writeMode = choice;
3660
+ }
3661
+ await pullAgents({
3662
+ strategy: options.strategy,
3663
+ outputPath: resolvedPath,
3664
+ writeMode
3665
+ });
3666
+ console.log(`Saved agent instructions to ${displayPath}`);
3667
+ } catch (error) {
3668
+ handleCommandError(error);
3669
+ }
3670
+ });
3671
+ addExamples(command, [
3672
+ "scripts agents",
3673
+ "scripts agents -s claude",
3674
+ "scripts agents -s cursor",
3675
+ "scripts agents ./config/AGENTS.md"
3676
+ ]);
3677
+ }
3678
+
3506
3679
  // src/cli.ts
3507
3680
  var cliName = "scripts";
3508
3681
  var cliDescription = "Joyco utility scripts bundled as a pnpx CLI.";
@@ -3510,15 +3683,16 @@ var commandRegistrations = [
3510
3683
  register,
3511
3684
  register2,
3512
3685
  register3,
3513
- register4
3686
+ register4,
3687
+ register5
3514
3688
  ];
3515
3689
  function buildProgram() {
3516
3690
  const program2 = new Command();
3517
3691
  program2.name(cliName);
3518
3692
  program2.description(cliDescription);
3519
3693
  program2.version(package_default.version);
3520
- for (const register5 of commandRegistrations) {
3521
- register5(program2);
3694
+ for (const register6 of commandRegistrations) {
3695
+ register6(program2);
3522
3696
  }
3523
3697
  return program2;
3524
3698
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joycostudio/scripts",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Joyco utility scripts as a pnpx CLI",
5
5
  "bin": {
6
6
  "scripts": "dist/cli.js"