postemi 1.0.1 → 1.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/dist/index.js CHANGED
@@ -421,10 +421,10 @@ var PostemiAPI = class {
421
421
  };
422
422
 
423
423
  // src/commands/auth.ts
424
- var import_fs2 = require("fs");
425
- var import_path2 = require("path");
426
- var import_os2 = require("os");
427
- var import_readline = require("readline");
424
+ var import_fs3 = require("fs");
425
+ var import_path4 = require("path");
426
+ var import_os3 = require("os");
427
+ var import_readline2 = require("readline");
428
428
 
429
429
  // src/settings.ts
430
430
  var import_fs = require("fs");
@@ -450,6 +450,9 @@ function getSetting(key) {
450
450
  return typeof value === "string" && value ? value : void 0;
451
451
  }
452
452
  function saveSetting(key, value) {
453
+ saveRawSetting(key, value);
454
+ }
455
+ function saveRawSetting(key, value) {
453
456
  if (!(0, import_fs.existsSync)(SETTINGS_DIR)) {
454
457
  (0, import_fs.mkdirSync)(SETTINGS_DIR, { recursive: true, mode: 448 });
455
458
  }
@@ -622,15 +625,345 @@ function resolveDateInput(input, timezone, flagName = "--date") {
622
625
  return { iso: instant.toISOString(), appliedTimezone: timezone };
623
626
  }
624
627
 
628
+ // src/commands/skills.ts
629
+ var import_os2 = require("os");
630
+ var import_path3 = require("path");
631
+ var import_readline = require("readline");
632
+
633
+ // src/skills.ts
634
+ var import_fs2 = require("fs");
635
+ var import_path2 = require("path");
636
+ var OPTIONAL_SETS = ["writing", "growth"];
637
+ var SKILL_SETS = {
638
+ core: ["postemi"],
639
+ writing: ["postemi-writing", "postemi-templates"],
640
+ growth: ["postemi-growth"]
641
+ };
642
+ var SET_SUMMARY = {
643
+ core: "the postemi commands and their rules (always on)",
644
+ writing: "write posts: ideas, hooks, formatting, network rules, templates",
645
+ growth: "grow an audience: niche, cadence, 30-day plan, weekly review"
646
+ };
647
+ var AGENT_IDS = ["claude", "codex", "cursor", "grok"];
648
+ function knownAgents(home, env = {}) {
649
+ const claudeHome = env.CLAUDE_CONFIG_DIR || (0, import_path2.join)(home, ".claude");
650
+ const codexHome = env.CODEX_HOME || (0, import_path2.join)(home, ".codex");
651
+ const cursorHome = (0, import_path2.join)(home, ".cursor");
652
+ const grokHome = (0, import_path2.join)(home, ".grok");
653
+ return [
654
+ { id: "claude", name: "Claude Code", home: claudeHome, skillsDir: (0, import_path2.join)(claudeHome, "skills") },
655
+ { id: "codex", name: "Codex", home: codexHome, skillsDir: (0, import_path2.join)(codexHome, "skills") },
656
+ { id: "cursor", name: "Cursor", home: cursorHome, skillsDir: (0, import_path2.join)(cursorHome, "skills") },
657
+ { id: "grok", name: "Grok Build", home: grokHome, skillsDir: (0, import_path2.join)(grokHome, "skills") }
658
+ ];
659
+ }
660
+ function detectAgents(home, env = {}) {
661
+ return knownAgents(home, env).filter((agent) => isDir(agent.home));
662
+ }
663
+ function parseSetNames(names) {
664
+ const out = /* @__PURE__ */ new Set();
665
+ for (const raw of names) {
666
+ const name = raw.trim().toLowerCase().replace(/^postemi-?/, "") || "core";
667
+ if (name === "all") OPTIONAL_SETS.forEach((s) => out.add(s));
668
+ else if (name === "templates") out.add("writing");
669
+ else if (name === "core" || name === "writing" || name === "growth") out.add(name);
670
+ else throw new Error(`Unknown skill "${raw}". Use writing, growth, all or core.`);
671
+ }
672
+ return [...out];
673
+ }
674
+ function isDir(path) {
675
+ try {
676
+ return (0, import_fs2.statSync)(path).isDirectory();
677
+ } catch (e) {
678
+ return false;
679
+ }
680
+ }
681
+ function listFiles(dir, prefix = "") {
682
+ const out = [];
683
+ for (const name of (0, import_fs2.readdirSync)(dir).sort()) {
684
+ const path = (0, import_path2.join)(dir, name);
685
+ if (isDir(path)) out.push(...listFiles(path, (0, import_path2.join)(prefix, name)));
686
+ else out.push((0, import_path2.join)(prefix, name));
687
+ }
688
+ return out;
689
+ }
690
+ function sameTree(a, b) {
691
+ const fa = listFiles(a);
692
+ const fb = listFiles(b);
693
+ return fa.length === fb.length && fa.every((f, i) => fb[i] === f && (0, import_fs2.readFileSync)((0, import_path2.join)(a, f)).equals((0, import_fs2.readFileSync)((0, import_path2.join)(b, f))));
694
+ }
695
+ function skillName(dir) {
696
+ try {
697
+ const text = (0, import_fs2.readFileSync)((0, import_path2.join)(dir, "SKILL.md"), "utf8");
698
+ const match = /^---\r?\n[\s\S]*?^name:\s*["']?([\w-]+)["']?\s*$/m.exec(text);
699
+ return match ? match[1] : null;
700
+ } catch (e) {
701
+ return null;
702
+ }
703
+ }
704
+ function folderState(source, folder, agent) {
705
+ const target = (0, import_path2.join)(agent.skillsDir, folder);
706
+ if (skillName(target) !== folder) return "missing";
707
+ return sameTree((0, import_path2.join)(source, folder), target) ? "installed" : "outdated";
708
+ }
709
+ function setState(source, set, agent) {
710
+ const states = SKILL_SETS[set].map((f) => folderState(source, f, agent));
711
+ if (states.includes("missing")) return "missing";
712
+ if (states.includes("outdated")) return "outdated";
713
+ return "installed";
714
+ }
715
+ function installSets(source, sets, agent) {
716
+ const folders = foldersFor(sets.includes("core") ? sets : ["core", ...sets]);
717
+ for (const folder of folders) {
718
+ if (skillName((0, import_path2.join)(source, folder)) !== folder) {
719
+ throw new Error(`The package has no ${folder} skill at ${(0, import_path2.join)(source, folder)}`);
720
+ }
721
+ const target = (0, import_path2.join)(agent.skillsDir, folder);
722
+ if ((0, import_fs2.existsSync)(target) && skillName(target) !== folder) {
723
+ throw new Error(`${target} exists and is not the ${folder} skill; move it away first`);
724
+ }
725
+ }
726
+ (0, import_fs2.mkdirSync)(agent.skillsDir, { recursive: true });
727
+ for (const folder of folders) {
728
+ const target = (0, import_path2.join)(agent.skillsDir, folder);
729
+ (0, import_fs2.rmSync)(target, { recursive: true, force: true });
730
+ (0, import_fs2.cpSync)((0, import_path2.join)(source, folder), target, { recursive: true });
731
+ }
732
+ return folders;
733
+ }
734
+ function removeSets(sets, agent) {
735
+ const removed = [];
736
+ for (const folder of foldersFor(sets)) {
737
+ const target = (0, import_path2.join)(agent.skillsDir, folder);
738
+ if (skillName(target) !== folder) continue;
739
+ (0, import_fs2.rmSync)(target, { recursive: true, force: true });
740
+ removed.push(folder);
741
+ }
742
+ return removed;
743
+ }
744
+ function foldersFor(sets) {
745
+ return [...new Set(sets.flatMap((s) => SKILL_SETS[s]))];
746
+ }
747
+ function terminalFrom(argv, env = process.env) {
748
+ return {
749
+ stdinTTY: !!process.stdin.isTTY,
750
+ stderrTTY: !!process.stderr.isTTY,
751
+ json: !!argv.json,
752
+ ci: !!env.CI && env.CI !== "false" && env.CI !== "0"
753
+ };
754
+ }
755
+ function canAsk(t) {
756
+ return t.stdinTTY && t.stderrTTY && !t.json && !t.ci;
757
+ }
758
+ var ANSWER_KEY = {
759
+ writing: "skills.writing",
760
+ growth: "skills.growth"
761
+ };
762
+ var HINT_KEY = "skills.hint";
763
+ var QUESTIONS = {
764
+ writing: "Postemi can also help you write posts. Install the optional writing skill (ideas, hooks, templates)? [y/N] ",
765
+ growth: "Install the optional growth skill (niche, cadence, 30-day plan)? [y/N] "
766
+ };
767
+ var HINT = "Tip: optional agent skills for writing posts and growing an audience: postemi skills list, postemi skills add writing|growth";
768
+ function isYes(answer) {
769
+ return /^(y|yes)$/i.test(answer.trim());
770
+ }
771
+ function alreadyOffered(store) {
772
+ return OPTIONAL_SETS.every((s) => !!store.get(ANSWER_KEY[s]));
773
+ }
774
+ async function offerOptionalSkills(deps, force = false) {
775
+ const { terminal, store, ask: ask3, log } = deps;
776
+ if (!force && alreadyOffered(store)) return [];
777
+ if (!canAsk(terminal)) {
778
+ if (!store.get(HINT_KEY)) {
779
+ log(HINT);
780
+ store.set(HINT_KEY, "shown");
781
+ }
782
+ return [];
783
+ }
784
+ const chosen = [];
785
+ for (const set of OPTIONAL_SETS) {
786
+ const yes = isYes(await ask3(QUESTIONS[set]));
787
+ store.set(ANSWER_KEY[set], yes ? "yes" : "no");
788
+ if (yes) chosen.push(set);
789
+ }
790
+ if (!chosen.length) log("No optional skills. Add them any time with: postemi skills add");
791
+ return chosen;
792
+ }
793
+ async function chooseAgents(opts) {
794
+ const { found, all, requested, yes, terminal, ask: ask3, log } = opts;
795
+ if (requested && requested.length) {
796
+ const ids = requested.flatMap((r) => String(r).split(",")).map((r) => r.trim().toLowerCase()).filter(Boolean);
797
+ if (ids.includes("all")) return found;
798
+ return ids.map((id) => {
799
+ const agent = all.find((a) => a.id === id);
800
+ if (!agent) throw new Error(`Unknown agent "${id}". Use ${AGENT_IDS.join(", ")} or all.`);
801
+ return agent;
802
+ });
803
+ }
804
+ if (found.length <= 1 || yes || !canAsk(terminal)) return found;
805
+ log("Agents found on this machine:");
806
+ found.forEach((a, i) => log(` ${i + 1}. ${a.name} (${a.skillsDir})`));
807
+ const answer = (await ask3(`Install for which? [all, or numbers like 1,3] `)).trim().toLowerCase();
808
+ if (!answer || answer === "all" || answer === "a") return found;
809
+ const picked = answer.split(/[\s,]+/).map((n) => found[Number(n) - 1]).filter((a) => !!a);
810
+ return [...new Set(picked)];
811
+ }
812
+
813
+ // src/commands/skills.ts
814
+ function bundledSkillsDir() {
815
+ return (0, import_path3.join)(__dirname, "..", "skills");
816
+ }
817
+ var settingsStore = {
818
+ get: (key) => {
819
+ const value = loadSettings()[key];
820
+ return typeof value === "string" && value ? value : void 0;
821
+ },
822
+ set: (key, value) => saveRawSetting(key, value)
823
+ };
824
+ function ask(question) {
825
+ const rl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stderr });
826
+ return new Promise(
827
+ (resolve) => rl.question(question, (answer) => {
828
+ rl.close();
829
+ resolve(answer);
830
+ })
831
+ );
832
+ }
833
+ function die(message) {
834
+ console.error(`\u274C ${message}`);
835
+ process.exit(1);
836
+ }
837
+ async function skillsList() {
838
+ const source = bundledSkillsDir();
839
+ const settings = loadSettings();
840
+ const agents = knownAgents((0, import_os2.homedir)(), process.env);
841
+ const found = new Set(detectAgents((0, import_os2.homedir)(), process.env).map((a) => a.id));
842
+ const sets = ["core", ...OPTIONAL_SETS];
843
+ result({
844
+ agents: agents.map((a) => ({ id: a.id, name: a.name, found: found.has(a.id), skillsDir: a.skillsDir })),
845
+ skills: sets.map((set) => {
846
+ var _a;
847
+ return {
848
+ name: set,
849
+ optional: set !== "core",
850
+ folders: SKILL_SETS[set],
851
+ about: SET_SUMMARY[set],
852
+ answer: set === "core" ? null : (_a = settings[ANSWER_KEY[set]]) != null ? _a : null,
853
+ installed: Object.fromEntries(
854
+ agents.filter((a) => found.has(a.id)).map((a) => [a.id, setState(source, set, a)])
855
+ )
856
+ };
857
+ })
858
+ });
859
+ }
860
+ async function install(sets, argv, terminal) {
861
+ const home = (0, import_os2.homedir)();
862
+ const agents = await chooseAgents({
863
+ found: detectAgents(home, process.env),
864
+ all: knownAgents(home, process.env),
865
+ requested: argv.agent,
866
+ yes: !!argv.yes,
867
+ terminal,
868
+ ask,
869
+ log: status
870
+ });
871
+ if (!agents.length) {
872
+ throw new Error(
873
+ `No agent skill folder found (~/.claude, ~/.codex, ~/.cursor, ~/.grok). Pass --agent claude (or codex, cursor, grok) to create one.`
874
+ );
875
+ }
876
+ const installed = {};
877
+ for (const agent of agents) {
878
+ try {
879
+ installed[agent.id] = installSets(bundledSkillsDir(), sets, agent);
880
+ } catch (error) {
881
+ throw new Error(`${agent.name}: ${error.message}`);
882
+ }
883
+ status(`\u2705 ${agent.name}: ${installed[agent.id].join(", ")} in ${agent.skillsDir}`);
884
+ }
885
+ for (const set of sets) {
886
+ if (set !== "core") settingsStore.set(ANSWER_KEY[set], "yes");
887
+ }
888
+ status("Start a new agent session to load them.");
889
+ return installed;
890
+ }
891
+ async function skillsAdd(argv) {
892
+ var _a;
893
+ const terminal = terminalFrom(argv);
894
+ const names = (_a = argv.skills) != null ? _a : [];
895
+ let sets;
896
+ if (!names.length) {
897
+ if (terminal.json || !terminal.stdinTTY || !terminal.stderrTTY || terminal.ci) {
898
+ die(`Name the skill: ${BRAND.cli} skills add writing|growth|all`);
899
+ }
900
+ sets = await offerOptionalSkills({ terminal, store: settingsStore, ask, log: status }, true);
901
+ if (!sets.length) {
902
+ result({ installed: {} });
903
+ return;
904
+ }
905
+ } else {
906
+ try {
907
+ sets = parseSetNames(names);
908
+ } catch (error) {
909
+ die(error.message);
910
+ }
911
+ }
912
+ try {
913
+ result({ installed: await install(sets, argv, terminal) });
914
+ } catch (error) {
915
+ die(error.message);
916
+ }
917
+ }
918
+ async function skillsRemove(argv) {
919
+ var _a, _b;
920
+ const names = (_a = argv.skills) != null ? _a : [];
921
+ if (!names.length) die(`Name the skill: ${BRAND.cli} skills remove writing|growth|all`);
922
+ let sets;
923
+ let agents;
924
+ try {
925
+ sets = parseSetNames(names);
926
+ agents = await chooseAgents({
927
+ found: detectAgents((0, import_os2.homedir)(), process.env),
928
+ all: knownAgents((0, import_os2.homedir)(), process.env),
929
+ requested: (_b = argv.agent) != null ? _b : ["all"],
930
+ yes: true,
931
+ terminal: terminalFrom(argv),
932
+ ask,
933
+ log: status
934
+ });
935
+ } catch (error) {
936
+ die(error.message);
937
+ }
938
+ const removed = {};
939
+ for (const agent of agents) {
940
+ removed[agent.id] = removeSets(sets, agent);
941
+ if (removed[agent.id].length) status(`\u{1F5D1}\uFE0F ${agent.name}: removed ${removed[agent.id].join(", ")}`);
942
+ }
943
+ for (const set of sets) {
944
+ if (set !== "core") settingsStore.set(ANSWER_KEY[set], "no");
945
+ }
946
+ result({ removed });
947
+ }
948
+ async function offerSkillsAfterLogin(argv) {
949
+ try {
950
+ const terminal = terminalFrom(argv);
951
+ const sets = await offerOptionalSkills({ terminal, store: settingsStore, ask, log: status });
952
+ if (sets.length) await install(sets, {}, terminal);
953
+ } catch (error) {
954
+ status(`Skills not installed: ${(error == null ? void 0 : error.message) || error}. Try: ${BRAND.cli} skills add`);
955
+ }
956
+ }
957
+
625
958
  // src/commands/auth.ts
