@hanhnd/agent-kit 1.0.32 → 1.0.34

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 (111) hide show
  1. package/dist/cli/commands/cli-digest-pending.test.js +111 -0
  2. package/dist/cli/commands/cli-memory.test.js +34 -0
  3. package/dist/cli/{memory.js → commands/memory.js} +24 -11
  4. package/dist/cli/index.js +2 -2
  5. package/dist/{utils → cli/utils}/args.d.ts +2 -1
  6. package/dist/{kit-cli.js → cli.js} +342 -58
  7. package/dist/{tools/config.d.ts → core/config/index.d.ts} +2 -7
  8. package/dist/{tools/config.js → core/config/index.js} +2 -13
  9. package/dist/core/handoffs/index.d.ts +17 -0
  10. package/dist/{tools/handoffs.js → core/handoffs/index.js} +15 -7
  11. package/dist/core/handoffs/index.test.js +88 -0
  12. package/dist/{tools/security.d.ts → core/security/index.d.ts} +0 -19
  13. package/dist/{tools/security.js → core/security/index.js} +3 -76
  14. package/dist/entrypoints/cli.js +11 -0
  15. package/dist/entrypoints/server.js +37 -0
  16. package/dist/{tools → mcp}/agent.d.ts +1 -1
  17. package/dist/{tools → mcp}/agent.js +4 -4
  18. package/dist/mcp/core.d.ts +17 -0
  19. package/dist/mcp/core.js +60 -0
  20. package/dist/mcp/core.test.js +98 -0
  21. package/dist/{tools → mcp}/integration.js +3 -3
  22. package/dist/mcp/memory.d.ts +15 -0
  23. package/dist/{tools → mcp}/memory.js +15 -13
  24. package/dist/{kit-server.js → server.js} +129 -98
  25. package/dist/services/digest/background.d.ts +11 -0
  26. package/dist/services/digest/background.js +258 -0
  27. package/dist/{memory → services}/digest/constants.d.ts +4 -1
  28. package/dist/{memory → services}/digest/constants.js +6 -2
  29. package/dist/services/digest/digest-background.test.js +206 -0
  30. package/dist/{tools/__tests__ → services/digest}/digest-init.test.js +4 -3
  31. package/dist/{memory/__tests__ → services/digest}/digest-llama-local.test.js +1 -13
  32. package/dist/{memory/__tests__ → services/digest}/digest-pending.test.js +39 -11
  33. package/dist/{memory/__tests__ → services/digest}/digest-processor.test.js +5 -7
  34. package/dist/{memory → services}/digest/files.d.ts +0 -1
  35. package/dist/{memory → services}/digest/files.js +2 -2
  36. package/dist/services/digest/model-registry.d.ts +2 -0
  37. package/dist/{memory → services}/digest/model-registry.js +9 -8
  38. package/dist/services/digest/processor.d.ts +13 -0
  39. package/dist/{memory → services}/digest/processor.js +48 -31
  40. package/dist/services/digest/providers/llama-local.d.ts +2 -0
  41. package/dist/{memory → services}/digest/providers/llama-local.js +3 -4
  42. package/dist/{memory → services}/digest/types.d.ts +34 -2
  43. package/dist/services/digest/types.js +6 -0
  44. package/dist/{memory → services}/digest/worker.d.ts +0 -1
  45. package/dist/{memory → services}/digest/worker.js +2 -2
  46. package/dist/{utils → services/integration}/credentials.js +1 -1
  47. package/dist/{utils/parser.js → services/integration/parser/adf.js} +1 -0
  48. package/dist/{memory → services/memory}/chunker.d.ts +0 -2
  49. package/dist/{memory → services/memory}/chunker.js +3 -3
  50. package/dist/{memory/__tests__ → services/memory}/chunker.test.js +1 -34
  51. package/dist/{memory → services/memory}/constants.d.ts +1 -1
  52. package/dist/{memory → services/memory}/constants.js +2 -1
  53. package/dist/{memory → services/memory}/embedder.d.ts +2 -2
  54. package/dist/{memory → services/memory}/embedder.js +5 -5
  55. package/dist/services/memory/embedder.test.js +13 -0
  56. package/dist/{memory → services/memory}/indexer.d.ts +2 -1
  57. package/dist/{memory → services/memory}/indexer.js +1 -1
  58. package/dist/{memory/__tests__ → services/memory}/indexer.test.js +4 -3
  59. package/dist/{tools/__tests__ → services/memory}/memory.test.js +54 -13
  60. package/dist/{memory/__tests__ → services/memory}/store.test.js +3 -2
  61. package/dist/{memory → services/memory}/types.d.ts +7 -2
  62. package/dist/services/memory/types.js +6 -0
  63. package/dist/utils/files.d.ts +0 -1
  64. package/dist/utils/files.js +1 -1
  65. package/dist/{memory/__tests__/lockfile.test.js → utils/files.test.js} +14 -14
  66. package/dist/utils/index.d.ts +6 -0
  67. package/dist/utils/index.js +6 -0
  68. package/dist/utils/json.d.ts +0 -1
  69. package/dist/utils/json.js +0 -10
  70. package/dist/utils/paths.d.ts +0 -1
  71. package/dist/utils/paths.js +1 -1
  72. package/package.json +6 -6
  73. package/dist/memory/__tests__/digest-worker.test.js +0 -46
  74. package/dist/memory/__tests__/embedder.test.js +0 -14
  75. package/dist/memory/digest/model-registry.d.ts +0 -6
  76. package/dist/memory/digest/processor.d.ts +0 -7
  77. package/dist/memory/digest/providers/llama-local.d.ts +0 -7
  78. package/dist/tools/__tests__/cli-digest-pending.test.js +0 -51
  79. package/dist/tools/__tests__/cli-memory.test.js +0 -22
  80. package/dist/tools/core.d.ts +0 -10
  81. package/dist/tools/core.js +0 -46
  82. package/dist/tools/handoffs.d.ts +0 -22
  83. package/dist/tools/memory.d.ts +0 -16
  84. /package/dist/{tools/__tests__ → cli/commands}/cli-digest-pending.test.d.ts +0 -0
  85. /package/dist/{tools/__tests__ → cli/commands}/cli-memory.test.d.ts +0 -0
  86. /package/dist/cli/{memory.d.ts → commands/memory.d.ts} +0 -0
  87. /package/dist/{utils → cli/utils}/args.js +0 -0
  88. /package/dist/{memory/__tests__/chunker.test.d.ts → core/handoffs/index.test.d.ts} +0 -0
  89. /package/dist/{kit-cli.d.ts → entrypoints/cli.d.ts} +0 -0
  90. /package/dist/{kit-server.d.ts → entrypoints/server.d.ts} +0 -0
  91. /package/dist/{memory/__tests__/digest-llama-local.test.d.ts → mcp/core.test.d.ts} +0 -0
  92. /package/dist/{tools → mcp}/integration.d.ts +0 -0
  93. /package/dist/{memory/__tests__/digest-pending.test.d.ts → services/digest/digest-background.test.d.ts} +0 -0
  94. /package/dist/{tools/__tests__ → services/digest}/digest-init.test.d.ts +0 -0
  95. /package/dist/{memory/__tests__/digest-processor.test.d.ts → services/digest/digest-llama-local.test.d.ts} +0 -0
  96. /package/dist/{memory/__tests__/digest-worker.test.d.ts → services/digest/digest-pending.test.d.ts} +0 -0
  97. /package/dist/{memory/__tests__/embedder.test.d.ts → services/digest/digest-processor.test.d.ts} +0 -0
  98. /package/dist/{utils → services/integration}/credentials.d.ts +0 -0
  99. /package/dist/{utils/parser.d.ts → services/integration/parser/adf.d.ts} +0 -0
  100. /package/dist/{memory/__tests__/indexer.test.d.ts → services/memory/chunker.test.d.ts} +0 -0
  101. /package/dist/{memory/__tests__/lockfile.test.d.ts → services/memory/embedder.test.d.ts} +0 -0
  102. /package/dist/{memory → services/memory}/index.d.ts +0 -0
  103. /package/dist/{memory → services/memory}/index.js +0 -0
  104. /package/dist/{memory/__tests__/store.test.d.ts → services/memory/indexer.test.d.ts} +0 -0
  105. /package/dist/{tools/__tests__ → services/memory}/memory.test.d.ts +0 -0
  106. /package/dist/{memory → services/memory}/store.d.ts +0 -0
  107. /package/dist/{memory → services/memory}/store.js +0 -0
  108. /package/dist/{memory/digest/types.js → services/memory/store.test.d.ts} +0 -0
  109. /package/dist/{memory/types.js → utils/files.test.d.ts} +0 -0
  110. /package/dist/{__tests__/temp-dir.d.ts → utils/temp-dir.test.d.ts} +0 -0
  111. /package/dist/{__tests__/temp-dir.js → utils/temp-dir.test.js} +0 -0
@@ -1,7 +1,8 @@
1
1
  import * as assert from 'node:assert/strict';
2
2
  import { describe, test } from 'node:test';
3
- import { resolveMemoryConfig } from '../config.js';
4
- import { registerMemoryToolHandlers } from '../memory.js';
3
+ import { EmbeddingModelName } from './types.js';
4
+ import { resolveMemoryConfig } from '../../core/config/index.js';
5
+ import { registerMemoryTools } from '../../mcp/memory.js';
5
6
  // Minimal McpServer stub that captures tool registrations
6
7
  function makeMockServer() {
7
8
  const tools = new Map();
@@ -30,7 +31,7 @@ const BASE_CONFIG = {
30
31
  topK: 5,
31
32
  chunkSize: 1500,
32
33
  overlapLines: 2,
33
- embeddingModel: 'Xenova/bge-small-en-v1.5',
34
+ embeddingModel: EmbeddingModelName.SMALL,
34
35
  vectorDimension: 384,
35
36
  };
36
37
  function makeIndexerStub(overrides = {}) {
@@ -61,7 +62,11 @@ describe('kit_memory_search', () => {
61
62
  const indexer = makeIndexerStub({ search: async () => [searchResult] });
62
63
  const store = makeStoreStub(true);
63
64
  const { server, tools } = makeMockServer();
64
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
65
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
66
+ indexer,
67
+ store,
68
+ config: BASE_CONFIG,
69
+ });
65
70
  const result = await tools.get('kit_memory_search')({ query: 'test query' });
66
71
  const text = extractText(result);
67
72
  assert.ok(text.includes('Important memory content'), 'Result must include chunk content');
@@ -73,7 +78,11 @@ describe('kit_memory_search', () => {
73
78
  const indexer = makeIndexerStub({ search: async () => [] });
74
79
  const store = makeStoreStub(true);
75
80
  const { server, tools } = makeMockServer();
76
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
81
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
82
+ indexer,
83
+ store,
84
+ config: BASE_CONFIG,
85
+ });
77
86
  const result = await tools.get('kit_memory_search')({ query: 'nothing here' });
78
87
  const text = extractText(result);
79
88
  assert.ok(text.toLowerCase().includes('no memories') || text.includes('No memories'), `Expected "no memories" message, got: ${text.slice(0, 100)}`);
@@ -82,7 +91,11 @@ describe('kit_memory_search', () => {
82
91
  const indexer = makeIndexerStub({ search: async () => [] });
83
92
  const store = makeStoreStub(false);
84
93
  const { server, tools } = makeMockServer();
85
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
94
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
95
+ indexer,
96
+ store,
97
+ config: BASE_CONFIG,
98
+ });
86
99
  const result = await tools.get('kit_memory_search')({ query: 'test' });
87
100
  const text = extractText(result);
88
101
  assert.ok(text.includes('Vector search unavailable') || text.includes('keyword-only'), `Expected degraded warning in: ${text.slice(0, 200)}`);
@@ -98,7 +111,11 @@ describe('kit_memory_search', () => {
98
111
  const indexer = makeIndexerStub({ search: async () => [searchResult] });
99
112
  const store = makeStoreStub(false);
100
113
  const { server, tools } = makeMockServer();
101
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
114
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
115
+ indexer,
116
+ store,
117
+ config: BASE_CONFIG,
118
+ });
102
119
  const result = await tools.get('kit_memory_search')({ query: 'test' });
103
120
  const text = extractText(result);
104
121
  assert.ok(text.includes('Vector search unavailable') || text.includes('keyword-only'), `Expected degraded warning with results in: ${text.slice(0, 200)}`);
@@ -115,7 +132,11 @@ describe('kit_memory_search', () => {
115
132
  const indexer = makeIndexerStub({ search: async () => [searchResult] });
116
133
  const store = makeStoreStub(true);
117
134
  const { server, tools } = makeMockServer();
118
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
135
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
136
+ indexer,
137
+ store,
138
+ config: BASE_CONFIG,
139
+ });
119
140
  const result = await tools.get('kit_memory_search')({ query: 'test' });
120
141
  const text = extractText(result);
121
142
  assert.ok(text.includes('Source file unavailable'), `Expected fallback warning in: ${text}`);
@@ -131,7 +152,11 @@ describe('kit_memory_search', () => {
131
152
  });
132
153
  const store = makeStoreStub(true);
133
154
  const { server, tools } = makeMockServer();
134
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
155
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
156
+ indexer,
157
+ store,
158
+ config: BASE_CONFIG,
159
+ });
135
160
  await tools.get('kit_memory_search')({ query: 'test', top_k: 3 });
136
161
  assert.equal(capturedTopK, 3);
137
162
  });
@@ -145,7 +170,11 @@ describe('kit_memory_search', () => {
145
170
  });
146
171
  const store = makeStoreStub(true);
147
172
  const { server, tools } = makeMockServer();
148
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
173
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
174
+ indexer,
175
+ store,
176
+ config: BASE_CONFIG,
177
+ });
149
178
  await tools.get('kit_memory_search')({ query: 'test' });
150
179
  assert.equal(capturedTopK, BASE_CONFIG.topK);
151
180
  });
@@ -157,7 +186,11 @@ describe('kit_memory_search', () => {
157
186
  });
158
187
  const store = makeStoreStub(true);
159
188
  const { server, tools } = makeMockServer();
160
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
189
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
190
+ indexer,
191
+ store,
192
+ config: BASE_CONFIG,
193
+ });
161
194
  const result = await tools.get('kit_memory_search')({ query: 'test' });
162
195
  const text = extractText(result);
163
196
  assert.ok(text.includes('kit_memory_search failed'), `Expected error prefix, got: ${text}`);
@@ -171,7 +204,11 @@ describe('kit_memory_save', () => {
171
204
  });
172
205
  const store = makeStoreStub(true);
173
206
  const { server, tools } = makeMockServer();
174
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
207
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
208
+ indexer,
209
+ store,
210
+ config: BASE_CONFIG,
211
+ });
175
212
  const result = await tools.get('kit_memory_save')({ content: 'Some important note' });
