@staff0rd/assist 0.193.1 → 0.195.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.193.1",
9
+ version: "0.195.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -1674,6 +1674,48 @@ async function parseItemBody(req) {
1674
1674
  async function parseStatusBody(req) {
1675
1675
  return JSON.parse(await readBody(req));
1676
1676
  }
1677
+ async function parseRewindBody(req) {
1678
+ return JSON.parse(await readBody(req));
1679
+ }
1680
+
1681
+ // src/commands/backlog/web/rewindItemPhase.ts
1682
+ async function rewindItemPhase(req, res, id) {
1683
+ const { phase, reason } = await parseRewindBody(req);
1684
+ const items = loadBacklog();
1685
+ const item = items.find((i) => i.id === id);
1686
+ if (!item) {
1687
+ respondJson(res, 404, { error: "Not found" });
1688
+ return;
1689
+ }
1690
+ const error = validateRewind(item, phase);
1691
+ if (error) {
1692
+ respondJson(res, 400, { error });
1693
+ return;
1694
+ }
1695
+ const phaseName = item.plan?.[phase - 1].name;
1696
+ addComment(
1697
+ item,
1698
+ `Rewound to phase ${phase} (${phaseName}): ${reason}`,
1699
+ phase
1700
+ );
1701
+ item.currentPhase = phase;
1702
+ item.status = "in-progress";
1703
+ saveBacklog(items);
1704
+ respondJson(res, 200, item);
1705
+ }
1706
+ function validateRewind(item, phase) {
1707
+ if (!item.plan || item.plan.length === 0) {
1708
+ return "Item has no plan phases.";
1709
+ }
1710
+ if (phase < 1 || phase > item.plan.length) {
1711
+ return `Phase ${phase} does not exist. Valid range: 1\u2013${item.plan.length}.`;
1712
+ }
1713
+ const currentPhase = item.currentPhase ?? 1;
1714
+ if (phase >= currentPhase) {
1715
+ return `Phase ${phase} is not earlier than the current phase (${currentPhase}).`;
1716
+ }
1717
+ return void 0;
1718
+ }
1677
1719
 
1678
1720
  // src/commands/backlog/web/shared.ts