626
- var CREDENTIALS_DIR = (0, import_path2.join)((0, import_os2.homedir)(), BRAND.configDirName);
627
- var CREDENTIALS_FILE = (0, import_path2.join)(CREDENTIALS_DIR, "credentials.json");
959
+ var CREDENTIALS_DIR = (0, import_path4.join)((0, import_os3.homedir)(), BRAND.configDirName);
960
+ var CREDENTIALS_FILE = (0, import_path4.join)(CREDENTIALS_DIR, "credentials.json");
628
961
  var DEFAULT_AUTH_SERVER = BRAND.defaultAuthServer;
629
962
  var DEFAULT_API_URL = BRAND.defaultApiUrl;
630
963
  function loadCredentials() {
631
964
  try {
632
- if (!(0, import_fs2.existsSync)(CREDENTIALS_FILE)) return null;
633
- const data = JSON.parse((0, import_fs2.readFileSync)(CREDENTIALS_FILE, "utf-8"));
965
+ if (!(0, import_fs3.existsSync)(CREDENTIALS_FILE)) return null;
966
+ const data = JSON.parse((0, import_fs3.readFileSync)(CREDENTIALS_FILE, "utf-8"));
634
967
  if (!data.accessToken) return null;
635
968
  return data;
636
969
  } catch (e) {
@@ -638,15 +971,15 @@ function loadCredentials() {
638
971
  }
639
972
  }
640
973
  function saveCredentials(credentials) {
641
- if (!(0, import_fs2.existsSync)(CREDENTIALS_DIR)) {
642
- (0, import_fs2.mkdirSync)(CREDENTIALS_DIR, { recursive: true, mode: 448 });
974
+ if (!(0, import_fs3.existsSync)(CREDENTIALS_DIR)) {
975
+ (0, import_fs3.mkdirSync)(CREDENTIALS_DIR, { recursive: true, mode: 448 });
643
976
  }
644
- (0, import_fs2.writeFileSync)(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { encoding: "utf-8", mode: 384 });
645
- (0, import_fs2.chmodSync)(CREDENTIALS_FILE, 384);
977
+ (0, import_fs3.writeFileSync)(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { encoding: "utf-8", mode: 384 });
978
+ (0, import_fs3.chmodSync)(CREDENTIALS_FILE, 384);
646
979
  }
647
980
  function deleteCredentials() {
648
- if ((0, import_fs2.existsSync)(CREDENTIALS_FILE)) {
649
- (0, import_fs2.unlinkSync)(CREDENTIALS_FILE);
981
+ if ((0, import_fs3.existsSync)(CREDENTIALS_FILE)) {
982
+ (0, import_fs3.unlinkSync)(CREDENTIALS_FILE);
650
983
  }
651
984
  }
652
985
  function openBrowser(url) {
@@ -660,8 +993,8 @@ function openBrowser(url) {
660
993
  function sleep(ms) {
661
994
  return new Promise((resolve) => setTimeout(resolve, ms));
662
995
  }
663
- function ask(question) {
664
- const rl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stderr });
996
+ function ask2(question) {
997
+ const rl = (0, import_readline2.createInterface)({ input: process.stdin, output: process.stderr });
665
998
  return new Promise(
666
999
  (resolve) => rl.question(question, (answer) => {
667
1000
  rl.close();
@@ -673,11 +1006,11 @@ async function maybeConfigureTimezone() {
673
1006
  if (getSetting("timezone")) return;
674
1007
  if (!process.stdin.isTTY || !process.stderr.isTTY) return;
675
1008
  const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;
676
- const answer = (await ask(`
1009
+ const answer = (await ask2(`
677
1010
  Scheduling timezone: ${detected} \u2014 OK? [Y/n] `)).trim().toLowerCase();
678
1011
  let timezone = detected;
679
1012
  if (answer === "n" || answer === "no") {
680
- const typed = (await ask(`Enter an IANA timezone name (e.g. ${BRAND.exampleTimezone}), or leave empty to skip: `)).trim();
1013
+ const typed = (await ask2(`Enter an IANA timezone name (e.g. ${BRAND.exampleTimezone}), or leave empty to skip: `)).trim();
681
1014
  if (!typed) {
682
1015
  console.error(
683
1016
  `Skipped. Dates without an explicit offset will be refused until you run: ${BRAND.cli} config:set timezone <IANA name>`
@@ -728,7 +1061,7 @@ async function chooseWorkspace(creds) {
728
1061
  );
729
1062
  return;
730
1063
  }
731
- const answer = (await ask(`Work in which one? [1-${workspaces.length}] `)).trim();
1064
+ const answer = (await ask2(`Work in which one? [1-${workspaces.length}] `)).trim();
732
1065
  const index = Number(answer) - 1;
733
1066
  const chosen = workspaces[index];
734
1067
  if (!chosen) {
@@ -809,6 +1142,7 @@ async function authLogin(argv) {
809
1142
  console.log(`\u{1F4C1} Credentials saved to ${CREDENTIALS_FILE}`);
810
1143
  await chooseWorkspace(creds);
811
1144
  await maybeConfigureTimezone();
1145
+ await offerSkillsAfterLogin(argv);
812
1146
  return;
813
1147
  }
814
1148
  if (data.error === "authorization_pending") {
@@ -910,7 +1244,7 @@ async function authSignup(argv) {
910
1244
  });
911
1245
  return;
912
1246
  }
913
- code = (await ask("Code from the e-mail: ")).trim();
1247
+ code = (await ask2("Code from the e-mail: ")).trim();
914
1248
  if (!code) {
915
1249
  console.error("\u274C No code given. Run the command again with --code <code>.");
916
1250
  process.exit(1);
@@ -926,7 +1260,7 @@ async function authSignup(argv) {
926
1260
  status(` Privacy notice: ${PRIVACY_URL}`);
927
1261
  let accepted = !!argv.acceptTerms;
928
1262
  if (!accepted && interactive) {
929
- const answer = (await ask("Do you agree to both? [y/N] ")).trim().toLowerCase();
1263
+ const answer = (await ask2("Do you agree to both? [y/N] ")).trim().toLowerCase();
930
1264
  accepted = answer === "y" || answer === "yes" || answer === "i" || answer === "igen";
931
1265
  }
932
1266
  if (!accepted) {
@@ -1150,7 +1484,7 @@ function getConfig() {
1150
1484
  }
1151
1485
 
1152
1486
  // src/commands/posts.ts
1153
- var import_fs3 = require("fs");
1487
+ var import_fs4 = require("fs");
1154
1488
  var pairContentsWithMedia = (argv) => {
1155
1489
  const read = (token, next, long, short) => {
1156
1490
  if (token === `--${long}` || token === `-${short}`) {
@@ -1240,11 +1574,11 @@ async function createPost(args) {
1240
1574
  if (args.json) {
1241
1575
  try {
1242
1576
  const jsonPath = args.json;
1243
- if (!(0, import_fs3.existsSync)(jsonPath)) {
1577
+ if (!(0, import_fs4.existsSync)(jsonPath)) {
1244
1578
  console.error(`\u274C JSON file not found: ${jsonPath}`);
1245
1579
  process.exit(1);
1246
1580
  }
1247
- const jsonContent = (0, import_fs3.readFileSync)(jsonPath, "utf-8");
1581
+ const jsonContent = (0, import_fs4.readFileSync)(jsonPath, "utf-8");
1248
1582
  postData = JSON.parse(jsonContent);
1249
1583
  } catch (error) {
1250
1584
  console.error(`\u274C Failed to parse JSON file: ${error.message}`);
@@ -1490,18 +1824,18 @@ async function getPostAnalytics(args) {
1490
1824
  }
1491
1825
 
1492
1826
  // src/commands/upload.ts
1493
- var import_fs4 = require("fs");
1494
- var import_path3 = require("path");
1827
+ var import_fs5 = require("fs");
1828
+ var import_path5 = require("path");
1495
1829
  async function uploadFile(args) {
1496
1830
  const config = getConfig();
1497
1831
  const api = new PostemiAPI(config);
1498
- if (!(0, import_fs4.existsSync)(args.file)) {
1832
+ if (!(0, import_fs5.existsSync)(args.file)) {
1499
1833
  console.error(`\u274C File not found: ${args.file}`);
1500
1834
  process.exit(1);
1501
1835
  }
1502
1836
  try {
1503
- const fileBuffer = (0, import_fs4.readFileSync)(args.file);
1504
- const filename = (0, import_path3.basename)(args.file) || "file";
1837
+ const fileBuffer = (0, import_fs5.readFileSync)(args.file);
1838
+ const filename = (0, import_path5.basename)(args.file) || "file";
1505
1839
  const res = await api.upload(fileBuffer, filename);
1506
1840
  status("\u2705 File uploaded successfully!");
1507
1841
  result(res);
@@ -2121,6 +2455,28 @@ async function billingManage(args) {
2121
2455
  });
2122
2456
  },
2123
2457
  billingManage
2458
+ ).command(
2459
+ "skills <command>",
2460
+ `Optional agent skills: install them into Claude Code, Codex, Cursor or Grok Build`,
2461
+ (yargs2) => {
2462
+ const target = (y) => y.positional("skills", {
2463
+ describe: "writing (with templates), growth, all, or core",
2464
+ type: "string",
2465
+ array: true
2466
+ }).option("agent", {
2467
+ describe: "Only these agents: claude, codex, cursor, grok, or all (skips the question)",
2468
+ type: "string",
2469
+ array: true
2470
+ }).option("yes", { alias: "y", describe: "Ask nothing; use every agent found", type: "boolean", default: false }).option("json", { describe: "Run as an agent or script: never ask", type: "boolean", default: false });
2471
+ return yargs2.command("list", "Show the core and optional skills, and where each is installed", {}, skillsList).command(
2472
+ "add [skills..]",
2473
+ "Install skills (writing, growth, all); asks which when you name none",
2474
+ (y) => target(y).example("$0 skills add writing", "Writing and template skills, plus the core skill").example("$0 skills add all --agent claude --yes", "Both optional skills, Claude Code only, no questions"),
2475
+ skillsAdd
2476
+ ).command("remove [skills..]", "Remove installed skills (writing, growth, all, core)", target, skillsRemove).demandCommand(1, `Use: ${BRAND.cli} skills list | add | remove`);
2477
+ },
2478
+ () => {
2479
+ }
2124
2480
  ).command(
2125
2481
  "config:set <key> <value>",
2126
2482
  `Save a CLI setting to ~/${BRAND.configDirName}/config.json`,
@@ -2154,6 +2510,10 @@ async function billingManage(args) {
2154
2510
  return yargs2.option("auth-server", {
2155
2511
  describe: `Auth server URL (default: ${BRAND.defaultApiUrl})`,
2156
2512
  type: "string"
2513
+ }).option("json", {
2514
+ describe: "Run as an agent or script: ask no setup questions after the login",
2515
+ type: "boolean",
2516
+ default: false
2157
2517
  }).example(
2158
2518
  "$0 auth:login",
2159
2519
  "Login via OAuth2 device flow"