@staff0rd/assist 0.363.0 → 0.365.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.363.0",
9
+ version: "0.365.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -55,6 +55,8 @@ var package_default = {
55
55
  entities: "^7.0.1",
56
56
  "is-wsl": "^3.1.0",
57
57
  "log-update": "^8.0.0",
58
+ marked: "^15.0.12",
59
+ "marked-terminal": "^7.3.0",
58
60
  minimatch: "^10.1.1",
59
61
  mssql: "^12.5.0",
60
62
  "node-notifier": "^10.0.1",
@@ -99,7 +101,6 @@ var package_default = {
99
101
  jscpd: "^4.0.5",
100
102
  jsdom: "^29.1.1",
101
103
  knip: "^5.71.0",
102
- marked: "^15.0.12",
103
104
  oxfmt: "^0.54.0",
104
105
  oxlint: "^1.69.0",
105
106
  react: "^19.2.4",
@@ -254,7 +255,8 @@ var assistConfigSchema = z2.strictObject({
254
255
  tokenExpiresAt: z2.number().optional()
255
256
  }).optional(),
256
257
  prs: z2.strictObject({
257
- slack: z2.string()
258
+ slack: z2.string().optional(),
259
+ required: z2.boolean().default(false)
258
260
  }).optional(),
259
261
  run: z2.array(z2.union([runConfigSchema, runLinkSchema])).optional(),
260
262
  subtasks: z2.array(
@@ -3120,7 +3122,7 @@ ${failed2.length} script(s) failed:`);
3120
3122
  }
3121
3123
  }
3122
3124
  function runEntry(entry) {
3123
- return new Promise((resolve17) => {
3125
+ return new Promise((resolve18) => {
3124
3126
  const startTime = Date.now();
3125
3127
  const child = spawnCommand(
3126
3128
  entry.fullCommand,
@@ -3132,7 +3134,7 @@ function runEntry(entry) {
3132
3134
  child.on("close", (code) => {
3133
3135
  const exitCode = code ?? 1;
3134
3136
  flushIfFailed(exitCode, chunks);
3135
- resolve17({
3137
+ resolve18({
3136
3138
  script: entry.name,
3137
3139
  code: exitCode,
3138
3140
  durationMs: Date.now() - startTime
@@ -4266,8 +4268,8 @@ function spawnClaude(prompt, options2 = {}) {
4266
4268
  stdio: "inherit",
4267
4269
  env
4268
4270
  });
4269
- const done2 = new Promise((resolve17, reject) => {
4270
- child.on("close", (code) => resolve17(code ?? 0));
4271
+ const done2 = new Promise((resolve18, reject) => {
4272
+ child.on("close", (code) => resolve18(code ?? 0));
4271
4273
  child.on("error", reject);
4272
4274
  });
4273
4275
  return { child, done: done2 };
@@ -4329,6 +4331,89 @@ function consumePause(itemId) {
4329
4331
  return true;
4330
4332
  }
4331
4333
 
4334
+ // src/commands/branch/createBranch.ts
4335
+ import { execSync as execSync21 } from "child_process";
4336
+
4337
+ // src/commands/branch/buildBranchName.ts
4338
+ function buildBranchName({
4339
+ prefix: prefix2,
4340
+ jira,
4341
+ slug
4342
+ }) {
4343
+ const segments = [];
4344
+ if (prefix2) segments.push(`${prefix2}/`);
4345
+ if (jira) segments.push(`${jira}-`);
4346
+ segments.push(slug);
4347
+ return segments.join("");
4348
+ }
4349
+
4350
+ // src/commands/branch/resolveDefaultBranch.ts
4351
+ import { execSync as execSync20 } from "child_process";
4352
+ var REMOTE_HEAD_REGEX = /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/m;
4353
+ function resolveDefaultBranch(override, cwd) {
4354
+ if (override) return override;
4355
+ try {
4356
+ const output = execSync20("git ls-remote --symref origin HEAD", {
4357
+ encoding: "utf8",
4358
+ stdio: ["pipe", "pipe", "pipe"],
4359
+ cwd
4360
+ });
4361
+ const match = output.match(REMOTE_HEAD_REGEX);
4362
+ if (match) return match[1];
4363
+ } catch {
4364
+ }
4365
+ return "main";
4366
+ }
4367
+
4368
+ // src/commands/branch/createBranch.ts
4369
+ async function createBranch({
4370
+ slug,
4371
+ jira
4372
+ }) {
4373
+ const config = loadConfig();
4374
+ const branchName = buildBranchName({
4375
+ prefix: config.branch?.prefix,
4376
+ jira,
4377
+ slug
4378
+ });
4379
+ const defaultBranch = resolveDefaultBranch(config.branch?.defaultBranch);
4380
+ execSync21("git fetch", { stdio: "inherit" });
4381
+ execSync21(
4382
+ `git switch -c ${shellQuote(branchName)} ${shellQuote(`origin/${defaultBranch}`)}`,
4383
+ { stdio: "inherit" }
4384
+ );
4385
+ await recordBranchActivity(branchName);
4386
+ return { branchName, defaultBranch };
4387
+ }
4388
+ async function recordBranchActivity(branchName) {
4389
+ if (resolveSessionItemId() === null) return;
4390
+ await recordSessionRefs([
4391
+ { kind: "branch", ref: branchName, url: gitRefUrl("branch", branchName) }
4392
+ ]);
4393
+ }
4394
+
4395
+ // src/commands/branch/deriveBranchSlug.ts
4396
+ function deriveBranchSlug(name) {
4397
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4398
+ return slug || "story";
4399
+ }
4400
+
4401
+ // src/commands/backlog/ensureStoryBranch.ts
4402
+ async function ensureStoryBranch(item) {
4403
+ const config = loadConfig();
4404
+ if (!config.prs?.required) return;
4405
+ if (hasBranchRef(item)) return;
4406
+ process.env.ASSIST_BACKLOG_ITEM_ID = String(item.id);
4407
+ const slug = deriveBranchSlug(item.name);
4408
+ const { branchName } = await createBranch({ slug, jira: item.jiraKey });
4409
+ appendDaemonLog(
4410
+ `backlog run ${item.id}: prs.required set and no branch recorded; created ${branchName}`
4411
+ );
4412
+ }
4413
+ function hasBranchRef(item) {
4414
+ return (item.gitRefs ?? []).some((ref) => ref.kind === "branch");
4415
+ }
4416
+
4332
4417
  // src/commands/backlog/shared.ts
4333
4418
  import chalk37 from "chalk";
4334
4419
 
@@ -4354,11 +4439,11 @@ function backupLocalBacklogFiles(dir) {
4354
4439
  }
4355
4440
 
4356
4441
  // src/commands/backlog/gitPullBacklog.ts
4357
- import { execSync as execSync20 } from "child_process";
4442
+ import { execSync as execSync22 } from "child_process";
4358
4443
  import chalk35 from "chalk";
4359
4444
  function gitPullBacklog(dir) {
4360
4445
  try {
4361
- execSync20("git pull --ff-only", {
4446
+ execSync22("git pull --ff-only", {
4362
4447
  cwd: dir,
4363
4448
  stdio: ["pipe", "pipe", "pipe"]
4364
4449
  });
@@ -5083,9 +5168,9 @@ Failed to launch Claude for ${context}: ${message}`)
5083
5168
  // src/commands/sessions/daemon/connectToDaemon.ts
5084
5169
  import * as net from "net";
5085
5170
  function connectToDaemon() {
5086
- return new Promise((resolve17, reject) => {
5171
+ return new Promise((resolve18, reject) => {
5087
5172
  const socket = net.connect(daemonPaths.socket);
5088
- socket.once("connect", () => resolve17(socket));
5173
+ socket.once("connect", () => resolve18(socket));
5089
5174
  socket.once("error", reject);
5090
5175
  });
5091
5176
  }
@@ -5532,6 +5617,7 @@ async function runOnce(item, startPhase, plan2, spawnOptions) {
5532
5617
  async function run2(id2, spawnOptions) {
5533
5618
  const prepared = await prepareRun(id2);
5534
5619
  if (!prepared) return false;
5620
+ await ensureStoryBranch(prepared.item);
5535
5621
  await setStatus(id2, "in-progress");
5536
5622
  discardStalePause(prepared.item.id);
5537
5623
  logProgress(id2, prepared);
@@ -5736,6 +5822,25 @@ function formatComment(entry) {
5736
5822
  ${entry.text}`;
5737
5823
  }
5738
5824
 
5825
+ // src/shared/renderMarkdownTerminal.ts
5826
+ import { Marked } from "marked";
5827
+ import { markedTerminal } from "marked-terminal";
5828
+ function renderMarkdownTerminal(text9) {
5829
+ const width = process.stdout.columns || 80;
5830
+ const marked = new Marked(markedTerminal({ width, reflowText: true }));
5831
+ marked.use({
5832
+ renderer: {
5833
+ text(token) {
5834
+ if (token && typeof token === "object" && "tokens" in token && token.tokens) {
5835
+ return this.parser.parseInline(token.tokens);
5836
+ }
5837
+ return false;
5838
+ }
5839
+ }
5840
+ });
5841
+ return marked.parse(text9).trimEnd();
5842
+ }
5843
+
5739
5844
  // src/commands/backlog/show/printActivity.ts
5740
5845
  import chalk48 from "chalk";
5741
5846
 
@@ -5869,7 +5974,10 @@ function printSubtasks(item) {
5869
5974
  const status2 = chalk52.dim(`[${subtask.status}]`);
5870
5975
  console.log(` ${i + 1}. ${status2} ${subtask.title}`);
5871
5976
  if (subtask.description) {
5872
- console.log(` ${chalk52.dim(subtask.description)}`);
5977
+ const rendered = renderMarkdownTerminal(subtask.description);
5978
+ for (const line of rendered.split("\n")) {
5979
+ console.log(` ${line}`);
5980
+ }
5873
5981
  }
5874
5982
  }
5875
5983
  console.log();
@@ -5910,7 +6018,7 @@ async function show(id2) {
5910
6018
  printHeader(item);
5911
6019
  if (item.description) {
5912
6020
  console.log(chalk53.bold("Description"));
5913
- console.log(item.description);
6021
+ console.log(renderMarkdownTerminal(item.description));
5914
6022
  console.log();
5915
6023
  }
5916
6024
  printAcceptanceCriteria(item.acceptanceCriteria);
@@ -5926,7 +6034,7 @@ import chalk59 from "chalk";
5926
6034
  import { WebSocketServer } from "ws";
5927
6035
 
5928
6036
  // src/shared/getInstallDir.ts
5929
- import { execSync as execSync21 } from "child_process";
6037
+ import { execSync as execSync23 } from "child_process";
5930
6038
  import { dirname as dirname16, resolve as resolve7 } from "path";
5931
6039
  import { fileURLToPath as fileURLToPath2 } from "url";
5932
6040
  var __filename2 = fileURLToPath2(import.meta.url);
@@ -5936,7 +6044,7 @@ function getInstallDir() {
5936
6044
  }
5937
6045
  function isGitRepo(dir) {
5938
6046
  try {
5939
- const result = execSync21("git rev-parse --show-toplevel", {
6047
+ const result = execSync23("git rev-parse --show-toplevel", {
5940
6048
  cwd: dir,
5941
6049
  stdio: "pipe"
5942
6050
  }).toString().trim();
@@ -5953,11 +6061,11 @@ import {
5953
6061
  import chalk54 from "chalk";
5954
6062
 
5955
6063
  // src/lib/openBrowser.ts
5956
- import { execSync as execSync22 } from "child_process";
6064
+ import { execSync as execSync24 } from "child_process";
5957
6065
  function tryExec(commands) {
5958
6066
  for (const cmd of commands) {
5959
6067
  try {
5960
- execSync22(cmd, { stdio: "ignore" });
6068
+ execSync24(cmd, { stdio: "ignore" });
5961
6069
  return true;
5962
6070
  } catch {
5963
6071
  }
@@ -6145,7 +6253,7 @@ function spawnDaemon(reason) {
6145
6253
  child.unref();
6146
6254
  }
6147
6255
  function delay(ms) {
6148
- return new Promise((resolve17) => setTimeout(resolve17, ms));
6256
+ return new Promise((resolve18) => setTimeout(resolve18, ms));
6149
6257
  }
6150
6258
 
6151
6259
  // src/shared/createBundleHandler.ts
@@ -6355,12 +6463,12 @@ async function loadVisibleItems(req) {
6355
6463
 
6356
6464
  // src/commands/backlog/web/parseStatusBody.ts
6357
6465
  function readBody(req) {
6358
- return new Promise((resolve17, reject) => {
6466
+ return new Promise((resolve18, reject) => {
6359
6467
  let body = "";
6360
6468
  req.on("data", (chunk) => {
6361
6469
  body += chunk.toString();
6362
6470
  });
6363
- req.on("end", () => resolve17(body));
6471
+ req.on("end", () => resolve18(body));
6364
6472
  req.on("error", reject);
6365
6473
  });
6366
6474
  }
@@ -7107,17 +7215,17 @@ async function stopDaemon() {
7107
7215
  }
7108
7216
  }
7109
7217
  function closedBeforeTimeout(socket) {
7110
- return new Promise((resolve17) => {
7218
+ return new Promise((resolve18) => {
7111
7219
  const timer = setTimeout(() => {
7112
7220
  socket.destroy();
7113
- resolve17(false);
7221
+ resolve18(false);
7114
7222
  }, STOP_TIMEOUT_MS);
7115
7223
  socket.resume();
7116
7224
  socket.on("error", () => {
7117
7225
  });
7118
7226
  socket.once("close", () => {
7119
7227
  clearTimeout(timer);
7120
- resolve17(true);
7228
+ resolve18(true);
7121
7229
  });
7122
7230
  });
7123
7231
  }
@@ -7168,8 +7276,8 @@ async function restartWeb(req, res, deps2 = {}) {
7168
7276
  respondJson(res, 400, { error: "Invalid target" });
7169
7277
  return;
7170
7278
  }
7171
- await new Promise((resolve17) => {
7172
- res.once("finish", resolve17);
7279
+ await new Promise((resolve18) => {
7280
+ res.once("finish", resolve18);
7173
7281
  respondJson(res, 200, { ok: true });
7174
7282
  });
7175
7283
  if (target === "daemon" || target === "both") {
@@ -7618,12 +7726,12 @@ import chalk61 from "chalk";
7618
7726
  import { eq as eq17 } from "drizzle-orm";
7619
7727
 
7620
7728
  // src/commands/jira/fetchIssue.ts
7621
- import { execSync as execSync23 } from "child_process";
7729
+ import { execSync as execSync25 } from "child_process";
7622
7730
  import chalk60 from "chalk";
7623
7731
  function fetchIssue(issueKey, fields) {
7624
7732
  let result;
7625
7733
  try {
7626
- result = execSync23(
7734
+ result = execSync25(
7627
7735
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
7628
7736
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
7629
7737
  );
@@ -8225,7 +8333,10 @@ function registerItemCommands(cmd) {
8225
8333
  "--status <type>",
8226
8334
  "Filter by status (todo, in-progress, done, wontdo)"
8227
8335
  ).option("-a, --all", "Include done/wontdo items").option("--all-repos", "List items across all repositories").option("-v, --verbose", "Show all item details").action(list2);
8228
- cmd.command("add").description("Add a new backlog item").option("--name <name>", "Item name").option("--type <type>", "Item type (story or bug)").option("--desc <description>", "Item description").option("--ac <criterion...>", "Acceptance criteria (repeatable)").action(add);
8336
+ cmd.command("add").description("Add a new backlog item").option("--name <name>", "Item name").option("--type <type>", "Item type (story or bug)").option(
8337
+ "--desc <description>",
8338
+ String.raw`Item description (Markdown supported; use \n for line breaks)`
8339
+ ).option("--ac <criterion...>", "Acceptance criteria (repeatable)").action(add);
8229
8340
  cmd.command("add-phase <id> <name>").description("Add a phase to an existing backlog item").option("--task <task...>", "Task description (repeatable)").option(
8230
8341
  "--manual-check <check...>",
8231
8342
  "Manual check description (repeatable)"
@@ -8848,7 +8959,8 @@ async function addSubtask(id2, options2) {
8848
8959
  return;
8849
8960
  }
8850
8961
  const { orm, item } = found;
8851
- await insertSubtask(orm, item.id, title, options2.desc);
8962
+ const description = options2.desc?.replaceAll(String.raw`\n`, "\n");
8963
+ await insertSubtask(orm, item.id, title, description);
8852
8964
  console.log(chalk91.green(`Added sub-task to item #${id2}: ${title}`));
8853
8965
  }
8854
8966
 
@@ -8897,7 +9009,10 @@ async function subtaskStatus(id2, index3, status2) {
8897
9009
 
8898
9010
  // src/commands/backlog/registerSubtaskCommands.ts
8899
9011
  function registerSubtaskCommands(cmd) {
8900
- cmd.command("add-subtask <id>").description("Add a sub-task to an existing backlog item").requiredOption("--title <title>", "Sub-task title").option("--desc <description>", "Sub-task description").action(addSubtask);
9012
+ cmd.command("add-subtask <id>").description("Add a sub-task to an existing backlog item").requiredOption("--title <title>", "Sub-task title").option(
9013
+ "--desc <description>",
9014
+ String.raw`Sub-task description (Markdown supported; use \n for line breaks)`
9015
+ ).action(addSubtask);
8901
9016
  cmd.command("subtask-status <id> <idx> <status>").description(
8902
9017
  "Set a sub-task's status (todo, in-progress, done) by its 1-based index"
8903
9018
  ).action(subtaskStatus);
@@ -9272,7 +9387,7 @@ function buildUpdateValues(options2) {
9272
9387
  fieldNames.push("name");
9273
9388
  }
9274
9389
  if (desc6) {
9275
- set.description = desc6;
9390
+ set.description = desc6.replaceAll(String.raw`\n`, "\n");
9276
9391
  fieldNames.push("description");
9277
9392
  }
9278
9393
  if (type) {
@@ -9320,7 +9435,10 @@ function collect2(value, previous) {
9320
9435
  return [...previous, value];
9321
9436
  }
9322
9437
  function registerUpdateCommands(cmd) {
9323
- cmd.command("update-field <id>").description("Update fields on a backlog item").option("--name <name>", "New item name").option("--desc <description>", "New description").option("--type <type>", "New type (story or bug)").option("--ac <criterion...>", "Replace acceptance criteria (repeatable)").option(
9438
+ cmd.command("update-field <id>").description("Update fields on a backlog item").option("--name <name>", "New item name").option(
9439
+ "--desc <description>",
9440
+ String.raw`New description (Markdown supported; use \n for line breaks)`
9441
+ ).option("--type <type>", "New type (story or bug)").option("--ac <criterion...>", "Replace acceptance criteria (repeatable)").option(
9324
9442
  "--add-ac <text>",
9325
9443
  "Append one acceptance criterion (repeatable)",
9326
9444
  collect2,
@@ -9372,40 +9490,6 @@ function registerBacklog(program2) {
9372
9490
  }
9373
9491
  }
9374
9492
 
9375
- // src/commands/branch/branch.ts
9376
- import { execSync as execSync25 } from "child_process";
9377
-
9378
- // src/commands/branch/buildBranchName.ts
9379
- function buildBranchName({
9380
- prefix: prefix2,
9381
- jira,
9382
- slug
9383
- }) {
9384
- const segments = [];
9385
- if (prefix2) segments.push(`${prefix2}/`);
9386
- if (jira) segments.push(`${jira}-`);
9387
- segments.push(slug);
9388
- return segments.join("");
9389
- }
9390
-
9391
- // src/commands/branch/resolveDefaultBranch.ts
9392
- import { execSync as execSync24 } from "child_process";
9393
- var REMOTE_HEAD_REGEX = /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/m;
9394
- function resolveDefaultBranch(override, cwd) {
9395
- if (override) return override;
9396
- try {
9397
- const output = execSync24("git ls-remote --symref origin HEAD", {
9398
- encoding: "utf8",
9399
- stdio: ["pipe", "pipe", "pipe"],
9400
- cwd
9401
- });
9402
- const match = output.match(REMOTE_HEAD_REGEX);
9403
- if (match) return match[1];
9404
- } catch {
9405
- }
9406
- return "main";
9407
- }
9408
-
9409
9493
  // src/commands/branch/validateSlug.ts
9410
9494
  var KEBAB_CASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
9411
9495
  var HASH_REF_REGEX = /#\d+/;
@@ -9433,23 +9517,14 @@ async function branch(slug, options2) {
9433
9517
  console.error(`Error: ${slugError}`);
9434
9518
  process.exit(1);
9435
9519
  }
9436
- const config = loadConfig();
9437
- const branchName = buildBranchName({
9438
- prefix: config.branch?.prefix,
9439
- jira: options2.jira,
9440
- slug
9441
- });
9442
9520
  try {
9443
- const defaultBranch = resolveDefaultBranch(config.branch?.defaultBranch);
9444
- execSync25("git fetch", { stdio: "inherit" });
9445
- execSync25(
9446
- `git switch -c ${shellQuote(branchName)} ${shellQuote(`origin/${defaultBranch}`)}`,
9447
- { stdio: "inherit" }
9448
- );
9521
+ const { branchName, defaultBranch } = await createBranch({
9522
+ slug,
9523
+ jira: options2.jira
9524
+ });
9449
9525
  console.log(
9450
9526
  `Created and switched to ${branchName} (from origin/${defaultBranch})`
9451
9527
  );
9452
- await recordBranchActivity(branchName);
9453
9528
  process.exit(0);
9454
9529
  } catch (error) {
9455
9530
  console.error(
@@ -9458,12 +9533,6 @@ async function branch(slug, options2) {
9458
9533
  process.exit(1);
9459
9534
  }
9460
9535
  }
9461
- async function recordBranchActivity(branchName) {
9462
- if (resolveSessionItemId() === null) return;
9463
- await recordSessionRefs([
9464
- { kind: "branch", ref: branchName, url: gitRefUrl("branch", branchName) }
9465
- ]);
9466
- }
9467
9536
 
9468
9537
  // src/commands/registerBranch.ts
9469
9538
  function registerBranch(program2) {
@@ -10246,12 +10315,12 @@ function hasSubcommands(helpText) {
10246
10315
  // src/commands/permitCliReads/runHelp.ts
10247
10316
  import { exec as exec2 } from "child_process";
10248
10317
  function runHelp(args) {
10249
- return new Promise((resolve17) => {
10318
+ return new Promise((resolve18) => {
10250
10319
  exec2(
10251
10320
  `${args.join(" ")} --help`,
10252
10321
  { encoding: "utf8", timeout: 3e4 },
10253
10322
  (_err, stdout, stderr) => {
10254
- resolve17(stdout || stderr || "");
10323
+ resolve18(stdout || stderr || "");
10255
10324
  }
10256
10325
  );
10257
10326
  });
@@ -13890,25 +13959,25 @@ function isVisibleText(t) {
13890
13959
  return /[a-zA-Z]{3,}/.test(t);
13891
13960
  }
13892
13961
  var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
13893
- function collectRscText(v, resolve17, sink2, seen) {
13962
+ function collectRscText(v, resolve18, sink2, seen) {
13894
13963
  if (v == null) return;
13895
13964
  if (typeof v === "string") {
13896
13965
  if (isRscRef(v)) {
13897
13966
  if (!seen.has(v)) {
13898
13967
  seen.add(v);
13899
- collectRscText(resolve17(v), resolve17, sink2, seen);
13968
+ collectRscText(resolve18(v), resolve18, sink2, seen);
13900
13969
  }
13901
13970
  } else if (isHashtag(v)) sink2.hashtags.push(v);
13902
13971
  else if (isVisibleText(v)) sink2.text.push(v);
13903
13972
  return;
13904
13973
  }
13905
13974
  if (Array.isArray(v)) {
13906
- for (const x of v) collectRscText(x, resolve17, sink2, seen);
13975
+ for (const x of v) collectRscText(x, resolve18, sink2, seen);
13907
13976
  return;
13908
13977
  }
13909
13978
  if (typeof v === "object") {
13910
13979
  for (const val of Object.values(v)) {
13911
- collectRscText(val, resolve17, sink2, seen);
13980
+ collectRscText(val, resolve18, sink2, seen);
13912
13981
  }
13913
13982
  }
13914
13983
  }
@@ -13940,7 +14009,7 @@ function visitObjects(root, fn) {
13940
14009
  }
13941
14010
  }
13942
14011
  }
13943
- function buildMentionMap(rows, resolve17) {
14012
+ function buildMentionMap(rows, resolve18) {
13944
14013
  const map = /* @__PURE__ */ new Map();
13945
14014
  visitObjects(rows, (o) => {
13946
14015
  const url = profileActionUrl(o);
@@ -13948,7 +14017,7 @@ function buildMentionMap(rows, resolve17) {
13948
14017
  const slug = slugFromProfileUrl(url);
13949
14018
  if (!slug || map.has(slug)) return;
13950
14019
  const sink2 = { text: [], hashtags: [] };
13951
- collectRscText(o.children, resolve17, sink2, /* @__PURE__ */ new Set());
14020
+ collectRscText(o.children, resolve18, sink2, /* @__PURE__ */ new Set());
13952
14021
  const name = sink2.text.join(" ").replace(/\s+/g, " ").trim();
13953
14022
  map.set(slug, name ? { slug, name, url } : { slug, url });
13954
14023
  });
@@ -14034,10 +14103,10 @@ function buildPost(raw, mentionMap, author) {
14034
14103
 
14035
14104
  // src/commands/netcap/walkPostRow.ts
14036
14105
  var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
14037
- function walkPostRow(v, resolve17, raw) {
14106
+ function walkPostRow(v, resolve18, raw) {
14038
14107
  if (v == null || typeof v !== "object") return;
14039
14108
  if (Array.isArray(v)) {
14040
- for (const x of v) walkPostRow(x, resolve17, raw);
14109
+ for (const x of v) walkPostRow(x, resolve18, raw);
14041
14110
  return;
14042
14111
  }
14043
14112
  const o = v;
@@ -14051,9 +14120,9 @@ function walkPostRow(v, resolve17, raw) {
14051
14120
  }
14052
14121
  if (isCommentary(o)) {
14053
14122
  const sink2 = { text: raw.text, hashtags: raw.hashtags };
14054
- collectRscText(o.children, resolve17, sink2, /* @__PURE__ */ new Set());
14123
+ collectRscText(o.children, resolve18, sink2, /* @__PURE__ */ new Set());
14055
14124
  }
14056
- for (const val of Object.values(o)) walkPostRow(val, resolve17, raw);
14125
+ for (const val of Object.values(o)) walkPostRow(val, resolve18, raw);
14057
14126
  }
14058
14127
 
14059
14128
  // src/commands/netcap/extractLinkedInPosts.ts
@@ -14067,8 +14136,8 @@ function findCommentaryRows(rows) {
14067
14136
  }
14068
14137
  function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
14069
14138
  const rows = parseRscRows(flight);
14070
- const resolve17 = makeRscResolver(rows);
14071
- const mentionMap = buildMentionMap(rows, resolve17);
14139
+ const resolve18 = makeRscResolver(rows);
14140
+ const mentionMap = buildMentionMap(rows, resolve18);
14072
14141
  const posts = [];
14073
14142
  for (const id2 of findCommentaryRows(rows)) {
14074
14143
  const raw = {
@@ -14078,7 +14147,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
14078
14147
  links: [],
14079
14148
  related: []
14080
14149
  };
14081
- walkPostRow(rows[id2], resolve17, raw);
14150
+ walkPostRow(rows[id2], resolve18, raw);
14082
14151
  const post = buildPost(raw, mentionMap, author);
14083
14152
  if (post) posts.push(post);
14084
14153
  }
@@ -15957,7 +16026,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
15957
16026
 
15958
16027
  // src/commands/refactor/check/index.ts
15959
16028
  function runScript(script, cwd) {
15960
- return new Promise((resolve17) => {
16029
+ return new Promise((resolve18) => {
15961
16030
  const child = spawn5("npm", ["run", script], {
15962
16031
  stdio: "pipe",
15963
16032
  shell: true,
@@ -15971,7 +16040,7 @@ function runScript(script, cwd) {
15971
16040
  output += data.toString();
15972
16041
  });
15973
16042
  child.on("close", (code) => {
15974
- resolve17({ script, code: code ?? 1, output });
16043
+ resolve18({ script, code: code ?? 1, output });
15975
16044
  });
15976
16045
  });
15977
16046
  }
@@ -18717,12 +18786,12 @@ function onCloseResult(ctx, code) {
18717
18786
  return { ...closed, stderr: ctx.stderr.value, stdout: ctx.stdout.value };
18718
18787
  }
18719
18788
  function waitForChildExit(ctx) {
18720
- return new Promise((resolve17) => {
18789
+ return new Promise((resolve18) => {
18721
18790
  let settled = false;
18722
18791
  const settle = (result) => {
18723
18792
  if (settled) return;
18724
18793
  settled = true;
18725
- resolve17(result);
18794
+ resolve18(result);
18726
18795
  };
18727
18796
  ctx.child.on("error", (err) => settle(onErrorResult(ctx, err)));
18728
18797
  ctx.child.on("close", (code) => settle(onCloseResult(ctx, code)));
@@ -19799,9 +19868,9 @@ function createReadlineInterface() {
19799
19868
  });
19800
19869
  }
19801
19870
  function askQuestion(rl, question) {
19802
- return new Promise((resolve17) => {
19871
+ return new Promise((resolve18) => {
19803
19872
  rl.question(question, (answer) => {
19804
- resolve17(answer.trim());
19873
+ resolve18(answer.trim());
19805
19874
  });
19806
19875
  });
19807
19876
  }
@@ -20449,7 +20518,7 @@ function extractCode(url, expectedState) {
20449
20518
  return code;
20450
20519
  }
20451
20520
  function waitForCallback(port, expectedState) {
20452
- return new Promise((resolve17, reject) => {
20521
+ return new Promise((resolve18, reject) => {
20453
20522
  const timeout = setTimeout(() => {
20454
20523
  server.close();
20455
20524
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -20466,7 +20535,7 @@ function waitForCallback(port, expectedState) {
20466
20535
  const code = extractCode(url, expectedState);
20467
20536
  respondHtml(res, 200, "Authorization successful!");
20468
20537
  server.close();
20469
- resolve17(code);
20538
+ resolve18(code);
20470
20539
  } catch (error) {
20471
20540
  respondHtml(res, 400, error.message);
20472
20541
  server.close();
@@ -21215,10 +21284,10 @@ var STATUS_TIMEOUT_MS = 5e3;
21215
21284
  function queryDaemon(socket) {
21216
21285
  socket.write(`${JSON.stringify({ type: "ping" })}
21217
21286
  `);
21218
- return new Promise((resolve17) => {
21287
+ return new Promise((resolve18) => {
21219
21288
  const result = { sessions: [] };
21220
21289
  const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
21221
- const timer = setTimeout(() => resolve17(result), STATUS_TIMEOUT_MS);
21290
+ const timer = setTimeout(() => resolve18(result), STATUS_TIMEOUT_MS);
21222
21291
  const lines = createInterface5({ input: socket });
21223
21292
  lines.on("error", () => {
21224
21293
  });
@@ -21226,7 +21295,7 @@ function queryDaemon(socket) {
21226
21295
  applyLine(result, pending, line);
21227
21296
  if (pending.size === 0) {
21228
21297
  clearTimeout(timer);
21229
- resolve17(result);
21298
+ resolve18(result);
21230
21299
  }
21231
21300
  });
21232
21301
  });
@@ -21412,8 +21481,8 @@ async function drainDaemon() {
21412
21481
  function requestDrain(socket) {
21413
21482
  socket.write(`${JSON.stringify({ type: "drain" })}
21414
21483
  `);
21415
- return new Promise((resolve17) => {
21416
- const timer = setTimeout(() => resolve17(0), DRAIN_TIMEOUT_MS);
21484
+ return new Promise((resolve18) => {
21485
+ const timer = setTimeout(() => resolve18(0), DRAIN_TIMEOUT_MS);
21417
21486
  const lines = createInterface6({ input: socket });
21418
21487
  lines.on("error", () => {
21419
21488
  });
@@ -21422,7 +21491,7 @@ function requestDrain(socket) {
21422
21491
  const data = JSON.parse(line);
21423
21492
  if (data.type === "drained") {
21424
21493
  clearTimeout(timer);
21425
- resolve17(data.count ?? 0);
21494
+ resolve18(data.count ?? 0);
21426
21495
  }
21427
21496
  } catch {
21428
21497
  }
@@ -22508,7 +22577,7 @@ function windowsDaemonHost() {
22508
22577
  var CONNECT_TIMEOUT_MS = 2e3;
22509
22578
  var KEEPALIVE_PROBE_MS = 1e4;
22510
22579
  function connectToWindowsDaemon() {
22511
- return new Promise((resolve17, reject) => {
22580
+ return new Promise((resolve18, reject) => {
22512
22581
  const socket = net2.connect(windowsDaemonPort(), windowsDaemonHost());
22513
22582
  socket.setTimeout(CONNECT_TIMEOUT_MS);
22514
22583
  socket.once("timeout", () => {
@@ -22518,7 +22587,7 @@ function connectToWindowsDaemon() {
22518
22587
  socket.once("connect", () => {
22519
22588
  socket.setTimeout(0);
22520
22589
  socket.setKeepAlive(true, KEEPALIVE_PROBE_MS);
22521
- resolve17(socket);
22590
+ resolve18(socket);
22522
22591
  });
22523
22592
  socket.once("error", reject);
22524
22593
  });
@@ -22596,7 +22665,7 @@ async function waitForWindowsDaemon() {
22596
22665
  );
22597
22666
  }
22598
22667
  function delay2(ms) {
22599
- return new Promise((resolve17) => setTimeout(resolve17, ms));
22668
+ return new Promise((resolve18) => setTimeout(resolve18, ms));
22600
22669
  }
22601
22670
 
22602
22671
  // src/commands/sessions/daemon/defaultConnect.ts
@@ -22844,7 +22913,7 @@ async function healWindowsDaemon() {
22844
22913
  daemonLog("windows daemon: auto-heal: stale daemon stopped");
22845
22914
  }
22846
22915
  function runOnWindowsHost(command, timeoutMs) {
22847
- return new Promise((resolve17, reject) => {
22916
+ return new Promise((resolve18, reject) => {
22848
22917
  const child = spawn11("pwsh.exe", ["-Command", command], {
22849
22918
  stdio: ["ignore", "pipe", "pipe"]
22850
22919
  });
@@ -22864,7 +22933,7 @@ function runOnWindowsHost(command, timeoutMs) {
22864
22933
  });
22865
22934
  child.on("exit", (code) => {
22866
22935
  clearTimeout(timer);
22867
- if (code === 0) resolve17();
22936
+ if (code === 0) resolve18();
22868
22937
  else
22869
22938
  reject(
22870
22939
  new Error(
@@ -24133,6 +24202,48 @@ function buildLimitsSegment(rateLimits) {
24133
24202
  return ` | Limits - ${fiveHr}, ${sevenDay}`;
24134
24203
  }
24135
24204
 
24205
+ // src/commands/readGitBranch.ts
24206
+ import { readFileSync as readFileSync47, statSync as statSync11 } from "fs";
24207
+ import { isAbsolute as isAbsolute2, join as join63, resolve as resolve16 } from "path";
24208
+ function resolveGitDir(cwd) {
24209
+ const dotGit = join63(cwd, ".git");
24210
+ let stat2;
24211
+ try {
24212
+ stat2 = statSync11(dotGit);
24213
+ } catch {
24214
+ return null;
24215
+ }
24216
+ if (stat2.isDirectory()) {
24217
+ return dotGit;
24218
+ }
24219
+ let contents;
24220
+ try {
24221
+ contents = readFileSync47(dotGit, "utf8");
24222
+ } catch {
24223
+ return null;
24224
+ }
24225
+ const match = /^gitdir:\s*(.+)$/m.exec(contents.trim());
24226
+ if (!match) {
24227
+ return null;
24228
+ }
24229
+ const gitDir = match[1].trim();
24230
+ return isAbsolute2(gitDir) ? gitDir : resolve16(cwd, gitDir);
24231
+ }
24232
+ function readGitBranch(cwd) {
24233
+ const gitDir = resolveGitDir(cwd);
24234
+ if (!gitDir) {
24235
+ return null;
24236
+ }
24237
+ let head;
24238
+ try {
24239
+ head = readFileSync47(join63(gitDir, "HEAD"), "utf8");
24240
+ } catch {
24241
+ return null;
24242
+ }
24243
+ const match = /^ref:\s*refs\/heads\/(.+)$/m.exec(head.trim());
24244
+ return match ? match[1] : null;
24245
+ }
24246
+
24136
24247
  // src/commands/relayRateLimits.ts
24137
24248
  async function relayRateLimits(rateLimits) {
24138
24249
  if (!rateLimits) return;
@@ -24168,8 +24279,11 @@ async function statusLine() {
24168
24279
  const model = data.model.display_name;
24169
24280
  const { total_input_tokens: totalIn, total_output_tokens: totalOut } = data.context_window;
24170
24281
  const usedPct = data.context_window.used_percentage ?? 0;
24282
+ const dir = data.workspace?.current_dir ?? data.cwd;
24283
+ const branch2 = dir ? readGitBranch(windowsCwdToWslPath(dir)) : null;
24284
+ const branchSegment = branch2 ? `\u{1F343}\uFE0F ${chalk191.cyan(branch2)} | ` : "";
24171
24285
  console.log(
24172
- `${model} | Tokens - ${formatNumber(totalOut)} \u2191 : ${formatNumber(totalIn)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
24286
+ `${branchSegment}${model} | Tokens - ${formatNumber(totalOut)} \u2191 : ${formatNumber(totalIn)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
24173
24287
  );
24174
24288
  await relayRateLimits(data.rate_limits);
24175
24289
  await relayUsage(data.session_id, totalIn, totalOut);