@basestream/cli 0.2.8 → 0.2.10

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +24 -14
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -250,7 +250,7 @@ async function login() {
250
250
  // src/cli/commands/init.ts
251
251
  var CLAUDE_DIR = path2.join(os2.homedir(), ".claude");
252
252
  var CLAUDE_SETTINGS_PATH = path2.join(CLAUDE_DIR, "settings.json");
253
- var CLAUDE_SKILLS_PATH = path2.join(CLAUDE_DIR, "skills", "bs-summarize.md");
253
+ var CLAUDE_SKILLS_PATH = path2.join(CLAUDE_DIR, "skills", "bs-summarize", "SKILL.md");
254
254
  var CLAUDE_MD_PATH = path2.join(CLAUDE_DIR, "CLAUDE.md");
255
255
  var HOOK_COMMAND = "npx --yes @basestream/cli@latest _hook-stop";
256
256
  var HOOK_MARKER = "_hook-stop";
@@ -258,14 +258,20 @@ var HOOK_TIMEOUT = 60;
258
258
  var CLAUDE_MD_MARKER = "<!-- basestream -->";
259
259
  var CLAUDE_MD_RULE = `${CLAUDE_MD_MARKER}
260
260
  - Before starting any non-trivial task, if the reason or context behind the work isn't already clear, ask: "What's the context for this?" Skip this for small tasks, typo fixes, or anything self-explanatory.
261
- - After completing any meaningful work (fixing a bug, implementing a feature, making a significant change), invoke /bs-summarize to keep the session summary up to date. Include the "why" if it was provided.
261
+ - After writing or editing any file, you MUST invoke /bs-summarize before your next response. No exceptions \u2014 this keeps the session record accurate even if the conversation ends unexpectedly.
262
262
  <!-- /basestream -->`;
263
263
  var SKILL_CONTENT = `---
264
264
  name: bs-summarize
265
265
  description: Update the Basestream session summary with what's been accomplished so far
266
266
  ---
267
267
 
268
- First, read the existing summary file at \`~/.basestream/sessions/\${CLAUDE_SESSION_ID}-summary.md\` if it exists \u2014 this is the running record of work done so far this session.
268
+ First, find the current session ID:
269
+ \`\`\`
270
+ cat ~/.basestream/current-session-id
271
+ \`\`\`
272
+ If the file doesn't exist, skip this skill entirely \u2014 the session hasn't registered with Basestream yet (this happens on the very first turn of a brand new install before any Stop hook has fired).
273
+
274
+ Read the existing summary file at \`~/.basestream/sessions/{sessionId}-summary.md\` if it exists \u2014 this is the running record of work done so far this session.
269
275
 
270
276
  Then write an updated summary that aggregates the previous summary with everything that has happened since. Focus on:
271
277
  - Why the work was done (if context was provided \u2014 skip if not known)
@@ -275,7 +281,7 @@ Then write an updated summary that aggregates the previous summary with everythi
275
281
 
276
282
  Do not just append \u2014 synthesize everything into a single cohesive summary. Merge related work together, avoid repeating the same point twice, and drop anything superseded by later changes. Be concise \u2014 let the scope of the work determine the length. A small fix deserves one sentence; a large multi-part session can be a short paragraph. Plain prose, no bullet points.
277
283
 
278
- Write the result to \`~/.basestream/sessions/\${CLAUDE_SESSION_ID}-summary.md\`, overwriting the file.
284
+ Write the result to \`~/.basestream/sessions/{sessionId}-summary.md\`, overwriting the file.
279
285
  `;
280
286
  var BASESTREAM_DIR2 = path2.join(os2.homedir(), ".basestream");
281
287
  var REQUIRED_PERMISSIONS = [
@@ -616,9 +622,13 @@ function analyzeTranscript(transcriptPath, acc) {
616
622
  if (!fs5.existsSync(transcriptPath)) return acc;
617
623
  const content = fs5.readFileSync(transcriptPath, "utf-8");
618
624
  const lines = content.split("\n").filter(Boolean);
625
+ let firstTimestamp;
619
626
  for (const line of lines) {
620
627
  const entry = parseTranscriptLine(line);
621
628
  if (!entry) continue;
629
+ if (!firstTimestamp && entry.timestamp) {
630
+ firstTimestamp = entry.timestamp;
631
+ }
622
632
  const message = entry.message;
623
633
  const contentBlocks = Array.isArray(message?.content) ? message.content : [];
624
634
  if (entry.type === "assistant" && contentBlocks.length > 0) {
@@ -647,7 +657,7 @@ function analyzeTranscript(transcriptPath, acc) {
647
657
  for (const block of contentBlocks) {
648
658
  if (block.type === "tool_result") {
649
659
  const resultContent = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c2) => c2.text || "").join("\n") : "";
650
- const shaMatch = resultContent.match(/\[([a-f0-9]{7,12})\]\s/);
660
+ const shaMatch = resultContent.match(/\[(?:[^\]]+?\s)?([a-f0-9]{7,12})\]/);
651
661
  if (shaMatch) {
652
662
  acc.commitShas.add(shaMatch[1]);
653
663
  }
@@ -655,6 +665,9 @@ function analyzeTranscript(transcriptPath, acc) {
655
665
  }
656
666
  }
657
667
  }
668
+ if (firstTimestamp) {
669
+ acc.startedAt = firstTimestamp;
670
+ }
658
671
  return acc;
659
672
  }
660
673
  function categorizeWork(acc) {
@@ -671,20 +684,16 @@ function categorizeWork(acc) {
671
684
  const configFiles = files.filter(
672
685
  (f) => f.includes("Dockerfile") || f.includes(".yml") || f.includes(".yaml") || f.includes("ci")
673
686
  );
674
- if (testFiles.length > fileCount / 2) category = WorkCategory.TESTING;
675
- else if (docFiles.length > fileCount / 2) category = WorkCategory.DOCS;
676
- else if (configFiles.length > fileCount / 2) category = WorkCategory.DEVOPS;
687
+ if (testFiles.length >= fileCount / 2) category = WorkCategory.TESTING;
688
+ else if (docFiles.length >= fileCount / 2) category = WorkCategory.DOCS;
689
+ else if (configFiles.length >= fileCount / 2) category = WorkCategory.DEVOPS;
677
690
  else category = WorkCategory.FEATURE;
678
691
  } else {
679
692
  const tools = acc.toolCalls.map((t) => t.tool);
680
- const writeTools = tools.filter(
681
- (t) => ["Write", "Edit", "NotebookEdit"].includes(t)
682
- );
683
693
  const readTools = tools.filter(
684
694
  (t) => ["Read", "Grep", "Glob", "WebFetch", "WebSearch"].includes(t)
685
695
  );
686
- if (writeTools.length > 0) category = WorkCategory.FEATURE;
687
- else if (readTools.length > tools.length / 2) category = WorkCategory.REFACTOR;
696
+ if (readTools.length >= tools.length / 2) category = WorkCategory.REFACTOR;
688
697
  }
689
698
  let complexity = Complexity.LOW;
690
699
  if (fileCount >= 7 || acc.toolCalls.length >= 30) complexity = Complexity.HIGH;
@@ -810,6 +819,7 @@ async function hookStop() {
810
819
  if (!session_id) process.exit(0);
811
820
  ensureDirs();
812
821
  pruneOldLogs();
822
+ fs5.writeFileSync(path5.join(BASESTREAM_DIR, "current-session-id"), session_id);
813
823
  const log = makeLogger(session_id);
814
824
  log("hook fired", "cwd=" + cwd);
815
825
  let acc = readSessionAccumulator(session_id);
@@ -972,7 +982,7 @@ async function main() {
972
982
  process.exit(0);
973
983
  }
974
984
  if (command === "--version" || command === "-v") {
975
- console.log(true ? "0.2.8" : "dev");
985
+ console.log(true ? "0.2.10" : "dev");
976
986
  process.exit(0);
977
987
  }
978
988
  switch (command || "init") {
package/package.json CHANGED
@@ -18,5 +18,5 @@
18
18
  "unlink:cli": "npm unlink -g @basestream/cli"
19
19
  },
20
20
  "type": "module",
21
- "version": "0.2.8"
21
+ "version": "0.2.10"
22
22
  }