176
213
  const text = extractText(result);
177
214
  const parsed = JSON.parse(text);
@@ -187,7 +224,11 @@ describe('kit_memory_save', () => {
187
224
  });
188
225
  const store = makeStoreStub(true);
189
226
  const { server, tools } = makeMockServer();
190
- registerMemoryToolHandlers(server, indexer, store, BASE_CONFIG);
227
+ registerMemoryTools(server, { memory: { enabled: true } }, '/tmp', {
228
+ indexer,
229
+ store,
230
+ config: BASE_CONFIG,
231
+ });
191
232
  const result = await tools.get('kit_memory_save')({ content: 'note' });
192
233
  const text = extractText(result);
193
234
  const parsed = JSON.parse(text);
@@ -3,14 +3,15 @@ import * as fs from 'node:fs';
3
3
  import * as os from 'node:os';
4
4
  import * as path from 'node:path';
5
5
  import { after, before, describe, test } from 'node:test';
6
- import { MemoryStore } from '../store.js';
6
+ import { MemoryStore } from './store.js';
7
+ import { EmbeddingModelName } from './types.js';
7
8
  const TEST_CONFIG = {
8
9
  enabled: true,
9
10
  wikiDir: '',
10
11
  topK: 5,
11
12
  chunkSize: 1500,
12
13
  overlapLines: 2,
13
- embeddingModel: 'Xenova/bge-small-en-v1.5',
14
+ embeddingModel: EmbeddingModelName.SMALL,
14
15
  vectorDimension: 384,
15
16
  };
