@staff0rd/assist 0.514.2 → 0.516.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.514.2",
9
+ version: "0.516.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -107,6 +107,7 @@ var package_default = {
107
107
  jscpd: "^4.0.5",
108
108
  jsdom: "^29.1.1",
109
109
  knip: "^5.71.0",
110
+ "monaco-editor": "^0.56.0",
110
111
  oxfmt: "^0.54.0",
111
112
  oxlint: "^1.69.0",
112
113
  react: "^19.2.4",
@@ -1963,9 +1964,6 @@ function stageAndCommit(files, message3) {
1963
1964
  return commitStaged(message3);
1964
1965
  }
1965
1966
 
1966
- // src/commands/sessions/summarise/iterateUserMessages.ts
1967
- import * as fs from "fs";
1968
-
1969
1967
  // src/commands/sessions/summarise/parseUserLine.ts
1970
1968
  function parseUserLine(line) {
1971
1969
  let entry;
@@ -1991,21 +1989,27 @@ function parseUserLine(line) {
1991
1989
  };
1992
1990
  }
1993
1991
 
1994
- // src/commands/sessions/summarise/iterateUserMessages.ts
1995
- function* iterateUserMessages(filePath, maxBytes = 65536) {
1996
- let content;
1992
+ // src/commands/sessions/summarise/readTranscriptHead.ts
1993
+ import * as fs from "fs";
1994
+ function readTranscriptHead(filePath, maxBytes = 65536) {
1997
1995
  try {
1998
1996
  const fd = fs.openSync(filePath, "r");
1999
1997
  try {
2000
1998
  const buf = Buffer.alloc(maxBytes);
2001
1999
  const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
2002
- content = buf.toString("utf8", 0, bytesRead);
2000
+ return buf.toString("utf8", 0, bytesRead);
2003
2001
  } finally {
2004
2002
  fs.closeSync(fd);
2005
2003
  }
2006
2004
  } catch {
2007
- return;
2005
+ return void 0;
2008
2006
  }
2007
+ }
2008
+
2009
+ // src/commands/sessions/summarise/iterateUserMessages.ts
2010
+ function* iterateUserMessages(filePath, maxBytes = 65536) {
2011
+ const content = readTranscriptHead(filePath, maxBytes);
2012
+ if (content === void 0) return;
2009
2013
  for (const line of content.split("\n")) {
2010
2014
  if (!line) continue;
2011
2015
  const entry = parseUserLine(line);
@@ -12081,6 +12085,19 @@ var routes2 = {
12081
12085
  "commands/sessions/web/bundle.css",
12082
12086
  "text/css"
12083
12087
  ),
12088
+ "GET /monaco.js": createBundleHandler(
12089
+ import.meta.url,
12090
+ "commands/sessions/web/monaco.js"
12091
+ ),
12092
+ "GET /monaco.worker.js": createBundleHandler(
12093
+ import.meta.url,
12094
+ "commands/sessions/web/monaco.worker.js"
12095
+ ),
12096
+ "GET /monaco.css": createBundleHandler(
12097
+ import.meta.url,
12098
+ "commands/sessions/web/monaco.css",
12099
+ "text/css"
12100
+ ),
12084
12101
  "GET /api/items": listItems,
12085
12102
  "GET /api/backlog/summary": getBacklogSummary,
12086
12103
  "POST /api/open-in-code": openInCode,
@@ -30315,9 +30332,17 @@ var ISSUE_KEY = /^[A-Z][A-Z0-9]+-\d+$/;
30315
30332
  var HASH_NUMBER = /^#\d+$/;
30316
30333
  var ASSIST_ITEM_ID = /^a[0-9a-f]{2,}$/;
30317
30334
  function isReferenceOnlyPrompt(prompt) {
30318
- const tokens = prompt.trim().split(/\s+/).filter(Boolean);
30335
+ const tokens = tokenise(prompt);
30336
+ if (tokens.length === 0) return false;
30337
+ return tokens.some(isTrackerUrl) || isBareReferencePrompt(prompt);
30338
+ }
30339
+ function isBareReferencePrompt(prompt) {
30340
+ const tokens = tokenise(prompt);
30319
30341
  if (tokens.length === 0) return false;
30320
- return tokens.some(isTrackerUrl) || tokens.every(isReference);
30342
+ return tokens.every(isReference);
30343
+ }
30344
+ function tokenise(prompt) {
30345
+ return prompt.trim().split(/\s+/).filter(Boolean);
30321
30346
  }
30322
30347
  function isReference(token) {
30323
30348
  return isTrackerUrl(token) || ISSUE_KEY.test(token) || HASH_NUMBER.test(token) || ASSIST_ITEM_ID.test(token);
@@ -30889,6 +30914,88 @@ async function reconcileTranscriptStatus(session, onStatusChange) {
30889
30914
  onStatusChange(session, derived);
30890
30915
  }
30891
30916
 
30917
+ // src/commands/sessions/shared/toolTarget.ts
30918
+ function toolTarget(input) {
30919
+ if (!input || typeof input !== "object") return "";
30920
+ const i = input;
30921
+ const str = (v) => typeof v === "string" ? v : "";
30922
+ const target = str(i.file_path) || str(i.path) || str(i.notebook_path) || str(i.command) || str(i.pattern) || str(i.url) || str(i.query) || str(i.description) || str(i.prompt);
30923
+ return target.replace(/\s+/g, " ").trim().slice(0, 120);
30924
+ }
30925
+
30926
+ // src/commands/sessions/shared/entryMessages.ts
30927
+ function entryMessages(entry) {
30928
+ const content = entry.message?.content;
30929
+ if (entry.type === "user") return userMessages(content);
30930
+ if (entry.type === "assistant") return assistantMessages(content);
30931
+ return [];
30932
+ }
30933
+ function userMessages(content) {
30934
+ if (typeof content === "string") return text16("user", cleanUserText(content));
30935
+ if (!Array.isArray(content)) return [];
30936
+ return content.filter((c) => c.type === "text").flatMap((c) => text16("user", cleanUserText(c.text ?? "")));
30937
+ }
30938
+ function assistantMessages(content) {
30939
+ if (typeof content === "string") return text16("assistant", content.trim());
30940
+ if (!Array.isArray(content)) return [];
30941
+ return content.flatMap((c) => assistantItem(c));
30942
+ }
30943
+ function assistantItem(c) {
30944
+ if (c.type === "text") return text16("assistant", (c.text ?? "").trim());
30945
+ if (c.type === "tool_use")
30946
+ return [
30947
+ {
30948
+ role: "tool",
30949
+ tool: typeof c.name === "string" ? c.name : "tool",
30950
+ target: toolTarget(c.input)
30951
+ }
30952
+ ];
30953
+ return [];
30954
+ }
30955
+ function text16(role, value) {
30956
+ return value ? [{ role, text: value }] : [];
30957
+ }
30958
+ function cleanUserText(value) {
30959
+ return value.replace(/<command-[^>]*>[\s\S]*?<\/command-[^>]*>/g, "").replace(/<local-command-[^>]*>[\s\S]*?<\/local-command-[^>]*>/g, "").trim();
30960
+ }
30961
+
30962
+ // src/commands/sessions/summarise/extractContextAfterReference.ts
30963
+ var MIN_CONTEXT_CHARS = 120;
30964
+ var MAX_CONTEXT_CHARS = 800;
30965
+ function extractContextAfterReference(filePath) {
30966
+ const head = readTranscriptHead(filePath);
30967
+ if (head === void 0) return void 0;
30968
+ const parts = [];
30969
+ let length = 0;
30970
+ for (const text17 of conversationText(head)) {
30971
+ if (parts.length === 0 && isBareReferencePrompt(text17)) continue;
30972
+ parts.push(text17);
30973
+ length += text17.length;
30974
+ if (length >= MAX_CONTEXT_CHARS) break;
30975
+ }
30976
+ if (length < MIN_CONTEXT_CHARS) return void 0;
30977
+ return parts.join("\n").slice(0, MAX_CONTEXT_CHARS);
30978
+ }
30979
+ function* conversationText(head) {
30980
+ for (const line of head.split("\n")) {
30981
+ if (!line) continue;
30982
+ const entry = parseEntry(line);
30983
+ if (!entry || entry.isSidechain || entry.isMeta) continue;
30984
+ for (const message3 of entryMessages(entry)) {
30985
+ if (message3.role === "tool") continue;
30986
+ const text17 = message3.text.trim();
30987
+ if (text17) yield text17;
30988
+ }
30989
+ }
30990
+ }
30991
+ function parseEntry(line) {
30992
+ try {
30993
+ return JSON.parse(line);
30994
+ } catch {
30995
+ return void 0;
30996
+ }
30997
+ }
30998
+
30892
30999
  // src/commands/sessions/summarise/extractFirstUserMessage.ts
30893
31000
  function extractFirstUserMessage(filePath) {
30894
31001
  for (const text17 of iterateUserMessages(filePath)) {
@@ -30904,17 +31011,25 @@ function truncate3(text17, maxChars = 500) {
30904
31011
 
30905
31012
  // src/commands/sessions/daemon/startTranscriptTitleGeneration.ts
30906
31013
  function startTranscriptTitleGeneration(session, notify2) {
30907
- if (session.commandType !== "claude") return;
30908
31014
  if (session.generatedTitle || session.titleGenerationStarted) return;
30909
- if (session.initialPrompt?.trim()) return;
31015
+ const source = titleSource(session);
31016
+ if (!source) return;
30910
31017
  const filePath = transcriptPath(session);
30911
31018
  if (!filePath) return;
30912
- const firstMessage = extractFirstUserMessage(filePath);
30913
- if (!firstMessage) return;
31019
+ const context = source === "after-reference" ? extractContextAfterReference(filePath) : extractFirstUserMessage(filePath);
31020
+ if (!context) return;
30914
31021
  daemonLog(
30915
- `session ${session.id} deriving title from first transcript message`
31022
+ source === "after-reference" ? `session ${session.id} deriving title from transcript context after the reference` : `session ${session.id} deriving title from first transcript message`
30916
31023
  );
30917
- runSessionTitleGeneration(session, firstMessage, notify2);
31024
+ runSessionTitleGeneration(session, context, notify2);
31025
+ }
31026
+ function titleSource(session) {
31027
+ if (session.commandType === "claude")
31028
+ return session.initialPrompt?.trim() ? void 0 : "first-message";
31029
+ if (session.activity?.itemName) return void 0;
31030
+ const prompt = sessionTitlePrompt(session);
31031
+ if (!prompt || !isReferenceOnlyPrompt(prompt)) return void 0;
31032
+ return "after-reference";
30918
31033
  }
30919
31034
  function transcriptPath(session) {
30920
31035
  if (session.transcriptPath) return session.transcriptPath;
@@ -33394,53 +33509,6 @@ function handleSetStatus(client, m, d) {
33394
33509
 
33395
33510
  // src/commands/sessions/shared/parseTranscript.ts
33396
33511
  import * as fs39 from "fs";
33397
-
33398
- // src/commands/sessions/shared/toolTarget.ts
33399
- function toolTarget(input) {
33400
- if (!input || typeof input !== "object") return "";
33401
- const i = input;
33402
- const str = (v) => typeof v === "string" ? v : "";
33403
- const target = str(i.file_path) || str(i.path) || str(i.notebook_path) || str(i.command) || str(i.pattern) || str(i.url) || str(i.query) || str(i.description) || str(i.prompt);
33404
- return target.replace(/\s+/g, " ").trim().slice(0, 120);
33405
- }
33406
-
33407
- // src/commands/sessions/shared/entryMessages.ts
33408
- function entryMessages(entry) {
33409
- const content = entry.message?.content;
33410
- if (entry.type === "user") return userMessages(content);
33411
- if (entry.type === "assistant") return assistantMessages(content);
33412
- return [];
33413
- }
33414
- function userMessages(content) {
33415
- if (typeof content === "string") return text16("user", cleanUserText(content));
33416
- if (!Array.isArray(content)) return [];
33417
- return content.filter((c) => c.type === "text").flatMap((c) => text16("user", cleanUserText(c.text ?? "")));
33418
- }
33419
- function assistantMessages(content) {
33420
- if (typeof content === "string") return text16("assistant", content.trim());
33421
- if (!Array.isArray(content)) return [];
33422
- return content.flatMap((c) => assistantItem(c));
33423
- }
33424
- function assistantItem(c) {
33425
- if (c.type === "text") return text16("assistant", (c.text ?? "").trim());
33426
- if (c.type === "tool_use")
33427
- return [
33428
- {
33429
- role: "tool",
33430
- tool: typeof c.name === "string" ? c.name : "tool",
33431
- target: toolTarget(c.input)
33432
- }
33433
- ];
33434
- return [];
33435
- }
33436
- function text16(role, value) {
33437
- return value ? [{ role, text: value }] : [];
33438
- }
33439
- function cleanUserText(value) {
33440
- return value.replace(/<command-[^>]*>[\s\S]*?<\/command-[^>]*>/g, "").replace(/<local-command-[^>]*>[\s\S]*?<\/local-command-[^>]*>/g, "").trim();
33441
- }
33442
-
33443
- // src/commands/sessions/shared/parseTranscript.ts
33444
33512
  async function parseTranscript(sessionId) {
33445
33513
  const filePath = await findSessionJsonlPath(sessionId);
33446
33514
  if (!filePath) return [];
@@ -33966,6 +34034,13 @@ import chalk213 from "chalk";
33966
34034
  // src/shared/rateLimitLevel.ts
33967
34035
  var FIVE_HOUR_SECONDS = 5 * 3600;
33968
34036
  var SEVEN_DAY_SECONDS = 7 * 86400;
34037
+ function rateLimitElapsedFraction(resetsAt, windowSeconds, now) {
34038
+ if (resetsAt == null) return void 0;
34039
+ const timeRemaining = Math.max(0, resetsAt - now);
34040
+ const elapsed = Math.max(0, windowSeconds - timeRemaining) / windowSeconds;
34041
+ if (elapsed < 0.05) return void 0;
34042
+ return elapsed;
34043
+ }
33969
34044
  function formatRateLimitTimeLeft(resetsAt, now) {
33970
34045
  const seconds = Math.max(0, resetsAt - now);
33971
34046
  const days = Math.floor(seconds / 86400);
@@ -33976,10 +34051,8 @@ function formatRateLimitTimeLeft(resetsAt, now) {
33976
34051
  return `${minutes}m`;
33977
34052
  }
33978
34053
  function projectUsage(pct, resetsAt, windowSeconds, now) {
33979
- if (resetsAt == null) return void 0;
33980
- const timeRemaining = Math.max(0, resetsAt - now);
33981
- const elapsed = Math.max(0, windowSeconds - timeRemaining) / windowSeconds;
33982
- if (elapsed < 0.05) return void 0;
34054
+ const elapsed = rateLimitElapsedFraction(resetsAt, windowSeconds, now);
34055
+ if (elapsed == null) return void 0;
33983
34056
  return pct / elapsed;
33984
34057
  }
33985
34058
  function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.514.2",
3
+ "version": "0.516.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -101,6 +101,7 @@
101
101
  "jscpd": "^4.0.5",
102
102
  "jsdom": "^29.1.1",
103
103
  "knip": "^5.71.0",
104
+ "monaco-editor": "^0.56.0",
104
105
  "oxfmt": "^0.54.0",
105
106
  "oxlint": "^1.69.0",
106
107
  "react": "^19.2.4",