clixad 0.0.1-beta.17 → 0.0.1-beta.18

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 (2) hide show
  1. package/dist/clixad.mjs +140 -21
  2. package/package.json +1 -1
package/dist/clixad.mjs CHANGED
@@ -246,6 +246,11 @@ var init_client = __esm({
246
246
  referral_bonus: "referral bonus",
247
247
  redeem_code: "code redeemed",
248
248
  ad_reward: "offer reward",
249
+ // Our own survey, and it is deliberately not called an offer. Every other
250
+ // earn line on this list is a network paying for something; this one is us.
251
+ // The name is the only place a user would ever learn the difference, and
252
+ // "offer reward" would file it next to the wall it did not come from.
253
+ own_survey_reward: "Clixad survey",
249
254
  ad_screenout_bonus: "screenout bonus (didn't qualify)",
250
255
  ad_sponsor_impression: "sponsored line shown",
251
256
  ad_reversal: "offer reward reversed by the provider",
@@ -826,7 +831,18 @@ var init_client = __esm({
826
831
  });
827
832
 
828
833
  // src/config.ts
829
- import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
834
+ import {
835
+ chmodSync,
836
+ closeSync,
837
+ fsyncSync,
838
+ mkdirSync,
839
+ openSync,
840
+ readFileSync,
841
+ renameSync,
842
+ unlinkSync,
843
+ writeFileSync,
844
+ writeSync
845
+ } from "node:fs";
830
846
  import { homedir } from "node:os";
831
847
  import { dirname, join } from "node:path";
832
848
  function sameEndpoint(a, b) {
@@ -841,11 +857,42 @@ function sameEndpoint(a, b) {
841
857
  };
842
858
  return norm(a) === norm(b);
843
859
  }
844
- function loadConfig() {
845
- let stored = {};
860
+ function takeConfigNotices() {
861
+ const out = notices;
862
+ notices = [];
863
+ return out;
864
+ }
865
+ function readStored() {
866
+ let raw;
846
867
  try {
847
- stored = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
868
+ raw = readFileSync(CONFIG_PATH, "utf8");
869
+ } catch (err) {
870
+ const code = err.code;
871
+ if (code === "ENOENT") return { stored: {} };
872
+ return { stored: {}, problem: `could not be read (${code ?? err.message})` };
873
+ }
874
+ if (raw.trim() === "") return { stored: {}, problem: "was empty", raw };
875
+ let parsed;
876
+ try {
877
+ parsed = JSON.parse(raw);
848
878
  } catch {
879
+ return { stored: {}, problem: "is not valid JSON", raw };
880
+ }
881
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
882
+ return { stored: {}, problem: "is not a JSON object", raw };
883
+ }
884
+ return { stored: parsed };
885
+ }
886
+ function loadConfig() {
887
+ notices = [];
888
+ envApplied.clear();
889
+ const read = readStored();
890
+ const stored = read.stored;
891
+ if (read.problem) {
892
+ notices.push(
893
+ `Your Clixad config (${CONFIG_PATH}) ${read.problem}, so this session starts signed out.
894
+ It is kept at ${QUARANTINE_PATH} the next time anything is saved \u2014 sign in again with \`/login\`.`
895
+ );
849
896
  }
850
897
  const mintedAgainst = stored.gatewayUrl;
851
898
  for (const [key, stale] of Object.entries(SUPERSEDED_DEFAULTS)) {
@@ -857,17 +904,76 @@ function loadConfig() {
857
904
  const config = { ...DEFAULTS, ...stored };
858
905
  for (const [key, envVar] of ENV_OVERRIDES) {
859
906
  const value = process.env[envVar];
860
- if (value) config[key] = value;
907
+ if (value) {
908
+ config[key] = value;
909
+ envApplied.add(key);
910
+ }
861
911
  }
862
- const migratedGateway = mintedAgainst !== void 0 && stored.gatewayUrl === void 0;
863
- if (migratedGateway && !sameEndpoint(mintedAgainst, config.gatewayUrl)) {
912
+ const boundTo = stored.tokenGateway ?? mintedAgainst;
913
+ const redirected = envApplied.has("gatewayUrl");
914
+ if (!redirected && boundTo !== void 0 && !sameEndpoint(boundTo, config.gatewayUrl)) {
915
+ if (stored.token !== void 0) {
916
+ notices.push(
917
+ `Signed out: the saved account belongs to ${boundTo}, and this run talks to ${config.gatewayUrl}.
918
+ Sign in again with \`/login\` (or \`clixad login\`).`
919
+ );
920
+ }
864
921
  for (const key of IDENTITY_KEYS) delete config[key];
865
922
  }
923
+ baseline = { ...config };
866
924
  return config;
867
925
  }
926
+ function changedKeys(config) {
927
+ const current = config;
928
+ if (!baseline) return Object.keys(current);
929
+ const before = baseline;
930
+ const keys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(current)]);
931
+ return [...keys].filter((key) => before[key] !== current[key]);
932
+ }
933
+ function writeAtomically(contents) {
934
+ const tmp = `${CONFIG_PATH}.${process.pid}.tmp`;
935
+ try {
936
+ const fd = openSync(tmp, "w", 384);
937
+ try {
938
+ writeSync(fd, contents);
939
+ fsyncSync(fd);
940
+ } finally {
941
+ closeSync(fd);
942
+ }
943
+ renameSync(tmp, CONFIG_PATH);
944
+ } catch (err) {
945
+ try {
946
+ unlinkSync(tmp);
947
+ } catch {
948
+ }
949
+ throw err;
950
+ }
951
+ }
868
952
  function saveConfig(config) {
869
953
  mkdirSync(dirname(CONFIG_PATH), { recursive: true, mode: 448 });
870
- writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
954
+ const changed = changedKeys(config);
955
+ const current = readStored();
956
+ let base = {};
957
+ if (current.problem) {
958
+ if (current.raw !== void 0) {
959
+ try {
960
+ writeFileSync(QUARANTINE_PATH, current.raw, { encoding: "utf8", mode: 384 });
961
+ } catch {
962
+ }
963
+ }
964
+ } else {
965
+ base = current.stored;
966
+ }
967
+ const next = { ...base };
968
+ const source = config;
969
+ for (const key of changed) {
970
+ const value = source[key];
971
+ if (value === void 0) delete next[key];
972
+ else next[key] = value;
973
+ }
974
+ writeAtomically(`${JSON.stringify(next, null, 2)}
975
+ `);
976
+ baseline = { ...config };
871
977
  try {
872
978
  chmodSync(CONFIG_PATH, 384);
873
979
  } catch {
@@ -876,11 +982,12 @@ function saveConfig(config) {
876
982
  function configPath() {
877
983
  return CONFIG_PATH;
878
984
  }
879
- var CONFIG_PATH, DEFAULTS, ENV_OVERRIDES, SUPERSEDED_DEFAULTS, IDENTITY_KEYS;
985
+ var CONFIG_PATH, QUARANTINE_PATH, DEFAULTS, ENV_OVERRIDES, SUPERSEDED_DEFAULTS, IDENTITY_KEYS, baseline, envApplied, notices;
880
986
  var init_config = __esm({
881
987
  "src/config.ts"() {
882
988
  "use strict";
883
989
  CONFIG_PATH = join(homedir(), ".clixad", "config.json");
990
+ QUARANTINE_PATH = `${CONFIG_PATH}.corrupt`;
884
991
  DEFAULTS = {
885
992
  gatewayUrl: "https://clixad.onrender.com",
886
993
  // Same origin as the gateway: the ad wall is served by the gateway process
@@ -898,7 +1005,9 @@ var init_config = __esm({
898
1005
  gatewayUrl: ["http://127.0.0.1:8787", "http://localhost:8787"],
899
1006
  dashboardUrl: ["http://127.0.0.1:8788", "http://localhost:8788"]
900
1007
  };
901
- IDENTITY_KEYS = ["token", "userId", "email", "login"];
1008
+ IDENTITY_KEYS = ["token", "userId", "email", "login", "tokenGateway"];
1009
+ envApplied = /* @__PURE__ */ new Set();
1010
+ notices = [];
902
1011
  }
903
1012
  });
904
1013
 
@@ -958,6 +1067,7 @@ async function githubLogin(client, config, start, invite, report, signal) {
958
1067
  config.userId = poll.userId;
959
1068
  config.email = poll.email;
960
1069
  config.login = poll.login;
1070
+ config.tokenGateway = config.gatewayUrl;
961
1071
  saveConfig(config);
962
1072
  return {
963
1073
  status: "ok",
@@ -987,6 +1097,7 @@ async function devLogin(client, config, email, invite) {
987
1097
  config.token = res.token;
988
1098
  config.userId = res.userId;
989
1099
  config.email = res.email;
1100
+ config.tokenGateway = config.gatewayUrl;
990
1101
  delete config.login;
991
1102
  saveConfig(config);
992
1103
  return { status: "ok", account: { email: res.email, balance: res.balance, created: true } };
@@ -5129,7 +5240,7 @@ function useTerminalSize() {
5129
5240
  }, [stdout]);
5130
5241
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
5131
5242
  }
5132
- function App({ client, config, wallet, streak, session, initialTask, sponsorServe }) {
5243
+ function App({ client, config, wallet, streak, session, initialTask, notices: notices2, sponsorServe }) {
5133
5244
  const { exit } = useApp();
5134
5245
  const { stdout, write: writeToStdout } = useStdout();
5135
5246
  const idRef = useRef(1);
@@ -5283,6 +5394,7 @@ function App({ client, config, wallet, streak, session, initialTask, sponsorServ
5283
5394
  useEffect(() => dropDelta, [dropDelta]);
5284
5395
  useEffect(() => {
5285
5396
  client.onNotice = (text2) => push({ kind: "notice", tone: "warn", text: text2 });
5397
+ for (const text2 of notices2 ?? []) push({ kind: "notice", tone: "warn", text: ` ${text2}` });
5286
5398
  const files = contextRef.current.files;
5287
5399
  if (files.length) push({ kind: "notice", text: ` context: ${files.join(", ")}` });
5288
5400
  const streakLine = streak && streak.claimed ? streakLabel(streak) : null;
@@ -6769,6 +6881,8 @@ async function main() {
6769
6881
  const [cmd, ...rest] = process.argv.slice(2);
6770
6882
  const config = loadConfig();
6771
6883
  const client = new GatewayClient(config);
6884
+ const configNotices = takeConfigNotices();
6885
+ for (const text of configNotices) console.error(c.yellow(text));
6772
6886
  switch (cmd) {
6773
6887
  case "login":
6774
6888
  return login(client, config, rest);
@@ -6793,15 +6907,15 @@ async function main() {
6793
6907
  case "ask":
6794
6908
  return ask(client, config, rest.join(" "));
6795
6909
  case "agent":
6796
- return repl(client, config, { task: rest.join(" ").trim() || void 0 });
6910
+ return repl(client, config, { task: rest.join(" ").trim() || void 0, notices: configNotices });
6797
6911
  case "-p":
6798
6912
  case "--print":
6799
6913
  return printCmd(client, config, rest.join(" ").trim());
6800
6914
  case "-c":
6801
6915
  case "--continue":
6802
- return repl(client, config, { resume: "latest" });
6916
+ return repl(client, config, { resume: "latest", notices: configNotices });
6803
6917
  case "--resume":
6804
- return repl(client, config, { resume: rest[0] ?? "pick" });
6918
+ return repl(client, config, { resume: rest[0] ?? "pick", notices: configNotices });
6805
6919
  case "code":
6806
6920
  return codeCmd(client, config, rest);
6807
6921
  case "help":
@@ -6816,7 +6930,7 @@ async function main() {
6816
6930
  case "-v":
6817
6931
  return void console.log(VERSION);
6818
6932
  case void 0:
6819
- return repl(client, config);
6933
+ return repl(client, config, { notices: configNotices });
6820
6934
  default:
6821
6935
  if (cmd.startsWith("-")) {
6822
6936
  console.error(c.red(`unknown option: ${cmd}`));
@@ -6824,7 +6938,7 @@ async function main() {
6824
6938
  process.exitCode = 1;
6825
6939
  return;
6826
6940
  }
6827
- return repl(client, config, { task: [cmd, ...rest].join(" ").trim() });
6941
+ return repl(client, config, { task: [cmd, ...rest].join(" ").trim(), notices: configNotices });
6828
6942
  }
6829
6943
  }
6830
6944
  async function login(client, config, args) {
@@ -6893,10 +7007,7 @@ function wrapPlain(text, width) {
6893
7007
  var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
6894
7008
  var credits = (n) => n.toLocaleString("en-US");
6895
7009
  function logout(config) {
6896
- delete config.token;
6897
- delete config.userId;
6898
- delete config.email;
6899
- delete config.login;
7010
+ for (const key of IDENTITY_KEYS) delete config[key];
6900
7011
  saveConfig(config);
6901
7012
  console.log(c.green("\u2713 logged out"));
6902
7013
  }
@@ -7235,7 +7346,15 @@ async function repl(client, config, opts = {}) {
7235
7346
  const wallet = await safeWallet(client);
7236
7347
  clearScreen();
7237
7348
  const { startTui: startTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
7238
- await startTui2({ client, config, wallet, streak, session, initialTask: opts.task });
7349
+ await startTui2({
7350
+ client,
7351
+ config,
7352
+ wallet,
7353
+ streak,
7354
+ session,
7355
+ initialTask: opts.task,
7356
+ ...opts.notices?.length ? { notices: opts.notices } : {}
7357
+ });
7239
7358
  }
7240
7359
  async function runTurn(client, config, messages) {
7241
7360
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clixad",
3
- "version": "0.0.1-beta.17",
3
+ "version": "0.0.1-beta.18",
4
4
  "description": "Free AI coding agent in your terminal, funded by rewarded ads.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",