@j0hanz/thinkseq-mcp 1.2.6 → 2.0.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.
Files changed (92) hide show
  1. package/README.md +1 -0
  2. package/dist/app.d.ts +2 -2
  3. package/dist/app.js +5 -3
  4. package/dist/appConfig/runDependencies.d.ts +0 -1
  5. package/dist/appConfig/runDependencies.js +12 -3
  6. package/dist/appConfig/shutdown.d.ts +0 -1
  7. package/dist/appConfig/shutdown.js +0 -1
  8. package/dist/appConfig/types.d.ts +0 -1
  9. package/dist/appConfig/types.js +0 -1
  10. package/dist/engine/revision.d.ts +4 -3
  11. package/dist/engine/revision.js +25 -21
  12. package/dist/engine/thoughtQueries.d.ts +0 -1
  13. package/dist/engine/thoughtQueries.js +26 -19
  14. package/dist/engine/thoughtStore.d.ts +12 -3
  15. package/dist/engine/thoughtStore.js +71 -31
  16. package/dist/engine.d.ts +2 -1
  17. package/dist/engine.js +99 -60
  18. package/dist/engineConfig.d.ts +0 -1
  19. package/dist/engineConfig.js +0 -1
  20. package/dist/index.d.ts +0 -1
  21. package/dist/index.js +0 -1
  22. package/dist/instructions.md +22 -16
  23. package/dist/lib/cli.d.ts +0 -1
  24. package/dist/lib/cli.js +0 -1
  25. package/dist/lib/context.d.ts +0 -1
  26. package/dist/lib/context.js +0 -1
  27. package/dist/lib/diagnostics.d.ts +0 -1
  28. package/dist/lib/diagnostics.js +0 -1
  29. package/dist/lib/errors.d.ts +0 -1
  30. package/dist/lib/errors.js +0 -1
  31. package/dist/lib/mcpLogging.d.ts +4 -2
  32. package/dist/lib/mcpLogging.js +27 -10
  33. package/dist/lib/package.d.ts +0 -1
  34. package/dist/lib/package.js +0 -1
  35. package/dist/lib/stdioGuards.d.ts +0 -1
  36. package/dist/lib/stdioGuards.js +0 -1
  37. package/dist/lib/types.d.ts +1 -1
  38. package/dist/lib/types.js +0 -1
  39. package/dist/schemas/inputs.d.ts +1 -1
  40. package/dist/schemas/inputs.js +6 -1
  41. package/dist/schemas/outputs.d.ts +5 -6
  42. package/dist/schemas/outputs.js +5 -6
  43. package/dist/tools/thinkseq.d.ts +0 -1
  44. package/dist/tools/thinkseq.js +70 -60
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +10 -12
  47. package/dist/app.d.ts.map +0 -1
  48. package/dist/app.js.map +0 -1
  49. package/dist/appConfig/runDependencies.d.ts.map +0 -1
  50. package/dist/appConfig/runDependencies.js.map +0 -1
  51. package/dist/appConfig/shutdown.d.ts.map +0 -1
  52. package/dist/appConfig/shutdown.js.map +0 -1
  53. package/dist/appConfig/types.d.ts.map +0 -1
  54. package/dist/appConfig/types.js.map +0 -1
  55. package/dist/appConfig.d.ts +0 -5
  56. package/dist/appConfig.d.ts.map +0 -1
  57. package/dist/appConfig.js +0 -3
  58. package/dist/appConfig.js.map +0 -1
  59. package/dist/engine/revision.d.ts.map +0 -1
  60. package/dist/engine/revision.js.map +0 -1
  61. package/dist/engine/thoughtQueries.d.ts.map +0 -1
  62. package/dist/engine/thoughtQueries.js.map +0 -1
  63. package/dist/engine/thoughtStore.d.ts.map +0 -1
  64. package/dist/engine/thoughtStore.js.map +0 -1
  65. package/dist/engine.d.ts.map +0 -1
  66. package/dist/engine.js.map +0 -1
  67. package/dist/engineConfig.d.ts.map +0 -1
  68. package/dist/engineConfig.js.map +0 -1
  69. package/dist/index.d.ts.map +0 -1
  70. package/dist/index.js.map +0 -1
  71. package/dist/lib/cli.d.ts.map +0 -1
  72. package/dist/lib/cli.js.map +0 -1
  73. package/dist/lib/context.d.ts.map +0 -1
  74. package/dist/lib/context.js.map +0 -1
  75. package/dist/lib/diagnostics.d.ts.map +0 -1
  76. package/dist/lib/diagnostics.js.map +0 -1
  77. package/dist/lib/errors.d.ts.map +0 -1
  78. package/dist/lib/errors.js.map +0 -1
  79. package/dist/lib/mcpLogging.d.ts.map +0 -1
  80. package/dist/lib/mcpLogging.js.map +0 -1
  81. package/dist/lib/package.d.ts.map +0 -1
  82. package/dist/lib/package.js.map +0 -1
  83. package/dist/lib/stdioGuards.d.ts.map +0 -1
  84. package/dist/lib/stdioGuards.js.map +0 -1
  85. package/dist/lib/types.d.ts.map +0 -1
  86. package/dist/lib/types.js.map +0 -1
  87. package/dist/schemas/inputs.d.ts.map +0 -1
  88. package/dist/schemas/inputs.js.map +0 -1
  89. package/dist/schemas/outputs.d.ts.map +0 -1
  90. package/dist/schemas/outputs.js.map +0 -1
  91. package/dist/tools/thinkseq.d.ts.map +0 -1
  92. package/dist/tools/thinkseq.js.map +0 -1