1679
1721
  function listItems(req, res) {
@@ -1755,6 +1797,11 @@ var itemRoutes = {
1755
1797
  DELETE: (_req, res, id) => deleteItem2(res, id)
1756
1798
  };
1757
1799
  async function handleItemRoute(req, res, pathname) {
1800
+ const rewindMatch = pathname.match(/^\/api\/items\/(\d+)\/rewind$/);
1801
+ if (rewindMatch && req.method === "POST") {
1802
+ await rewindItemPhase(req, res, Number.parseInt(rewindMatch[1], 10));
1803
+ return true;
1804
+ }
1758
1805
  const match = pathname.match(/^\/api\/items\/(\d+)$/);
1759
1806
  if (!match) return false;
1760
1807
  const handler = itemRoutes[req.method ?? "GET"];
@@ -4403,7 +4450,7 @@ function registerLinkCommands(cmd) {
4403
4450
 
4404
4451
  // src/commands/backlog/rewindPhase.ts
4405
4452
  import chalk53 from "chalk";
4406
- function validateRewind(item, phaseNumber) {
4453
+ function validateRewind2(item, phaseNumber) {
4407
4454
  if (!item.plan || item.plan.length === 0) {
4408
4455
  return `Item #${item.id} has no plan phases.`;
4409
4456
  }
@@ -4422,7 +4469,7 @@ function rewindPhase(id, phase, opts) {
4422
4469
  const result = loadAndFindItem(id);
4423
4470
  if (!result) return;
4424
4471
  const { item } = result;
4425
- const error = validateRewind(item, phaseNumber);
4472
+ const error = validateRewind2(item, phaseNumber);
4426
4473
  if (error) {
4427
4474
  console.log(chalk53.red(error));
4428
4475
  process.exitCode = 1;
@@ -12446,6 +12493,45 @@ var routes3 = {
12446
12493
  var handleRequest3 = createFallbackHandler(routes3, htmlHandler2);
12447
12494
 
12448
12495
  // src/commands/sessions/web/handleSocket.ts
12496
+ function dispatch(ws, manager, data) {
12497
+ switch (data.type) {
12498
+ case "create": {
12499
+ const id = manager.spawn(
12500
+ data.prompt,
12501
+ data.cwd
12502
+ );
12503
+ ws.send(JSON.stringify({ type: "created", sessionId: id }));
12504
+ break;
12505
+ }
12506
+ case "input":
12507
+ manager.writeToSession(data.sessionId, data.data);
12508
+ break;
12509
+ case "resize":
12510
+ manager.resizeSession(
12511
+ data.sessionId,
12512
+ data.cols,
12513
+ data.rows
12514
+ );
12515
+ break;
12516
+ case "resume": {
12517
+ const id = manager.resume(
12518
+ data.sessionId,
12519
+ data.cwd,
12520
+ data.name
12521
+ );
12522
+ ws.send(JSON.stringify({ type: "created", sessionId: id }));
12523
+ break;
12524
+ }
12525
+ case "dismiss":
12526
+ manager.dismissSession(data.sessionId);
12527
+ break;
12528
+ case "history":
12529
+ manager.getHistory().then((history) => {
12530
+ ws.send(JSON.stringify({ type: "history", sessions: history }));
12531
+ });
12532
+ break;
12533
+ }
12534
+ }
12449
12535
  function handleSocket(ws, manager) {
12450
12536
  manager.addClient(ws);
12451
12537
  ws.on("message", (msg) => {
@@ -12455,40 +12541,7 @@ function handleSocket(ws, manager) {
12455
12541
  } catch {
12456
12542
  return;
12457
12543
  }
12458
- switch (data.type) {
12459
- case "create": {
12460
- const id = manager.spawn(data.prompt);
12461
- ws.send(JSON.stringify({ type: "created", sessionId: id }));
12462
- break;
12463
- }
12464
- case "input":
12465
- manager.writeToSession(data.sessionId, data.data);
12466
- break;
12467
- case "resize":
12468
- manager.resizeSession(
12469
- data.sessionId,
12470
- data.cols,
12471
- data.rows
12472
- );
12473
- break;
12474
- case "resume": {
12475
- const id = manager.resume(
12476
- data.sessionId,
12477
- data.cwd,
12478
- data.name
12479
- );
12480
- ws.send(JSON.stringify({ type: "created", sessionId: id }));
12481
- break;
12482
- }
12483
- case "dismiss":
12484
- manager.dismissSession(data.sessionId);
12485
- break;
12486
- case "history":
12487
- manager.getHistory().then((history) => {
12488
- ws.send(JSON.stringify({ type: "history", sessions: history }));
12489
- });
12490
- break;
12491
- }
12544
+ dispatch(ws, manager, data);
12492
12545
  });
12493
12546
  ws.on("close", () => {
12494
12547
  manager.removeClient(ws);
@@ -12520,13 +12573,13 @@ function shellEscape(s) {
12520
12573
  }
12521
12574
 
12522
12575
  // src/commands/sessions/web/createSession.ts
12523
- function createSession(id, prompt) {
12576
+ function createSession(id, prompt, cwd) {
12524
12577
  return {
12525
12578
  id,
12526
12579
  name: prompt?.slice(0, 40) || `Session ${id}`,
12527
12580
  status: "running",
12528
12581
  startedAt: Date.now(),
12529
- pty: spawnClaude2({ prompt }),
12582
+ pty: spawnClaude2({ prompt, cwd }),
12530
12583
  scrollback: "",
12531
12584
  idleTimer: null,
12532
12585
  lastResizeAt: 0
@@ -12702,14 +12755,47 @@ function wirePtyEvents(session, clients, onStatusChange) {
12702
12755
  });
12703
12756
  }
12704
12757
 
12758
+ // src/commands/sessions/web/writeToSession.ts
12759
+ function writeToSession(sessions, id, data) {
12760
+ const s = sessions.get(id);
12761
+ if (s && s.status !== "done") s.pty.write(data);
12762
+ }
12763
+ function resizeSession(sessions, id, cols, rows) {
12764
+ const s = sessions.get(id);
12765
+ if (s && s.status !== "done") {
12766
+ s.lastResizeAt = Date.now();
12767
+ s.pty.resize(cols, rows);
12768
+ }
12769
+ }
12770
+ function dismissSession(sessions, id) {
12771
+ const s = sessions.get(id);
12772
+ if (!s) return false;
12773
+ if (s.status !== "done") s.pty.kill();
12774
+ clearIdle(s);
12775
+ sessions.delete(id);
12776
+ return true;
12777
+ }
12778
+
12705
12779
  // src/commands/sessions/web/SessionManager.ts
12706
12780
  var SessionManager = class {
12707
12781
  sessions = /* @__PURE__ */ new Map();
12708
12782
  clients = /* @__PURE__ */ new Set();
12709
12783
  nextId = 1;
12784
+ repoCwd;
12785
+ constructor() {
12786
+ const cwd = process.cwd();
12787
+ this.repoCwd = isGitRepo(cwd) ? cwd : void 0;
12788
+ }
12710
12789
  addClient(ws) {
12711
12790
  this.clients.add(ws);
12712
- wsSend(ws, { type: "sessions", sessions: this.listSessions() });
12791
+ wsSend(ws, {
12792
+ type: "sessions",
12793
+ cwd: this.repoCwd,
12794
+ sessions: this.listSessions()
12795
+ });
12796
+ this.replayScrollback(ws);
12797
+ }
12798
+ replayScrollback(ws) {
12713
12799
  for (const s of this.sessions.values()) {
12714
12800
  if (s.scrollback)
12715
12801
  wsSend(ws, { type: "output", sessionId: s.id, data: s.scrollback });
@@ -12718,9 +12804,9 @@ var SessionManager = class {
12718
12804
  removeClient(ws) {
12719
12805
  this.clients.delete(ws);
12720
12806
  }
12721
- spawn(prompt) {
12807
+ spawn(prompt, cwd) {
12722
12808
  const id = String(this.nextId++);
12723
- const session = createSession(id, prompt);
12809
+ const session = createSession(id, prompt, cwd);
12724
12810
  this.wire(session);
12725
12811
  return id;
12726
12812
  }
@@ -12743,23 +12829,13 @@ var SessionManager = class {
12743
12829
  this.notify();
12744
12830
  }
12745
12831
  writeToSession(id, data) {
12746
- const s = this.sessions.get(id);
12747
- if (s && s.status !== "done") s.pty.write(data);
12832
+ writeToSession(this.sessions, id, data);
12748
12833
  }
12749
12834
  resizeSession(id, cols, rows) {
12750
- const s = this.sessions.get(id);
12751
- if (s && s.status !== "done") {
12752
- s.lastResizeAt = Date.now();
12753
- s.pty.resize(cols, rows);
12754
- }
12835
+ resizeSession(this.sessions, id, cols, rows);
12755
12836
  }
12756
12837
  dismissSession(id) {
12757
- const s = this.sessions.get(id);
12758
- if (!s) return;
12759
- if (s.status !== "done") s.pty.kill();
12760
- clearIdle(s);
12761
- this.sessions.delete(id);
12762
- this.notify();
12838
+ if (dismissSession(this.sessions, id)) this.notify();
12763
12839
  }
12764
12840
  listSessions() {
12765
12841
  return [...this.sessions.values()].map(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.193.1",
3
+ "version": "0.195.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {