@staff0rd/assist 0.286.0 → 0.288.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.286.0",
9
+ version: "0.288.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -5003,18 +5003,28 @@ function getCwdParam(req, res) {
5003
5003
  return cwd;
5004
5004
  }
5005
5005
 
5006
+ // src/commands/sessions/web/windowsCwdToWslPath.ts
5007
+ function windowsCwdToWslPath(cwd) {
5008
+ const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
5009
+ if (!match) return cwd;
5010
+ const drive = match[1].toLowerCase();
5011
+ const rest = match[2].replace(/\\/g, "/");
5012
+ return `/mnt/${drive}/${rest}`;
5013
+ }
5014
+
5006
5015
  // src/commands/sessions/web/githubUrl.ts
5007
5016
  function githubUrl(req, res) {
5008
5017
  const cwd = getCwdParam(req, res);
5009
5018
  if (!cwd) return;
5010
- const repo = getPreferredRemoteRepo(cwd);
5019
+ const repo = getPreferredRemoteRepo(windowsCwdToWslPath(cwd));
5011
5020
  respondJson(res, 200, {
5012
5021
  url: repo ? `https://github.com/${repo.org}/${repo.repo}` : null
5013
5022
  });
5014
5023
  }
5015
5024
 
5016
5025
  // src/commands/sessions/web/gitStatus.ts
5017
- import { execSync as execSync22 } from "child_process";
5026
+ import { execFile } from "child_process";
5027
+ import { promisify } from "util";
5018
5028
 
5019
5029
  // src/commands/sessions/web/parseGitStatus.ts
