cliskill 1.1.0 → 1.1.1

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "../chunk-LHS6LLBW.js";
4
+ } from "../chunk-PRO7DR3G.js";
5
5
  import "../chunk-AJENHWD3.js";
6
6
  export {
7
7
  runCli
@@ -5540,6 +5540,32 @@ var EnhancedMemoryStore = class {
5540
5540
  }
5541
5541
  return result;
5542
5542
  }
5543
+ /**
5544
+ * Get a formatted summary of all memories for injection into system prompt.
5545
+ * Returns empty string if no memories stored.
5546
+ */
5547
+ getSummary() {
5548
+ if (this.entries.size === 0) return "";
5549
+ const sections = [];
5550
+ for (const [topic, entries] of this.entries) {
5551
+ const latest = entries[entries.length - 1];
5552
+ if (!latest) continue;
5553
+ const age = Date.now() - latest.timestamp;
5554
+ const ageDays = Math.floor(age / (1e3 * 60 * 60 * 24));
5555
+ const ageStr = ageDays === 0 ? "today" : ageDays === 1 ? "yesterday" : `${ageDays}d ago`;
5556
+ sections.push(`- **${topic}**: ${latest.content} (${ageStr})`);
5557
+ }
5558
+ if (sections.length === 0) return "";
5559
+ return [
5560
+ "<global-memory>",
5561
+ "The following memories were saved in previous sessions and persist across conversations:",
5562
+ "",
5563
+ ...sections,
5564
+ "",
5565
+ "Use the memory tool to save new facts or search/recall existing memories.",
5566
+ "</global-memory>"
5567
+ ].join("\n");
5568
+ }
5543
5569
  async persist(topic) {
5544
5570
  const entries = this.entries.get(topic);
5545
5571
  if (!entries || entries.length === 0) {
@@ -5555,6 +5581,25 @@ var EnhancedMemoryStore = class {
5555
5581
  }
5556
5582
  };
5557
5583
 
5584
+ // src/memory/global-memory.ts
5585
+ var cachedSummary = null;
5586
+ async function loadGlobalMemorySummary() {
5587
+ if (cachedSummary !== null) return cachedSummary;
5588
+ try {
5589
+ const dir = getGlobalMemoryDir();
5590
+ const store = new EnhancedMemoryStore(dir);
5591
+ await store.init();
5592
+ cachedSummary = store.getSummary();
5593
+ return cachedSummary;
5594
+ } catch {
5595
+ cachedSummary = "";
5596
+ return "";
5597
+ }
5598
+ }
5599
+ function invalidateGlobalMemoryCache() {
5600
+ cachedSummary = null;
5601
+ }
5602
+
5558
5603
  // src/tools/builtins/memory-tool.ts
5559
5604
  var memoryInputSchema = z19.object({
5560
5605
  action: z19.enum(["save", "recall", "search", "list", "delete"]).describe(
@@ -5590,6 +5635,7 @@ var MemoryTool = class extends BaseTool {
5590
5635
  return "Error: topic and content are required for save action";
5591
5636
  }
5592
5637
  await store.addMemory(input.topic, input.content, input.tags ?? [], "agent");
5638
+ invalidateGlobalMemoryCache();
5593
5639
  return `\u2705 Saved to "${input.topic}": ${input.content.slice(0, 100)}${input.content.length > 100 ? "..." : ""}`;
5594
5640
  }
5595
5641
  case "recall": {
@@ -5637,6 +5683,7 @@ var MemoryTool = class extends BaseTool {
5637
5683
  entry.entry.lastAccessed = 0;
5638
5684
  }
5639
5685
  await store.prune();
5686
+ invalidateGlobalMemoryCache();
5640
5687
  return `\u{1F5D1}\uFE0F Deleted ${topicEntries.length} entries from "${input.topic}"`;
5641
5688
  }
5642
5689
  default:
@@ -6401,6 +6448,147 @@ ${m.content}`;
6401
6448
  ].join("\n");
6402
6449
  }
6403
6450
 
6451
+ // src/services/session-recovery.ts
6452
+ import { readFile as readFile9, readdir as readdir5 } from "fs/promises";
6453
+ import { join as join10 } from "path";
6454
+ import { existsSync as existsSync5 } from "fs";
6455
+ async function recoverSession(filePath) {
6456
+ const raw = await readFile9(filePath, "utf-8");
6457
+ const lines = raw.split("\n").filter((line) => line.trim().length > 0);
6458
+ const entries = [];
6459
+ for (const line of lines) {
6460
+ try {
6461
+ const entry = JSON.parse(line);
6462
+ if (entry.type && entry.content !== void 0) {
6463
+ entries.push(entry);
6464
+ }
6465
+ } catch {
6466
+ }
6467
+ }
6468
+ const messages = reconstructMessages(entries);
6469
+ const firstEntry = entries[0];
6470
+ const timestamp = firstEntry?.timestamp ?? 0;
6471
+ return {
6472
+ sessionId: filePath,
6473
+ filePath,
6474
+ timestamp,
6475
+ messages,
6476
+ entryCount: entries.length
6477
+ };
6478
+ }
6479
+ async function listSessions(limit = 20) {
6480
+ const dir = getSessionsDir();
6481
+ if (!existsSync5(dir)) return [];
6482
+ const files = await readdir5(dir);
6483
+ const sessionFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
6484
+ const sessions = [];
6485
+ for (const fileName of sessionFiles) {
6486
+ const filePath = join10(dir, fileName);
6487
+ try {
6488
+ const raw = await readFile9(filePath, "utf-8");
6489
+ const lines = raw.split("\n").filter((line) => line.trim().length > 0);
6490
+ let lastActivity = 0;
6491
+ let entryCount = 0;
6492
+ for (const line of lines) {
6493
+ try {
6494
+ const entry = JSON.parse(line);
6495
+ if (entry.timestamp && entry.timestamp > lastActivity) {
6496
+ lastActivity = entry.timestamp;
6497
+ }
6498
+ entryCount++;
6499
+ } catch {
6500
+ }
6501
+ }
6502
+ const dateStr = fileName.replace("session-", "").replace(".jsonl", "");
6503
+ const fileTimestamp = Date.parse(dateStr) || lastActivity;
6504
+ sessions.push({
6505
+ fileName,
6506
+ filePath,
6507
+ timestamp: fileTimestamp,
6508
+ entryCount,
6509
+ lastActivity
6510
+ });
6511
+ } catch {
6512
+ }
6513
+ }
6514
+ sessions.sort((a, b) => b.lastActivity - a.lastActivity);
6515
+ return sessions.slice(0, limit);
6516
+ }
6517
+ async function findLatestSession() {
6518
+ const sessions = await listSessions(1);
6519
+ return sessions[0] ?? null;
6520
+ }
6521
+ async function getLastSessionSummary() {
6522
+ try {
6523
+ const latest = await findLatestSession();
6524
+ if (!latest) return "";
6525
+ const raw = await readFile9(latest.filePath, "utf-8");
6526
+ const lines = raw.split("\n").filter((line) => line.trim().length > 0);
6527
+ const userMessages = [];
6528
+ const assistantTopics = [];
6529
+ for (const line of lines) {
6530
+ try {
6531
+ const entry = JSON.parse(line);
6532
+ if (entry.type === "user" && entry.content.trim()) {
6533
+ userMessages.push(entry.content.trim());
6534
+ } else if (entry.type === "assistant" && entry.content.trim()) {
6535
+ const preview = entry.content.trim().slice(0, 120);
6536
+ assistantTopics.push(preview);
6537
+ }
6538
+ } catch {
6539
+ }
6540
+ }
6541
+ if (userMessages.length === 0) return "";
6542
+ const date = new Date(latest.lastActivity).toLocaleString();
6543
+ const lastUserMsg = userMessages[userMessages.length - 1];
6544
+ const lastAssistant = assistantTopics.length > 0 ? assistantTopics[assistantTopics.length - 1] : "N/A";
6545
+ return [
6546
+ "<last-session-context>",
6547
+ `Previous session (${date}, ${lines.length} entries):`,
6548
+ ` Last user message: ${lastUserMsg.slice(0, 200)}`,
6549
+ ` Last assistant response: ${lastAssistant.slice(0, 200)}`,
6550
+ ` Total user messages in session: ${userMessages.length}`,
6551
+ "",
6552
+ "Use the memory tool to recall specific details from past interactions.",
6553
+ "</last-session-context>"
6554
+ ].join("\n");
6555
+ } catch {
6556
+ return "";
6557
+ }
6558
+ }
6559
+ function reconstructMessages(entries) {
6560
+ const messages = [];
6561
+ let i = 0;
6562
+ while (i < entries.length) {
6563
+ const entry = entries[i];
6564
+ if (entry.type === "user") {
6565
+ const content = [{ type: "text", text: entry.content }];
6566
+ messages.push({ role: "user", content });
6567
+ i++;
6568
+ } else if (entry.type === "assistant") {
6569
+ const content = [{ type: "text", text: entry.content }];
6570
+ messages.push({ role: "assistant", content });
6571
+ i++;
6572
+ } else if (entry.type === "tool_use") {
6573
+ const lastMsg = messages[messages.length - 1];
6574
+ if (lastMsg && lastMsg.role === "assistant") {
6575
+ }
6576
+ i++;
6577
+ } else if (entry.type === "tool_result") {
6578
+ const content = [{
6579
+ type: "tool_result",
6580
+ toolUseId: `recovered-${i}`,
6581
+ content: entry.content
6582
+ }];
6583
+ messages.push({ role: "user", content });
6584
+ i++;
6585
+ } else {
6586
+ i++;
6587
+ }
6588
+ }
6589
+ return messages;
6590
+ }
6591
+
6404
6592
  // src/core/loop.ts
6405
6593
  var MAX_TURNS = 50;
6406
6594
  var MAX_CONSECUTIVE_TOOL_ERRORS = 3;
@@ -6463,7 +6651,9 @@ ${result.summary}` }]
6463
6651
  });
