adsinagents 0.1.10 → 0.1.11
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 +41 -4
- package/daemon/dist/main.js +53 -5
- package/package.json +1 -1
- package/statusline/dist/index.js +28 -2
package/cli/dist/index.js
CHANGED
|
@@ -4209,7 +4209,14 @@ var DaemonStateSchema = external_exports.object({
|
|
|
4209
4209
|
todayCents: external_exports.number().int().nonnegative().default(0),
|
|
4210
4210
|
/** Claude is mid-turn (prompt received, Stop not yet). Drives the statusline
|
|
4211
4211
|
* working glyph. Additive — older daemons omit it. */
|
|
4212
|
-
working: external_exports.boolean().default(false)
|
|
4212
|
+
working: external_exports.boolean().default(false),
|
|
4213
|
+
/** Unix ms of the last ad rotation (== lastPollMs). Anchors the rotation
|
|
4214
|
+
* countdown bar; the statusline derives fill from (now - rotatedAtMs).
|
|
4215
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4216
|
+
rotatedAtMs: external_exports.number().int().nonnegative().default(0),
|
|
4217
|
+
/** Rotation period in ms (== pollIntervalSec * 1000). Bar denominator.
|
|
4218
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4219
|
+
rotationMs: external_exports.number().int().nonnegative().default(0)
|
|
4213
4220
|
});
|
|
4214
4221
|
var ImpressionSchema = external_exports.object({
|
|
4215
4222
|
id: external_exports.string(),
|
|
@@ -4246,11 +4253,20 @@ var TERMINAL_BUNDLE_IDS = /* @__PURE__ */ new Set([
|
|
|
4246
4253
|
"com.mitchellh.ghostty",
|
|
4247
4254
|
"dev.warp.Warp-Stable",
|
|
4248
4255
|
"dev.warp.Warp-Preview",
|
|
4256
|
+
"com.cmuxterm.app",
|
|
4257
|
+
// cmux
|
|
4249
4258
|
// VS Code / Cursor integrated terminal => coarser confidence, still counts.
|
|
4250
4259
|
"com.microsoft.VSCode",
|
|
4251
4260
|
"com.todesktop.230313mzl4w4u92"
|
|
4252
4261
|
// Cursor
|
|
4253
4262
|
]);
|
|
4263
|
+
var ENV_TERMINAL_BUNDLE_IDS = new Set((process.env.ADSINAGENTS_TERMINAL_BUNDLE_IDS ?? "").split(",").map((s) => s.trim()).filter(Boolean));
|
|
4264
|
+
function isTerminalBundle(bundleId) {
|
|
4265
|
+
return TERMINAL_BUNDLE_IDS.has(bundleId) || ENV_TERMINAL_BUNDLE_IDS.has(bundleId);
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4268
|
+
// ../../shared/dist/earnings.js
|
|
4269
|
+
var DAILY_CAP_MILLICENTS = 1e4 * 1e3;
|
|
4254
4270
|
|
|
4255
4271
|
// ../../shared/dist/nonce.js
|
|
4256
4272
|
var NONCE_TTL_MS = 30 * 60 * 1e3;
|
|
@@ -4277,10 +4293,12 @@ var DarwinPlatform = class {
|
|
|
4277
4293
|
const { stdout } = await pExecFile(PATHS.frontmostBin, [], { timeout: 800 });
|
|
4278
4294
|
const parsed = FocusProbeSchema.safeParse(JSON.parse(stdout));
|
|
4279
4295
|
if (parsed.success) {
|
|
4296
|
+
const focused = isTerminalBundle(parsed.data.bundleId);
|
|
4280
4297
|
return {
|
|
4281
|
-
focused
|
|
4298
|
+
focused,
|
|
4282
4299
|
locked: parsed.data.locked,
|
|
4283
|
-
screenAwake: parsed.data.screenAwake
|
|
4300
|
+
screenAwake: parsed.data.screenAwake,
|
|
4301
|
+
unknownFrontApp: focused ? void 0 : parsed.data.bundleId || void 0
|
|
4284
4302
|
};
|
|
4285
4303
|
}
|
|
4286
4304
|
} catch {
|
|
@@ -4296,7 +4314,13 @@ var DarwinPlatform = class {
|
|
|
4296
4314
|
'tell application "System Events" to get bundle identifier of first application process whose frontmost is true'
|
|
4297
4315
|
], { timeout: 800 });
|
|
4298
4316
|
const bundleId = stdout.trim();
|
|
4299
|
-
|
|
4317
|
+
const focused = isTerminalBundle(bundleId);
|
|
4318
|
+
return {
|
|
4319
|
+
focused,
|
|
4320
|
+
locked: false,
|
|
4321
|
+
screenAwake: true,
|
|
4322
|
+
unknownFrontApp: focused ? void 0 : bundleId || void 0
|
|
4323
|
+
};
|
|
4300
4324
|
} catch {
|
|
4301
4325
|
return { focused: false, locked: false, screenAwake: true };
|
|
4302
4326
|
}
|
|
@@ -4880,6 +4904,19 @@ async function runDoctor() {
|
|
|
4880
4904
|
ok: focusOk,
|
|
4881
4905
|
detail: focusOk ? "native frontmost helper present" : "Node fallback (osascript)"
|
|
4882
4906
|
});
|
|
4907
|
+
try {
|
|
4908
|
+
const fm = await platform.frontmost();
|
|
4909
|
+
if (fm.unknownFrontApp) {
|
|
4910
|
+
checks.push({
|
|
4911
|
+
name: "Terminal recognized",
|
|
4912
|
+
ok: false,
|
|
4913
|
+
detail: `frontmost app "${fm.unknownFrontApp}" isn't a known terminal \u2014 impressions won't fire. If this is your terminal: set ADSINAGENTS_TERMINAL_BUNDLE_IDS=${fm.unknownFrontApp} and restart the daemon.`
|
|
4914
|
+
});
|
|
4915
|
+
} else if (fm.focused) {
|
|
4916
|
+
checks.push({ name: "Terminal recognized", ok: true, detail: "frontmost app is a known terminal" });
|
|
4917
|
+
}
|
|
4918
|
+
} catch {
|
|
4919
|
+
}
|
|
4883
4920
|
let key = null;
|
|
4884
4921
|
try {
|
|
4885
4922
|
key = await platform.getSecret("publisher-key");
|
package/daemon/dist/main.js
CHANGED
|
@@ -4217,7 +4217,14 @@ var DaemonStateSchema = external_exports.object({
|
|
|
4217
4217
|
todayCents: external_exports.number().int().nonnegative().default(0),
|
|
4218
4218
|
/** Claude is mid-turn (prompt received, Stop not yet). Drives the statusline
|
|
4219
4219
|
* working glyph. Additive — older daemons omit it. */
|
|
4220
|
-
working: external_exports.boolean().default(false)
|
|
4220
|
+
working: external_exports.boolean().default(false),
|
|
4221
|
+
/** Unix ms of the last ad rotation (== lastPollMs). Anchors the rotation
|
|
4222
|
+
* countdown bar; the statusline derives fill from (now - rotatedAtMs).
|
|
4223
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4224
|
+
rotatedAtMs: external_exports.number().int().nonnegative().default(0),
|
|
4225
|
+
/** Rotation period in ms (== pollIntervalSec * 1000). Bar denominator.
|
|
4226
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4227
|
+
rotationMs: external_exports.number().int().nonnegative().default(0)
|
|
4221
4228
|
});
|
|
4222
4229
|
var ImpressionSchema = external_exports.object({
|
|
4223
4230
|
id: external_exports.string(),
|
|
@@ -4254,11 +4261,20 @@ var TERMINAL_BUNDLE_IDS = /* @__PURE__ */ new Set([
|
|
|
4254
4261
|
"com.mitchellh.ghostty",
|
|
4255
4262
|
"dev.warp.Warp-Stable",
|
|
4256
4263
|
"dev.warp.Warp-Preview",
|
|
4264
|
+
"com.cmuxterm.app",
|
|
4265
|
+
// cmux
|
|
4257
4266
|
// VS Code / Cursor integrated terminal => coarser confidence, still counts.
|
|
4258
4267
|
"com.microsoft.VSCode",
|
|
4259
4268
|
"com.todesktop.230313mzl4w4u92"
|
|
4260
4269
|
// Cursor
|
|
4261
4270
|
]);
|
|
4271
|
+
var ENV_TERMINAL_BUNDLE_IDS = new Set((process.env.ADSINAGENTS_TERMINAL_BUNDLE_IDS ?? "").split(",").map((s) => s.trim()).filter(Boolean));
|
|
4272
|
+
function isTerminalBundle(bundleId) {
|
|
4273
|
+
return TERMINAL_BUNDLE_IDS.has(bundleId) || ENV_TERMINAL_BUNDLE_IDS.has(bundleId);
|
|
4274
|
+
}
|
|
4275
|
+
|
|
4276
|
+
// ../../shared/dist/earnings.js
|
|
4277
|
+
var DAILY_CAP_MILLICENTS = 1e4 * 1e3;
|
|
4262
4278
|
|
|
4263
4279
|
// ../../shared/dist/nonce.js
|
|
4264
4280
|
var NONCE_TTL_MS = 30 * 60 * 1e3;
|
|
@@ -4285,10 +4301,12 @@ var DarwinPlatform = class {
|
|
|
4285
4301
|
const { stdout } = await pExecFile(PATHS.frontmostBin, [], { timeout: 800 });
|
|
4286
4302
|
const parsed = FocusProbeSchema.safeParse(JSON.parse(stdout));
|
|
4287
4303
|
if (parsed.success) {
|
|
4304
|
+
const focused = isTerminalBundle(parsed.data.bundleId);
|
|
4288
4305
|
return {
|
|
4289
|
-
focused
|
|
4306
|
+
focused,
|
|
4290
4307
|
locked: parsed.data.locked,
|
|
4291
|
-
screenAwake: parsed.data.screenAwake
|
|
4308
|
+
screenAwake: parsed.data.screenAwake,
|
|
4309
|
+
unknownFrontApp: focused ? void 0 : parsed.data.bundleId || void 0
|
|
4292
4310
|
};
|
|
4293
4311
|
}
|
|
4294
4312
|
} catch {
|
|
@@ -4304,7 +4322,13 @@ var DarwinPlatform = class {
|
|
|
4304
4322
|
'tell application "System Events" to get bundle identifier of first application process whose frontmost is true'
|
|
4305
4323
|
], { timeout: 800 });
|
|
4306
4324
|
const bundleId = stdout.trim();
|
|
4307
|
-
|
|
4325
|
+
const focused = isTerminalBundle(bundleId);
|
|
4326
|
+
return {
|
|
4327
|
+
focused,
|
|
4328
|
+
locked: false,
|
|
4329
|
+
screenAwake: true,
|
|
4330
|
+
unknownFrontApp: focused ? void 0 : bundleId || void 0
|
|
4331
|
+
};
|
|
4308
4332
|
} catch {
|
|
4309
4333
|
return { focused: false, locked: false, screenAwake: true };
|
|
4310
4334
|
}
|
|
@@ -4961,6 +4985,14 @@ var FocusPoller = class {
|
|
|
4961
4985
|
terminalFocused() {
|
|
4962
4986
|
return this.last.focused;
|
|
4963
4987
|
}
|
|
4988
|
+
/**
|
|
4989
|
+
* Bundle id of the frontmost app when it's a foreground app we DON'T recognize
|
|
4990
|
+
* as a terminal — the daemon warns on it so an unlisted terminal can't silently
|
|
4991
|
+
* zero out earnings. Undefined when on a known terminal. Diagnostics only.
|
|
4992
|
+
*/
|
|
4993
|
+
unknownFrontApp() {
|
|
4994
|
+
return this.last.unknownFrontApp;
|
|
4995
|
+
}
|
|
4964
4996
|
async poll() {
|
|
4965
4997
|
try {
|
|
4966
4998
|
this.last = await this.platform.frontmost();
|
|
@@ -5335,6 +5367,7 @@ function pendingReason(s) {
|
|
|
5335
5367
|
var TICK_MS = 1e3;
|
|
5336
5368
|
var SESSION_REAP_MS = 6 * 60 * 60 * 1e3;
|
|
5337
5369
|
var SYNC_EVERY_TICKS = 30;
|
|
5370
|
+
var UNKNOWN_TERM_WARN_MS = 10 * 60 * 1e3;
|
|
5338
5371
|
async function fileLog(line) {
|
|
5339
5372
|
try {
|
|
5340
5373
|
writeFileSync4(PATHS.daemonLog, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
@@ -5354,6 +5387,7 @@ async function main() {
|
|
|
5354
5387
|
let currentAd = null;
|
|
5355
5388
|
let lastPollMs = 0;
|
|
5356
5389
|
let tickCount = 0;
|
|
5390
|
+
const unknownTermWarnedAt = /* @__PURE__ */ new Map();
|
|
5357
5391
|
let earnings = { balanceCents: 0, todayCents: 0 };
|
|
5358
5392
|
const now = () => Date.now();
|
|
5359
5393
|
const { server, port } = await startServer({
|
|
@@ -5416,6 +5450,16 @@ async function main() {
|
|
|
5416
5450
|
const lastStop = sessions.lastStop();
|
|
5417
5451
|
const adDisplayable = working || lastStop !== null && nowMs - lastStop <= cfg.idleGraceSec * 1e3;
|
|
5418
5452
|
const probe = focus.current();
|
|
5453
|
+
const unknownTerm = focus.unknownFrontApp();
|
|
5454
|
+
if (sessionLive && currentAd !== null && adDisplayable && unknownTerm) {
|
|
5455
|
+
const lastWarn = unknownTermWarnedAt.get(unknownTerm) ?? 0;
|
|
5456
|
+
if (nowMs - lastWarn >= UNKNOWN_TERM_WARN_MS) {
|
|
5457
|
+
unknownTermWarnedAt.set(unknownTerm, nowMs);
|
|
5458
|
+
await fileLog(
|
|
5459
|
+
`WARN unrecognized terminal "${unknownTerm}" is frontmost \u2014 impressions can't fire. If this is your terminal, set ADSINAGENTS_TERMINAL_BUNDLE_IDS=${unknownTerm} and restart the daemon.`
|
|
5460
|
+
);
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5419
5463
|
const sample = {
|
|
5420
5464
|
nowMs,
|
|
5421
5465
|
sessionLive,
|
|
@@ -5449,7 +5493,11 @@ async function main() {
|
|
|
5449
5493
|
updatedAt: nowMs,
|
|
5450
5494
|
balanceCents: earnings.balanceCents,
|
|
5451
5495
|
todayCents: earnings.todayCents,
|
|
5452
|
-
working
|
|
5496
|
+
working,
|
|
5497
|
+
// Anchor + period for the statusline rotation countdown bar. lastPollMs
|
|
5498
|
+
// is the last ad swap; the bar fills over pollIntervalSec toward the next.
|
|
5499
|
+
rotatedAtMs: lastPollMs,
|
|
5500
|
+
rotationMs: cfg.pollIntervalSec * 1e3
|
|
5453
5501
|
};
|
|
5454
5502
|
writeDaemonState(state);
|
|
5455
5503
|
if (tickCount % SYNC_EVERY_TICKS === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adsinagents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|
package/statusline/dist/index.js
CHANGED
|
@@ -4193,7 +4193,14 @@ var DaemonStateSchema = external_exports.object({
|
|
|
4193
4193
|
todayCents: external_exports.number().int().nonnegative().default(0),
|
|
4194
4194
|
/** Claude is mid-turn (prompt received, Stop not yet). Drives the statusline
|
|
4195
4195
|
* working glyph. Additive — older daemons omit it. */
|
|
4196
|
-
working: external_exports.boolean().default(false)
|
|
4196
|
+
working: external_exports.boolean().default(false),
|
|
4197
|
+
/** Unix ms of the last ad rotation (== lastPollMs). Anchors the rotation
|
|
4198
|
+
* countdown bar; the statusline derives fill from (now - rotatedAtMs).
|
|
4199
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4200
|
+
rotatedAtMs: external_exports.number().int().nonnegative().default(0),
|
|
4201
|
+
/** Rotation period in ms (== pollIntervalSec * 1000). Bar denominator.
|
|
4202
|
+
* Additive — 0 from older daemons hides the bar. */
|
|
4203
|
+
rotationMs: external_exports.number().int().nonnegative().default(0)
|
|
4197
4204
|
});
|
|
4198
4205
|
var ImpressionSchema = external_exports.object({
|
|
4199
4206
|
id: external_exports.string(),
|
|
@@ -4222,6 +4229,7 @@ var FocusProbeSchema = external_exports.object({
|
|
|
4222
4229
|
locked: external_exports.boolean(),
|
|
4223
4230
|
screenAwake: external_exports.boolean()
|
|
4224
4231
|
});
|
|
4232
|
+
var ENV_TERMINAL_BUNDLE_IDS = new Set((process.env.ADSINAGENTS_TERMINAL_BUNDLE_IDS ?? "").split(",").map((s) => s.trim()).filter(Boolean));
|
|
4225
4233
|
|
|
4226
4234
|
// ../../shared/dist/render.js
|
|
4227
4235
|
function osc8(url, text) {
|
|
@@ -4253,6 +4261,15 @@ function renderEarningsSegment(balanceCents, todayCents, theme = "plain") {
|
|
|
4253
4261
|
const d = (c) => t.money(`$${(Math.max(0, c) / 100).toFixed(2)}`);
|
|
4254
4262
|
return `${d(todayCents)} today \xB7 ${d(balanceCents)}`;
|
|
4255
4263
|
}
|
|
4264
|
+
var ROTATION_BAR_CELLS = 8;
|
|
4265
|
+
function renderRotationBar(nowMs, rotatedAtMs, rotationMs, theme = "plain") {
|
|
4266
|
+
if (rotationMs <= 0 || rotatedAtMs <= 0)
|
|
4267
|
+
return "";
|
|
4268
|
+
const frac = Math.min(1, Math.max(0, (nowMs - rotatedAtMs) / rotationMs));
|
|
4269
|
+
const filled = Math.min(ROTATION_BAR_CELLS, Math.round(frac * ROTATION_BAR_CELLS));
|
|
4270
|
+
const bar = "\u25B0".repeat(filled) + "\u25B1".repeat(ROTATION_BAR_CELLS - filled);
|
|
4271
|
+
return THEMES[theme ?? "plain"].mark(bar);
|
|
4272
|
+
}
|
|
4256
4273
|
function renderLoadingSegment(theme = "plain") {
|
|
4257
4274
|
const s = "Ad: loading\u2026";
|
|
4258
4275
|
return theme === "plain" ? s : DIM(s);
|
|
@@ -4267,6 +4284,9 @@ function composeStatusLine(priorOutput, ...segments) {
|
|
|
4267
4284
|
return parts.join(" \u2502 ");
|
|
4268
4285
|
}
|
|
4269
4286
|
|
|
4287
|
+
// ../../shared/dist/earnings.js
|
|
4288
|
+
var DAILY_CAP_MILLICENTS = 1e4 * 1e3;
|
|
4289
|
+
|
|
4270
4290
|
// ../../shared/dist/nonce.js
|
|
4271
4291
|
var NONCE_TTL_MS = 30 * 60 * 1e3;
|
|
4272
4292
|
|
|
@@ -4370,6 +4390,12 @@ function main() {
|
|
|
4370
4390
|
theme
|
|
4371
4391
|
});
|
|
4372
4392
|
const seg = state.working ? `${workingGlyph(Date.now(), theme)} ${adSeg}` : adSeg;
|
|
4373
|
-
|
|
4393
|
+
const rotationSeg = renderRotationBar(
|
|
4394
|
+
Date.now(),
|
|
4395
|
+
state.rotatedAtMs,
|
|
4396
|
+
state.rotationMs,
|
|
4397
|
+
theme
|
|
4398
|
+
);
|
|
4399
|
+
process.stdout.write(composeStatusLine(prior, seg, rotationSeg, earningsSeg) + "\n");
|
|
4374
4400
|
}
|
|
4375
4401
|
main();
|