5020
5030
  function extractPath(rest) {
@@ -5042,20 +5052,24 @@ function parseGitStatus(output) {
5042
5052
  }
5043
5053
 
5044
5054
  // src/commands/sessions/web/gitStatus.ts
5045
- function gitStatus(req, res) {
5055
+ var execFileAsync = promisify(execFile);
5056
+ async function gitStatus(req, res) {
5046
5057
  const cwd = getCwdParam(req, res);
5047
5058
  if (!cwd) return;
5048
5059
  try {
5049
- const output = execSync22("git status --porcelain", {
5050
- encoding: "utf-8",
5051
- stdio: ["pipe", "pipe", "pipe"],
5052
- cwd
5053
- });
5054
- respondJson(res, 200, parseGitStatus(output));
5060
+ respondJson(res, 200, parseGitStatus(await runGitStatus(cwd)));
5055
5061
  } catch {
5056
5062
  respondJson(res, 200, { new: [], modified: [], deleted: [] });
5057
5063
  }
5058
5064
  }
5065
+ function runGitStatus(cwd) {
5066
+ const args = ["status", "--porcelain"];
5067
+ const { file, argv } = /^[A-Za-z]:[\\/]/.test(cwd) ? { file: "git.exe", argv: ["-C", cwd, ...args] } : { file: "git", argv: args };
5068
+ return execFileAsync(file, argv, {
5069
+ encoding: "utf-8",
5070
+ ...file === "git" ? { cwd } : {}
5071
+ }).then((r) => r.stdout);
5072
+ }
5059
5073
 
5060
5074
  // src/commands/news/shared.ts
5061
5075
  import { decodeHTML } from "entities";
@@ -5182,13 +5196,14 @@ async function listNewsItems(_req, res) {
5182
5196
 
5183
5197
  // src/commands/sessions/web/openInCode.ts
5184
5198
  import { exec } from "child_process";
5185
- import { promisify } from "util";
5186
- var execAsync = promisify(exec);
5199
+ import { promisify as promisify2 } from "util";
5200
+ var execAsync = promisify2(exec);
5187
5201
  async function openInCode(req, res) {
5188
5202
  const cwd = getCwdParam(req, res);
5189
5203
  if (!cwd) return;
5190
5204
  try {
5191
- await execAsync(`code "${cwd}"`);
5205
+ const command = /^[A-Za-z]:[\\/]/.test(cwd) ? `cmd.exe /c code "${cwd}"` : `code "${cwd}"`;
5206
+ await execAsync(command);
5192
5207
  respondJson(res, 200, { ok: true });
5193
5208
  } catch {
5194
5209
  respondJson(res, 500, {
@@ -5235,6 +5250,79 @@ var handleRequest = createFallbackHandler(
5235
5250
 
5236
5251
  // src/commands/sessions/web/handleSocket.ts
5237
5252
  import { createInterface as createInterface2 } from "readline";
5253
+
5254
+ // src/commands/sessions/daemon/toWindowsSessionId.ts
5255
+ var PREFIX = "w-";
5256
+ function toWindowsSessionId(id) {
5257
+ return `${PREFIX}${id}`;
5258
+ }
5259
+ function isWindowsSessionId(id) {
5260
+ return id.startsWith(PREFIX);
5261
+ }
5262
+ function stripWindowsSessionId(id) {
5263
+ return id.startsWith(PREFIX) ? id.slice(PREFIX.length) : id;
5264
+ }
5265
+
5266
+ // src/commands/sessions/web/ui/repoLabel.ts
5267
+ function repoLabel(cwd) {
5268
+ if (!cwd) return "";
5269
+ const segments = cwd.split(/[/\\]/).filter(Boolean);
5270
+ return segments[segments.length - 1] ?? "";
5271
+ }
5272
+
5273
+ // src/commands/sessions/web/createSessionLifecycleLogger.ts
5274
+ function createSessionLifecycleLogger() {
5275
+ const known = /* @__PURE__ */ new Map();
5276
+ return (line) => {
5277
+ const sessions = parseSnapshot(line);
5278
+ if (sessions) applySnapshot(known, sessions);
5279
+ };
5280
+ }
5281
+ function parseSnapshot(line) {
5282
+ try {
5283
+ const data = JSON.parse(line);
5284
+ if (data.type === "sessions" && Array.isArray(data.sessions))
5285
+ return data.sessions;
5286
+ } catch {
5287
+ }
5288
+ return null;
5289
+ }
5290
+ function applySnapshot(known, sessions) {
5291
+ const present = /* @__PURE__ */ new Set();
5292
+ for (const session of sessions) {
5293
+ present.add(session.id);
5294
+ const previous = known.get(session.id);
5295
+ known.set(session.id, session);
5296
+ if (previous === void 0) logEvent("started", session);
5297
+ else if (isDone(session) && !isDone(previous)) logEvent("ended", session);
5298
+ }
5299
+ for (const [id, session] of [...known]) {
5300
+ if (present.has(id)) continue;
5301
+ known.delete(id);
5302
+ if (!isDone(session)) logEvent("ended", session);
5303
+ }
5304
+ }
5305
+ function isDone(session) {
5306
+ return session.status === "done";
5307
+ }
5308
+ function logEvent(event, session) {
5309
+ const origin = isWindowsSessionId(session.id) ? "windows" : "wsl";
5310
+ console.log(
5311
+ `${(/* @__PURE__ */ new Date()).toISOString()} session ${event}: ${session.id}${describe(session)} [${origin} daemon]`
5312
+ );
5313
+ }
5314
+ function describe(session) {
5315
+ const parts = [];
5316
+ const repo = repoLabel(session.cwd);
5317
+ if (repo) parts.push(repo);
5318
+ const { itemId, phase, totalPhases } = session.activity ?? {};
5319
+ if (itemId !== void 0) parts.push(`#${itemId}`);
5320
+ if (phase !== void 0)
5321
+ parts.push(`phase ${phase}${totalPhases ? `/${totalPhases}` : ""}`);
5322
+ return parts.length ? ` ${parts.join(" ")}` : "";
5323
+ }
5324
+
5325
+ // src/commands/sessions/web/handleSocket.ts
5238
5326
  var CWD_DEFAULTED_TYPES = /* @__PURE__ */ new Set(["create", "create-run", "create-assist"]);
5239
5327
  function handleSocket(ws, ctx) {
5240
5328
  const connection = openDaemonConnection(ws, ctx);
@@ -5266,6 +5354,7 @@ function relayDaemonLines(conn, ws, repoCwd) {
5266
5354
  lines.on("error", () => {
5267
5355
  });
5268
5356
  lines.on("line", (line) => {
5357
+ logSessionLifecycle(line);
5269
5358
  if (ws.readyState === ws.OPEN) ws.send(withRepoCwd(line, repoCwd));
5270
5359
  });
5271
5360
  conn.on("error", () => {
@@ -5292,6 +5381,7 @@ function withDefaultCwd(raw, serverCwd) {
5292
5381
  return raw;
5293
5382
  }
5294
5383
  }
5384
+ var logSessionLifecycle = createSessionLifecycleLogger();
5295
5385
  function withRepoCwd(line, repoCwd) {
5296
5386
  if (!repoCwd) return line;
5297
5387
  try {
@@ -7798,7 +7888,7 @@ import { homedir as homedir9 } from "os";
7798
7888
  import { join as join22 } from "path";
7799
7889
 
7800
7890
  // src/shared/checkCliAvailable.ts
7801
- import { execSync as execSync23 } from "child_process";
7891
+ import { execSync as execSync22 } from "child_process";
7802
7892
  function checkCliAvailable(cli) {
7803
7893
  const binary = cli.split(/\s+/)[0];
7804
7894
  const opts = {
@@ -7806,11 +7896,11 @@ function checkCliAvailable(cli) {
7806
7896
  stdio: ["ignore", "pipe", "pipe"]
7807
7897
  };
7808
7898
  try {
7809
- execSync23(`command -v ${binary}`, opts);
7899
+ execSync22(`command -v ${binary}`, opts);
7810
7900
  return true;
7811
7901
  } catch {
7812
7902
  try {
7813
- execSync23(`where ${binary}`, opts);
7903
+ execSync22(`where ${binary}`, opts);
7814
7904
  return true;
7815
7905
  } catch {
7816
7906
  return false;
@@ -8946,7 +9036,7 @@ function loadBlogSkipDays(repoName) {
8946
9036
  }
8947
9037
 
8948
9038
  // src/commands/devlog/shared.ts
8949
- import { execSync as execSync24 } from "child_process";
9039
+ import { execSync as execSync23 } from "child_process";
8950
9040
  import chalk92 from "chalk";
8951
9041
 
8952
9042
  // src/shared/getRepoName.ts
@@ -9038,7 +9128,7 @@ function loadAllDevlogLatestDates() {
9038
9128
  // src/commands/devlog/shared.ts
9039
9129
  function getCommitFiles(hash) {
9040
9130
  try {
9041
- const output = execSync24(`git show --name-only --format="" ${hash}`, {
9131
+ const output = execSync23(`git show --name-only --format="" ${hash}`, {
9042
9132
  encoding: "utf-8"
9043
9133
  });
9044
9134
  return output.trim().split("\n").filter(Boolean);
@@ -9134,11 +9224,11 @@ function list3(options2) {
9134
9224
  }
9135
9225
 
9136
9226
  // src/commands/devlog/getLastVersionInfo.ts
9137
- import { execFileSync as execFileSync2, execSync as execSync25 } from "child_process";
9227
+ import { execFileSync as execFileSync2, execSync as execSync24 } from "child_process";
9138
9228
  import semver from "semver";
9139
9229
  function getVersionAtCommit(hash) {
9140
9230
  try {
9141
- const content = execSync25(`git show ${hash}:package.json`, {
9231
+ const content = execSync24(`git show ${hash}:package.json`, {
9142
9232
  encoding: "utf-8"
9143
9233
  });
9144
9234
  const pkg = JSON.parse(content);
@@ -9311,7 +9401,7 @@ function next2(options2) {
9311
9401
  }
9312
9402
 
9313
9403
  // src/commands/devlog/repos/index.ts
9314
- import { execSync as execSync26 } from "child_process";
9404
+ import { execSync as execSync25 } from "child_process";
9315
9405
 
9316
9406
  // src/commands/devlog/repos/printReposTable.ts
9317
9407
  import chalk96 from "chalk";
@@ -9346,7 +9436,7 @@ function getStatus(lastPush, lastDevlog) {
9346
9436
  return lastDevlog < lastPush ? "outdated" : "ok";
9347
9437
  }
9348
9438
  function fetchRepos(days, all) {
9349
- const json = execSync26(
9439
+ const json = execSync25(
9350
9440
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
9351
9441
  { encoding: "utf-8" }
9352
9442
  );
@@ -9706,7 +9796,7 @@ async function deps(csprojPath, options2) {
9706
9796
  }
9707
9797
 
9708
9798
  // src/commands/dotnet/getChangedCsFiles.ts
9709
- import { execSync as execSync27 } from "child_process";
9799
+ import { execSync as execSync26 } from "child_process";
9710
9800
  var SCOPE_ALL = "all";
9711
9801
  var SCOPE_BASE = "base:";
9712
9802
  var SCOPE_COMMIT = "commit:";
@@ -9730,7 +9820,7 @@ function getChangedCsFiles(scope) {
9730
9820
  } else {
9731
9821
  cmd = "git diff --name-only HEAD";
9732
9822
  }
9733
- const output = execSync27(cmd, { encoding: "utf-8" }).trim();
9823
+ const output = execSync26(cmd, { encoding: "utf-8" }).trim();
9734
9824
  if (output === "") return [];
9735
9825
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
9736
9826
  }
@@ -9928,14 +10018,14 @@ function parseInspectReport(json) {
9928
10018
  }
9929
10019
 
9930
10020
  // src/commands/dotnet/runInspectCode.ts
9931
- import { execSync as execSync28 } from "child_process";
10021
+ import { execSync as execSync27 } from "child_process";
9932
10022
  import { existsSync as existsSync30, readFileSync as readFileSync24, unlinkSync as unlinkSync7 } from "fs";
9933
10023
  import { tmpdir as tmpdir3 } from "os";
9934
10024
  import path25 from "path";
9935
10025
  import chalk106 from "chalk";
9936
10026
  function assertJbInstalled() {
9937
10027
  try {
9938
- execSync28("jb inspectcode --version", { stdio: "pipe" });
10028
+ execSync27("jb inspectcode --version", { stdio: "pipe" });
9939
10029
  } catch {
9940
10030
  console.error(chalk106.red("jb is not installed. Install with:"));
9941
10031
  console.error(
@@ -9949,7 +10039,7 @@ function runInspectCode(slnPath, include, swea) {
9949
10039
  const includeFlag = include ? ` --include="${include}"` : "";
9950
10040
  const sweaFlag = swea ? " --swea" : "";
9951
10041
  try {
9952
- execSync28(
10042
+ execSync27(
9953
10043
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
9954
10044
  { stdio: "pipe" }
9955
10045
  );
@@ -9970,7 +10060,7 @@ function runInspectCode(slnPath, include, swea) {
9970
10060
  }
9971
10061
 
9972
10062
  // src/commands/dotnet/runRoslynInspect.ts
9973
- import { execSync as execSync29 } from "child_process";
10063
+ import { execSync as execSync28 } from "child_process";
9974
10064
  import chalk107 from "chalk";
9975
10065
  function resolveMsbuildPath() {
9976
10066
  const { run: run4 } = loadConfig();
@@ -9981,7 +10071,7 @@ function resolveMsbuildPath() {
9981
10071
  function assertMsbuildInstalled() {
9982
10072
  const msbuild = resolveMsbuildPath();
9983
10073
  try {
9984
- execSync29(`"${msbuild}" -version`, { stdio: "pipe" });
10074
+ execSync28(`"${msbuild}" -version`, { stdio: "pipe" });
9985
10075
  } catch {
9986
10076
  console.error(chalk107.red(`msbuild not found at: ${msbuild}`));
9987
10077
  console.error(
@@ -10007,7 +10097,7 @@ function runRoslynInspect(slnPath) {
10007
10097
  const msbuild = resolveMsbuildPath();
10008
10098
  let output;
10009
10099
  try {
10010
- output = execSync29(
10100
+ output = execSync28(
10011
10101
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
10012
10102
  { encoding: "utf-8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
10013
10103
  );
@@ -10585,12 +10675,12 @@ function adfToText(doc) {
10585
10675
  }
10586
10676
 
10587
10677
  // src/commands/jira/fetchIssue.ts
10588
- import { execSync as execSync30 } from "child_process";
10678
+ import { execSync as execSync29 } from "child_process";
10589
10679
  import chalk111 from "chalk";
10590
10680
  function fetchIssue(issueKey, fields) {
10591
10681
  let result;
10592
10682
  try {
10593
- result = execSync30(
10683
+ result = execSync29(
10594
10684
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
10595
10685
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
10596
10686
  );
@@ -10636,7 +10726,7 @@ function acceptanceCriteria(issueKey) {
10636
10726
  }
10637
10727
 
10638
10728
  // src/commands/jira/jiraAuth.ts
10639
- import { execSync as execSync31 } from "child_process";
10729
+ import { execSync as execSync30 } from "child_process";
10640
10730
 
10641
10731
  // src/shared/loadJson.ts
10642
10732
  import { existsSync as existsSync33, mkdirSync as mkdirSync11, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
@@ -10700,7 +10790,7 @@ async function jiraAuth() {
10700
10790
  console.error("All fields are required.");
10701
10791
  process.exit(1);
10702
10792
  }
10703
- execSync31(`acli jira auth login --site ${site} --email "${email}" --token`, {
10793
+ execSync30(`acli jira auth login --site ${site} --email "${email}" --token`, {
10704
10794
  encoding: "utf-8",
10705
10795
  input: token,
10706
10796
  stdio: ["pipe", "inherit", "inherit"]
@@ -10995,7 +11085,7 @@ function registerPrompts(program2) {
10995
11085
  }
10996
11086
 
10997
11087
  // src/commands/prs/shared.ts
10998
- import { execSync as execSync32 } from "child_process";
11088
+ import { execSync as execSync31 } from "child_process";
10999
11089
  function isGhNotInstalled(error) {
11000
11090
  if (error instanceof Error) {
11001
11091
  const msg = error.message.toLowerCase();
@@ -11013,12 +11103,12 @@ function getRepoInfo() {
11013
11103
  const preferred = getPreferredRemoteRepo();
11014
11104
  if (preferred) return preferred;
11015
11105
  const repoInfo = JSON.parse(
11016
- execSync32("gh repo view --json owner,name", { encoding: "utf-8" })
11106
+ execSync31("gh repo view --json owner,name", { encoding: "utf-8" })
11017
11107
  );
11018
11108
  return { org: repoInfo.owner.login, repo: repoInfo.name };
11019
11109
  }
11020
11110
  function getCurrentBranch() {
11021
- return execSync32("git rev-parse --abbrev-ref HEAD", {
11111
+ return execSync31("git rev-parse --abbrev-ref HEAD", {
11022
11112
  encoding: "utf-8"
11023
11113
  }).trim();
11024
11114
  }
@@ -11026,7 +11116,7 @@ function viewCurrentPr(fields) {
11026
11116
  const { org, repo } = getRepoInfo();
11027
11117
  const branch = getCurrentBranch();
11028
11118
  return JSON.parse(
11029
- execSync32(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
11119
+ execSync31(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
11030
11120
  encoding: "utf-8"
11031
11121
  })
11032
11122
  );
@@ -11130,7 +11220,7 @@ function comment2(path54, line, body, startLine) {
11130
11220
  }
11131
11221
 
11132
11222
  // src/commands/prs/edit.ts
11133
- import { execSync as execSync33 } from "child_process";
11223
+ import { execSync as execSync32 } from "child_process";
11134
11224
 
11135
11225
  // src/commands/prs/buildPrBody.ts
11136
11226
  function jiraBrowseUrl(key) {
@@ -11256,17 +11346,17 @@ function edit(options2) {
11256
11346
  if (options2.title) args.push(`--title ${shellQuote(options2.title)}`);
11257
11347
  args.push(`--body ${shellQuote(newBody)}`);
11258
11348
  try {
11259
- execSync33(args.join(" "), { stdio: "inherit" });
11349
+ execSync32(args.join(" "), { stdio: "inherit" });
11260
11350
  } catch (_error) {
11261
11351
  process.exit(1);
11262
11352
  }
11263
11353
  }
11264
11354
 
11265
11355
  // src/commands/prs/fixed.ts
11266
- import { execSync as execSync35 } from "child_process";
11356
+ import { execSync as execSync34 } from "child_process";
11267
11357
 
11268
11358
  // src/commands/prs/resolveCommentWithReply.ts
11269
- import { execSync as execSync34 } from "child_process";
11359
+ import { execSync as execSync33 } from "child_process";
11270
11360
  import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync23 } from "fs";
11271
11361
  import { tmpdir as tmpdir5 } from "os";
11272
11362
  import { join as join34 } from "path";
@@ -11296,7 +11386,7 @@ function deleteCommentsCache(prNumber) {
11296
11386
 
11297
11387
  // src/commands/prs/resolveCommentWithReply.ts
11298
11388
  function replyToComment(org, repo, prNumber, commentId, message) {
11299
- execSync34(
11389
+ execSync33(
11300
11390
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
11301
11391
  { stdio: ["inherit", "pipe", "inherit"] }
11302
11392
  );
@@ -11306,7 +11396,7 @@ function resolveThread(threadId) {
11306
11396
  const queryFile = join34(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
11307
11397
  writeFileSync23(queryFile, mutation);
11308
11398
  try {
11309
- execSync34(
11399
+ execSync33(
11310
11400
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
11311
11401
  { stdio: ["inherit", "pipe", "inherit"] }
11312
11402
  );
@@ -11358,7 +11448,7 @@ function resolveCommentWithReply(commentId, message) {
11358
11448
  // src/commands/prs/fixed.ts
11359
11449
  function verifySha(sha) {
11360
11450
  try {
11361
- return execSync35(`git rev-parse --verify ${sha}`, {
11451
+ return execSync34(`git rev-parse --verify ${sha}`, {
11362
11452
  encoding: "utf-8"
11363
11453
  }).trim();
11364
11454
  } catch {
@@ -11372,7 +11462,7 @@ function fixed(commentId, sha) {
11372
11462
  const { org, repo } = getRepoInfo();
11373
11463
  const repoUrl = `https://github.com/${org}/${repo}`;
11374
11464
  const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
11375
- execSync35("git push", { stdio: "inherit" });
11465
+ execSync34("git push", { stdio: "inherit" });
11376
11466
  resolveCommentWithReply(commentId, message);
11377
11467
  } catch (error) {
11378
11468
  if (isGhNotInstalled(error)) {
@@ -11390,7 +11480,7 @@ import { join as join36 } from "path";
11390
11480
  import { stringify } from "yaml";
11391
11481
 
11392
11482
  // src/commands/prs/fetchThreadIds.ts
11393
- import { execSync as execSync36 } from "child_process";
11483
+ import { execSync as execSync35 } from "child_process";
11394
11484
  import { unlinkSync as unlinkSync11, writeFileSync as writeFileSync24 } from "fs";
11395
11485
  import { tmpdir as tmpdir6 } from "os";
11396
11486
  import { join as join35 } from "path";
@@ -11399,7 +11489,7 @@ function fetchThreadIds(org, repo, prNumber) {
11399
11489
  const queryFile = join35(tmpdir6(), `gh-query-${Date.now()}.graphql`);
11400
11490
  writeFileSync24(queryFile, THREAD_QUERY);
11401
11491
  try {
11402
- const result = execSync36(
11492
+ const result = execSync35(
11403
11493
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
11404
11494
  { encoding: "utf-8" }
11405
11495
  );
@@ -11421,9 +11511,9 @@ function fetchThreadIds(org, repo, prNumber) {
11421
11511
  }
11422
11512
 
11423
11513
  // src/commands/prs/listComments/fetchReviewComments.ts
11424
- import { execSync as execSync37 } from "child_process";
11514
+ import { execSync as execSync36 } from "child_process";
11425
11515
  function fetchJson(endpoint) {
11426
- const result = execSync37(`gh api --paginate ${endpoint}`, {
11516
+ const result = execSync36(`gh api --paginate ${endpoint}`, {
11427
11517
  encoding: "utf-8"
11428
11518
  });
11429
11519
  if (!result.trim()) return [];
@@ -11562,7 +11652,7 @@ async function listComments() {
11562
11652
  }
11563
11653
 
11564
11654
  // src/commands/prs/prs/index.ts
11565
- import { execSync as execSync38 } from "child_process";
11655
+ import { execSync as execSync37 } from "child_process";
11566
11656
 
11567
11657
  // src/commands/prs/prs/displayPaginated/index.ts
11568
11658
  import enquirer9 from "enquirer";
@@ -11669,7 +11759,7 @@ async function prs(options2) {
11669
11759
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
11670
11760
  try {
11671
11761
  const { org, repo } = getRepoInfo();
11672
- const result = execSync38(
11762
+ const result = execSync37(
11673
11763
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
11674
11764
  { encoding: "utf-8" }
11675
11765
  );
@@ -11692,7 +11782,7 @@ async function prs(options2) {
11692
11782
  }
11693
11783
 
11694
11784
  // src/commands/prs/raise.ts
11695
- import { execSync as execSync39 } from "child_process";
11785
+ import { execSync as execSync38 } from "child_process";
11696
11786
 
11697
11787
  // src/commands/prs/buildCreateArgs.ts
11698
11788
  function buildCreateArgs(title, body, options2) {
@@ -11752,14 +11842,14 @@ function raise(options2) {
11752
11842
  `--body ${shellQuote(body)}`
11753
11843
  ] : buildCreateArgs(options2.title, body, options2);
11754
11844
  try {
11755
- execSync39(args.join(" "), { stdio: "inherit" });
11845
+ execSync38(args.join(" "), { stdio: "inherit" });
11756
11846
  } catch (_error) {
11757
11847
  process.exit(1);
11758
11848
  }
11759
11849
  }
11760
11850
 
11761
11851
  // src/commands/prs/wontfix.ts
11762
- import { execSync as execSync40 } from "child_process";
11852
+ import { execSync as execSync39 } from "child_process";
11763
11853
  function validateReason(reason) {
11764
11854
  const lowerReason = reason.toLowerCase();
11765
11855
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -11776,7 +11866,7 @@ function validateShaReferences(reason) {
11776
11866
  const invalidShas = [];
11777
11867
  for (const sha of shas) {
11778
11868
  try {
11779
- execSync40(`git cat-file -t ${sha}`, { stdio: "pipe" });
11869
+ execSync39(`git cat-file -t ${sha}`, { stdio: "pipe" });
11780
11870
  } catch {
11781
11871
  invalidShas.push(sha);
11782
11872
  }
@@ -11935,10 +12025,10 @@ import chalk124 from "chalk";
11935
12025
  import Enquirer2 from "enquirer";
11936
12026
 
11937
12027
  // src/commands/ravendb/searchItems.ts
11938
- import { execSync as execSync41 } from "child_process";
12028
+ import { execSync as execSync40 } from "child_process";
11939
12029
  import chalk123 from "chalk";
11940
12030
  function opExec(args) {
11941
- return execSync41(`op ${args}`, {
12031
+ return execSync40(`op ${args}`, {
11942
12032
  encoding: "utf-8",
11943
12033
  stdio: ["pipe", "pipe", "pipe"]
11944
12034
  }).trim();
@@ -12077,10 +12167,10 @@ async function getAccessToken(apiKey) {
12077
12167
  }
12078
12168
  });
12079
12169
  if (!response.ok) {
12080
- const errorText2 = await response.text();
12170
+ const errorText = await response.text();
12081
12171
  throw new Error(
12082
12172
  `Failed to get access token: ${response.status} ${response.statusText}
12083
- ${errorText2}`
12173
+ ${errorText}`
12084
12174
  );
12085
12175
  }
12086
12176
  const tokenData = await response.json();
@@ -12090,7 +12180,7 @@ ${errorText2}`
12090
12180
  }
12091
12181
 
12092
12182
  // src/commands/ravendb/resolveOpSecret.ts
12093
- import { execSync as execSync42 } from "child_process";
12183
+ import { execSync as execSync41 } from "child_process";
12094
12184
  import chalk128 from "chalk";
12095
12185
  function resolveOpSecret(reference) {
12096
12186
  if (!reference.startsWith("op://")) {
@@ -12098,7 +12188,7 @@ function resolveOpSecret(reference) {
12098
12188
  process.exit(1);
12099
12189
  }
12100
12190
  try {
12101
- return execSync42(`op read "${reference}"`, {
12191
+ return execSync41(`op read "${reference}"`, {
12102
12192
  encoding: "utf-8",
12103
12193
  stdio: ["pipe", "pipe", "pipe"]
12104
12194
  }).trim();
@@ -12347,7 +12437,7 @@ Refactor check failed:
12347
12437
  }
12348
12438
 
12349
12439
  // src/commands/refactor/check/getViolations/index.ts
12350
- import { execSync as execSync43 } from "child_process";
12440
+ import { execSync as execSync42 } from "child_process";
12351
12441
  import fs18 from "fs";
12352
12442
  import { minimatch as minimatch5 } from "minimatch";
12353
12443
 
@@ -12397,7 +12487,7 @@ function getGitFiles(options2) {
12397
12487
  }
12398
12488
  const files = /* @__PURE__ */ new Set();
12399
12489
  if (options2.staged || options2.modified) {
12400
- const staged = execSync43("git diff --cached --name-only", {
12490
+ const staged = execSync42("git diff --cached --name-only", {
12401
12491
  encoding: "utf-8"
12402
12492
  });
12403
12493
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -12405,7 +12495,7 @@ function getGitFiles(options2) {
12405
12495
  }
12406
12496
  }
12407
12497
  if (options2.unstaged || options2.modified) {
12408
- const unstaged = execSync43("git diff --name-only", { encoding: "utf-8" });
12498
+ const unstaged = execSync42("git diff --name-only", { encoding: "utf-8" });
12409
12499
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
12410
12500
  files.add(file);
12411
12501
  }
@@ -13981,9 +14071,9 @@ function buildReviewPaths(repoRoot, key) {
13981
14071
  }
13982
14072
 
13983
14073
  // src/commands/review/fetchExistingComments.ts
13984
- import { execSync as execSync44 } from "child_process";
14074
+ import { execSync as execSync43 } from "child_process";
13985
14075
  function fetchRawComments(org, repo, prNumber) {
13986
- const out = execSync44(
14076
+ const out = execSync43(
13987
14077
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
13988
14078
  { encoding: "utf-8", maxBuffer: 64 * 1024 * 1024 }
13989
14079
  );
@@ -14014,14 +14104,14 @@ function fetchExistingComments() {
14014
14104
  }
14015
14105
 
14016
14106
  // src/commands/review/gatherContext.ts
14017
- import { execSync as execSync47 } from "child_process";
14107
+ import { execSync as execSync46 } from "child_process";
14018
14108
 
14019
14109
  // src/commands/review/fetchPrDiff.ts
14020
- import { execSync as execSync45 } from "child_process";
14110
+ import { execSync as execSync44 } from "child_process";
14021
14111
  function fetchPrDiff(prNumber, baseSha, headSha) {
14022
14112
  const { org, repo } = getRepoInfo();
14023
14113
  try {
14024
- return execSync45(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
14114
+ return execSync44(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
14025
14115
  encoding: "utf-8",
14026
14116
  maxBuffer: 256 * 1024 * 1024,
14027
14117
  stdio: ["ignore", "pipe", "pipe"]
@@ -14036,19 +14126,19 @@ function isDiffTooLarge(error) {
14036
14126
  }
14037
14127
  function fetchDiffViaGit(baseSha, headSha) {
14038
14128
  try {
14039
- execSync45(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
14129
+ execSync44(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
14040
14130
  } catch {
14041
14131
  }
14042
- return execSync45(`git diff ${baseSha}...${headSha}`, {
14132
+ return execSync44(`git diff ${baseSha}...${headSha}`, {
14043
14133
  encoding: "utf-8",
14044
14134
  maxBuffer: 256 * 1024 * 1024
14045
14135
  });
14046
14136
  }
14047
14137
 
14048
14138
  // src/commands/review/fetchPrDiffInfo.ts
14049
- import { execSync as execSync46 } from "child_process";
14139
+ import { execSync as execSync45 } from "child_process";
14050
14140
  function getCurrentBranch2() {
14051
- return execSync46("git rev-parse --abbrev-ref HEAD", {
14141
+ return execSync45("git rev-parse --abbrev-ref HEAD", {
14052
14142
  encoding: "utf-8"
14053
14143
  }).trim();
14054
14144
  }
@@ -14058,7 +14148,7 @@ function fetchPrDiffInfo() {
14058
14148
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
14059
14149
  let raw;
14060
14150
  try {
14061
- raw = execSync46(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
14151
+ raw = execSync45(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
14062
14152
  encoding: "utf-8",
14063
14153
  stdio: ["ignore", "pipe", "pipe"]
14064
14154
  });
@@ -14082,7 +14172,7 @@ function fetchPrDiffInfo() {
14082
14172
  }
14083
14173
  function fetchPrChangedFiles(prNumber) {
14084
14174
  const { org, repo } = getRepoInfo();
14085
- const out = execSync46(
14175
+ const out = execSync45(
14086
14176
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
14087
14177
  {
14088
14178
  encoding: "utf-8",
@@ -14094,11 +14184,11 @@ function fetchPrChangedFiles(prNumber) {
14094
14184
 
14095
14185
  // src/commands/review/gatherContext.ts
14096
14186
  function gatherContext() {
14097
- const branch = execSync47("git rev-parse --abbrev-ref HEAD", {
14187
+ const branch = execSync46("git rev-parse --abbrev-ref HEAD", {
14098
14188
  encoding: "utf-8"
14099
14189
  }).trim();
14100
- const sha = execSync47("git rev-parse HEAD", { encoding: "utf-8" }).trim();
14101
- const shortSha = execSync47("git rev-parse --short=7 HEAD", {
14190
+ const sha = execSync46("git rev-parse HEAD", { encoding: "utf-8" }).trim();
14191
+ const shortSha = execSync46("git rev-parse --short=7 HEAD", {
14102
14192
  encoding: "utf-8"
14103
14193
  }).trim();
14104
14194
  const prInfo = fetchPrDiffInfo();
@@ -16934,7 +17024,7 @@ import { mkdirSync as mkdirSync18 } from "fs";
16934
17024
  import { join as join47 } from "path";
16935
17025
 
16936
17026
  // src/commands/voice/checkLockFile.ts
16937
- import { execSync as execSync48 } from "child_process";
17027
+ import { execSync as execSync47 } from "child_process";
16938
17028
  import { existsSync as existsSync45, mkdirSync as mkdirSync17, readFileSync as readFileSync35, writeFileSync as writeFileSync29 } from "fs";
16939
17029
  import { join as join46 } from "path";
16940
17030
  function isProcessAlive2(pid) {
@@ -16963,7 +17053,7 @@ function bootstrapVenv() {
16963
17053
  if (existsSync45(getVenvPython())) return;
16964
17054
  console.log("Setting up Python environment...");
16965
17055
  const pythonDir = getPythonDir();
16966
- execSync48(
17056
+ execSync47(
16967
17057
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
16968
17058
  {
16969
17059
  stdio: "inherit",
@@ -17440,11 +17530,11 @@ function resolveParams(params, cliArgs) {
17440
17530
  }
17441
17531
 
17442
17532
  // src/commands/run/runPreCommands.ts
17443
- import { execSync as execSync49 } from "child_process";
17533
+ import { execSync as execSync48 } from "child_process";
17444
17534
  function runPreCommands(pre, cwd) {
17445
17535
  for (const cmd of pre) {
17446
17536
  try {
17447
- execSync49(cmd, { stdio: "inherit", cwd });
17537
+ execSync48(cmd, { stdio: "inherit", cwd });
17448
17538
  } catch (err) {
17449
17539
  const code = err && typeof err === "object" && "status" in err ? err.status : 1;
17450
17540
  process.exit(code);
@@ -17728,7 +17818,7 @@ function registerRun(program2) {
17728
17818
  }
17729
17819
 
17730
17820
  // src/commands/screenshot/index.ts
17731
- import { execSync as execSync50 } from "child_process";
17821
+ import { execSync as execSync49 } from "child_process";
17732
17822
  import { existsSync as existsSync50, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync32 } from "fs";
17733
17823
  import { tmpdir as tmpdir7 } from "os";
17734
17824
  import { join as join53, resolve as resolve13 } from "path";
@@ -17871,7 +17961,7 @@ function runPowerShellScript(processName, outputPath) {
17871
17961
  const scriptPath = join53(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
17872
17962
  writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
17873
17963
  try {
17874
- execSync50(
17964
+ execSync49(
17875
17965
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
17876
17966
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
17877
17967
  );
@@ -18240,6 +18330,7 @@ function greetClient(client, sessions, list4, windowsProxy) {
18240
18330
  sendTo(client, { type: "sessions", sessions: list4() });
18241
18331
  replayScrollback(sessions, client);
18242
18332
  windowsProxy.replayScrollback(client);
18333
+ void windowsProxy.discover();
18243
18334
  }
18244
18335
 
18245
18336
  // src/commands/sessions/daemon/shouldAutoDismiss.ts
@@ -18479,6 +18570,33 @@ function shutdownSessions(sessions) {
18479
18570
  }
18480
18571
  }
18481
18572
 
18573
+ // src/commands/sessions/daemon/autoHealWindowsDaemon.ts
18574
+ async function autoHealWindowsDaemon(conn, state, heal, version2) {
18575
+ daemonLog(`windows proxy: auto-healing windows daemon (mismatch ${version2})`);
18576
+ notifyHealing(state);
18577
+ try {
18578
+ conn.dispose();
18579
+ await heal();
18580
+ daemonLog("windows proxy: heal complete, reconnecting to windows daemon");
18581
+ await conn.ensure();
18582
+ } catch (e) {
18583
+ const message = e instanceof Error ? e.message : String(e);
18584
+ daemonLog(`windows proxy: auto-heal failed: ${message}`);
18585
+ state.broadcast({
18586
+ type: "error",
18587
+ message: `Windows host auto-update failed: ${message}`
18588
+ });
18589
+ }
18590
+ }
18591
+ function notifyHealing(state) {
18592
+ for (const client of state.pendingCreators)
18593
+ sendTo(client, {
18594
+ type: "error",
18595
+ message: "Windows host is out of date; updating it now \u2014 reselect the repo once the update finishes."
18596
+ });
18597
+ state.pendingCreators = [];
18598
+ }
18599
+
18482
18600
  // src/commands/sessions/daemon/connectToWindowsDaemon.ts
18483
18601
  import * as net2 from "net";
18484
18602
 
@@ -18514,16 +18632,19 @@ import { spawn as spawn10 } from "child_process";
18514
18632
  var SPAWN_TIMEOUT_MS2 = 3e4;
18515
18633
  var RETRY_DELAY_MS2 = 300;
18516
18634
  async function ensureWindowsDaemonRunning() {
18517
- if (await isWindowsDaemonRunning()) return;
18635
+ if (await isWindowsDaemonRunning()) {
18636
+ daemonLog("windows daemon: already running");
18637
+ return;
18638
+ }
18639
+ daemonLog("windows daemon: not running, launching via pwsh.exe");
18518
18640
  launchWindowsDaemon();
18519
18641
  await waitForWindowsDaemon();
18520
18642
  }
18521
18643
  function launchWindowsDaemon() {
18522
- const child = spawn10(
18523
- "cmd.exe",
18524
- ["/c", "start", "", "assist", "daemon", "run"],
18525
- { detached: true, stdio: "ignore" }
18526
- );
18644
+ const child = spawn10("pwsh.exe", ["-Command", "assist daemon run"], {
18645
+ detached: true,
18646
+ stdio: "ignore"
18647
+ });
18527
18648
  child.on(
18528
18649
  "error",
18529
18650
  (e) => daemonLog(`failed to launch windows daemon: ${e.message}`)
@@ -18531,11 +18652,22 @@ function launchWindowsDaemon() {
18531
18652
  child.unref();
18532
18653
  }
18533
18654
  async function waitForWindowsDaemon() {
18534
- const deadline = Date.now() + SPAWN_TIMEOUT_MS2;
18655
+ const start3 = Date.now();
18656
+ const deadline = start3 + SPAWN_TIMEOUT_MS2;
18657
+ let attempts = 0;
18535
18658
  while (Date.now() < deadline) {
18536
18659
  await delay2(RETRY_DELAY_MS2);
18537
- if (await isWindowsDaemonRunning()) return;
18660
+ attempts++;
18661
+ if (await isWindowsDaemonRunning()) {
18662
+ daemonLog(
18663
+ `windows daemon: up after ${Date.now() - start3}ms (${attempts} attempts)`
18664
+ );
18665
+ return;
18666
+ }
18538
18667
  }
18668
+ daemonLog(
18669
+ `windows daemon: did NOT start within ${SPAWN_TIMEOUT_MS2}ms (${attempts} attempts)`
18670
+ );
18539
18671
  throw new Error(
18540
18672
  "Windows daemon did not start; is assist installed on the Windows host?"
18541
18673
  );
@@ -18544,6 +18676,42 @@ function delay2(ms) {
18544
18676
  return new Promise((resolve16) => setTimeout(resolve16, ms));
18545
18677
  }
18546
18678
 
18679
+ // src/commands/sessions/daemon/defaultConnect.ts
18680
+ async function defaultConnect() {
18681
+ await ensureWindowsDaemonRunning();
18682
+ return connectToWindowsDaemon();
18683
+ }
18684
+
18685
+ // src/commands/sessions/daemon/discoverWindowsSessions.ts
18686
+ async function discoverWindowsSessions(conn) {
18687
+ if (conn.connected || !await isWindowsDaemonRunning()) return;
18688
+ daemonLog("windows proxy: discovering sessions on running windows daemon");
18689
+ try {
18690
+ await conn.ensure();
18691
+ } catch (e) {
18692
+ const message = e instanceof Error ? e.message : String(e);
18693
+ daemonLog(`windows proxy: discovery failed: ${message}`);
18694
+ }
18695
+ }
18696
+
18697
+ // src/commands/sessions/daemon/forwardWindowsCreate.ts
18698
+ async function forwardWindowsCreate(conn, state, client, data) {
18699
+ daemonLog(`windows proxy: routing ${data.type} (cwd=${data.cwd})`);
18700
+ try {
18701
+ await conn.ensure();
18702
+ daemonLog("windows proxy: connection ready, forwarding create");
18703
+ state.pendingCreators.push(client);
18704
+ conn.write(data);
18705
+ } catch (e) {
18706
+ const message = e instanceof Error ? e.message : String(e);
18707
+ daemonLog(`windows proxy: forwardCreate failed: ${message}`);
18708
+ sendTo(client, {
18709
+ type: "error",
18710
+ message: `Windows session unavailable: ${message}`
18711
+ });
18712
+ }
18713
+ }
18714
+
18547
18715
  // src/commands/sessions/daemon/buildHello.ts
18548
18716
  var ASSIST_VERSION = package_default.version;
18549
18717
  function buildHello() {
@@ -18556,27 +18724,16 @@ function versionsMatch(a, b) {
18556
18724
  return a === b;
18557
18725
  }
18558
18726
 
18559
- // src/commands/sessions/daemon/toWindowsSessionId.ts
18560
- var PREFIX = "w-";
18561
- function toWindowsSessionId(id) {
18562
- return `${PREFIX}${id}`;
18563
- }
18564
- function isWindowsSessionId(id) {
18565
- return id.startsWith(PREFIX);
18566
- }
18567
- function stripWindowsSessionId(id) {
18568
- return id.startsWith(PREFIX) ? id.slice(PREFIX.length) : id;
18569
- }
18570
-
18571
18727
  // src/commands/sessions/daemon/WindowsProxyState.ts
18572
18728
  var MAX_SCROLLBACK2 = 256 * 1024;
18573
- function createState(broadcast2, onSessionsChanged) {
18729
+ function createState(broadcast2, onSessionsChanged, onVersionMismatch) {
18574
18730
  return {
18575
18731
  windowsSessions: [],
18576
18732
  scrollback: /* @__PURE__ */ new Map(),
18577
18733
  pendingCreators: [],
18578
18734
  broadcast: broadcast2,
18579
- onSessionsChanged
18735
+ onSessionsChanged,
18736
+ onVersionMismatch
18580
18737
  };
18581
18738
  }
18582
18739
  function resetState(state) {
@@ -18607,22 +18764,29 @@ function handleInbound(state, line) {
18607
18764
  inbound[msg.type]?.(state, msg);
18608
18765
  }
18609
18766
  var inbound = {
18610
- hello: (_state, msg) => handleHello(msg),
18767
+ hello: handleHello,
18611
18768
  created: handleCreated,
18612
18769
  sessions: handleSessions,
18613
18770
  output: handleOutput,
18614
18771
  clear: relayWithSessionId,
18615
- error: (state, msg) => state.broadcast(msg)
18772
+ error: (state, msg) => {
18773
+ daemonLog(`windows daemon: inbound error: ${msg.message}`);
18774
+ state.broadcast(msg);
18775
+ }
18616
18776
  };
18617
- function handleHello(msg) {
18618
- if (isHello(msg) && !versionsMatch(msg.version, ASSIST_VERSION))
18777
+ function handleHello(state, msg) {
18778
+ if (isHello(msg) && !versionsMatch(msg.version, ASSIST_VERSION)) {
18619
18779
  daemonLog(
18620
18780
  `windows daemon version mismatch: ${msg.version} (wsl ${ASSIST_VERSION})`
18621
18781
  );
18782
+ state.onVersionMismatch(msg.version);
18783
+ }
18622
18784
  }
18623
18785
  function handleCreated(state, msg) {
18786
+ daemonLog(`windows daemon: created session ${nsId(msg)}`);
18624
18787
  const client = state.pendingCreators.shift();
18625
18788
  if (client) sendTo(client, { type: "created", sessionId: nsId(msg) });
18789
+ else daemonLog("windows daemon: created with no pending creator (dropped)");
18626
18790
  }
18627
18791
  function handleSessions(state, msg) {
18628
18792
  state.windowsSessions = msg.sessions.map((s) => ({
@@ -18647,6 +18811,57 @@ function nsId(msg) {
18647
18811
  return toWindowsSessionId(msg.sessionId);
18648
18812
  }
18649
18813
 
18814
+ // src/commands/sessions/daemon/healWindowsDaemon.ts
18815
+ import { spawn as spawn11 } from "child_process";
18816
+ import { createInterface as createInterface5 } from "readline";
18817
+ var UPDATE_TIMEOUT_MS = 5 * 6e4;
18818
+ var STOP_TIMEOUT_MS2 = 3e4;
18819
+ async function healWindowsDaemon() {
18820
+ daemonLog("windows daemon: auto-heal: running `assist update` on host");
18821
+ await runOnWindowsHost("assist update", UPDATE_TIMEOUT_MS);
18822
+ daemonLog("windows daemon: auto-heal: update done, stopping stale daemon");
18823
+ await runOnWindowsHost("assist daemon stop", STOP_TIMEOUT_MS2);
18824
+ daemonLog("windows daemon: auto-heal: stale daemon stopped");
18825
+ }
18826
+ function runOnWindowsHost(command, timeoutMs) {
18827
+ return new Promise((resolve16, reject) => {
18828
+ const child = spawn11("pwsh.exe", ["-Command", command], {
18829
+ stdio: ["ignore", "pipe", "pipe"]
18830
+ });
18831
+ logStream(child.stdout, command);
18832
+ logStream(child.stderr, command);
18833
+ const timer = setTimeout(() => {
18834
+ child.kill();
18835
+ reject(
18836
+ new Error(
18837
+ `'${command}' on the Windows host timed out after ${timeoutMs}ms`
18838
+ )
18839
+ );
18840
+ }, timeoutMs);
18841
+ child.on("error", (e) => {
18842
+ clearTimeout(timer);
18843
+ reject(e);
18844
+ });
18845
+ child.on("exit", (code) => {
18846
+ clearTimeout(timer);
18847
+ if (code === 0) resolve16();
18848
+ else
18849
+ reject(
18850
+ new Error(
18851
+ `'${command}' on the Windows host exited with code ${code}`
18852
+ )
18853
+ );
18854
+ });
18855
+ });
18856
+ }
18857
+ function logStream(stream, command) {
18858
+ if (!stream) return;
18859
+ const lines = createInterface5({ input: stream });
18860
+ lines.on("line", (line) => daemonLog(`[windows ${command}] ${line}`));
18861
+ lines.on("error", () => {
18862
+ });
18863
+ }
18864
+
18650
18865
  // src/commands/sessions/daemon/isWindowsCwd.ts
18651
18866
  function isWindowsCwd(cwd) {
18652
18867
  return /^[A-Za-z]:[\\/]/.test(cwd);
@@ -18655,14 +18870,25 @@ function shouldProxyToWindows(cwd) {
18655
18870
  return detectPlatform() === "wsl" && isWindowsCwd(cwd);
18656
18871
  }
18657
18872
 
18873
+ // src/commands/sessions/daemon/isWindowsCreate.ts
18874
+ function isWindowsCreate(data) {
18875
+ return typeof data.cwd === "string" && shouldProxyToWindows(data.cwd);
18876
+ }
18877
+ function isWindowsIo(data) {
18878
+ return typeof data.sessionId === "string" && isWindowsSessionId(data.sessionId);
18879
+ }
18880
+
18658
18881
  // src/commands/sessions/daemon/WindowsConnection.ts
18659
- import { createInterface as createInterface5 } from "readline";
18882
+ import { createInterface as createInterface6 } from "readline";
18660
18883
  var WindowsConnection = class {
18661
18884
  constructor(deps2) {
18662
18885
  this.deps = deps2;
18663
18886
  }
18664
18887
  connection = null;
18665
18888
  socket = null;
18889
+ get connected() {
18890
+ return this.connection !== null;
18891
+ }
18666
18892
  ensure() {
18667
18893
  if (this.connection) return this.connection;
18668
18894
  const connection = this.open();
@@ -18686,9 +18912,11 @@ var WindowsConnection = class {
18686
18912
  this.reset();
18687
18913
  }
18688
18914
  async open() {
18915
+ daemonLog("windows connection: opening (launch + tcp connect)");
18689
18916
  const socket = await this.deps.connect();
18917
+ daemonLog("windows connection: tcp connected, sending hello");
18690
18918
  this.socket = socket;
18691
- const lines = createInterface5({ input: socket });
18919
+ const lines = createInterface6({ input: socket });
18692
18920
  lines.on("error", () => {
18693
18921
  });
18694
18922
  lines.on("line", (line) => this.deps.onLine(line));
@@ -18709,12 +18937,12 @@ var WindowsConnection = class {
18709
18937
 
18710
18938
  // src/commands/sessions/daemon/WindowsProxy.ts
18711
18939
  var WindowsProxy = class {
18712
- state;
18713
- conn;
18714
- constructor(clients, onSessionsChanged, connect3 = defaultConnect) {
18940
+ constructor(clients, onSessionsChanged, connect3 = defaultConnect, heal = healWindowsDaemon) {
18941
+ this.heal = heal;
18715
18942
  this.state = createState(
18716
18943
  (msg) => broadcast(clients, msg),
18717
- onSessionsChanged
18944
+ onSessionsChanged,
18945
+ (version2) => void this.handleVersionMismatch(version2)
18718
18946
  );
18719
18947
  this.conn = new WindowsConnection({
18720
18948
  connect: connect3,
@@ -18722,9 +18950,17 @@ var WindowsProxy = class {
18722
18950
  onClose: () => this.handleClose()
18723
18951
  });
18724
18952
  }
18953
+ state;
18954
+ conn;
18955
+ // why: heal runs once per proxy lifetime; if WSL is the older side, updating Windows can't close the gap, so a repeat mismatch must not loop
18956
+ healAttempted = false;
18957
+ healing = false;
18725
18958
  sessions() {
18726
18959
  return this.state.windowsSessions;
18727
18960
  }
18961
+ discover() {
18962
+ return discoverWindowsSessions(this.conn);
18963
+ }
18728
18964
  replayScrollback(client) {
18729
18965
  replayScrollback2(this.state, client);
18730
18966
  }
@@ -18732,7 +18968,7 @@ var WindowsProxy = class {
18732
18968
  // windows-origin cwd is forwarded, as is I/O for a namespaced session id.
18733
18969
  route(client, data) {
18734
18970
  if (isWindowsCreate(data)) {
18735
- void this.forwardCreate(client, data);
18971
+ void forwardWindowsCreate(this.conn, this.state, client, data);
18736
18972
  return true;
18737
18973
  }
18738
18974
  if (isWindowsIo(data)) {
@@ -18745,19 +18981,18 @@ var WindowsProxy = class {
18745
18981
  dispose() {
18746
18982
  this.conn.dispose();
18747
18983
  }
18748
- async forwardCreate(client, data) {
18984
+ async handleVersionMismatch(version2) {
18985
+ if (this.healing || this.healAttempted) return;
18986
+ this.healing = true;
18987
+ this.healAttempted = true;
18749
18988
  try {
18750
- await this.conn.ensure();
18751
- this.state.pendingCreators.push(client);
18752
- this.conn.write(data);
18753
- } catch (e) {
18754
- sendTo(client, {
18755
- type: "error",
18756
- message: `Windows session unavailable: ${errorText(e)}`
18757
- });
18989
+ await autoHealWindowsDaemon(this.conn, this.state, this.heal, version2);
18990
+ } finally {
18991
+ this.healing = false;
18758
18992
  }
18759
18993
  }
18760
18994
  handleClose() {
18995
+ daemonLog("windows proxy: connection to windows daemon closed");
18761
18996
  for (const client of this.state.pendingCreators)
18762
18997
  sendTo(client, {
18763
18998
  type: "error",
@@ -18767,19 +19002,6 @@ var WindowsProxy = class {
18767
19002
  this.state.onSessionsChanged();
18768
19003
  }
18769
19004
  };
18770
- function isWindowsCreate(data) {
18771
- return typeof data.cwd === "string" && shouldProxyToWindows(data.cwd);
18772
- }
18773
- function isWindowsIo(data) {
18774
- return typeof data.sessionId === "string" && isWindowsSessionId(data.sessionId);
18775
- }
18776
- async function defaultConnect() {
18777
- await ensureWindowsDaemonRunning();
18778
- return connectToWindowsDaemon();
18779
- }
18780
- function errorText(e) {
18781
- return e instanceof Error ? e.message : String(e);
18782
- }
18783
19005
 
18784
19006
  // src/commands/sessions/daemon/watchClaudeSessionId.ts
18785
19007
  import * as fs27 from "fs";
@@ -19175,7 +19397,7 @@ import { unlinkSync as unlinkSync19 } from "fs";
19175
19397
  import * as net3 from "net";
19176
19398
 
19177
19399
  // src/commands/sessions/daemon/handleConnection.ts
19178
- import { createInterface as createInterface6 } from "readline";
19400
+ import { createInterface as createInterface7 } from "readline";
19179
19401
 
19180
19402
  // src/commands/sessions/shared/parseTranscript.ts
19181
19403
  import * as fs28 from "fs";
@@ -19269,10 +19491,10 @@ function safeParse2(line) {
19269
19491
  }
19270
19492
 
19271
19493
  // src/commands/sessions/daemon/dispatchMessage.ts
19272
- function creator(spawn11) {
19494
+ function creator(spawn12) {
19273
19495
  return (client, m, d) => {
19274
19496
  if (m.windowsProxy.route(client, d)) return;
19275
- sendTo(client, { type: "created", sessionId: spawn11(m, d) });
19497
+ sendTo(client, { type: "created", sessionId: spawn12(m, d) });
19276
19498
  };
19277
19499
  }
19278
19500
  function handleHistory(client) {
@@ -19353,7 +19575,7 @@ function handleConnection(socket, manager) {
19353
19575
  }
19354
19576
  };
19355
19577
  manager.addClient(client);
19356
- const lines = createInterface6({ input: socket });
19578
+ const lines = createInterface7({ input: socket });
19357
19579
  lines.on("error", () => {
19358
19580
  });
19359
19581
  lines.on("line", (line) => {
@@ -19871,7 +20093,7 @@ function syncCommands(claudeDir, targetBase) {
19871
20093
  }
19872
20094
 
19873
20095
  // src/commands/update.ts
19874
- import { execSync as execSync51 } from "child_process";
20096
+ import { execSync as execSync50 } from "child_process";
19875
20097
  import * as path53 from "path";
19876
20098
  function isGlobalNpmInstall(dir) {
19877
20099
  try {
@@ -19879,7 +20101,7 @@ function isGlobalNpmInstall(dir) {
19879
20101
  if (resolved.split(path53.sep).includes("node_modules")) {
19880
20102
  return true;
19881
20103
  }
19882
- const globalPrefix = execSync51("npm prefix -g", { stdio: "pipe" }).toString().trim();
20104
+ const globalPrefix = execSync50("npm prefix -g", { stdio: "pipe" }).toString().trim();
19883
20105
  return resolved.toLowerCase().startsWith(path53.resolve(globalPrefix).toLowerCase());
19884
20106
  } catch {
19885
20107
  return false;
@@ -19890,18 +20112,18 @@ async function update2() {
19890
20112
  console.log(`Assist is installed at: ${installDir}`);
19891
20113
  if (isGitRepo(installDir)) {
19892
20114
  console.log("Detected git repo installation, pulling latest...");
19893
- execSync51("git pull", { cwd: installDir, stdio: "inherit" });
20115
+ execSync50("git pull", { cwd: installDir, stdio: "inherit" });
19894
20116
  console.log("Installing dependencies...");
19895
- execSync51("npm i", { cwd: installDir, stdio: "inherit" });
20117
+ execSync50("npm i", { cwd: installDir, stdio: "inherit" });
19896
20118
  console.log("Building...");
19897
- execSync51("npm run build", { cwd: installDir, stdio: "inherit" });
20119
+ execSync50("npm run build", { cwd: installDir, stdio: "inherit" });
19898
20120
  console.log("Syncing commands...");
19899
- execSync51("assist sync", { stdio: "inherit" });
20121
+ execSync50("assist sync", { stdio: "inherit" });
19900
20122
  } else if (isGlobalNpmInstall(installDir)) {
19901
20123
  console.log("Detected global npm installation, updating...");
19902
- execSync51("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
20124
+ execSync50("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
19903
20125
  console.log("Syncing commands...");
19904
- execSync51("assist sync", { stdio: "inherit" });
20126
+ execSync50("assist sync", { stdio: "inherit" });
19905
20127
  } else {
19906
20128
  console.error(
19907
20129
  "Could not determine installation method. Expected a git repo or global npm install."