standout 0.5.38 → 0.6.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/README.md +17 -0
- package/dist/cli.js +429 -114
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -11,3 +11,20 @@ get matched with roles through [Standout](https://standout.work).
|
|
|
11
11
|
|
|
12
12
|
Optional: pass a job slug to apply directly (`npx standout <job>`), or `--chat`
|
|
13
13
|
to build a full profile interactively.
|
|
14
|
+
|
|
15
|
+
## Runs monthly, automatically
|
|
16
|
+
|
|
17
|
+
After a full run, standout schedules a monthly refresh (1st of each month) so
|
|
18
|
+
your stats never decay — local session logs only cover ~30 days, and the
|
|
19
|
+
refresh keeps your full history intact. Uses launchd on macOS and cron on
|
|
20
|
+
Linux; not available on Windows.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx standout schedule status # is it on? command, log path, last run
|
|
24
|
+
npx standout schedule off # disable (won't be re-added automatically)
|
|
25
|
+
npx standout schedule [job] # re-enable / install manually
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Scheduled runs are unattended: they upload your refreshed stats and write the
|
|
29
|
+
wrapped link to the log (`~/Library/Logs/standout.log` on macOS,
|
|
30
|
+
`~/.standout/standout.log` on Linux) instead of opening a browser.
|
package/dist/cli.js
CHANGED
|
@@ -3,10 +3,10 @@ var __toBinaryNode = Uint8Array.fromBase64 || ((base64) => new Uint8Array(Buffer
|
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import Anthropic from "@anthropic-ai/sdk";
|
|
6
|
-
import
|
|
7
|
-
import { writeFileSync } from "node:fs";
|
|
6
|
+
import chalk3 from "chalk";
|
|
7
|
+
import { writeFileSync as writeFileSync2 } from "node:fs";
|
|
8
8
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
9
|
-
import { join as
|
|
9
|
+
import { join as join7 } from "node:path";
|
|
10
10
|
import { createInterface as createInterface3 } from "readline";
|
|
11
11
|
|
|
12
12
|
// src/sources.ts
|
|
@@ -514,8 +514,12 @@ function computeHours(aiUsage) {
|
|
|
514
514
|
for (const src of WRAPPED_SOURCES) {
|
|
515
515
|
const stats = aiUsage[src];
|
|
516
516
|
if (!stats) continue;
|
|
517
|
-
totalHours += num2(
|
|
518
|
-
|
|
517
|
+
totalHours += num2(
|
|
518
|
+
stats.all_time?.total_duration_hours ?? stats.total_duration_hours
|
|
519
|
+
);
|
|
520
|
+
totalSessions += num2(
|
|
521
|
+
stats.all_time?.total_sessions ?? stats.total_sessions
|
|
522
|
+
);
|
|
519
523
|
}
|
|
520
524
|
return { total_hours: totalHours, total_sessions: totalSessions };
|
|
521
525
|
}
|
|
@@ -5144,6 +5148,305 @@ The JSON should follow this structure:
|
|
|
5144
5148
|
- Ask interactive questions ONE AT A TIME.
|
|
5145
5149
|
- If you receive a pause_turn stop reason, your turn will be continued automatically \u2014 just keep going.`;
|
|
5146
5150
|
|
|
5151
|
+
// src/schedule.ts
|
|
5152
|
+
import chalk from "chalk";
|
|
5153
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
5154
|
+
import {
|
|
5155
|
+
existsSync as existsSync6,
|
|
5156
|
+
mkdirSync as mkdirSync2,
|
|
5157
|
+
readFileSync as readFileSync6,
|
|
5158
|
+
rmSync as rmSync2,
|
|
5159
|
+
statSync as statSync5,
|
|
5160
|
+
writeFileSync
|
|
5161
|
+
} from "node:fs";
|
|
5162
|
+
import { homedir as homedir6 } from "node:os";
|
|
5163
|
+
import { join as join6 } from "node:path";
|
|
5164
|
+
var LAUNCHD_LABEL = "work.standout.monthly";
|
|
5165
|
+
var CRON_MARKER = "# standout-monthly";
|
|
5166
|
+
var ACCENT = "#ad5cff";
|
|
5167
|
+
var SLUG_RE = /^[a-z0-9][a-z0-9_-]*$/i;
|
|
5168
|
+
var FLAG_ALLOWLIST = ["--local", "--no-upload", "--terminal"];
|
|
5169
|
+
function parseScheduleArgs(args) {
|
|
5170
|
+
if (args[0] === "unschedule") return { kind: "remove" };
|
|
5171
|
+
const rest = args.slice(1);
|
|
5172
|
+
if (rest[0] === "off" || rest[0] === "remove") return { kind: "remove" };
|
|
5173
|
+
if (rest[0] === "status") return { kind: "status" };
|
|
5174
|
+
let slug;
|
|
5175
|
+
const flags = [];
|
|
5176
|
+
for (const arg of rest) {
|
|
5177
|
+
if (arg === "--chat") {
|
|
5178
|
+
throw new Error(
|
|
5179
|
+
"--chat needs an interactive terminal and can't be scheduled"
|
|
5180
|
+
);
|
|
5181
|
+
}
|
|
5182
|
+
if (arg.startsWith("-")) {
|
|
5183
|
+
if (!FLAG_ALLOWLIST.includes(arg)) {
|
|
5184
|
+
throw new Error(
|
|
5185
|
+
`unknown flag for schedule: ${arg} (allowed: ${FLAG_ALLOWLIST.join(", ")})`
|
|
5186
|
+
);
|
|
5187
|
+
}
|
|
5188
|
+
if (!flags.includes(arg)) flags.push(arg);
|
|
5189
|
+
continue;
|
|
5190
|
+
}
|
|
5191
|
+
if (slug) throw new Error(`unexpected argument: ${arg}`);
|
|
5192
|
+
if (!SLUG_RE.test(arg)) throw new Error(`invalid job slug: ${arg}`);
|
|
5193
|
+
slug = arg;
|
|
5194
|
+
}
|
|
5195
|
+
return { kind: "install", slug, flags };
|
|
5196
|
+
}
|
|
5197
|
+
function buildRunCommand(slug, flags) {
|
|
5198
|
+
return ["npx", "-y", "standout@latest", ...slug ? [slug] : [], ...flags].join(" ").trim();
|
|
5199
|
+
}
|
|
5200
|
+
function escapeXml(text) {
|
|
5201
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
5202
|
+
}
|
|
5203
|
+
function unescapeXml(text) {
|
|
5204
|
+
return text.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
5205
|
+
}
|
|
5206
|
+
function buildLaunchdPlist(command, logPath) {
|
|
5207
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
5208
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
5209
|
+
<plist version="1.0">
|
|
5210
|
+
<dict>
|
|
5211
|
+
<key>Label</key><string>${LAUNCHD_LABEL}</string>
|
|
5212
|
+
<key>ProgramArguments</key>
|
|
5213
|
+
<array>
|
|
5214
|
+
<string>/bin/zsh</string>
|
|
5215
|
+
<string>-lc</string>
|
|
5216
|
+
<string>${escapeXml(command)}</string>
|
|
5217
|
+
</array>
|
|
5218
|
+
<key>StartCalendarInterval</key>
|
|
5219
|
+
<dict>
|
|
5220
|
+
<key>Day</key><integer>1</integer>
|
|
5221
|
+
<key>Hour</key><integer>10</integer>
|
|
5222
|
+
<key>Minute</key><integer>0</integer>
|
|
5223
|
+
</dict>
|
|
5224
|
+
<key>StandardOutPath</key><string>${escapeXml(logPath)}</string>
|
|
5225
|
+
<key>StandardErrorPath</key><string>${escapeXml(logPath)}</string>
|
|
5226
|
+
</dict>
|
|
5227
|
+
</plist>
|
|
5228
|
+
`;
|
|
5229
|
+
}
|
|
5230
|
+
function buildCronLine(command, logPath) {
|
|
5231
|
+
return `0 10 1 * * /bin/bash -lc '${command}' >> "${logPath}" 2>&1 ${CRON_MARKER}`;
|
|
5232
|
+
}
|
|
5233
|
+
function stripCronEntries(crontab) {
|
|
5234
|
+
return crontab.split("\n").filter((line) => !line.includes(CRON_MARKER)).join("\n");
|
|
5235
|
+
}
|
|
5236
|
+
function supportedPlatform() {
|
|
5237
|
+
return process.platform === "darwin" || process.platform === "linux";
|
|
5238
|
+
}
|
|
5239
|
+
function stateDir() {
|
|
5240
|
+
return join6(homedir6(), ".standout");
|
|
5241
|
+
}
|
|
5242
|
+
function optOutPath() {
|
|
5243
|
+
return join6(stateDir(), "no-schedule");
|
|
5244
|
+
}
|
|
5245
|
+
function plistPath() {
|
|
5246
|
+
return join6(homedir6(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
5247
|
+
}
|
|
5248
|
+
function schedLogPath() {
|
|
5249
|
+
return process.platform === "darwin" ? join6(homedir6(), "Library", "Logs", "standout.log") : join6(stateDir(), "standout.log");
|
|
5250
|
+
}
|
|
5251
|
+
function isOptedOut() {
|
|
5252
|
+
return existsSync6(optOutPath());
|
|
5253
|
+
}
|
|
5254
|
+
function writeOptOut() {
|
|
5255
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
5256
|
+
writeFileSync(
|
|
5257
|
+
optOutPath(),
|
|
5258
|
+
"created by `standout schedule off` \u2014 delete (or run `npx standout schedule`) to re-enable monthly runs\n"
|
|
5259
|
+
);
|
|
5260
|
+
}
|
|
5261
|
+
function clearOptOut() {
|
|
5262
|
+
rmSync2(optOutPath(), { force: true });
|
|
5263
|
+
}
|
|
5264
|
+
function launchctl(args) {
|
|
5265
|
+
const res = spawnSync2("launchctl", args, { encoding: "utf8" });
|
|
5266
|
+
return {
|
|
5267
|
+
status: res.status,
|
|
5268
|
+
stdout: res.stdout ?? "",
|
|
5269
|
+
stderr: res.stderr ?? ""
|
|
5270
|
+
};
|
|
5271
|
+
}
|
|
5272
|
+
function uid() {
|
|
5273
|
+
return process.getuid?.() ?? 0;
|
|
5274
|
+
}
|
|
5275
|
+
function readCrontab() {
|
|
5276
|
+
const res = spawnSync2("crontab", ["-l"], { encoding: "utf8" });
|
|
5277
|
+
return res.status === 0 ? res.stdout ?? "" : "";
|
|
5278
|
+
}
|
|
5279
|
+
function writeCrontab(content) {
|
|
5280
|
+
const res = spawnSync2("crontab", ["-"], {
|
|
5281
|
+
input: content,
|
|
5282
|
+
encoding: "utf8"
|
|
5283
|
+
});
|
|
5284
|
+
if (res.status !== 0) {
|
|
5285
|
+
throw new Error(`crontab update failed: ${res.stderr?.trim() || "error"}`);
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
function installJob(command) {
|
|
5289
|
+
if (process.platform === "darwin") {
|
|
5290
|
+
const path2 = plistPath();
|
|
5291
|
+
mkdirSync2(join6(homedir6(), "Library", "LaunchAgents"), { recursive: true });
|
|
5292
|
+
writeFileSync(path2, buildLaunchdPlist(command, schedLogPath()));
|
|
5293
|
+
launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
|
|
5294
|
+
const res = launchctl(["bootstrap", `gui/${uid()}`, path2]);
|
|
5295
|
+
if (res.status !== 0) {
|
|
5296
|
+
throw new Error(
|
|
5297
|
+
`launchctl bootstrap failed (${res.stderr.trim() || res.status}) \u2014 plist written to ${path2}; load it manually with: launchctl bootstrap gui/$(id -u) ${path2}`
|
|
5298
|
+
);
|
|
5299
|
+
}
|
|
5300
|
+
} else {
|
|
5301
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
5302
|
+
const stripped = stripCronEntries(readCrontab());
|
|
5303
|
+
const base = stripped === "" || stripped.endsWith("\n") ? stripped : stripped + "\n";
|
|
5304
|
+
writeCrontab(base + buildCronLine(command, schedLogPath()) + "\n");
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
function installedCommand() {
|
|
5308
|
+
if (process.platform === "darwin") {
|
|
5309
|
+
if (!existsSync6(plistPath())) return null;
|
|
5310
|
+
const xml = readFileSync6(plistPath(), "utf8");
|
|
5311
|
+
const m = xml.match(/<string>-lc<\/string>\s*<string>([^<]*)<\/string>/);
|
|
5312
|
+
return m ? unescapeXml(m[1]) : null;
|
|
5313
|
+
}
|
|
5314
|
+
if (process.platform === "linux") {
|
|
5315
|
+
const line = readCrontab().split("\n").find((l) => l.includes(CRON_MARKER));
|
|
5316
|
+
const m = line?.match(/-lc '([^']*)'/);
|
|
5317
|
+
return m ? m[1] : null;
|
|
5318
|
+
}
|
|
5319
|
+
return null;
|
|
5320
|
+
}
|
|
5321
|
+
async function installSchedule(slug, flags) {
|
|
5322
|
+
if (!supportedPlatform()) {
|
|
5323
|
+
process.stderr.write(
|
|
5324
|
+
"\n scheduling isn't supported on this platform yet \u2014 run `npx standout` manually.\n\n"
|
|
5325
|
+
);
|
|
5326
|
+
process.exit(1);
|
|
5327
|
+
}
|
|
5328
|
+
clearOptOut();
|
|
5329
|
+
const command = buildRunCommand(slug, flags);
|
|
5330
|
+
installJob(command);
|
|
5331
|
+
process.stderr.write(
|
|
5332
|
+
`
|
|
5333
|
+
${chalk.hex(ACCENT)("\u2713")} ${chalk.white("monthly refresh scheduled")} ${chalk.dim("(1st of each month, 10:00)")}
|
|
5334
|
+
` + chalk.dim(` runs: ${command}
|
|
5335
|
+
`) + chalk.dim(` log: ${schedLogPath()}
|
|
5336
|
+
`) + chalk.dim(" disable anytime with `npx standout schedule off`\n\n")
|
|
5337
|
+
);
|
|
5338
|
+
}
|
|
5339
|
+
async function removeSchedule() {
|
|
5340
|
+
if (!supportedPlatform()) {
|
|
5341
|
+
process.stderr.write(
|
|
5342
|
+
"\n scheduling isn't supported on this platform \u2014 nothing to remove.\n\n"
|
|
5343
|
+
);
|
|
5344
|
+
return;
|
|
5345
|
+
}
|
|
5346
|
+
writeOptOut();
|
|
5347
|
+
let removed = false;
|
|
5348
|
+
if (process.platform === "darwin") {
|
|
5349
|
+
launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
|
|
5350
|
+
if (existsSync6(plistPath())) {
|
|
5351
|
+
rmSync2(plistPath(), { force: true });
|
|
5352
|
+
removed = true;
|
|
5353
|
+
}
|
|
5354
|
+
} else {
|
|
5355
|
+
const current = readCrontab();
|
|
5356
|
+
const stripped = stripCronEntries(current);
|
|
5357
|
+
if (stripped !== current) {
|
|
5358
|
+
writeCrontab(stripped);
|
|
5359
|
+
removed = true;
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
process.stderr.write(
|
|
5363
|
+
removed ? `
|
|
5364
|
+
${chalk.hex(ACCENT)("\u2713")} ${chalk.white("monthly refresh disabled")}
|
|
5365
|
+
` + chalk.dim(
|
|
5366
|
+
" it won't be scheduled again \u2014 re-enable with `npx standout schedule`\n\n"
|
|
5367
|
+
) : `
|
|
5368
|
+
${chalk.dim("no monthly schedule installed \u2014 future runs won't add one (re-enable with `npx standout schedule`)")}
|
|
5369
|
+
|
|
5370
|
+
`
|
|
5371
|
+
);
|
|
5372
|
+
}
|
|
5373
|
+
async function scheduleStatus() {
|
|
5374
|
+
if (!supportedPlatform()) {
|
|
5375
|
+
process.stderr.write(
|
|
5376
|
+
"\n scheduling isn't supported on this platform.\n\n"
|
|
5377
|
+
);
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5380
|
+
const command = installedCommand();
|
|
5381
|
+
if (!command) {
|
|
5382
|
+
process.stderr.write(
|
|
5383
|
+
`
|
|
5384
|
+
${chalk.white("no monthly schedule installed")}` + (isOptedOut() ? chalk.dim(" (opted out)") : "") + "\n" + chalk.dim(" enable with `npx standout schedule`\n\n")
|
|
5385
|
+
);
|
|
5386
|
+
return;
|
|
5387
|
+
}
|
|
5388
|
+
process.stderr.write(
|
|
5389
|
+
`
|
|
5390
|
+
${chalk.hex(ACCENT)("\u2713")} ${chalk.white("monthly refresh is on")} ${chalk.dim("(1st of each month, 10:00)")}
|
|
5391
|
+
` + chalk.dim(` runs: ${command}
|
|
5392
|
+
`) + chalk.dim(` log: ${schedLogPath()}
|
|
5393
|
+
`)
|
|
5394
|
+
);
|
|
5395
|
+
if (process.platform === "darwin") {
|
|
5396
|
+
const res = launchctl(["print", `gui/${uid()}/${LAUNCHD_LABEL}`]);
|
|
5397
|
+
const exitLine = res.stdout.split("\n").find((l) => l.includes("last exit code"));
|
|
5398
|
+
if (res.status !== 0) {
|
|
5399
|
+
process.stderr.write(
|
|
5400
|
+
chalk.dim(
|
|
5401
|
+
" warning: job not loaded in launchd \u2014 re-run `npx standout schedule`\n"
|
|
5402
|
+
)
|
|
5403
|
+
);
|
|
5404
|
+
} else if (exitLine) {
|
|
5405
|
+
process.stderr.write(chalk.dim(` ${exitLine.trim()}
|
|
5406
|
+
`));
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
if (existsSync6(schedLogPath())) {
|
|
5410
|
+
const mtime = statSync5(schedLogPath()).mtime;
|
|
5411
|
+
const tail = readFileSync6(schedLogPath(), "utf8").trimEnd().split("\n").slice(-10);
|
|
5412
|
+
process.stderr.write(
|
|
5413
|
+
chalk.dim(` last log activity: ${mtime.toLocaleString()}
|
|
5414
|
+
|
|
5415
|
+
`) + tail.map((l) => chalk.dim(` \u2502 ${l}
|
|
5416
|
+
`)).join("")
|
|
5417
|
+
);
|
|
5418
|
+
}
|
|
5419
|
+
process.stderr.write("\n");
|
|
5420
|
+
}
|
|
5421
|
+
async function maybeAutoInstallSchedule(slug) {
|
|
5422
|
+
try {
|
|
5423
|
+
if (!supportedPlatform() || isOptedOut()) return;
|
|
5424
|
+
const command = buildRunCommand(slug, []);
|
|
5425
|
+
if (installedCommand() === command) {
|
|
5426
|
+
process.stderr.write(
|
|
5427
|
+
chalk.dim(
|
|
5428
|
+
" monthly refresh is on \u2014 `npx standout schedule off` to disable\n\n"
|
|
5429
|
+
)
|
|
5430
|
+
);
|
|
5431
|
+
return;
|
|
5432
|
+
}
|
|
5433
|
+
installJob(command);
|
|
5434
|
+
process.stderr.write(
|
|
5435
|
+
` ${chalk.hex(ACCENT)("\u2713")} ${chalk.white("monthly refresh scheduled")} ${chalk.dim("(1st of each month) \u2014 disable with `npx standout schedule off`")}
|
|
5436
|
+
|
|
5437
|
+
`
|
|
5438
|
+
);
|
|
5439
|
+
} catch (error) {
|
|
5440
|
+
process.stderr.write(
|
|
5441
|
+
chalk.dim(
|
|
5442
|
+
` (couldn't schedule the monthly refresh: ${error instanceof Error ? error.message : String(error)})
|
|
5443
|
+
|
|
5444
|
+
`
|
|
5445
|
+
)
|
|
5446
|
+
);
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
|
|
5147
5450
|
// src/tools.ts
|
|
5148
5451
|
import { execSync as execSync3 } from "child_process";
|
|
5149
5452
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -6014,7 +6317,7 @@ function computeConversation(aiUsage, line, themes) {
|
|
|
6014
6317
|
|
|
6015
6318
|
// src/wrapped/render.ts
|
|
6016
6319
|
import boxen from "boxen";
|
|
6017
|
-
import
|
|
6320
|
+
import chalk2 from "chalk";
|
|
6018
6321
|
import gradient from "gradient-string";
|
|
6019
6322
|
|
|
6020
6323
|
// src/wrapped/chrono-critters.ts
|
|
@@ -6191,8 +6494,8 @@ function hasHistogramData(view) {
|
|
|
6191
6494
|
return view.hour_histogram.some((v) => v > 0);
|
|
6192
6495
|
}
|
|
6193
6496
|
function divider(label) {
|
|
6194
|
-
return
|
|
6195
|
-
${label.padEnd(48, " ")} ${
|
|
6497
|
+
return chalk2.dim(`
|
|
6498
|
+
${label.padEnd(48, " ")} ${chalk2.dim("[press \u21B5]")}
|
|
6196
6499
|
`);
|
|
6197
6500
|
}
|
|
6198
6501
|
function wrapWords(text, width) {
|
|
@@ -6230,7 +6533,7 @@ function centerBlock(art, color) {
|
|
|
6230
6533
|
function bar2(value, max, width) {
|
|
6231
6534
|
if (max === 0) return " ".repeat(width);
|
|
6232
6535
|
const filled = Math.round(value / max * width);
|
|
6233
|
-
return
|
|
6536
|
+
return chalk2.hex("#ff8a00")("\u2588".repeat(filled)) + chalk2.gray("\u2591".repeat(width - filled));
|
|
6234
6537
|
}
|
|
6235
6538
|
function compactNum(n) {
|
|
6236
6539
|
const sign = n < 0 ? "-" : "";
|
|
@@ -6240,12 +6543,12 @@ function compactNum(n) {
|
|
|
6240
6543
|
return `${sign}${abs}`;
|
|
6241
6544
|
}
|
|
6242
6545
|
function coloredBar(value, max, width, hex) {
|
|
6243
|
-
if (max <= 0) return
|
|
6546
|
+
if (max <= 0) return chalk2.gray("\u2591".repeat(width));
|
|
6244
6547
|
const filled = Math.max(
|
|
6245
6548
|
0,
|
|
6246
6549
|
Math.min(width, Math.round(value / max * width))
|
|
6247
6550
|
);
|
|
6248
|
-
return
|
|
6551
|
+
return chalk2.hex(hex)("\u2588".repeat(filled)) + chalk2.gray("\u2591".repeat(width - filled));
|
|
6249
6552
|
}
|
|
6250
6553
|
function sparkline2(buckets) {
|
|
6251
6554
|
if (!buckets.length) return "";
|
|
@@ -6273,8 +6576,8 @@ function hourlyChart(buckets, critter = null) {
|
|
|
6273
6576
|
}
|
|
6274
6577
|
}
|
|
6275
6578
|
const left = [
|
|
6276
|
-
|
|
6277
|
-
|
|
6579
|
+
chalk2.hex("#ad5cff")(spark.padEnd(width, " ")),
|
|
6580
|
+
chalk2.dim(axis.join(""))
|
|
6278
6581
|
];
|
|
6279
6582
|
if (!critter) return left.map((l) => ` ${l}`);
|
|
6280
6583
|
const critterLines = critter.art.split("\n");
|
|
@@ -6316,12 +6619,12 @@ function card1Open(view) {
|
|
|
6316
6619
|
const verdict = perDay >= 6 ? "that's a second full-time job. 996 who?" : perDay >= 3 ? "basically a part-time gig with the machines." : perDay >= 1 ? "a daily habit at this point." : "just getting warmed up.";
|
|
6317
6620
|
const bench = benchmarkInline(view, view.rank_summary.hours_percentile);
|
|
6318
6621
|
const lines = [
|
|
6319
|
-
|
|
6622
|
+
chalk2.dim("YOU MANAGED"),
|
|
6320
6623
|
"",
|
|
6321
6624
|
bigNumber(` ${hours} session-hours`) + (bench ? ` ${bench}` : ""),
|
|
6322
6625
|
"",
|
|
6323
|
-
|
|
6324
|
-
|
|
6626
|
+
chalk2.white(` ${verdict}`),
|
|
6627
|
+
chalk2.dim(" across parallel agent sessions, last 30 days")
|
|
6325
6628
|
].join("\n");
|
|
6326
6629
|
return box(lines, { borderColor: "yellow" });
|
|
6327
6630
|
}
|
|
@@ -6331,7 +6634,7 @@ function cardAllTime(view) {
|
|
|
6331
6634
|
const max = Math.max(...months.map((m) => m.duration_hours), 1);
|
|
6332
6635
|
const rows = months.map((m) => {
|
|
6333
6636
|
const label = monthYearShort(m.month).padEnd(6);
|
|
6334
|
-
return ` ${
|
|
6637
|
+
return ` ${chalk2.dim(label)} ${bar2(m.duration_hours, max, 20)} ${chalk2.dim(`${Math.round(m.duration_hours)}h`)}`;
|
|
6335
6638
|
});
|
|
6336
6639
|
const since = view.all_time.first_session ? new Date(view.all_time.first_session).toISOString().slice(0, 7) : "your first local log";
|
|
6337
6640
|
const latest = months[months.length - 1];
|
|
@@ -6341,14 +6644,14 @@ function cardAllTime(view) {
|
|
|
6341
6644
|
)[0];
|
|
6342
6645
|
const trend = latest && prior && prior.duration_hours > 0 ? `${monthShort(latest.month)}: ${latest.duration_hours >= prior.duration_hours ? "+" : ""}${Math.round((latest.duration_hours - prior.duration_hours) / prior.duration_hours * 100)}% vs previous month` : latest && prior && latest.duration_hours > 0 ? `${monthShort(latest.month)}: active after a quiet month` : null;
|
|
6343
6646
|
const lines = [
|
|
6344
|
-
|
|
6647
|
+
chalk2.dim("YOUR AI CODING YEAR"),
|
|
6345
6648
|
"",
|
|
6346
6649
|
` ${bigNumber(`~${Math.round(view.all_time.total_hours).toLocaleString()} hours`)} from local logs`,
|
|
6347
|
-
` ${
|
|
6348
|
-
...trend ? [` ${
|
|
6650
|
+
` ${chalk2.white(view.all_time.total_sessions.toLocaleString())} sessions detected since ${since}`,
|
|
6651
|
+
...trend ? [` ${chalk2.dim(trend)}`] : [],
|
|
6349
6652
|
"",
|
|
6350
6653
|
...rows,
|
|
6351
|
-
best ? ` ${
|
|
6654
|
+
best ? ` ${chalk2.dim(`best local-log month: ${monthShort(best.month)} \xB7 ~${Math.round(best.duration_hours)}h`)}` : ""
|
|
6352
6655
|
].join("\n");
|
|
6353
6656
|
return box(lines, { borderColor: "cyan" });
|
|
6354
6657
|
}
|
|
@@ -6367,25 +6670,25 @@ function cardRhythm(view) {
|
|
|
6367
6670
|
const isNightOwl = critter?.key === "night_owl";
|
|
6368
6671
|
const subhead = isNightOwl ? "while the 9-5ers sleep, you ship." : weekendPct < 10 ? "locked in on weekdays, weekends are yours." : weekendPct >= 35 ? "weekends are just more reps for you." : peak !== null && peak < 9 ? "up before standup. menace." : "you keep your own hours.";
|
|
6369
6672
|
const lines = [
|
|
6370
|
-
|
|
6673
|
+
chalk2.dim("WHEN YOU CODE"),
|
|
6371
6674
|
"",
|
|
6372
6675
|
...hourlyChart(
|
|
6373
6676
|
view.hour_histogram,
|
|
6374
|
-
critter ? { art: critter.art, color:
|
|
6677
|
+
critter ? { art: critter.art, color: chalk2.magenta } : null
|
|
6375
6678
|
),
|
|
6376
6679
|
"",
|
|
6377
|
-
` ${
|
|
6680
|
+
` ${chalk2.white(caption)}`,
|
|
6378
6681
|
"",
|
|
6379
|
-
` ${
|
|
6380
|
-
` ${
|
|
6682
|
+
` ${chalk2.white("weekdays".padEnd(9))} ${bar2(weekdayPct, 100, 20)} ${chalk2.dim(weekdayPct + "%")}`,
|
|
6683
|
+
` ${chalk2.white("weekends".padEnd(9))} ${bar2(weekendPct, 100, 20)} ${chalk2.dim(weekendPct + "%")}`,
|
|
6381
6684
|
...weekendBench ? ["", ` ${weekendBench}`] : [],
|
|
6382
6685
|
""
|
|
6383
6686
|
];
|
|
6384
6687
|
if (view.rhythm_comment) {
|
|
6385
6688
|
for (const l of wrapWords(view.rhythm_comment, 47))
|
|
6386
|
-
lines.push(
|
|
6689
|
+
lines.push(chalk2.italic.white(" " + l));
|
|
6387
6690
|
} else {
|
|
6388
|
-
lines.push(
|
|
6691
|
+
lines.push(chalk2.dim(" " + subhead));
|
|
6389
6692
|
}
|
|
6390
6693
|
return box(lines.join("\n"), { borderColor });
|
|
6391
6694
|
}
|
|
@@ -6398,10 +6701,10 @@ function cardProjects(view) {
|
|
|
6398
6701
|
if (!usageReady(view)) return "";
|
|
6399
6702
|
const projects = view.top_projects.filter((p) => p.commits > 0 || p.sessions > 0).slice(0, 3);
|
|
6400
6703
|
if (projects.length === 0) return "";
|
|
6401
|
-
const lines = [
|
|
6704
|
+
const lines = [chalk2.dim("YOUR TOP PROJECTS"), ""];
|
|
6402
6705
|
const c = view.contributions;
|
|
6403
6706
|
if (c && c.one_liner) {
|
|
6404
|
-
for (const l of wrapWords(c.one_liner, 50)) lines.push(
|
|
6707
|
+
for (const l of wrapWords(c.one_liner, 50)) lines.push(chalk2.dim(l));
|
|
6405
6708
|
lines.push("");
|
|
6406
6709
|
}
|
|
6407
6710
|
projects.forEach((p, i) => {
|
|
@@ -6411,14 +6714,14 @@ function cardProjects(view) {
|
|
|
6411
6714
|
lines.push(` ${bigNumber(`\u25B8 ${name}`)} ${TITLE_GRADIENT(count)}`);
|
|
6412
6715
|
if (p.blurb)
|
|
6413
6716
|
for (const l of wrapWords(p.blurb, 44))
|
|
6414
|
-
lines.push(` ${
|
|
6717
|
+
lines.push(` ${chalk2.white(l)}`);
|
|
6415
6718
|
} else {
|
|
6416
6719
|
const namePart = `\u25B8 ${name}`;
|
|
6417
6720
|
const pad = " ".repeat(Math.max(2, 24 - namePart.length));
|
|
6418
|
-
lines.push(` ${
|
|
6721
|
+
lines.push(` ${chalk2.white(namePart)}${pad}${chalk2.dim(count)}`);
|
|
6419
6722
|
if (p.blurb)
|
|
6420
6723
|
for (const l of wrapWords(p.blurb, 44))
|
|
6421
|
-
lines.push(` ${
|
|
6724
|
+
lines.push(` ${chalk2.dim(l)}`);
|
|
6422
6725
|
}
|
|
6423
6726
|
lines.push("");
|
|
6424
6727
|
});
|
|
@@ -6434,17 +6737,17 @@ function card7AINative(view) {
|
|
|
6434
6737
|
);
|
|
6435
6738
|
const streak = view.streak_days;
|
|
6436
6739
|
const lines = [
|
|
6437
|
-
|
|
6740
|
+
chalk2.dim("YOU'RE AI-NATIVE"),
|
|
6438
6741
|
"",
|
|
6439
|
-
` commits since 2024: ${
|
|
6440
|
-
` AI co-authored: ${
|
|
6742
|
+
` commits since 2024: ${chalk2.white(view.total_commits.toLocaleString())}`,
|
|
6743
|
+
` AI co-authored: ${chalk2.white(view.ai_assisted_commits.toLocaleString())}`,
|
|
6441
6744
|
"",
|
|
6442
|
-
` ${bar2(pct, 100, 22)} ${
|
|
6745
|
+
` ${bar2(pct, 100, 22)} ${chalk2.white(pct + "%")}${bench ? ` ${bench}` : ""}`,
|
|
6443
6746
|
...streak >= 2 ? [
|
|
6444
|
-
` ${
|
|
6747
|
+
` ${chalk2.white(`${streak}-day streak`)}${chalk2.dim(", coding without missing a day.")}`
|
|
6445
6748
|
] : [],
|
|
6446
6749
|
"",
|
|
6447
|
-
|
|
6750
|
+
chalk2.dim(subhead)
|
|
6448
6751
|
].join("\n");
|
|
6449
6752
|
return box(lines, { borderColor: "yellow" });
|
|
6450
6753
|
}
|
|
@@ -6457,7 +6760,7 @@ function benchmarkInline(view, percentile) {
|
|
|
6457
6760
|
const top = topPercentNumber(percentile);
|
|
6458
6761
|
if (top === null) return "";
|
|
6459
6762
|
const pct = `${top}%`;
|
|
6460
|
-
return top < 10 ?
|
|
6763
|
+
return top < 10 ? chalk2.dim("(top ") + TITLE_GRADIENT(pct) + chalk2.dim(" of users)") : chalk2.dim(`(top ${pct} of users)`);
|
|
6461
6764
|
}
|
|
6462
6765
|
function formatTokens(n) {
|
|
6463
6766
|
if (n >= 1e9) return (n / 1e9).toFixed(1) + "B";
|
|
@@ -6477,24 +6780,24 @@ function cardTokens(view) {
|
|
|
6477
6780
|
const max = Math.max(...t.by_tool.map((x) => x.tokens), 1);
|
|
6478
6781
|
const toolRows = t.by_tool.length > 0 ? t.by_tool.slice(0, 3).map((x) => {
|
|
6479
6782
|
const padTool = x.tool.padEnd(13, " ");
|
|
6480
|
-
return ` ${
|
|
6481
|
-
}).join("\n") :
|
|
6482
|
-
const deltaLine = t.multiplier_vs_prior !== null && t.multiplier_vs_prior >= 1.05 ?
|
|
6783
|
+
return ` ${chalk2.white(padTool)} ${bar2(x.tokens, max, 16)} ${chalk2.dim(formatTokens(x.tokens))}`;
|
|
6784
|
+
}).join("\n") : chalk2.dim(" (no tool breakdown available)");
|
|
6785
|
+
const deltaLine = t.multiplier_vs_prior !== null && t.multiplier_vs_prior >= 1.05 ? chalk2.hex("#ff8a00")(
|
|
6483
6786
|
` \u2191 ${t.multiplier_vs_prior.toFixed(1)}\xD7 vs last period`
|
|
6484
|
-
) : t.multiplier_vs_prior !== null && t.multiplier_vs_prior < 0.95 ?
|
|
6787
|
+
) : t.multiplier_vs_prior !== null && t.multiplier_vs_prior < 0.95 ? chalk2.dim(
|
|
6485
6788
|
` \u2193 ${(1 / t.multiplier_vs_prior).toFixed(1)}\xD7 less than last period`
|
|
6486
|
-
) : t.total_prior_30d > 0 ?
|
|
6789
|
+
) : t.total_prior_30d > 0 ? chalk2.dim(` \u2248 same as last period`) : chalk2.dim(` rolling 30-day window`);
|
|
6487
6790
|
const cost = t.estimated_retail_cost_usd;
|
|
6488
|
-
const costLine = cost > 0 ? ` ${
|
|
6489
|
-
const cursorNote = t.cursor_estimated ? t.cursor_token_share >= 0.9 ?
|
|
6791
|
+
const costLine = cost > 0 ? ` ${chalk2.dim("would have cost")} ${TITLE_GRADIENT(`~$${cost.toLocaleString()}`)} ${chalk2.dim("at retail API rates")}` : "";
|
|
6792
|
+
const cursorNote = t.cursor_estimated ? t.cursor_token_share >= 0.9 ? chalk2.dim(
|
|
6490
6793
|
" \u2248 estimated from time spent in Cursor (no local token data)"
|
|
6491
|
-
) :
|
|
6794
|
+
) : chalk2.dim(
|
|
6492
6795
|
" includes Cursor (tokens + cost estimated from active time)"
|
|
6493
6796
|
) : "";
|
|
6494
|
-
const cachedNote = t.cache_tokens > t.work_tokens ?
|
|
6495
|
-
const generatedLine = t.work_tokens > 0 ? ` ${
|
|
6797
|
+
const cachedNote = t.cache_tokens > t.work_tokens ? chalk2.dim(" thankfully, most of them were cached :)") : t.cache_tokens > 0 ? chalk2.dim(" (includes cached context, re-read each turn)") : "";
|
|
6798
|
+
const generatedLine = t.work_tokens > 0 ? ` ${chalk2.white(formatTokens(t.work_tokens))} ${chalk2.dim("were actually generated fresh")}` : "";
|
|
6496
6799
|
const lines = [
|
|
6497
|
-
|
|
6800
|
+
chalk2.dim("YOU BURNED THIS MANY TOKENS"),
|
|
6498
6801
|
"",
|
|
6499
6802
|
` ${totalLine}${tokensBench ? ` ${tokensBench}` : ""}`,
|
|
6500
6803
|
"",
|
|
@@ -6516,23 +6819,23 @@ function cardToolRelationship(view) {
|
|
|
6516
6819
|
if (r.kind === "insufficient") {
|
|
6517
6820
|
return "";
|
|
6518
6821
|
}
|
|
6519
|
-
const streakLine = view.streak_days >= 2 ? ` ${
|
|
6822
|
+
const streakLine = view.streak_days >= 2 ? ` ${chalk2.white(`${view.streak_days}-day streak, coding without missing a day.`)}` : null;
|
|
6520
6823
|
if (r.kind === "switch") {
|
|
6521
6824
|
const rows = r.timeline.slice(-6).map((t) => {
|
|
6522
6825
|
const monthShort2 = t.month.slice(2).replace("-", "/");
|
|
6523
6826
|
const filled = Math.round(t.share * 10);
|
|
6524
|
-
const bar3 =
|
|
6525
|
-
const label = t.dominant === r.from_tool ?
|
|
6526
|
-
return ` ${
|
|
6827
|
+
const bar3 = chalk2.hex("#ff8a00")("\u2588".repeat(filled)) + chalk2.gray("\u2591".repeat(10 - filled));
|
|
6828
|
+
const label = t.dominant === r.from_tool ? chalk2.dim(t.dominant) : chalk2.white(t.dominant);
|
|
6829
|
+
return ` ${chalk2.dim(monthShort2)} ${bar3} ${label}`;
|
|
6527
6830
|
});
|
|
6528
6831
|
return box(
|
|
6529
6832
|
[
|
|
6530
|
-
|
|
6833
|
+
chalk2.dim("YOU SWITCHED TOOLS"),
|
|
6531
6834
|
"",
|
|
6532
6835
|
...rows,
|
|
6533
6836
|
"",
|
|
6534
|
-
|
|
6535
|
-
|
|
6837
|
+
chalk2.dim(` joined the "${r.from_tool} \u2192 ${r.to_tool}" club`),
|
|
6838
|
+
chalk2.dim(` in ${r.switch_month}.`),
|
|
6536
6839
|
...streakLine ? ["", streakLine] : []
|
|
6537
6840
|
].join("\n"),
|
|
6538
6841
|
{ borderColor: "cyan" }
|
|
@@ -6541,14 +6844,14 @@ function cardToolRelationship(view) {
|
|
|
6541
6844
|
if (r.kind === "loyalist") {
|
|
6542
6845
|
return box(
|
|
6543
6846
|
[
|
|
6544
|
-
|
|
6847
|
+
chalk2.dim("YOU'RE A LOYALIST"),
|
|
6545
6848
|
"",
|
|
6546
6849
|
` ${bigNumber(r.tool.toUpperCase())}`,
|
|
6547
6850
|
"",
|
|
6548
|
-
|
|
6851
|
+
chalk2.dim(
|
|
6549
6852
|
` ${r.sessions_count} sessions across ${r.months_count} month${r.months_count === 1 ? "" : "s"}.`
|
|
6550
6853
|
),
|
|
6551
|
-
|
|
6854
|
+
chalk2.dim(" no second-guessing. you knew what you wanted."),
|
|
6552
6855
|
...streakLine ? ["", streakLine] : []
|
|
6553
6856
|
].join("\n"),
|
|
6554
6857
|
{ borderColor: "cyan" }
|
|
@@ -6557,16 +6860,16 @@ function cardToolRelationship(view) {
|
|
|
6557
6860
|
if (r.kind === "polyglot") {
|
|
6558
6861
|
const rows = r.tools.slice(0, 4).map((t) => {
|
|
6559
6862
|
const filled = Math.round(t.share * 22);
|
|
6560
|
-
const bar3 =
|
|
6561
|
-
return ` ${
|
|
6863
|
+
const bar3 = chalk2.hex("#ff8a00")("\u2588".repeat(filled)) + chalk2.gray("\u2591".repeat(22 - filled));
|
|
6864
|
+
return ` ${chalk2.white(t.tool.padEnd(12, " "))} ${bar3} ${chalk2.dim(Math.round(t.share * 100) + "%")}`;
|
|
6562
6865
|
});
|
|
6563
6866
|
return box(
|
|
6564
6867
|
[
|
|
6565
|
-
|
|
6868
|
+
chalk2.dim("YOU'RE A POLYGLOT"),
|
|
6566
6869
|
"",
|
|
6567
6870
|
...rows,
|
|
6568
6871
|
"",
|
|
6569
|
-
|
|
6872
|
+
chalk2.dim(" you don't pick favorites. respect."),
|
|
6570
6873
|
...streakLine ? ["", streakLine] : []
|
|
6571
6874
|
].join("\n"),
|
|
6572
6875
|
{ borderColor: "cyan" }
|
|
@@ -6628,17 +6931,17 @@ function cardModelsStack(view) {
|
|
|
6628
6931
|
const column = (mm) => {
|
|
6629
6932
|
if (!mm) return [];
|
|
6630
6933
|
const c = modelProviderColor(mm.prov);
|
|
6631
|
-
const hex = (s) =>
|
|
6934
|
+
const hex = (s) => chalk2.hex(c)(s);
|
|
6632
6935
|
const cap = " " + hex("\u256D" + "\u2500".repeat(8) + "\u256E") + " ";
|
|
6633
6936
|
const base = " " + hex("\u2570" + "\u2500".repeat(8) + "\u256F") + " ";
|
|
6634
6937
|
const side = " " + hex("\u2502") + " ".repeat(8) + hex("\u2502") + " ";
|
|
6635
|
-
const num3 = " " + hex("\u2502") +
|
|
6938
|
+
const num3 = " " + hex("\u2502") + chalk2.bold.white(center("#" + mm.rank, 8)) + hex("\u2502") + " ";
|
|
6636
6939
|
const h = heights[mm.rank];
|
|
6637
6940
|
const mid = Math.floor((h - 1) / 2);
|
|
6638
6941
|
const body = [];
|
|
6639
6942
|
for (let i = 0; i < h; i++) body.push(i === mid ? num3 : side);
|
|
6640
|
-
const label = mm.rank === 1 ? bigNumber(center(mm.name)) :
|
|
6641
|
-
return [label,
|
|
6943
|
+
const label = mm.rank === 1 ? bigNumber(center(mm.name)) : chalk2.white(center(mm.name));
|
|
6944
|
+
return [label, chalk2.dim(center(mm.pct + "%")), cap, ...body, base];
|
|
6642
6945
|
};
|
|
6643
6946
|
const cols = [column(second), column(first), column(third)];
|
|
6644
6947
|
const maxH = Math.max(...cols.map((col) => col.length));
|
|
@@ -6646,20 +6949,20 @@ function cardModelsStack(view) {
|
|
|
6646
6949
|
(col) => Array(maxH - col.length).fill(blankCol).concat(col)
|
|
6647
6950
|
);
|
|
6648
6951
|
const header = ranked.length === 1 ? "YOUR MODEL & STACK" : "YOUR MODELS & STACK";
|
|
6649
|
-
const lines = [
|
|
6952
|
+
const lines = [chalk2.dim(header), ""];
|
|
6650
6953
|
lines.push(
|
|
6651
|
-
" " + [blankCol,
|
|
6954
|
+
" " + [blankCol, chalk2.hex("#ffd700")(center("\u265B")), blankCol].join(" ")
|
|
6652
6955
|
);
|
|
6653
6956
|
for (let r = 0; r < maxH; r++)
|
|
6654
6957
|
lines.push(" " + [padded[0][r], padded[1][r], padded[2][r]].join(" "));
|
|
6655
6958
|
lines.push("");
|
|
6656
6959
|
lines.push(
|
|
6657
|
-
` top pick: ${
|
|
6960
|
+
` top pick: ${chalk2.white(first.name)} ${chalk2.dim(`\u2014 ${first.pct}% of sessions`)}`
|
|
6658
6961
|
);
|
|
6659
6962
|
if (view.stack_comment) {
|
|
6660
6963
|
lines.push("");
|
|
6661
6964
|
for (const l of wrapWords(view.stack_comment, 46))
|
|
6662
|
-
lines.push(
|
|
6965
|
+
lines.push(chalk2.italic.white(" " + l));
|
|
6663
6966
|
}
|
|
6664
6967
|
return box(lines.join("\n"), { borderColor: "magenta" });
|
|
6665
6968
|
}
|
|
@@ -6670,25 +6973,25 @@ function cardCodeFootprint(view) {
|
|
|
6670
6973
|
const netLabel = `${f.net >= 0 ? "+" : ""}${compactNum(f.net)}`;
|
|
6671
6974
|
const subhead = f.label === "Cleaner" ? "you delete more than you add. the slop stops with you." : f.label === "Shipper" ? `${f.additive_ratio >= 0 ? Math.round(f.additive_ratio * 100) : 0}% of your churn is brand-new code.` : "you rework as much as you write. nothing ships half-baked.";
|
|
6672
6975
|
const lines = [
|
|
6673
|
-
|
|
6976
|
+
chalk2.dim("YOUR CODE FOOTPRINT"),
|
|
6674
6977
|
"",
|
|
6675
6978
|
` ${bigNumber(f.label.toUpperCase())}`,
|
|
6676
6979
|
"",
|
|
6677
|
-
` ${
|
|
6678
|
-
` ${
|
|
6980
|
+
` ${chalk2.green("+ " + compactNum(f.lines_added).padEnd(7))} ${coloredBar(f.lines_added, max, 22, "#22c55e")} ${chalk2.dim("added")}`,
|
|
6981
|
+
` ${chalk2.red("- " + compactNum(f.lines_deleted).padEnd(7))} ${coloredBar(f.lines_deleted, max, 22, "#ef4444")} ${chalk2.dim("deleted")}`,
|
|
6679
6982
|
"",
|
|
6680
|
-
` ${
|
|
6983
|
+
` ${chalk2.white("net " + netLabel)} ${chalk2.dim("lines since 2024")}`
|
|
6681
6984
|
];
|
|
6682
6985
|
if (f.median_commit_size > 0)
|
|
6683
6986
|
lines.push(
|
|
6684
|
-
` ${
|
|
6987
|
+
` ${chalk2.dim(`typical commit ~${compactNum(f.median_commit_size)} lines \xB7 biggest ${compactNum(f.biggest_commit_size)}`)}`
|
|
6685
6988
|
);
|
|
6686
6989
|
lines.push("");
|
|
6687
6990
|
if (f.line) {
|
|
6688
6991
|
for (const l of wrapWords(f.line, 47))
|
|
6689
|
-
lines.push(
|
|
6992
|
+
lines.push(chalk2.italic.white(" " + l));
|
|
6690
6993
|
} else {
|
|
6691
|
-
lines.push(
|
|
6994
|
+
lines.push(chalk2.dim(" " + subhead));
|
|
6692
6995
|
}
|
|
6693
6996
|
return box(lines.join("\n"), { borderColor: "green" });
|
|
6694
6997
|
}
|
|
@@ -6699,20 +7002,20 @@ function cardConcurrency(view) {
|
|
|
6699
7002
|
const longest = days >= 1.5 ? `${days.toFixed(0)} days` : `${Math.round(c.longest_session_hours)}h`;
|
|
6700
7003
|
const bench = benchmarkInline(view, view.rank_summary.avg_agents_percentile);
|
|
6701
7004
|
const lines = [
|
|
6702
|
-
|
|
7005
|
+
chalk2.dim("HOW MANY AGENTS YOU JUGGLE"),
|
|
6703
7006
|
"",
|
|
6704
|
-
` ${bigNumber(`~${c.open_tab_avg}`)} ${
|
|
7007
|
+
` ${bigNumber(`~${c.open_tab_avg}`)} ${chalk2.white("agents open at once")}${bench ? ` ${bench}` : ""}`,
|
|
6705
7008
|
"",
|
|
6706
|
-
` ${
|
|
6707
|
-
` ${
|
|
6708
|
-
` ${
|
|
7009
|
+
` ${chalk2.white("peak".padEnd(14))} ${chalk2.dim(`${c.open_tab_peak} at once`)}`,
|
|
7010
|
+
` ${chalk2.white("longest tab".padEnd(14))} ${chalk2.dim(`${longest} open`)}`,
|
|
7011
|
+
` ${chalk2.white("2+ active".padEnd(14))} ${chalk2.dim(`${Math.round(c.active_juggle_pct * 100)}% of your coding time`)}`,
|
|
6709
7012
|
""
|
|
6710
7013
|
];
|
|
6711
7014
|
if (c.line) {
|
|
6712
7015
|
for (const l of wrapWords(c.line, 47))
|
|
6713
|
-
lines.push(
|
|
7016
|
+
lines.push(chalk2.italic.white(" " + l));
|
|
6714
7017
|
} else {
|
|
6715
|
-
lines.push(
|
|
7018
|
+
lines.push(chalk2.dim(" a one-agent setup could never."));
|
|
6716
7019
|
}
|
|
6717
7020
|
return box(lines.join("\n"), { borderColor: "blue" });
|
|
6718
7021
|
}
|
|
@@ -6729,22 +7032,22 @@ function cardTalk(view) {
|
|
|
6729
7032
|
const c = view.conversation;
|
|
6730
7033
|
const v = view.collaboration;
|
|
6731
7034
|
if ((!c || c.total_prompts < 10) && !v) return "";
|
|
6732
|
-
const lines = [
|
|
7035
|
+
const lines = [chalk2.dim("HOW YOU TALK"), ""];
|
|
6733
7036
|
if (c?.line) {
|
|
6734
7037
|
for (const l of wrapWords(c.line, 47))
|
|
6735
|
-
lines.push(
|
|
7038
|
+
lines.push(chalk2.italic.white(" " + l));
|
|
6736
7039
|
lines.push("");
|
|
6737
7040
|
}
|
|
6738
7041
|
if (v) {
|
|
6739
7042
|
lines.push(` ${bigNumber(v.style_label)}`);
|
|
6740
7043
|
if (v.summary)
|
|
6741
7044
|
for (const l of wrapWords(v.summary, 47))
|
|
6742
|
-
lines.push(
|
|
7045
|
+
lines.push(chalk2.white(" " + l));
|
|
6743
7046
|
const sigs = [
|
|
6744
7047
|
["reads", v.signals.fact_checking],
|
|
6745
7048
|
["drives", v.signals.autonomy]
|
|
6746
7049
|
].filter(([, t]) => t).map(
|
|
6747
|
-
([label, t]) => ` ${
|
|
7050
|
+
([label, t]) => ` ${chalk2.dim(label.padEnd(8))} ${chalk2.white(briefSignal(t))}`
|
|
6748
7051
|
);
|
|
6749
7052
|
if (sigs.length > 0) {
|
|
6750
7053
|
lines.push("");
|
|
@@ -6754,11 +7057,11 @@ function cardTalk(view) {
|
|
|
6754
7057
|
if (c) {
|
|
6755
7058
|
lines.push("");
|
|
6756
7059
|
lines.push(
|
|
6757
|
-
` ${
|
|
7060
|
+
` ${chalk2.white(c.total_prompts.toLocaleString())} ${chalk2.dim("prompts")} \xB7 ${chalk2.white(Math.round(c.question_ratio * 100) + "%")} ${chalk2.dim("questions")} \xB7 ${chalk2.white("~" + c.avg_prompt_chars)} ${chalk2.dim("chars")}`
|
|
6758
7061
|
);
|
|
6759
7062
|
if (c.themes.length > 0)
|
|
6760
7063
|
lines.push(
|
|
6761
|
-
` ${
|
|
7064
|
+
` ${chalk2.dim("recurring: " + c.themes.slice(0, 4).join(", "))}`
|
|
6762
7065
|
);
|
|
6763
7066
|
}
|
|
6764
7067
|
return box(lines.join("\n"), { borderColor: "magenta" });
|
|
@@ -6770,13 +7073,13 @@ function cardProficiency(view) {
|
|
|
6770
7073
|
if (!p) {
|
|
6771
7074
|
return box(
|
|
6772
7075
|
[
|
|
6773
|
-
|
|
7076
|
+
chalk2.dim(" you are\u2026"),
|
|
6774
7077
|
"",
|
|
6775
|
-
|
|
7078
|
+
chalk2.hex("#ff8a00")(mascot),
|
|
6776
7079
|
"",
|
|
6777
7080
|
` ${archetype}`,
|
|
6778
7081
|
"",
|
|
6779
|
-
` ${
|
|
7082
|
+
` ${chalk2.italic.white(`"${view.zinger}"`)}`
|
|
6780
7083
|
].join("\n"),
|
|
6781
7084
|
{ borderColor: "yellow" }
|
|
6782
7085
|
);
|
|
@@ -6784,27 +7087,27 @@ function cardProficiency(view) {
|
|
|
6784
7087
|
const scoreTop = topPercentNumber(p.score_percentile ?? null);
|
|
6785
7088
|
const sampleSize = view.rank_summary.sample_size;
|
|
6786
7089
|
const cohort = scoreTop != null && sampleSize > 0 ? `top ${scoreTop}% of ${sampleSize.toLocaleString()} users` : view.cohort_size > 0 ? `among ${view.cohort_size.toLocaleString()} users so far` : "";
|
|
6787
|
-
const metricRow = (label, value) => value === null ? null : ` ${
|
|
7090
|
+
const metricRow = (label, value) => value === null ? null : ` ${chalk2.white(label.padEnd(12))} ${bar2(value, 100, 10)} ${chalk2.dim(String(value))}`;
|
|
6788
7091
|
const bars = [
|
|
6789
7092
|
metricRow("intensity", p.intensity),
|
|
6790
7093
|
metricRow("consistency", p.consistency),
|
|
6791
|
-
p.craft_bonus > 0 ? ` ${
|
|
7094
|
+
p.craft_bonus > 0 ? ` ${chalk2.white("craft".padEnd(12))} ${chalk2.hex("#ff8a00")(`+${p.craft_bonus}`)} ${chalk2.dim("clean prompting")}` : null
|
|
6792
7095
|
].filter((r) => r !== null);
|
|
6793
7096
|
const zingerLines = wrapWords(`"${view.zinger}"`, INNER_WIDTH).map(
|
|
6794
|
-
(l) => centerText(l,
|
|
7097
|
+
(l) => centerText(l, chalk2.italic.white)
|
|
6795
7098
|
);
|
|
6796
7099
|
const commentLines = p.comment ? wrapWords(p.comment, INNER_WIDTH - 4).map(
|
|
6797
|
-
(l, i) => i === 0 ? ` ${
|
|
7100
|
+
(l, i) => i === 0 ? ` ${chalk2.hex("#ff8a00")(">")} ${chalk2.white(l)}` : ` ${chalk2.white(l)}`
|
|
6798
7101
|
) : [];
|
|
6799
7102
|
const tier = tierForScore2(p.score);
|
|
6800
7103
|
const lines = [
|
|
6801
|
-
centerBlock(tier.art,
|
|
7104
|
+
centerBlock(tier.art, chalk2.hex("#ff8a00")),
|
|
6802
7105
|
"",
|
|
6803
7106
|
centerText(`\u2500\u2500 ${tier.label} \u2500\u2500`, bigNumber),
|
|
6804
7107
|
centerText(`${p.score} / 100`, bigNumber),
|
|
6805
|
-
cohort ? centerText(cohort,
|
|
7108
|
+
cohort ? centerText(cohort, chalk2.dim) : null,
|
|
6806
7109
|
"",
|
|
6807
|
-
centerText(view.archetype_label,
|
|
7110
|
+
centerText(view.archetype_label, chalk2.bold.hex("#ad5cff")),
|
|
6808
7111
|
...zingerLines,
|
|
6809
7112
|
"",
|
|
6810
7113
|
...bars,
|
|
@@ -6842,7 +7145,7 @@ async function renderWrappedAll(view) {
|
|
|
6842
7145
|
" " + TITLE_GRADIENT.multiline("\u2591\u2592\u2593 YOUR AI WRAPPED \u2593\u2592\u2591") + "\n"
|
|
6843
7146
|
);
|
|
6844
7147
|
process.stdout.write(
|
|
6845
|
-
|
|
7148
|
+
chalk2.dim(` ${view.name.toLowerCase()} \xB7 last 30 days
|
|
6846
7149
|
|
|
6847
7150
|
`)
|
|
6848
7151
|
);
|
|
@@ -7065,18 +7368,18 @@ var MODE_OPTIONS = [
|
|
|
7065
7368
|
function renderModeMenu(selected) {
|
|
7066
7369
|
const out = [
|
|
7067
7370
|
"",
|
|
7068
|
-
|
|
7371
|
+
chalk3.white(" How do you want to run Standout?"),
|
|
7069
7372
|
""
|
|
7070
7373
|
];
|
|
7071
7374
|
MODE_OPTIONS.forEach((opt, i) => {
|
|
7072
7375
|
const active = i === selected;
|
|
7073
|
-
const pointer = active ?
|
|
7074
|
-
const title = active ?
|
|
7376
|
+
const pointer = active ? chalk3.hex("#ad5cff")("\u276F ") : " ";
|
|
7377
|
+
const title = active ? chalk3.bold.white(opt.title) + chalk3.dim(opt.tag) : chalk3.dim(opt.title + opt.tag);
|
|
7075
7378
|
out.push(`${pointer}${title}`);
|
|
7076
|
-
for (const line of opt.lines) out.push(
|
|
7379
|
+
for (const line of opt.lines) out.push(chalk3.dim(` ${line}`));
|
|
7077
7380
|
out.push("");
|
|
7078
7381
|
});
|
|
7079
|
-
out.push(
|
|
7382
|
+
out.push(chalk3.dim(" \u2191/\u2193 to move \xB7 enter to select"));
|
|
7080
7383
|
return out.join("\n");
|
|
7081
7384
|
}
|
|
7082
7385
|
async function chooseMode() {
|
|
@@ -7179,8 +7482,8 @@ function startLoadingLine(label) {
|
|
|
7179
7482
|
let frame = 0;
|
|
7180
7483
|
const render = () => {
|
|
7181
7484
|
const dots = frames[frame % frames.length];
|
|
7182
|
-
const accent =
|
|
7183
|
-
const text =
|
|
7485
|
+
const accent = chalk3.hex("#ad5cff")(dots);
|
|
7486
|
+
const text = chalk3.white(label);
|
|
7184
7487
|
process.stderr.write(`\r\x1B[2K ${accent} ${text}`);
|
|
7185
7488
|
frame += 1;
|
|
7186
7489
|
};
|
|
@@ -7212,7 +7515,7 @@ async function maybeShareWrapped(wrapped) {
|
|
|
7212
7515
|
return;
|
|
7213
7516
|
}
|
|
7214
7517
|
const ans = await askLine(
|
|
7215
|
-
|
|
7518
|
+
chalk3.white(" press enter to see your ai wrapped ")
|
|
7216
7519
|
);
|
|
7217
7520
|
process.stderr.write("\n");
|
|
7218
7521
|
const shared = !ans || ans.toLowerCase() !== "n";
|
|
@@ -7308,8 +7611,8 @@ async function runLocal() {
|
|
|
7308
7611
|
);
|
|
7309
7612
|
return;
|
|
7310
7613
|
}
|
|
7311
|
-
const file =
|
|
7312
|
-
|
|
7614
|
+
const file = join7(tmpdir2(), `standout-wrapped-${Date.now()}.png`);
|
|
7615
|
+
writeFileSync2(file, png);
|
|
7313
7616
|
process.stderr.write("\n");
|
|
7314
7617
|
const shown = showImageInline(png);
|
|
7315
7618
|
if (!shown) {
|
|
@@ -7533,6 +7836,17 @@ async function runAgent(jobId) {
|
|
|
7533
7836
|
async function main() {
|
|
7534
7837
|
ensureHeapHeadroom();
|
|
7535
7838
|
const args = process.argv.slice(2);
|
|
7839
|
+
if (args[0] === "schedule" || args[0] === "unschedule") {
|
|
7840
|
+
const action = parseScheduleArgs(args);
|
|
7841
|
+
if (action.kind === "install") {
|
|
7842
|
+
await installSchedule(action.slug, action.flags);
|
|
7843
|
+
} else if (action.kind === "remove") {
|
|
7844
|
+
await removeSchedule();
|
|
7845
|
+
} else {
|
|
7846
|
+
await scheduleStatus();
|
|
7847
|
+
}
|
|
7848
|
+
return;
|
|
7849
|
+
}
|
|
7536
7850
|
const proxy = configureProxyFromEnv();
|
|
7537
7851
|
if (proxy) process.stderr.write(` (using proxy ${proxy})
|
|
7538
7852
|
`);
|
|
@@ -7558,6 +7872,7 @@ async function main() {
|
|
|
7558
7872
|
} else {
|
|
7559
7873
|
if (jobId) process.env.STANDOUT_JOB_ID = jobId;
|
|
7560
7874
|
await runAgent(jobId);
|
|
7875
|
+
await maybeAutoInstallSchedule(jobId);
|
|
7561
7876
|
}
|
|
7562
7877
|
}
|
|
7563
7878
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "standout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Build your developer profile with AI. One command, zero friction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -63,5 +63,10 @@
|
|
|
63
63
|
"license": "MIT",
|
|
64
64
|
"optionalDependencies": {
|
|
65
65
|
"better-sqlite3": "^12.9.0"
|
|
66
|
+
},
|
|
67
|
+
"allowScripts": {
|
|
68
|
+
"better-sqlite3": true,
|
|
69
|
+
"esbuild": true,
|
|
70
|
+
"fsevents": true
|
|
66
71
|
}
|
|
67
72
|
}
|