package/README.md CHANGED
@@ -133,6 +133,7 @@ Record a concise thinking step. Be brief: capture only the essential insight, ca
133
133
  | Field | Type | Required | Description |
134
134
  | :--------------- | :----- | :------: | :----------------------------------------------------------------- |
135
135
  | `thought` | string | yes | Current thinking step (1-8000 chars). |
136
+ | `sessionId` | string | no | Optional session identifier to isolate thought histories. |
136
137
  | `totalThoughts` | number | no | Estimated total thoughts (1-25, default: 3). |
137
138
  | `revisesThought` | number | no | Revise a previous thought by number. Original preserved for audit. |
138
139
 
package/dist/app.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type ProcessLike, type RunDependencies } from './appConfig.js';
1
+ import type { RunDependencies } from './appConfig/runDependencies.js';
2
+ import type { ProcessLike } from './appConfig/types.js';
2
3
  interface ProcessErrorHandlerDeps {
3
4
  processLike?: ProcessLike;
4
5
  logError?: (message: string) => void;
@@ -7,4 +8,3 @@ interface ProcessErrorHandlerDeps {
7
8
  export declare function installProcessErrorHandlers(deps?: ProcessErrorHandlerDeps): void;
8
9
  export declare function run(deps?: RunDependencies): Promise<void>;
9
10
  export {};
10
- //# sourceMappingURL=app.d.ts.map
package/dist/app.js CHANGED
@@ -1,4 +1,5 @@
1
- import { buildShutdownDependencies, resolvePackageIdentity, resolveRunDependencies, } from './appConfig.js';
1
+ import { resolvePackageIdentity, resolveRunDependencies, } from './appConfig/runDependencies.js';
2
+ import { buildShutdownDependencies } from './appConfig/shutdown.js';
2
3
  import { installConsoleBridge, installMcpLogging } from './lib/mcpLogging.js';
3
4
  const toError = (value) => value instanceof Error ? value : new Error(String(value));
4
5
  const createExit = (proc, exit) => exit ?? ((code) => proc.exit(code));
@@ -21,7 +22,8 @@ export async function run(deps = {}) {
21
22
  const { name, version } = resolvePackageIdentity(pkg);
22
23
  const server = resolved.createServer(name, version);
23
24
  installMcpLogging(server);
24
- installConsoleBridge(server);
25
+ const { flush: flushConsole, restore: restoreConsole } = installConsoleBridge(server);
26
+ process.on('exit', restoreConsole);
25
27
  resolved.publishLifecycleEvent({
26
28
  type: 'lifecycle.started',
27
29
  ts: resolved.now(),
@@ -29,6 +31,6 @@ export async function run(deps = {}) {
29
31
  const engine = resolved.engineFactory();
30
32
  resolved.registerTool(server, engine);
31
33
  const transport = await resolved.connectServer(server);
34
+ flushConsole();
32
35
  resolved.installShutdownHandlers(buildShutdownDependencies(resolved, { server, engine, transport }));
33
36
  }
34
- //# sourceMappingURL=app.js.map
@@ -33,4 +33,3 @@ export declare function resolvePackageIdentity(pkg: PackageInfo): {
33
33
  name: string;
34
34
  version: string;
35
35
  };
36
- //# sourceMappingURL=runDependencies.d.ts.map
@@ -23,7 +23,17 @@ function loadServerInstructions() {
23
23
  return trimmed.length > 0 ? trimmed : INSTRUCTIONS_FALLBACK;
24
24
  }
25
25
  function registerInstructionsResource(server) {
26
- server.registerResource('instructions', new ResourceTemplate('internal://instructions', { list: undefined }), { title: 'Instructions', mimeType: 'text/markdown' }, (uri) => ({
26
+ server.registerResource('instructions', new ResourceTemplate('internal://instructions', {
27
+ list: () => ({
28
+ resources: [
29
+ {
30
+ uri: 'internal://instructions',
31
+ name: 'Instructions',
32
+ mimeType: 'text/markdown',
33
+ },
34
+ ],
35
+ }),
36
+ }), { title: 'Instructions', mimeType: 'text/markdown' }, (uri) => ({
27
37
  contents: [
28
38
  {
29
39
  uri: uri.href,
@@ -40,7 +50,7 @@ function buildServerConfig() {
40
50
  instructions: SERVER_INSTRUCTIONS,
41
51
  capabilities: {
42
52
  logging: {},
43
- tools: { listChanged: true },
53
+ tools: { listChanged: false },
44
54
  resources: { subscribe: false, listChanged: false },
45
55
  prompts: { listChanged: false },
46
56
  },
@@ -105,4 +115,3 @@ export function resolvePackageIdentity(pkg) {
105
115
  version: pkg.version ?? '0.0.0',
106
116
  };
107
117
  }
108
- //# sourceMappingURL=runDependencies.js.map
@@ -16,4 +16,3 @@ export declare function buildShutdownDependencies(resolved: ResolvedRunDependenc
16
16
  engine: unknown;
17
17
  transport: unknown;
18
18
  }): ShutdownDependencies;
19
- //# sourceMappingURL=shutdown.d.ts.map
@@ -67,4 +67,3 @@ export function buildShutdownDependencies(resolved, payload) {
67
67
  ? { ...base, shutdownTimeoutMs: resolved.shutdownTimeoutMs }
68
68
  : base;
69
69
  }
70
- //# sourceMappingURL=shutdown.js.map
@@ -3,4 +3,3 @@ export type { CloseFn, EngineLike } from '../lib/types.js';
3
3
  export type ProcessLike = Pick<typeof process, 'on' | 'exit'>;
4
4
  export type TransportLike = Parameters<McpServer['connect']>[0];
5
5
  export type ServerLike = Pick<McpServer, 'connect' | 'registerTool' | 'registerResource' | 'registerPrompt' | 'sendLoggingMessage'>;
6
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -1,9 +1,10 @@
1
1
  import type { ProcessResult, StoredThought, ThoughtData } from '../lib/types.js';
2
- export declare function resolveRevisionTarget(input: ThoughtData, getThoughtByNumber: (thoughtNumber: number) => StoredThought | undefined): {
2
+ export type RevisionTargetResolution = {
3
3
  ok: true;
4
4
  targetNumber: number;
5
+ target: StoredThought;
5
6
  } | {
6
7
  ok: false;
7
- error: ProcessResult;
8
+ result: ProcessResult;
8
9
  };
9
- //# sourceMappingURL=revision.d.ts.map
10
+ export declare function resolveRevisionTarget(input: ThoughtData, getThoughtByNumber: (thoughtNumber: number) => StoredThought | undefined): RevisionTargetResolution;
@@ -1,26 +1,31 @@
1
+ function missingRevisionError() {
2
+ return {
3
+ ok: false,
4
+ result: buildRevisionError('E_REVISION_MISSING', 'revisesThought is required for revision'),
5
+ };
6
+ }
7
+ function targetNotFoundError(targetNumber) {
8
+ return {
9
+ ok: false,
10
+ result: buildRevisionError('E_REVISION_TARGET_NOT_FOUND', `Thought ${targetNumber} not found`),
11
+ };
12
+ }
13
+ function targetSupersededError(targetNumber) {
14
+ return {
15
+ ok: false,
16
+ result: buildRevisionError('E_REVISION_TARGET_SUPERSEDED', `Thought ${targetNumber} was already superseded`),
17
+ };
18
+ }
1
19
  export function resolveRevisionTarget(input, getThoughtByNumber) {
2
20
  const targetNumber = input.revisesThought;
3
- if (targetNumber === undefined) {
4
- return {
5
- ok: false,
6
- error: buildRevisionError('E_REVISION_MISSING', 'revisesThought is required for revision'),
7
- };
8
- }
9
- const validationError = validateRevisionTarget(getThoughtByNumber, targetNumber);
10
- if (validationError) {
11
- return { ok: false, error: validationError };
12
- }
13
- return { ok: true, targetNumber };
14
- }
15
- function validateRevisionTarget(getThoughtByNumber, targetNumber) {
21
+ if (targetNumber === undefined)
22
+ return missingRevisionError();
16
23
  const target = getThoughtByNumber(targetNumber);
17
- if (!target) {
18
- return buildRevisionError('E_REVISION_TARGET_NOT_FOUND', `Thought ${targetNumber} not found`);
19
- }
20
- if (!target.isActive) {
21
- return buildRevisionError('E_REVISION_TARGET_SUPERSEDED', `Thought ${targetNumber} was already superseded`);
22
- }
23
- return undefined;
24
+ if (!target)
25
+ return targetNotFoundError(targetNumber);
26
+ if (!target.isActive)
27
+ return targetSupersededError(targetNumber);
28
+ return { ok: true, targetNumber, target };
24
29
  }
25
30
  function buildRevisionError(code, message) {
26
31
  return {
@@ -28,4 +33,3 @@ function buildRevisionError(code, message) {
28
33
  error: { code, message },
29
34
  };
30
35
  }
31
- //# sourceMappingURL=revision.js.map
@@ -1,3 +1,2 @@
1
1
  import type { ContextSummary, RevisionInfo, StoredThought } from '../lib/types.js';
2
2
  export declare function buildContextSummary(activeThoughts: readonly StoredThought[], revisionInfo?: RevisionInfo): ContextSummary;
3
- //# sourceMappingURL=thoughtQueries.d.ts.map
@@ -1,35 +1,42 @@
1
+ const MAX_PREVIEW_CHARS = 100;
2
+ const MAX_RECENT_THOUGHTS = 5;
3
+ const RECENT_TAIL_COUNT = 4;
1
4
  function selectRecentThoughts(activeThoughts) {
2
- if (activeThoughts.length <= 5) {
3
- const recent = activeThoughts.slice();
4
- const stepIndexes = recent.map((_, index) => index + 1);
5
- return { recent, stepIndexes };
5
+ const len = activeThoughts.length;
6
+ const recent = [];
7
+ const stepIndexes = [];
8
+ if (len > MAX_RECENT_THOUGHTS) {
9
+ const anchor = activeThoughts[0];
10
+ if (!anchor)
11
+ throw new Error('Invariant violation: anchor thought missing');
12
+ recent.push(anchor);
13
+ stepIndexes.push(1);
14
+ }
15
+ const start = len <= MAX_RECENT_THOUGHTS ? 0 : Math.max(0, len - RECENT_TAIL_COUNT);
16
+ for (let i = start; i < len; i += 1) {
17
+ const thought = activeThoughts[i];
18
+ if (thought) {
19
+ recent.push(thought);
20
+ stepIndexes.push(i + 1);
21
+ }
6
22
  }
7
- const anchor = activeThoughts[0];
8
- if (!anchor)
9
- throw new Error('Invariant violation: anchor thought missing');
10
- const tail = activeThoughts.slice(-4);
11
- const recent = [anchor, ...tail];
12
- const stepIndexes = [
13
- 1,
14
- ...tail.map((_, index) => activeThoughts.length - 4 + index + 1),
15
- ];
16
23
  return { recent, stepIndexes };
17
24
  }
18
- function formatThoughtPreview(thought) {
19
- if (thought.length <= 100)
20
- return thought;
21
- return `${thought.slice(0, 100)}...`;
25
+ function truncatePreview(input, maxChars) {
26
+ const codepoints = Array.from(input);
27
+ if (codepoints.length <= maxChars)
28
+ return input;
29
+ return `${codepoints.slice(0, maxChars).join('')}...`;
22
30
  }
23
31
  export function buildContextSummary(activeThoughts, revisionInfo) {
24
32
  const { recent, stepIndexes } = selectRecentThoughts(activeThoughts);
25
33
  const recentThoughts = recent.map((thought, index) => ({
26
34
  stepIndex: stepIndexes[index] ?? index + 1,
27
35
  number: thought.thoughtNumber,
28
- preview: formatThoughtPreview(thought.thought),
36
+ preview: truncatePreview(thought.thought, MAX_PREVIEW_CHARS),
29
37
  }));
30
38
  if (revisionInfo !== undefined) {
31
39
  return { recentThoughts, revisionInfo };
32
40
  }
33
41
  return { recentThoughts };
34
42
  }
35
- //# sourceMappingURL=thoughtQueries.js.map
@@ -4,6 +4,12 @@ export interface ThoughtStoreOptions {
4
4
  maxMemoryBytes: number;
5
5
  estimatedThoughtOverheadBytes: number;
6
6
  }
7
+ export interface PruneStats {
8
+ truncatedActive: boolean;
9
+ droppedActiveCount: number;
10
+ removedThoughtsCount: number;
11
+ oldestAvailableThoughtNumber: number | null;
12
+ }
7
13
  export declare class ThoughtStore {
8
14
  #private;
9
15
  constructor(options: ThoughtStoreOptions);
@@ -11,12 +17,15 @@ export declare class ThoughtStore {
11
17
  thoughtNumber: number;
12
18
  totalThoughts: number;
13
19
  };
20
+ getLastPruneStats(): PruneStats | null;
14
21
  storeThought(stored: StoredThought): void;
15
- supersedeFrom(targetNumber: number, supersededBy: number): readonly number[];
22
+ supersedeFrom(targetNumber: number, supersededBy: number, maxSupersedes?: number): {
23
+ supersedes: number[];
24
+ supersedesTotal: number;
25
+ };
16
26
  getActiveThoughts(): readonly StoredThought[];
17
- getActiveThoughtNumbers(): readonly number[];
27
+ getActiveThoughtNumbers(max?: number): number[];
18
28
  getThoughtByNumber(thoughtNumber: number): StoredThought | undefined;
19
29
  getTotalLength(): number;
20
30
  pruneHistoryIfNeeded(): void;
21
31
  }
22
- //# sourceMappingURL=thoughtStore.d.ts.map
@@ -8,6 +8,7 @@ export class ThoughtStore {
8
8
  #headIndex = 0;
9
9
  #nextThoughtNumber = 1;
10
10
  #estimatedBytes = 0;
11
+ #lastPruneStats = null;
11
12
  #maxThoughts;
12
13
  #maxMemoryBytes;
13
14
  #estimatedThoughtOverheadBytes;
@@ -19,11 +20,11 @@ export class ThoughtStore {
19
20
  nextThoughtNumbers(totalThoughts) {
20
21
  const thoughtNumber = this.#nextThoughtNumber;
21
22
  this.#nextThoughtNumber += 1;
22
- const effectiveTotalThoughts = Math.max(totalThoughts, thoughtNumber, this.#activeMaxTotalThoughts);
23
- return {
24
- thoughtNumber,
25
- totalThoughts: effectiveTotalThoughts,
26
- };
23
+ const effectiveTotalThoughts = Math.max(totalThoughts, this.#activeMaxTotalThoughts);
24
+ return { thoughtNumber, totalThoughts: effectiveTotalThoughts };
25
+ }
26
+ getLastPruneStats() {
27
+ return this.#lastPruneStats;
27
28
  }
28
29
  storeThought(stored) {
29
30
  this.#thoughts.push(stored);
@@ -42,34 +43,45 @@ export class ThoughtStore {
42
43
  }
43
44
  this.#activeMaxTotalThoughts = maxTotal;
44
45
  }
45
- #findActiveThoughtIndex(thoughtNumber) {
46
+ #findActiveLowerBound(thoughtNumber) {
46
47
  const activeThoughtNumbers = this.#activeThoughtNumbers;
47
48
  let low = 0;
48
49
  let high = activeThoughtNumbers.length;
49
50
  while (low < high) {
50
51
  const mid = (low + high) >>> 1;
51
52
  const midValue = activeThoughtNumbers[mid];
52
- if (midValue === undefined) {
53
+ if (midValue === undefined)
53
54
  return -1;
54
- }
55
- if (midValue < thoughtNumber) {
55
+ if (midValue < thoughtNumber)
56
56
  low = mid + 1;
57
- }
58
- else {
57
+ else
59
58
  high = mid;
60
- }
61
- }
62
- if (low < activeThoughtNumbers.length &&
63
- activeThoughtNumbers[low] === thoughtNumber) {
64
- return low;
65
59
  }
60
+ return low;
61
+ }
62
+ #findActiveThoughtIndex(thoughtNumber) {
63
+ const index = this.#findActiveLowerBound(thoughtNumber);
64
+ if (index < 0)
65
+ return -1;
66
+ if (index < this.#activeThoughtNumbers.length &&
67
+ this.#activeThoughtNumbers[index] === thoughtNumber)
68
+ return index;
66
69
  return -1;
67
70
  }
68
- supersedeFrom(targetNumber, supersededBy) {
71
+ #findFirstActiveIndexAfter(thoughtNumber) {
72
+ const index = this.#findActiveLowerBound(thoughtNumber);
73
+ if (index < 0)
74
+ return 0;
75
+ if (this.#activeThoughtNumbers[index] === thoughtNumber)
76
+ return index + 1;
77
+ return index;
78
+ }
79
+ supersedeFrom(targetNumber, supersededBy, maxSupersedes) {
69
80
  const startIndex = this.#findActiveThoughtIndex(targetNumber);
70
81
  if (startIndex < 0)
71
- return [];
82
+ return { supersedes: [], supersedesTotal: 0 };
72
83
  const supersedes = [];
84
+ let supersedesTotal = 0;
73
85
  for (let i = startIndex; i < this.#activeThoughts.length; i += 1) {
74
86
  const thought = this.#activeThoughts[i];
75
87
  if (!thought)
@@ -78,18 +90,29 @@ export class ThoughtStore {
78
90
  thought.isActive = false;
79
91
  thought.supersededBy = supersededBy;
80
92
  }
81
- supersedes.push(thought.thoughtNumber);
93
+ supersedesTotal += 1;
94
+ if (maxSupersedes === undefined || supersedes.length < maxSupersedes) {
95
+ supersedes.push(thought.thoughtNumber);
96
+ }
82
97
  }
83
98
  this.#activeThoughts.length = startIndex;
84
99
  this.#activeThoughtNumbers.length = startIndex;
85
100
  this.#recomputeActiveMaxTotalThoughts();
86
- return supersedes;
101
+ return { supersedes, supersedesTotal };
87
102
  }
88
103
  getActiveThoughts() {
89
104
  return this.#activeThoughts;
90
105
  }
91
- getActiveThoughtNumbers() {
92
- return this.#activeThoughtNumbers.slice();
106
+ getActiveThoughtNumbers(max) {
107
+ if (max === undefined) {
108
+ return this.#activeThoughtNumbers.slice();
109
+ }
110
+ if (max <= 0)
111
+ return [];
112
+ if (this.#activeThoughtNumbers.length <= max) {
113
+ return this.#activeThoughtNumbers.slice();
114
+ }
115
+ return this.#activeThoughtNumbers.slice(-max);
93
116
  }
94
117
  getThoughtByNumber(thoughtNumber) {
95
118
  return this.#thoughtIndex.get(thoughtNumber);
@@ -98,6 +121,18 @@ export class ThoughtStore {
98
121
  return this.#thoughts.length - this.#headIndex;
99
122
  }
100
123
  pruneHistoryIfNeeded() {
124
+ const beforeTotal = this.getTotalLength();
125
+ const beforeActive = this.#activeThoughts.length;
126
+ this.#lastPruneStats = {
127
+ truncatedActive: false,
128
+ droppedActiveCount: 0,
129
+ removedThoughtsCount: 0,
130
+ oldestAvailableThoughtNumber: this.#thoughts[this.#headIndex]?.thoughtNumber ?? null,
131
+ };
132
+ this.#performPruning();
133
+ this.#updatePruneStats(beforeTotal, beforeActive);
134
+ }
135
+ #performPruning() {
101
136
  const excess = this.getTotalLength() - this.#maxThoughts;
102
137
  if (excess > 0) {
103
138
  const batch = Math.max(excess, Math.ceil(this.#maxThoughts * 0.1));
@@ -109,19 +144,24 @@ export class ThoughtStore {
109
144
  this.#removeOldest(toRemove, { forceCompact: true });
110
145
  }
111
146
  }
147
+ #updatePruneStats(beforeTotal, beforeActive) {
148
+ if (!this.#lastPruneStats)
149
+ return;
150
+ const afterActive = this.#activeThoughts.length;
151
+ const stats = this.#lastPruneStats;
152
+ stats.removedThoughtsCount = Math.max(0, beforeTotal - this.getTotalLength());
153
+ stats.droppedActiveCount = Math.max(0, beforeActive - afterActive);
154
+ stats.truncatedActive = stats.droppedActiveCount > 0;
155
+ stats.oldestAvailableThoughtNumber =
156
+ this.#thoughts[this.#headIndex]?.thoughtNumber ?? null;
157
+ }
112
158
  #estimateThoughtBytes(thought) {
113
- return thought.thought.length * 2 + this.#estimatedThoughtOverheadBytes;
159
+ return thought.byteLength + this.#estimatedThoughtOverheadBytes;
114
160
  }
115
161
  #dropActiveThoughtsUpTo(thoughtNumber) {
116
162
  if (this.#activeThoughts.length === 0)
117
163
  return;
118
- let startIndex = 0;
119
- while (startIndex < this.#activeThoughts.length) {
120
- const thought = this.#activeThoughts[startIndex];
121
- if (!thought || thought.thoughtNumber > thoughtNumber)
122
- break;
123
- startIndex += 1;
124
- }
164
+ const startIndex = this.#findFirstActiveIndexAfter(thoughtNumber);
125
165
  if (startIndex === 0)
126
166
  return;
127
167
  this.#activeThoughts = this.#activeThoughts.slice(startIndex);
@@ -186,6 +226,6 @@ export class ThoughtStore {
186
226
  this.#headIndex = 0;
187
227
  this.#nextThoughtNumber = 1;
188
228
  this.#estimatedBytes = 0;
229
+ this.#lastPruneStats = null;
189
230
  }
190
231
  }
191
- //# sourceMappingURL=thoughtStore.js.map
package/dist/engine.d.ts CHANGED
@@ -3,11 +3,12 @@ export interface ThinkingEngineOptions {
3
3
  maxThoughts?: number;
4
4
  maxMemoryBytes?: number;
5
5
  estimatedThoughtOverheadBytes?: number;
6
+ maxSessions?: number;
6
7
  }
7
8
  export declare class ThinkingEngine {
8
9
  #private;
9
10
  static readonly DEFAULT_TOTAL_THOUGHTS = 3;
10
11
  constructor(options?: ThinkingEngineOptions);
11
12
  processThought(input: ThoughtData): ProcessResult;
13
+ processThoughtWithSession(sessionId: string, input: ThoughtData): ProcessResult;
12
14
  }
13
- //# sourceMappingURL=engine.d.ts.map