16
17
  function makeChunk(overrides = {}) {
@@ -1,4 +1,9 @@
1
- import type { ConversationDigestSettings } from './digest/types.js';
1
+ import type { ConversationDigestSettings } from '../digest/types.js';
2
+ export declare enum EmbeddingModelName {
3
+ TINY = "tiny",
4
+ SMALL = "small",
5
+ LARGE = "large"
6
+ }
2
7
  export interface MemoryChunk {
3
8
  id: string;
4
9
  source: string;
@@ -20,7 +25,7 @@ export interface MemoryConfig {
20
25
  topK: number;
21
26
  chunkSize: number;
22
27
  overlapLines: number;
23
- embeddingModel: string;
28
+ embeddingModel: EmbeddingModelName;
24
29
  vectorDimension: number;
25
30
  conversationDigest?: ConversationDigestSettings;
26
31
  }
@@ -0,0 +1,6 @@
1
+ export var EmbeddingModelName;
2
+ (function (EmbeddingModelName) {
3
+ EmbeddingModelName["TINY"] = "tiny";
4
+ EmbeddingModelName["SMALL"] = "small";
5
+ EmbeddingModelName["LARGE"] = "large";
6
+ })(EmbeddingModelName || (EmbeddingModelName = {}));
@@ -1,6 +1,5 @@
1
1
  export declare function atomicWriteTextFile(filePath: string, content: string): void;
2
2
  export declare function atomicWriteJsonFile(filePath: string, value: unknown): void;
3
- export declare function tryWriteFileExclusive(filePath: string, content: string): boolean;
4
3
  export declare function acquireLock(lockPath: string, timeoutMs: number, retryMs: number): Promise<boolean>;
5
4
  export declare function releaseLock(lockPath: string, opts?: {
6
5
  ignoreErrors?: boolean;
@@ -9,7 +9,7 @@ export function atomicWriteTextFile(filePath, content) {
9
9
  export function atomicWriteJsonFile(filePath, value) {
10
10
  atomicWriteTextFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
11
11
  }
12
- export function tryWriteFileExclusive(filePath, content) {
12
+ function tryWriteFileExclusive(filePath, content) {
13
13
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
14
14
  try {
15
15
  fs.writeFileSync(filePath, content, { flag: 'wx' });
@@ -2,9 +2,9 @@ import * as assert from 'node:assert/strict';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import { afterEach, describe, test } from 'node:test';
5
- import { createTempDirTracker } from '../../__tests__/temp-dir.js';
6
- import { DIGEST_LOCKFILE_REL_PATH } from '../digest/constants.js';
7
- import { releaseLock, tryAcquireProcessLock } from '../../utils/files.js';
5
+ import { createTempDirTracker } from './temp-dir.test.js';
6
+ import { DIGEST_LOCKFILE_REL_PATH } from '../services/digest/constants.js';
7
+ import { releaseLock, tryAcquireProcessLock } from './files.js';
8
8
  const tempDirs = createTempDirTracker();
9
9
  afterEach(() => {
10
10
  tempDirs.cleanup();
@@ -12,20 +12,22 @@ afterEach(() => {
12
12
  function lockPath(workspace) {
13
13
  return path.join(workspace, DIGEST_LOCKFILE_REL_PATH);
14
14
  }
15
+ function lockDir(workspace) {
16
+ return path.dirname(lockPath(workspace));
17
+ }
15
18
  describe('tryAcquireProcessLock', () => {
16
19
  test('C1: no lockfile → creates it with current PID and returns true', () => {
17
20
  const workspace = tempDirs.makeTempDir('lockfile-c1-');
18
21
  const acquired = tryAcquireProcessLock(lockPath(workspace));
19
22
  assert.equal(acquired, true);
20
- const lockFile = path.join(workspace, '.agent-kit', 'digest-worker.lock');
23
+ const lockFile = lockPath(workspace);
21
24
  const content = JSON.parse(fs.readFileSync(lockFile, 'utf8'));
22
25
  assert.equal(content.pid, process.pid);
23
26
  });
24
27
  test('C2: lockfile with live foreign PID → returns false without modifying file', () => {
25
28
  const workspace = tempDirs.makeTempDir('lockfile-c2-');
26
- const lockDir = path.join(workspace, '.agent-kit');
27
- const lockFile = path.join(lockDir, 'digest-worker.lock');
28
- fs.mkdirSync(lockDir, { recursive: true });
29
+ const lockFile = lockPath(workspace);
30
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
29
31
  // Use process.pid as "live" pid (current process is definitely alive)
30
32
  const livePid = process.pid;
31
33
  fs.writeFileSync(lockFile, JSON.stringify({ pid: livePid }), 'utf8');
@@ -37,9 +39,8 @@ describe('tryAcquireProcessLock', () => {
37
39
  });
38
40
  test('C3: lockfile with dead PID (ESRCH) → deletes stale lock, creates new one, returns true', () => {
39
41
  const workspace = tempDirs.makeTempDir('lockfile-c3-');
40
- const lockDir = path.join(workspace, '.agent-kit');
41
- const lockFile = path.join(lockDir, 'digest-worker.lock');
42
- fs.mkdirSync(lockDir, { recursive: true });
42
+ const lockFile = lockPath(workspace);
43
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
43
44
  // PID 999999999 is virtually guaranteed to be dead
44
45
  fs.writeFileSync(lockFile, JSON.stringify({ pid: 999999999 }), 'utf8');
45
46
  const acquired = tryAcquireProcessLock(lockPath(workspace));
@@ -57,9 +58,8 @@ describe('tryAcquireProcessLock', () => {
57
58
  });
58
59
  test('stale unparseable lockfile → treated as stale, returns true', () => {
59
60
  const workspace = tempDirs.makeTempDir('lockfile-stale-');
60
- const lockDir = path.join(workspace, '.agent-kit');
61
- const lockFile = path.join(lockDir, 'digest-worker.lock');
62
- fs.mkdirSync(lockDir, { recursive: true });
61
+ const lockFile = lockPath(workspace);
62
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
63
63
  fs.writeFileSync(lockFile, 'not-json', 'utf8');
64
64
  const acquired = tryAcquireProcessLock(lockPath(workspace));
65
65
  assert.equal(acquired, true);
@@ -69,7 +69,7 @@ describe('releaseLock', () => {
69
69
  test('C5: lockfile exists → deletes it', () => {
70
70
  const workspace = tempDirs.makeTempDir('lockfile-c5-');
71
71
  assert.equal(tryAcquireProcessLock(lockPath(workspace)), true);
72
- const lockFile = path.join(workspace, '.agent-kit', 'digest-worker.lock');
72
+ const lockFile = lockPath(workspace);
73
73
  assert.equal(fs.existsSync(lockFile), true);
74
74
  releaseLock(lockPath(workspace));
75
75
  assert.equal(fs.existsSync(lockFile), false);
@@ -0,0 +1,6 @@
1
+ export * from './async.js';
2
+ export * from './files.js';
3
+ export * from './hash.js';
4
+ export * from './json.js';
5
+ export * from './paths.js';
6
+ export * from './utils.js';
@@ -0,0 +1,6 @@
1
+ export * from './async.js';
2
+ export * from './files.js';
3
+ export * from './hash.js';
4
+ export * from './json.js';
5
+ export * from './paths.js';
6
+ export * from './utils.js';
@@ -1,2 +1 @@
1
1
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
2
- export declare function readJsonObjectFile(filePath: string): Record<string, unknown>;
@@ -1,13 +1,3 @@
1
- import * as fs from 'node:fs';
2
1
  export function isRecord(value) {
3
2
  return typeof value === 'object' && value !== null && !Array.isArray(value);
4
3
  }
5
- export function readJsonObjectFile(filePath) {
6
- if (!fs.existsSync(filePath))
7
- return {};
8
- const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
9
- if (!isRecord(parsed)) {
10
- throw new Error(`${filePath} must contain a JSON object`);
11
- }
12
- return parsed;
13
- }
@@ -1,4 +1,3 @@
1
- export declare const AGENT_KIT_HOME: string;
2
1
  export declare const CREDENTIALS_FILE: string;
3
2
  export declare const MODEL_CACHE_DIR: string;
4
3
  export declare const FASTEMBED_CACHE_DIR: string;
@@ -1,6 +1,6 @@
1
1
  import * as os from 'os';
2
2
  import * as path from 'path';
3
- export const AGENT_KIT_HOME = path.join(os.homedir(), '.agent-kit');
3
+ const AGENT_KIT_HOME = path.join(os.homedir(), '.agent-kit');
4
4
  export const CREDENTIALS_FILE = path.join(AGENT_KIT_HOME, 'credentials');
5
5
  export const MODEL_CACHE_DIR = path.join(AGENT_KIT_HOME, 'cache', 'models');
6
6
  export const FASTEMBED_CACHE_DIR = path.join(MODEL_CACHE_DIR, 'fastembed');
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@hanhnd/agent-kit",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Agent Kit MCP server for software development agent workflows",
5
5
  "type": "module",
6
- "main": "dist/kit-server.js",
6
+ "main": "dist/server.js",
7
7
  "bin": {
8
- "agent-kit": "dist/kit-server.js",
9
- "agent-kit-cli": "dist/kit-cli.js"
8
+ "agent-kit": "dist/server.js",
9
+ "cli": "dist/cli.js"
10
10
  },
11
11
  "files": [
12
12
  "dist",
@@ -22,10 +22,10 @@
22
22
  },
23
23
  "scripts": {
24
24
  "build": "rm -rf dist && tsc && npm run bundle",
25
- "bundle": "esbuild src/kit-server.ts src/kit-cli.ts --bundle --platform=node --format=esm --outdir=dist --external:node:* --external:better-sqlite3 --external:sqlite-vec --external:fastembed --external:node-llama-cpp --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\"",
25
+ "bundle": "esbuild src/entrypoints/server.ts src/entrypoints/cli.ts --bundle --platform=node --format=esm --outdir=dist --external:node:* --external:better-sqlite3 --external:sqlite-vec --external:fastembed --external:node-llama-cpp --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\"",
26
26
  "dev": "tsc --watch",
27
27
  "prepublishOnly": "npm run build",
28
- "test": "tsc && node --test $(find src/memory/__tests__ src/tools/__tests__ -name '*.test.ts' | sed 's#^src/#dist/#; s#\\.ts$#.js#' | tr '\\n' ' ')"
28
+ "test": "tsc && node --test $(find dist -name '*.test.js' | tr '\\n' ' ')"
29
29
  },
30
30
  "dependencies": {
31
31
  "node-llama-cpp": "^3.0.0",
@@ -1,46 +0,0 @@
1
- import * as assert from 'node:assert/strict';
2
- import { describe, test } from 'node:test';
3
- import { parseDigestWorkerSuccess } from '../digest/worker.js';
4
- import { DIGEST_WORKER_RESULT_PREFIX } from '../digest/constants.js';
5
- function workerResultLine(result) {
6
- return DIGEST_WORKER_RESULT_PREFIX + JSON.stringify(result);
7
- }
8
- describe('parseDigestWorkerSuccess', () => {
9
- test('accepts a structured provisional digest worker line', () => {
10
- const stdout = [
11
- '[memory-kit] model-load: 612ms',
12
- workerResultLine({
13
- markdown: '/tmp/conversation-digests/abc-conv.md',
14
- status: 'provisional',
15
- contentHash: 'abc',
16
- indexed: true,
17
- skipped: false,
18
- }),
19
- ].join('\n');
20
- assert.equal(parseDigestWorkerSuccess(stdout), true);
21
- });
22
- test('rejects stdout that only mentions markdown as plain text', () => {
23
- const stdout = 'The model produced markdown but no digest result envelope.';
24
- assert.equal(parseDigestWorkerSuccess(stdout), false);
25
- });
26
- test('rejects unprefixed JSON objects', () => {
27
- const stdout = [
28
- JSON.stringify({ markdown: '/tmp/file.md', status: 'draft' }),
29
- JSON.stringify({ markdown: '/tmp/file.md', status: 'provisional' }),
30
- ].join('\n');
31
- assert.equal(parseDigestWorkerSuccess(stdout), false);
32
- });
33
- test('uses the last valid digest worker line after noisy output', () => {
34
- const stdout = [
35
- JSON.stringify({ event: 'model-load', markdown: false }),
36
- 'Metal cleanup warning',
37
- workerResultLine({ markdown: '/tmp/final.md', status: 'provisional' }),
38
- 'trailing non-json output',
39
- ].join('\n');
40
- assert.equal(parseDigestWorkerSuccess(stdout), true);
41
- });
42
- test('rejects malformed digest worker lines', () => {
43
- const stdout = ['[memory-kit] model-load: 612ms', DIGEST_WORKER_RESULT_PREFIX + '{"markdown":'].join('\n');
44
- assert.equal(parseDigestWorkerSuccess(stdout), false);
45
- });
46
- });
@@ -1,14 +0,0 @@
1
- import * as assert from 'node:assert/strict';
2
- import * as os from 'node:os';
3
- import * as path from 'node:path';
4
- import { describe, test } from 'node:test';
5
- import { DEFAULT_MODEL_CACHE_DIR, FASTEMBED_CACHE_DIR } from '../embedder.js';
6
- import { AGENT_KIT_HOME, CREDENTIALS_FILE } from '../../utils/paths.js';
7
- describe('Embedder cache paths', () => {
8
- test('uses global Agent Kit home for user-level files', () => {
9
- assert.equal(AGENT_KIT_HOME, path.join(os.homedir(), '.agent-kit'));
10
- assert.equal(CREDENTIALS_FILE, path.join(AGENT_KIT_HOME, 'credentials'));
11
- assert.equal(DEFAULT_MODEL_CACHE_DIR, path.join(AGENT_KIT_HOME, 'cache', 'models'));
12
- assert.equal(FASTEMBED_CACHE_DIR, path.join(DEFAULT_MODEL_CACHE_DIR, 'fastembed'));
13
- });
14
- });
@@ -1,6 +0,0 @@
1
- import type { DigestModelSpec } from './types.js';
2
- export declare class DigestModelRegistryError extends Error {
3
- constructor(message: string);
4
- }
5
- export declare const DIGEST_MODEL_REGISTRY: Record<string, DigestModelSpec>;
6
- export declare function getDigestModelSpec(modelId: string): DigestModelSpec;
@@ -1,7 +0,0 @@
1
- import type { DigestFileOptions, DigestPendingResult, ProvisionalDigestResult, ConversationDigestInitResult, InitializeConversationDigestInput } from './types.js';
2
- export declare function digestConversationFile(options: DigestFileOptions): Promise<ProvisionalDigestResult>;
3
- export declare function digestPendingConversations({ workspaceRoot, digestFn, }: {
4
- workspaceRoot: string;
5
- digestFn?: (opts: DigestFileOptions) => Promise<ProvisionalDigestResult>;
6
- }): Promise<DigestPendingResult>;
7
- export declare function initializeConversationDigestModel(input: InitializeConversationDigestInput): Promise<ConversationDigestInitResult>;
@@ -1,7 +0,0 @@
1
- import type { ConversationDigestProvider } from '../types.js';
2
- export declare class LlamaLocalDigestProviderError extends Error {
3
- constructor(message: string);
4
- }
5
- export declare function trimConversationExport(content: string, maxInputChars: number): string;
6
- export declare function sanitizeConversationDigestMarkdown(generatedText: string): string;
7
- export declare function createLlamaLocalDigestProvider(modelId: string): Promise<ConversationDigestProvider>;
@@ -1,51 +0,0 @@
1
- import * as assert from 'node:assert/strict';
2
- import { afterEach, describe, test } from 'node:test';
3
- import { createTempDirTracker } from '../../__tests__/temp-dir.js';
4
- import { runMemoryCli } from '../../cli/memory.js';
5
- const tempDirs = createTempDirTracker();
6
- afterEach(() => {
7
- tempDirs.cleanup();
8
- });
9
- describe('cmdDigestPending CLI', () => {
10
- test('C22: no --hook flag → writes usage to stderr and returns 1', async () => {
11
- const stderrChunks = [];
12
- const origWrite = process.stderr.write.bind(process.stderr);
13
- process.stderr.write = (chunk) => {
14
- stderrChunks.push(String(chunk));
15
- return true;
16
- };
17
- let code;
18
- try {
19
- code = await runMemoryCli(['digest-pending'], process.env);
20
- }
21
- finally {
22
- process.stderr.write = origWrite;
23
- }
24
- assert.equal(code, 1);
25
- assert.ok(stderrChunks.some((s) => s.includes('Usage')));
26
- });
27
- test('C23: --hook returns 0 and emits one JSON line matching DigestPendingResult', async () => {
28
- const workspace = tempDirs.makeTempDir('cli-pending-c23-');
29
- const stdoutChunks = [];
30
- const origWrite = process.stdout.write.bind(process.stdout);
31
- process.stdout.write = (chunk) => {
32
- stdoutChunks.push(String(chunk));
33
- return true;
34
- };
35
- let code;
36
- try {
37
- code = await runMemoryCli(['digest-pending', '--hook'], {
38
- ...process.env,
39
- WORKSPACE_DIR: workspace,
40
- });
41
- }
42
- finally {
43
- process.stdout.write = origWrite;
44
- }
45
- assert.equal(code, 0);
46
- const output = stdoutChunks.join('');
47
- const parsed = JSON.parse(output.trim());
48
- assert.ok('ok' in parsed, 'result must have ok field');
49
- assert.ok('action' in parsed, 'result must have action field');
50
- });
51
- });
@@ -1,22 +0,0 @@
1
- import * as assert from 'node:assert/strict';
2
- import { afterEach, describe, test } from 'node:test';
3
- import { createTempDirTracker } from '../../__tests__/temp-dir.js';
4
- import { runMemoryCli } from '../../cli/memory.js';
5
- const tempDirs = createTempDirTracker();
6
- afterEach(() => {
7
- tempDirs.cleanup();
8
- });
9
- describe('memory CLI', () => {
10
- test('digest-pending --hook returns 0 when settings are missing', async () => {
11
- const workspace = tempDirs.makeTempDir('digest-pending-');
12
- const code = await runMemoryCli(['digest-pending', '--hook'], {
13
- ...process.env,
14
- WORKSPACE_DIR: workspace,
15
- });
16
- assert.equal(code, 0);
17
- });
18
- test('unknown command returns 1', async () => {
19
- const code = await runMemoryCli(['unknown'], process.env);
20
- assert.equal(code, 1);
21
- });
22
- });
@@ -1,10 +0,0 @@
1
- /**
2
- * Core Tools - Extension info and handoff persistence
3
- */
4
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
- import { DEFAULT_EXTENSIONS } from './config.js';
6
- /**
7
- * Register core tools with MCP server
8
- */
9
- export declare function registerCoreTools(server: McpServer): void;
10
- export { DEFAULT_EXTENSIONS };
@@ -1,46 +0,0 @@
1
- /**
2
- * Core Tools - Extension info and handoff persistence
3
- */
4
- import * as fs from 'fs';
5
- import * as path from 'path';
6
- import { z } from 'zod';
7
- import { getWorkspaceRoot, mcpText } from '../utils/utils.js';
8
- import { DEFAULT_EXTENSIONS } from './config.js';
9
- import { HANDOFF_TYPES, resolveHandoffPath } from './handoffs.js';
10
- /**
11
- * Register core tools with MCP server
12
- */
13
- export function registerCoreTools(server) {
14
- // ═══════════════════════════════════════════════════════════════
15
- // TOOL: SAVE HANDOFF
16
- // Writes handoff artifacts to the workspace
17
- // Returns the saved file path to use in next-step instructions
18
- // ═══════════════════════════════════════════════════════════════
19
- server.tool('kit_save_handoff', `Save a handoff artifact to .agent-kit/handoffs/. Returns the saved file path to use in next-step instructions. Do NOT append version numbers (v2, v3, etc.) to the slug.`, {
20
- type: z.enum(HANDOFF_TYPES).describe('Handoff type'),
21
- content: z.string().describe('Full markdown content to save'),
22
- slug: z
23
- .string()
24
- .describe('Short identifier for the filename, e.g. "user-auth" or "PROJ-123". Do NOT append version numbers (v2, v3, etc.).'),
25
- }, async ({ type, content, slug }) => {
26
- try {
27
- const location = resolveHandoffPath({
28
- workspaceRoot: getWorkspaceRoot(),
29
- type,
30
- slug,
31
- content,
32
- });
33
- const handoffDir = path.dirname(location.filePath);
34
- if (!fs.existsSync(handoffDir)) {
35
- fs.mkdirSync(handoffDir, { recursive: true });
36
- }
37
- fs.writeFileSync(location.filePath, content, 'utf8');
38
- return mcpText(`✅ Saved to: ${location.filePath}`);
39
- }
40
- catch (error) {
41
- return mcpText(`Error saving handoff: ${error}`);
42
- }
43
- });
44
- }
45
- // Export DEFAULT_EXTENSIONS for backward compatibility
46
- export { DEFAULT_EXTENSIONS };
@@ -1,22 +0,0 @@
1
- export declare const HANDOFF_TYPES: readonly ["brainstorm", "clarification", "plan", "ticket", "research", "scenario", "investigation"];
2
- export type HandoffType = (typeof HANDOFF_TYPES)[number];
3
- export type CanonicalHandoffType = 'brainstorm' | 'clarification' | 'plan' | 'ticket' | 'research' | 'scenario' | 'investigation';
4
- export interface SavedHandoffLocation {
5
- featureSlug: string;
6
- canonicalType: CanonicalHandoffType;
7
- filePath: string;
8
- relativePath: string;
9
- }
10
- export declare function sanitizeFeatureSlug(value: string): string;
11
- export declare function normalizeHandoffType(type: HandoffType): CanonicalHandoffType;
12
- export declare function deriveFeatureSlug(input: {
13
- requestedSlug: string;
14
- content: string;
15
- type: CanonicalHandoffType;
16
- }): string;
17
- export declare function resolveHandoffPath(input: {
18
- workspaceRoot: string;
19
- type: HandoffType;
20
- slug: string;
21
- content: string;
22
- }): SavedHandoffLocation;
@@ -1,16 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { MemoryIndexer } from '../memory/indexer.js';
3
- import { MemoryStore } from '../memory/store.js';
4
- import type { MemoryConfig } from '../memory/types.js';
5
- import { type ProjectSettings } from './config.js';
6
- /**
7
- * Registers tool handlers onto an already-constructed indexer/store pair.
8
- * Exported for unit testing with mocks.
9
- */
10
- export declare function registerMemoryToolHandlers(server: McpServer, indexer: MemoryIndexer, store: MemoryStore, config: MemoryConfig, workspaceRoot?: string): void;
11
- /**
12
- * Initializes the memory subsystem and registers all memory tools.
13
- * Returns the MemoryIndexer so the caller can fire startupIndex() after server.connect().
14
- * Returns null when memory is disabled (settings.memory.enabled !== true).
15
- */
16
- export declare function registerMemoryTools(server: McpServer, settings: ProjectSettings, workspaceRoot: string): MemoryIndexer | null;
File without changes
File without changes