6464
6652
  const toolDefs = toolRegistry.getToolDefinitions();
6465
6653
  const projectMemory = await loadProjectMemoryPrompt(cwd2);
6466
- const effectiveSystemPrompt = systemPrompt + fastMode.getSystemPromptModifier() + (projectMemory ? "\n\n" + projectMemory : "");
6654
+ const globalMemory = await loadGlobalMemorySummary();
6655
+ const lastSessionSummary = await getLastSessionSummary();
6656
+ const effectiveSystemPrompt = systemPrompt + fastMode.getSystemPromptModifier() + (projectMemory ? "\n\n" + projectMemory : "") + (globalMemory ? "\n\n" + globalMemory : "") + (lastSessionSummary ? "\n\n" + lastSessionSummary : "");
6467
6657
  const toolContext = {
6468
6658
  cwd: cwd2,
6469
6659
  abortSignal,
@@ -6949,7 +7139,7 @@ function createMissingToolResults(toolCalls, errorMessage) {
6949
7139
  import { useState, useEffect, useCallback, useRef, useMemo, memo } from "react";
6950
7140
  import { Box, Text, render, useInput, useApp, useStdout } from "ink";
6951
7141
  import { readdirSync } from "fs";
6952
- import { join as join10, basename as basename2, dirname as dirname3 } from "path";
7142
+ import { join as join11, basename as basename2, dirname as dirname3 } from "path";
6953
7143
  import { exec as exec2, execSync as execSync2 } from "child_process";
6954
7144
  import { jsx, jsxs } from "react/jsx-runtime";
6955
7145
  var C = {
@@ -7543,10 +7733,10 @@ function InkApp({ model, toolCount, onSubmit, onCancel }) {
7543
7733
  const selected = currentFiles[selectedIdx];
7544
7734
  if (selected) {
7545
7735
  if (selected.isDir) {
7546
- setFileCwd(join10(fileCwd, selected.name));
7736
+ setFileCwd(join11(fileCwd, selected.name));
7547
7737
  setSelectedIdx(0);
7548
7738
  } else {
7549
- openInEditor(join10(fileCwd, selected.name));
7739
+ openInEditor(join11(fileCwd, selected.name));
7550
7740
  }
7551
7741
  }
7552
7742
  return;
@@ -8144,109 +8334,6 @@ async function registerMCPTools(mcpManager, registerFn) {
8144
8334
  return registered;
8145
8335
  }
8146
8336
 
8147
- // src/services/session-recovery.ts
8148
- import { readFile as readFile9, readdir as readdir5 } from "fs/promises";
8149
- import { join as join11 } from "path";
8150
- import { existsSync as existsSync5 } from "fs";
8151
- async function recoverSession(filePath) {
8152
- const raw = await readFile9(filePath, "utf-8");
8153
- const lines = raw.split("\n").filter((line) => line.trim().length > 0);
8154
- const entries = [];
8155
- for (const line of lines) {
8156
- try {
8157
- const entry = JSON.parse(line);
8158
- if (entry.type && entry.content !== void 0) {
8159
- entries.push(entry);
8160
- }
8161
- } catch {
8162
- }
8163
- }
8164
- const messages = reconstructMessages(entries);
8165
- const firstEntry = entries[0];
8166
- const timestamp = firstEntry?.timestamp ?? 0;
8167
- return {
8168
- sessionId: filePath,
8169
- filePath,
8170
- timestamp,
8171
- messages,
8172
- entryCount: entries.length
8173
- };
8174
- }
8175
- async function listSessions(limit = 20) {
8176
- const dir = getSessionsDir();
8177
- if (!existsSync5(dir)) return [];
8178
- const files = await readdir5(dir);
8179
- const sessionFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
8180
- const sessions = [];
8181
- for (const fileName of sessionFiles) {
8182
- const filePath = join11(dir, fileName);
8183
- try {
8184
- const raw = await readFile9(filePath, "utf-8");
8185
- const lines = raw.split("\n").filter((line) => line.trim().length > 0);
8186
- let lastActivity = 0;
8187
- let entryCount = 0;
8188
- for (const line of lines) {
8189
- try {
8190
- const entry = JSON.parse(line);
8191
- if (entry.timestamp && entry.timestamp > lastActivity) {
8192
- lastActivity = entry.timestamp;
8193
- }
8194
- entryCount++;
8195
- } catch {
8196
- }
8197
- }
8198
- const dateStr = fileName.replace("session-", "").replace(".jsonl", "");
8199
- const fileTimestamp = Date.parse(dateStr) || lastActivity;
8200
- sessions.push({
8201
- fileName,
8202
- filePath,
8203
- timestamp: fileTimestamp,
8204
- entryCount,
8205
- lastActivity
8206
- });
8207
- } catch {
8208
- }
8209
- }
8210
- sessions.sort((a, b) => b.lastActivity - a.lastActivity);
8211
- return sessions.slice(0, limit);
8212
- }
8213
- async function findLatestSession() {
8214
- const sessions = await listSessions(1);
8215
- return sessions[0] ?? null;
8216
- }
8217
- function reconstructMessages(entries) {
8218
- const messages = [];
8219
- let i = 0;
8220
- while (i < entries.length) {
8221
- const entry = entries[i];
8222
- if (entry.type === "user") {
8223
- const content = [{ type: "text", text: entry.content }];
8224
- messages.push({ role: "user", content });
8225
- i++;
8226
- } else if (entry.type === "assistant") {
8227
- const content = [{ type: "text", text: entry.content }];
8228
- messages.push({ role: "assistant", content });
8229
- i++;
8230
- } else if (entry.type === "tool_use") {
8231
- const lastMsg = messages[messages.length - 1];
8232
- if (lastMsg && lastMsg.role === "assistant") {
8233
- }
8234
- i++;
8235
- } else if (entry.type === "tool_result") {
8236
- const content = [{
8237
- type: "tool_result",
8238
- toolUseId: `recovered-${i}`,
8239
- content: entry.content
8240
- }];
8241
- messages.push({ role: "user", content });
8242
- i++;
8243
- } else {
8244
- i++;
8245
- }
8246
- }
8247
- return messages;
8248
- }
8249
-
8250
8337
  // src/ui/repl.ts
8251
8338
  var SessionSaver = class {
8252
8339
  filePath;
@@ -11553,4 +11640,4 @@ export {
11553
11640
  MCPConnectionManager,
11554
11641
  runCli
11555
11642
  };
11556
- //# sourceMappingURL=chunk-LHS6LLBW.js.map
11643
+ //# sourceMappingURL=chunk-PRO7DR3G.js.map