@pencil-agent/nano-pencil 1.11.16 → 1.11.17

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.
@@ -78,6 +78,18 @@ export interface Settings {
78
78
  autocompleteMaxVisible?: number;
79
79
  showHardwareCursor?: boolean;
80
80
  markdown?: MarkdownSettings;
81
+ /** NanoMem / Dream settings */
82
+ nanomem?: {
83
+ autoDream?: {
84
+ enabled?: boolean;
85
+ minHours?: number;
86
+ minSessions?: number;
87
+ scanIntervalMinutes?: number;
88
+ };
89
+ dream?: {
90
+ lockStaleMinutes?: number;
91
+ };
92
+ };
81
93
  }
82
94
  export type SettingsScope = "global" | "project";
83
95
  export interface SettingsStorage {
@@ -124,6 +136,8 @@ export declare class SettingsManager {
124
136
  private static migrateSettings;
125
137
  getGlobalSettings(): Settings;
126
138
  getProjectSettings(): Settings;
139
+ /** Get merged effective settings (project overrides global). */
140
+ getSettings(): Settings;
127
141
  reload(): void;
128
142
  /** Apply additional overrides on top of current settings */
129
143
  applyOverrides(overrides: Partial<Settings>): void;
@@ -181,6 +181,10 @@ export class SettingsManager {
181
181
  getProjectSettings() {
182
182
  return structuredClone(this.projectSettings);
183
183
  }
184
+ /** Get merged effective settings (project overrides global). */
185
+ getSettings() {
186
+ return structuredClone(this.settings);
187
+ }
184
188
  reload() {
185
189
  const globalLoad = SettingsManager.tryLoadFromStorage(this.storage, "global");
186
190
  if (!globalLoad.error) {
@@ -73,6 +73,7 @@ export declare class ExtensionRunner {
73
73
  private getContextUsageFn;
74
74
  private compactFn;
75
75
  private getSystemPromptFn;
76
+ private getSettingsFn;
76
77
  private newSessionHandler;
77
78
  private forkHandler;
78
79
  private navigateTreeHandler;
@@ -96,6 +96,7 @@ export class ExtensionRunner {
96
96
  getContextUsageFn = () => undefined;
97
97
  compactFn = () => { };
98
98
  getSystemPromptFn = () => "";
99
+ getSettingsFn = () => ({});
99
100
  newSessionHandler = async () => ({ cancelled: false });
100
101
  forkHandler = async () => ({ cancelled: false });
101
102
  navigateTreeHandler = async () => ({ cancelled: false });
@@ -165,6 +166,7 @@ export class ExtensionRunner {
165
166
  this.getContextUsageFn = contextActions.getContextUsage;
166
167
  this.compactFn = contextActions.compact;
167
168
  this.getSystemPromptFn = contextActions.getSystemPrompt;
169
+ this.getSettingsFn = contextActions.getSettings;
168
170
  // Process provider registrations queued during extension loading
169
171
  for (const { name, config } of this.runtime.pendingProviderRegistrations) {
170
172
  this.modelRegistry.registerProvider(name, config);
@@ -382,6 +384,7 @@ export class ExtensionRunner {
382
384
  getContextUsage: () => this.getContextUsageFn(),
383
385
  compact: (options) => this.compactFn(options),
384
386
  getSystemPrompt: () => this.getSystemPromptFn(),
387
+ getSettings: () => this.getSettingsFn(),
385
388
  };
386
389
  }
387
390
  createCommandContext() {
@@ -205,6 +205,8 @@ export interface ExtensionContext {
205
205
  compact(options?: CompactOptions): void;
206
206
  /** Get the current effective system prompt. */
207
207
  getSystemPrompt(): string;
208
+ /** Get current merged settings (project overrides global). */
209
+ getSettings(): import("../config/settings-manager.js").Settings;
208
210
  }
209
211
  /**
210
212
  * Extended context for command handlers.
@@ -931,6 +933,7 @@ export interface ExtensionContextActions {
931
933
  getContextUsage: () => ContextUsage | undefined;
932
934
  compact: (options?: CompactOptions) => void;
933
935
  getSystemPrompt: () => string;
936
+ getSettings: () => import("../config/settings-manager.js").Settings;
934
937
  }
935
938
  /**
936
939
  * Actions for ExtensionCommandContext (ctx.* in command handlers).
@@ -1815,6 +1815,7 @@ export class AgentSession {
1815
1815
  return undefined;
1816
1816
  }
1817
1817
  },
1818
+ getSettings: () => this.settingsManager.getSettings(),
1818
1819
  isIdle: () => !this.isStreaming,
1819
1820
  abort: () => this.abort(),
1820
1821
  hasPendingMessages: () => this.pendingMessageCount > 0,
@@ -319,5 +319,14 @@ export declare class SessionManager {
319
319
  * @param onProgress Optional callback for progress updates (loaded, total)
320
320
  */
321
321
  static listAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;
322
+ /**
323
+ * Lightweight scan: count session files with mtime > sinceMs without reading file contents.
324
+ * Designed for gate checks (e.g., auto-dream) where approximate counts are OK.
325
+ */
326
+ static countTouchedSince(cwd: string, sinceMs: number, options?: {
327
+ sessionDir?: string;
328
+ excludeBasename?: string;
329
+ concurrency?: number;
330
+ }): Promise<number>;
322
331
  }
323
332
  //# sourceMappingURL=session-manager.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, statSync, writeFileSync, } from "fs";
3
3
  import { readdir, readFile, stat } from "fs/promises";
4
- import { join, resolve } from "path";
4
+ import { basename, join, resolve } from "path";
5
5
  import { getAgentDir as getDefaultAgentDir, getSessionsDir } from "../../config.js";
6
6
  import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage, } from "../messages.js";
7
7
  export const CURRENT_SESSION_VERSION = 3;
@@ -413,6 +413,21 @@ async function listSessionsFromDir(dir, onProgress, progressOffset = 0, progress
413
413
  }
414
414
  return sessions;
415
415
  }
416
+ async function runWithConcurrency(items, concurrency, fn) {
417
+ const results = new Array(items.length);
418
+ let nextIndex = 0;
419
+ const worker = async () => {
420
+ while (true) {
421
+ const i = nextIndex++;
422
+ if (i >= items.length)
423
+ return;
424
+ results[i] = await fn(items[i]);
425
+ }
426
+ };
427
+ const poolSize = Math.max(1, Math.min(concurrency, items.length || 1));
428
+ await Promise.all(Array.from({ length: poolSize }, () => worker()));
429
+ return results;
430
+ }
416
431
  /**
417
432
  * Manages conversation sessions as append-only trees stored in JSONL files.
418
433
  *
@@ -1087,5 +1102,34 @@ export class SessionManager {
1087
1102
  return [];
1088
1103
  }
1089
1104
  }
1105
+ /**
1106
+ * Lightweight scan: count session files with mtime > sinceMs without reading file contents.
1107
+ * Designed for gate checks (e.g., auto-dream) where approximate counts are OK.
1108
+ */
1109
+ static async countTouchedSince(cwd, sinceMs, options) {
1110
+ const dir = options?.sessionDir ?? getDefaultSessionDir(cwd);
1111
+ const concurrency = options?.concurrency ?? 64;
1112
+ try {
1113
+ if (!existsSync(dir))
1114
+ return 0;
1115
+ const files = (await readdir(dir))
1116
+ .filter((f) => f.endsWith(".jsonl"))
1117
+ .filter((f) => (options?.excludeBasename ? basename(f, ".jsonl") !== options.excludeBasename : true))
1118
+ .map((f) => join(dir, f));
1119
+ const mtimes = await runWithConcurrency(files, concurrency, async (file) => {
1120
+ try {
1121
+ const s = await stat(file);
1122
+ return s.mtimeMs;
1123
+ }
1124
+ catch {
1125
+ return 0;
1126
+ }
1127
+ });
1128
+ return mtimes.filter((m) => m > sinceMs).length;
1129
+ }
1130
+ catch {
1131
+ return 0;
1132
+ }
1133
+ }
1090
1134
  }
1091
1135
  //# sourceMappingURL=session-manager.js.map
@@ -13,6 +13,7 @@ export const BUILTIN_SLASH_COMMANDS = [
13
13
  name: "memory",
14
14
  description: "Show project memory and knowledge (NanoMem)",
15
15
  },
16
+ { name: "dream", description: "Consolidate project memory (NanoMem)" },
16
17
  { name: "export", description: "Export session to HTML file" },
17
18
  { name: "share", description: "Share session as a secret GitHub gist" },
18
19
  { name: "copy", description: "Copy last agent message to clipboard" },