adsinagents 0.1.7 → 0.1.8
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/cli/dist/index.js +269 -41
- package/daemon/dist/main.js +25 -9
- package/native/build.sh +10 -0
- package/package.json +1 -1
package/cli/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ var __export = (target, all) => {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
// ../cli/src/index.ts
|
|
11
|
-
import { dirname as dirname4, join as
|
|
11
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
12
12
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
13
13
|
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "node:fs";
|
|
14
14
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
@@ -4542,8 +4542,8 @@ var ClaudeCodeAdapter = class {
|
|
|
4542
4542
|
else
|
|
4543
4543
|
priorValues.hooks = cur.hooks;
|
|
4544
4544
|
const mk = (path) => ({
|
|
4545
|
-
type: "
|
|
4546
|
-
|
|
4545
|
+
type: "command",
|
|
4546
|
+
command: hookCommand(path)
|
|
4547
4547
|
});
|
|
4548
4548
|
next.hooks = {
|
|
4549
4549
|
...hooks,
|
|
@@ -4568,8 +4568,8 @@ var ClaudeCodeAdapter = class {
|
|
|
4568
4568
|
const backup = this.backup();
|
|
4569
4569
|
const { next, diff } = this.merge(plan);
|
|
4570
4570
|
this.write(next);
|
|
4571
|
-
this.writeSlashCommand();
|
|
4572
|
-
return { backup, diff };
|
|
4571
|
+
const slashCommand = this.writeSlashCommand();
|
|
4572
|
+
return { backup, diff, slashCommand };
|
|
4573
4573
|
}
|
|
4574
4574
|
/** Path of the in-session settings command, e.g. ~/.claude/commands/adsinagents.md. */
|
|
4575
4575
|
slashCommandPath() {
|
|
@@ -4579,14 +4579,22 @@ var ClaudeCodeAdapter = class {
|
|
|
4579
4579
|
* Install /adsinagents — the status line itself is display-only, so this is
|
|
4580
4580
|
* the in-session settings surface: the user types /adsinagents and Claude
|
|
4581
4581
|
* drives the CLI. File is fully ours (sentinel comment), safe to delete on
|
|
4582
|
-
* remove.
|
|
4582
|
+
* remove. Reconciles: writes if missing or stale (content drift), skips if
|
|
4583
|
+
* already correct. Returns the outcome so init can REPORT failures instead of
|
|
4584
|
+
* silently swallowing them (the old try/catch hid a real install bug — the
|
|
4585
|
+
* file never wrote and doctor was the only thing that ever noticed).
|
|
4583
4586
|
*/
|
|
4584
4587
|
writeSlashCommand() {
|
|
4588
|
+
const p = this.slashCommandPath();
|
|
4585
4589
|
try {
|
|
4586
|
-
|
|
4590
|
+
if (existsSync2(p) && readFileSync2(p, "utf8") === SLASH_COMMAND_MD) {
|
|
4591
|
+
return { ok: true };
|
|
4592
|
+
}
|
|
4587
4593
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4588
4594
|
writeFileSync2(p, SLASH_COMMAND_MD);
|
|
4589
|
-
|
|
4595
|
+
return { ok: true };
|
|
4596
|
+
} catch (e) {
|
|
4597
|
+
return { ok: false, reason: e.message };
|
|
4590
4598
|
}
|
|
4591
4599
|
}
|
|
4592
4600
|
removeInstall() {
|
|
@@ -4716,10 +4724,18 @@ function spinnerVerbsFor(ad) {
|
|
|
4716
4724
|
`Brought to you by ${brand}`
|
|
4717
4725
|
];
|
|
4718
4726
|
}
|
|
4727
|
+
function hookCommand(path) {
|
|
4728
|
+
return [
|
|
4729
|
+
`p=$(node -e 'try{process.stdout.write(String(require(process.env.HOME+"/.adsinagents/daemon.json").port||""))}catch(e){}' 2>/dev/null)`,
|
|
4730
|
+
`[ -n "$p" ] && curl -s --max-time 2 -X POST "http://127.0.0.1:$p${path}" -H 'content-type: application/json' --data-binary @- >/dev/null 2>&1`,
|
|
4731
|
+
`true`
|
|
4732
|
+
].join("; ");
|
|
4733
|
+
}
|
|
4719
4734
|
function appendHook(existing, entry) {
|
|
4720
4735
|
const arr = Array.isArray(existing) ? existing.slice() : existing ? [existing] : [];
|
|
4721
|
-
arr.
|
|
4722
|
-
|
|
4736
|
+
const userOwned = arr.filter((e) => !(e && typeof e === "object" && e[ADLINE_SENTINEL]));
|
|
4737
|
+
userOwned.push({ hooks: [entry], [ADLINE_SENTINEL]: true });
|
|
4738
|
+
return userOwned;
|
|
4723
4739
|
}
|
|
4724
4740
|
function renderDiff(before, after) {
|
|
4725
4741
|
const keys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
@@ -4761,6 +4777,9 @@ function getAgent(name = "claude-code") {
|
|
|
4761
4777
|
|
|
4762
4778
|
// ../cli/src/settings.ts
|
|
4763
4779
|
var cc = () => getAgent("claude-code");
|
|
4780
|
+
function isInstalled() {
|
|
4781
|
+
return cc().isInstalled();
|
|
4782
|
+
}
|
|
4764
4783
|
function planMerge(plan) {
|
|
4765
4784
|
return cc().planInstall(plan);
|
|
4766
4785
|
}
|
|
@@ -4804,6 +4823,10 @@ function buildAndInstallNative() {
|
|
|
4804
4823
|
if (existsSync3(src)) {
|
|
4805
4824
|
copyFileSync2(src, dest);
|
|
4806
4825
|
chmodSync2(dest, 493);
|
|
4826
|
+
try {
|
|
4827
|
+
execFileSync3("codesign", ["-f", "--sign", "-", dest], { stdio: "pipe" });
|
|
4828
|
+
} catch {
|
|
4829
|
+
}
|
|
4807
4830
|
installed.push(dest);
|
|
4808
4831
|
}
|
|
4809
4832
|
}
|
|
@@ -4812,6 +4835,9 @@ function buildAndInstallNative() {
|
|
|
4812
4835
|
|
|
4813
4836
|
// ../cli/src/doctor.ts
|
|
4814
4837
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
|
|
4838
|
+
import { spawnSync } from "node:child_process";
|
|
4839
|
+
import { homedir as homedir3 } from "node:os";
|
|
4840
|
+
import { join as join5 } from "node:path";
|
|
4815
4841
|
function daemonAlive() {
|
|
4816
4842
|
if (!existsSync4(PATHS.daemonInfo)) return { ok: false, detail: "no daemon.json (not started)" };
|
|
4817
4843
|
try {
|
|
@@ -4863,8 +4889,133 @@ async function runDoctor() {
|
|
|
4863
4889
|
ok: key !== null,
|
|
4864
4890
|
detail: key ? "present (Keychain/file)" : "none \u2014 run `adsinagents login`"
|
|
4865
4891
|
});
|
|
4892
|
+
checks.push(checkStatusLine());
|
|
4893
|
+
checks.push(checkHookReachable());
|
|
4894
|
+
checks.push(checkSlashCommand());
|
|
4866
4895
|
return checks;
|
|
4867
4896
|
}
|
|
4897
|
+
function checkStatusLine() {
|
|
4898
|
+
const name = "Status line renders";
|
|
4899
|
+
const settingsPath = join5(claudeConfigDir(), "settings.json");
|
|
4900
|
+
if (!existsSync4(settingsPath)) {
|
|
4901
|
+
return { name, ok: true, detail: "no statusLine command configured" };
|
|
4902
|
+
}
|
|
4903
|
+
let settings;
|
|
4904
|
+
try {
|
|
4905
|
+
settings = JSON.parse(readFileSync3(settingsPath, "utf8"));
|
|
4906
|
+
} catch {
|
|
4907
|
+
return { name, ok: true, detail: "settings.json unreadable (skipped)" };
|
|
4908
|
+
}
|
|
4909
|
+
const cmd = settings.statusLine?.command;
|
|
4910
|
+
if (!cmd) {
|
|
4911
|
+
return { name, ok: true, detail: "no statusLine command configured" };
|
|
4912
|
+
}
|
|
4913
|
+
let hasAd = false;
|
|
4914
|
+
try {
|
|
4915
|
+
if (existsSync4(PATHS.currentAd)) {
|
|
4916
|
+
const ad = JSON.parse(readFileSync3(PATHS.currentAd, "utf8"));
|
|
4917
|
+
hasAd = !!(ad.adId && String(ad.adId).trim().length > 0);
|
|
4918
|
+
}
|
|
4919
|
+
} catch {
|
|
4920
|
+
hasAd = false;
|
|
4921
|
+
}
|
|
4922
|
+
const parts = cmd.split(" ");
|
|
4923
|
+
const exe = parts[0];
|
|
4924
|
+
const args = parts.slice(1);
|
|
4925
|
+
const sessionJson = JSON.stringify({
|
|
4926
|
+
session_id: "doctor",
|
|
4927
|
+
workspace: { current_dir: "/tmp" },
|
|
4928
|
+
model: { display_name: "x" }
|
|
4929
|
+
});
|
|
4930
|
+
const result = spawnSync(exe, args, {
|
|
4931
|
+
input: sessionJson,
|
|
4932
|
+
encoding: "utf8",
|
|
4933
|
+
timeout: 3e3
|
|
4934
|
+
});
|
|
4935
|
+
if (result.error) {
|
|
4936
|
+
const errCode = result.error.code;
|
|
4937
|
+
const msg = errCode === "ENOENT" ? "not found" : result.error.message;
|
|
4938
|
+
return { name, ok: false, detail: `statusLine command not found or not executable: ${exe} (${msg})` };
|
|
4939
|
+
}
|
|
4940
|
+
if (result.status !== 0) {
|
|
4941
|
+
return { name, ok: false, detail: `statusLine command exited with error (code ${result.status ?? "?"})` };
|
|
4942
|
+
}
|
|
4943
|
+
const stdout = (result.stdout ?? "").trim();
|
|
4944
|
+
if (hasAd && stdout.length === 0) {
|
|
4945
|
+
return { name, ok: false, detail: "statusLine command produced no output (ad exists but nothing rendered)" };
|
|
4946
|
+
}
|
|
4947
|
+
if (stdout.length > 0) {
|
|
4948
|
+
return { name, ok: true, detail: `rendered ${stdout.length} chars` };
|
|
4949
|
+
}
|
|
4950
|
+
return { name, ok: true, detail: "ok (no ad to render right now)" };
|
|
4951
|
+
}
|
|
4952
|
+
function checkHookReachable() {
|
|
4953
|
+
const name = "Hook reachable";
|
|
4954
|
+
let daemonPort = null;
|
|
4955
|
+
if (existsSync4(PATHS.daemonInfo)) {
|
|
4956
|
+
try {
|
|
4957
|
+
const info = JSON.parse(readFileSync3(PATHS.daemonInfo, "utf8"));
|
|
4958
|
+
daemonPort = info.port ?? null;
|
|
4959
|
+
} catch {
|
|
4960
|
+
daemonPort = null;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
if (daemonPort === null) {
|
|
4964
|
+
return { name, ok: true, detail: "daemon not running (skipped)" };
|
|
4965
|
+
}
|
|
4966
|
+
const settingsPath = join5(claudeConfigDir(), "settings.json");
|
|
4967
|
+
let hookPort = null;
|
|
4968
|
+
if (existsSync4(settingsPath)) {
|
|
4969
|
+
try {
|
|
4970
|
+
const s = JSON.parse(readFileSync3(settingsPath, "utf8"));
|
|
4971
|
+
const hooksStr = JSON.stringify(s.hooks ?? {});
|
|
4972
|
+
const m = /http:\/\/127\.0\.0\.1:(\d+)/.exec(hooksStr);
|
|
4973
|
+
if (m) {
|
|
4974
|
+
hookPort = Number(m[1]);
|
|
4975
|
+
} else {
|
|
4976
|
+
hookPort = daemonPort;
|
|
4977
|
+
}
|
|
4978
|
+
} catch {
|
|
4979
|
+
hookPort = daemonPort;
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
const result = spawnSync(
|
|
4983
|
+
"node",
|
|
4984
|
+
[
|
|
4985
|
+
"-e",
|
|
4986
|
+
`const h=require("node:http");const r=h.get("http://127.0.0.1:${daemonPort}/health",res=>{let b="";res.on("data",d=>b+=d);res.on("end",()=>{process.stdout.write(b);process.exit(0)});});r.on("error",e=>{process.exit(1)});r.setTimeout(2000,()=>{r.destroy();process.exit(2)});`
|
|
4987
|
+
],
|
|
4988
|
+
{ encoding: "utf8", timeout: 4e3 }
|
|
4989
|
+
);
|
|
4990
|
+
if (result.status !== 0) {
|
|
4991
|
+
return { name, ok: false, detail: `daemon unreachable on port ${daemonPort}` };
|
|
4992
|
+
}
|
|
4993
|
+
if (hookPort !== null && hookPort !== daemonPort) {
|
|
4994
|
+
return {
|
|
4995
|
+
name,
|
|
4996
|
+
ok: false,
|
|
4997
|
+
detail: `hooks point at port ${hookPort} but daemon is on ${daemonPort}`
|
|
4998
|
+
};
|
|
4999
|
+
}
|
|
5000
|
+
return { name, ok: true, detail: `daemon OK on port ${daemonPort}` };
|
|
5001
|
+
}
|
|
5002
|
+
function checkSlashCommand() {
|
|
5003
|
+
const name = "Slash command installed";
|
|
5004
|
+
const SENTINEL = "<!-- adsinagents:managed -->";
|
|
5005
|
+
const cmdPath = join5(claudeConfigDir(), "commands", "adsinagents.md");
|
|
5006
|
+
if (!existsSync4(cmdPath)) {
|
|
5007
|
+
return { name, ok: false, detail: "run `adsinagents init` to reinstall the /adsinagents command" };
|
|
5008
|
+
}
|
|
5009
|
+
try {
|
|
5010
|
+
const contents = readFileSync3(cmdPath, "utf8");
|
|
5011
|
+
if (!contents.includes(SENTINEL)) {
|
|
5012
|
+
return { name, ok: false, detail: "run `adsinagents init` to reinstall the /adsinagents command" };
|
|
5013
|
+
}
|
|
5014
|
+
} catch {
|
|
5015
|
+
return { name, ok: false, detail: "run `adsinagents init` to reinstall the /adsinagents command" };
|
|
5016
|
+
}
|
|
5017
|
+
return { name, ok: true, detail: `present at ${cmdPath.replace(homedir3(), "~")}` };
|
|
5018
|
+
}
|
|
4868
5019
|
function printDoctor(checks) {
|
|
4869
5020
|
for (const c of checks) {
|
|
4870
5021
|
const mark = c.ok ? "\u2713" : "\u2717";
|
|
@@ -4873,19 +5024,73 @@ function printDoctor(checks) {
|
|
|
4873
5024
|
}
|
|
4874
5025
|
}
|
|
4875
5026
|
|
|
5027
|
+
// ../cli/src/init-ui.ts
|
|
5028
|
+
var useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
5029
|
+
var ID = (s) => s;
|
|
5030
|
+
var dim = useColor ? (s) => `\x1B[2m${s}\x1B[0m` : ID;
|
|
5031
|
+
var bold = useColor ? (s) => `\x1B[1m${s}\x1B[0m` : ID;
|
|
5032
|
+
var green = useColor ? (s) => `\x1B[32m${s}\x1B[0m` : ID;
|
|
5033
|
+
var amber = useColor ? (s) => `\x1B[38;5;215m${s}\x1B[0m` : ID;
|
|
5034
|
+
function renderInitSummary(data) {
|
|
5035
|
+
const lines = [];
|
|
5036
|
+
const tick = green("\u2713");
|
|
5037
|
+
const warn = amber("!");
|
|
5038
|
+
const dot = dim("\xB7");
|
|
5039
|
+
if (data.firstRun) {
|
|
5040
|
+
lines.push(`${amber("\u258C")} ${bold("AdsInAgents")} ${dim("\u2014 sponsored status line for Claude Code")}`);
|
|
5041
|
+
lines.push("");
|
|
5042
|
+
const labelW = maxLabelWidth(data.steps);
|
|
5043
|
+
for (const step of data.steps) {
|
|
5044
|
+
const icon = step.ok ? tick : warn;
|
|
5045
|
+
const label = step.label.padEnd(labelW);
|
|
5046
|
+
const note = step.note ? ` ${dim("(" + step.note + ")")}` : "";
|
|
5047
|
+
lines.push(` ${icon} ${label} ${dot} ${step.detail}${note}`);
|
|
5048
|
+
}
|
|
5049
|
+
lines.push("");
|
|
5050
|
+
lines.push(` ${bold("You're live.")} Restart Claude Code to see your first ad.`);
|
|
5051
|
+
lines.push("");
|
|
5052
|
+
lines.push(` ${dim("Verify ")} adsinagents doctor`);
|
|
5053
|
+
if (data.claimUrl) {
|
|
5054
|
+
lines.push(` ${dim("Get paid")} ${amber(data.claimUrl)}`);
|
|
5055
|
+
}
|
|
5056
|
+
lines.push("");
|
|
5057
|
+
lines.push(` ${dim("Ads are test-only for now.")}`);
|
|
5058
|
+
} else {
|
|
5059
|
+
lines.push(`${amber("\u258C")} ${bold("AdsInAgents")} ${dim("\u2014 already set up, refreshed")}`);
|
|
5060
|
+
lines.push("");
|
|
5061
|
+
const labelW = maxLabelWidth(data.steps);
|
|
5062
|
+
for (const step of data.steps) {
|
|
5063
|
+
const icon = step.ok ? tick : warn;
|
|
5064
|
+
const label = step.label.padEnd(labelW);
|
|
5065
|
+
let detail = step.detail;
|
|
5066
|
+
if (step.label === "Device" && data.balanceCents !== void 0) {
|
|
5067
|
+
const dollars = `$${(data.balanceCents / 100).toFixed(2)}`;
|
|
5068
|
+
detail = `${detail} ${dot} balance ${green(dollars)}`;
|
|
5069
|
+
}
|
|
5070
|
+
lines.push(` ${icon} ${label} ${dot} ${detail}`);
|
|
5071
|
+
}
|
|
5072
|
+
lines.push("");
|
|
5073
|
+
lines.push(` ${dim("Nothing changed.")} Run ${bold("adsinagents doctor")} to check status.`);
|
|
5074
|
+
}
|
|
5075
|
+
return lines.join("\n") + "\n";
|
|
5076
|
+
}
|
|
5077
|
+
function maxLabelWidth(steps) {
|
|
5078
|
+
return steps.reduce((m, s) => Math.max(m, s.label.length), 0);
|
|
5079
|
+
}
|
|
5080
|
+
|
|
4876
5081
|
// ../cli/src/index.ts
|
|
4877
5082
|
var HERE2 = dirname4(fileURLToPath2(import.meta.url));
|
|
4878
5083
|
function readVersion() {
|
|
4879
5084
|
for (const rel of ["../../package.json", "../package.json"]) {
|
|
4880
5085
|
try {
|
|
4881
|
-
return JSON.parse(readFileSync4(
|
|
5086
|
+
return JSON.parse(readFileSync4(join6(HERE2, rel), "utf8")).version ?? "0.0.0";
|
|
4882
5087
|
} catch {
|
|
4883
5088
|
}
|
|
4884
5089
|
}
|
|
4885
5090
|
return "0.0.0";
|
|
4886
5091
|
}
|
|
4887
5092
|
var VERSION = readVersion();
|
|
4888
|
-
var DAEMON_ENTRY =
|
|
5093
|
+
var DAEMON_ENTRY = join6(HERE2, "..", "..", "daemon", "dist", "main.js");
|
|
4889
5094
|
function parseFlags(argv) {
|
|
4890
5095
|
const positional = [];
|
|
4891
5096
|
const flags = /* @__PURE__ */ new Map();
|
|
@@ -4901,8 +5106,8 @@ function parseFlags(argv) {
|
|
|
4901
5106
|
return { positional, flags };
|
|
4902
5107
|
}
|
|
4903
5108
|
function buildPlan(placement, spinnerVerbs) {
|
|
4904
|
-
const nativeStatusline =
|
|
4905
|
-
const statuslineCommand = existsSync5(nativeStatusline) ? nativeStatusline : `node ${
|
|
5109
|
+
const nativeStatusline = join6(dirname4(PATHS.frontmostBin), "adsinagents-statusline");
|
|
5110
|
+
const statuslineCommand = existsSync5(nativeStatusline) ? nativeStatusline : `node ${join6(HERE2, "..", "..", "statusline", "dist", "index.js")}`;
|
|
4906
5111
|
return {
|
|
4907
5112
|
statuslineCommand,
|
|
4908
5113
|
hookBaseUrl: `http://127.0.0.1:${HOOK_PORT}`,
|
|
@@ -4922,17 +5127,33 @@ async function cmdInit(flags) {
|
|
|
4922
5127
|
process.stdout.write(diff + "\n");
|
|
4923
5128
|
return;
|
|
4924
5129
|
}
|
|
5130
|
+
const firstRun = !isInstalled();
|
|
5131
|
+
const steps = [];
|
|
4925
5132
|
const native = buildAndInstallNative();
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
`
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
5133
|
+
steps.push({
|
|
5134
|
+
ok: native.ok,
|
|
5135
|
+
label: "Native helpers",
|
|
5136
|
+
detail: native.ok ? `${native.installed.length} installed` : `degraded mode`,
|
|
5137
|
+
note: native.ok ? void 0 : native.reason
|
|
5138
|
+
});
|
|
5139
|
+
const { backup, slashCommand } = applyMerge(plan);
|
|
5140
|
+
steps.push({
|
|
5141
|
+
ok: true,
|
|
5142
|
+
label: "Settings",
|
|
5143
|
+
detail: "merged",
|
|
5144
|
+
note: backup ? "backup saved" : void 0
|
|
5145
|
+
});
|
|
5146
|
+
steps.push({
|
|
5147
|
+
ok: slashCommand.ok,
|
|
5148
|
+
label: "Slash command",
|
|
5149
|
+
detail: slashCommand.ok ? "/adsinagents ready" : "not installed",
|
|
5150
|
+
note: slashCommand.ok ? void 0 : slashCommand.reason
|
|
5151
|
+
});
|
|
4934
5152
|
const cfg = loadConfigSafe();
|
|
4935
5153
|
let claimUrl = "";
|
|
5154
|
+
let deviceStepOk = true;
|
|
5155
|
+
let deviceDetail = "";
|
|
5156
|
+
let deviceNote;
|
|
4936
5157
|
if (!cfg.deviceToken) {
|
|
4937
5158
|
try {
|
|
4938
5159
|
const deviceId = `dev_${randomBytes(8).toString("hex")}`;
|
|
@@ -4945,36 +5166,43 @@ async function cmdInit(flags) {
|
|
|
4945
5166
|
const reg = await res.json();
|
|
4946
5167
|
writeConfigPatch({ deviceId: reg.deviceId, deviceToken: reg.deviceToken, claimToken: reg.claimToken });
|
|
4947
5168
|
claimUrl = reg.claimUrl;
|
|
4948
|
-
|
|
5169
|
+
deviceDetail = "registered, earning anonymously";
|
|
4949
5170
|
} catch (e) {
|
|
4950
|
-
|
|
4951
|
-
|
|
5171
|
+
deviceStepOk = false;
|
|
5172
|
+
deviceDetail = "registration skipped";
|
|
5173
|
+
deviceNote = e.message;
|
|
4952
5174
|
}
|
|
4953
5175
|
} else {
|
|
4954
|
-
|
|
5176
|
+
deviceDetail = "registered";
|
|
4955
5177
|
if (cfg.claimToken) claimUrl = `${cfg.serverUrl}/claim?t=${cfg.claimToken}`;
|
|
4956
5178
|
}
|
|
5179
|
+
steps.push({ ok: deviceStepOk, label: "Device", detail: deviceDetail, note: deviceNote });
|
|
4957
5180
|
const platform = getPlatform();
|
|
4958
5181
|
const nodeBin = process.execPath;
|
|
4959
|
-
|
|
4960
|
-
|
|
5182
|
+
let daemonOk = true;
|
|
5183
|
+
let daemonNote;
|
|
5184
|
+
try {
|
|
5185
|
+
await platform.installAutostart(nodeBin, [DAEMON_ENTRY]);
|
|
5186
|
+
} catch (e) {
|
|
5187
|
+
daemonOk = false;
|
|
5188
|
+
daemonNote = e.message;
|
|
5189
|
+
}
|
|
5190
|
+
steps.push({ ok: daemonOk, label: "Daemon", detail: daemonOk ? "running" : "not loaded", note: daemonNote });
|
|
4961
5191
|
if (flags.has("show-earnings")) {
|
|
4962
5192
|
writeConfigPatch({ showEarnings: flags.get("show-earnings") !== "false" });
|
|
4963
|
-
process.stdout.write("\u2713 live earnings segment enabled\n");
|
|
4964
5193
|
}
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
You're earning anonymously. To see earnings + get paid, claim this install:
|
|
4973
|
-
${claimUrl}
|
|
4974
|
-
(or run \`adsinagents claim\` anytime to reprint the link)
|
|
4975
|
-
`
|
|
4976
|
-
);
|
|
5194
|
+
let balanceCents;
|
|
5195
|
+
if (!firstRun && existsSync5(PATHS.daemonState)) {
|
|
5196
|
+
try {
|
|
5197
|
+
const state = JSON.parse(readFileSync4(PATHS.daemonState, "utf8"));
|
|
5198
|
+
if (typeof state.balanceCents === "number") balanceCents = state.balanceCents;
|
|
5199
|
+
} catch {
|
|
5200
|
+
}
|
|
4977
5201
|
}
|
|
5202
|
+
const summarySteps = firstRun ? steps : steps.filter((s) => s.label !== "Native helpers");
|
|
5203
|
+
process.stdout.write(
|
|
5204
|
+
renderInitSummary({ firstRun, steps: summarySteps, claimUrl: claimUrl || void 0, balanceCents })
|
|
5205
|
+
);
|
|
4978
5206
|
}
|
|
4979
5207
|
async function cmdRemove() {
|
|
4980
5208
|
const platform = getPlatform();
|
package/daemon/dist/main.js
CHANGED
|
@@ -4550,8 +4550,8 @@ var ClaudeCodeAdapter = class {
|
|
|
4550
4550
|
else
|
|
4551
4551
|
priorValues.hooks = cur.hooks;
|
|
4552
4552
|
const mk = (path) => ({
|
|
4553
|
-
type: "
|
|
4554
|
-
|
|
4553
|
+
type: "command",
|
|
4554
|
+
command: hookCommand(path)
|
|
4555
4555
|
});
|
|
4556
4556
|
next.hooks = {
|
|
4557
4557
|
...hooks,
|
|
@@ -4576,8 +4576,8 @@ var ClaudeCodeAdapter = class {
|
|
|
4576
4576
|
const backup = this.backup();
|
|
4577
4577
|
const { next, diff } = this.merge(plan);
|
|
4578
4578
|
this.write(next);
|
|
4579
|
-
this.writeSlashCommand();
|
|
4580
|
-
return { backup, diff };
|
|
4579
|
+
const slashCommand = this.writeSlashCommand();
|
|
4580
|
+
return { backup, diff, slashCommand };
|
|
4581
4581
|
}
|
|
4582
4582
|
/** Path of the in-session settings command, e.g. ~/.claude/commands/adsinagents.md. */
|
|
4583
4583
|
slashCommandPath() {
|
|
@@ -4587,14 +4587,22 @@ var ClaudeCodeAdapter = class {
|
|
|
4587
4587
|
* Install /adsinagents — the status line itself is display-only, so this is
|
|
4588
4588
|
* the in-session settings surface: the user types /adsinagents and Claude
|
|
4589
4589
|
* drives the CLI. File is fully ours (sentinel comment), safe to delete on
|
|
4590
|
-
* remove.
|
|
4590
|
+
* remove. Reconciles: writes if missing or stale (content drift), skips if
|
|
4591
|
+
* already correct. Returns the outcome so init can REPORT failures instead of
|
|
4592
|
+
* silently swallowing them (the old try/catch hid a real install bug — the
|
|
4593
|
+
* file never wrote and doctor was the only thing that ever noticed).
|
|
4591
4594
|
*/
|
|
4592
4595
|
writeSlashCommand() {
|
|
4596
|
+
const p = this.slashCommandPath();
|
|
4593
4597
|
try {
|
|
4594
|
-
|
|
4598
|
+
if (existsSync2(p) && readFileSync2(p, "utf8") === SLASH_COMMAND_MD) {
|
|
4599
|
+
return { ok: true };
|
|
4600
|
+
}
|
|
4595
4601
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4596
4602
|
writeFileSync2(p, SLASH_COMMAND_MD);
|
|
4597
|
-
|
|
4603
|
+
return { ok: true };
|
|
4604
|
+
} catch (e) {
|
|
4605
|
+
return { ok: false, reason: e.message };
|
|
4598
4606
|
}
|
|
4599
4607
|
}
|
|
4600
4608
|
removeInstall() {
|
|
@@ -4724,10 +4732,18 @@ function spinnerVerbsFor(ad) {
|
|
|
4724
4732
|
`Brought to you by ${brand}`
|
|
4725
4733
|
];
|
|
4726
4734
|
}
|
|
4735
|
+
function hookCommand(path) {
|
|
4736
|
+
return [
|
|
4737
|
+
`p=$(node -e 'try{process.stdout.write(String(require(process.env.HOME+"/.adsinagents/daemon.json").port||""))}catch(e){}' 2>/dev/null)`,
|
|
4738
|
+
`[ -n "$p" ] && curl -s --max-time 2 -X POST "http://127.0.0.1:$p${path}" -H 'content-type: application/json' --data-binary @- >/dev/null 2>&1`,
|
|
4739
|
+
`true`
|
|
4740
|
+
].join("; ");
|
|
4741
|
+
}
|
|
4727
4742
|
function appendHook(existing, entry) {
|
|
4728
4743
|
const arr = Array.isArray(existing) ? existing.slice() : existing ? [existing] : [];
|
|
4729
|
-
arr.
|
|
4730
|
-
|
|
4744
|
+
const userOwned = arr.filter((e) => !(e && typeof e === "object" && e[ADLINE_SENTINEL]));
|
|
4745
|
+
userOwned.push({ hooks: [entry], [ADLINE_SENTINEL]: true });
|
|
4746
|
+
return userOwned;
|
|
4731
4747
|
}
|
|
4732
4748
|
function renderDiff(before, after) {
|
|
4733
4749
|
const keys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)]);
|
package/native/build.sh
CHANGED
|
@@ -27,4 +27,14 @@ swiftc -O "$HERE/statusline.swift" -o "$OUT/adsinagents-statusline"
|
|
|
27
27
|
echo "Compiling frontmost..." >&2
|
|
28
28
|
swiftc -O "$HERE/frontmost.swift" -o "$OUT/frontmost"
|
|
29
29
|
|
|
30
|
+
# Re-sign with ad-hoc signature. macOS 26 (Tahoe) Taskgated invalidates the
|
|
31
|
+
# linker-signed signature when the binary is copied across paths (copyFileSync /
|
|
32
|
+
# install step). A fresh codesign -f after compile ensures the installed copy
|
|
33
|
+
# passes Taskgated validation without needing a Developer ID.
|
|
34
|
+
if command -v codesign >/dev/null 2>&1; then
|
|
35
|
+
echo "Signing binaries (ad-hoc)..." >&2
|
|
36
|
+
codesign -f --sign - "$OUT/adsinagents-statusline" >/dev/null 2>&1 || true
|
|
37
|
+
codesign -f --sign - "$OUT/frontmost" >/dev/null 2>&1 || true
|
|
38
|
+
fi
|
|
39
|
+
|
|
30
40
|
echo "Built: $OUT/adsinagents-statusline, $OUT/frontmost" >&2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adsinagents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Get paid while you build. AdsInAgents is the terminal-native ad layer for AI coding agents. Verified impressions pay you.",
|
|
5
5
|
"homepage": "https://adsinagents.com",
|
|
6
6
|
"license": "UNLICENSED",
|