@hanhnd/agent-kit 1.0.31 → 1.0.33

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 (105) 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/commands/memory.d.ts +1 -0
  4. package/dist/cli/commands/memory.js +90 -0
  5. package/dist/cli/index.d.ts +1 -0
  6. package/dist/cli/index.js +9 -0
  7. package/dist/cli/utils/args.d.ts +8 -0
  8. package/dist/cli/utils/args.js +31 -0
  9. package/dist/cli.js +16489 -0
  10. package/dist/{tools/config.d.ts → core/config/index.d.ts} +4 -9
  11. package/dist/{tools/config.js → core/config/index.js} +20 -23
  12. package/dist/core/handoffs/index.d.ts +16 -0
  13. package/dist/{tools/handoffs.js → core/handoffs/index.js} +4 -5
  14. package/dist/{tools/security.d.ts → core/security/index.d.ts} +0 -19
  15. package/dist/{tools/security.js → core/security/index.js} +3 -80
  16. package/dist/entrypoints/cli.d.ts +2 -0
  17. package/dist/entrypoints/cli.js +11 -0
  18. package/dist/entrypoints/server.js +37 -0
  19. package/dist/{tools → mcp}/agent.js +3 -14
  20. package/dist/{tools → mcp}/core.d.ts +1 -1
  21. package/dist/{tools → mcp}/core.js +3 -5
  22. package/dist/{tools → mcp}/integration.js +5 -11
  23. package/dist/mcp/memory.d.ts +15 -0
  24. package/dist/{tools → mcp}/memory.js +40 -12
  25. package/dist/{kit-server.js → server.js} +720 -224
  26. package/dist/services/digest/background.d.ts +11 -0
  27. package/dist/services/digest/background.js +258 -0
  28. package/dist/services/digest/constants.d.ts +17 -0
  29. package/dist/services/digest/constants.js +19 -0
  30. package/dist/services/digest/digest-background.test.js +206 -0
  31. package/dist/services/digest/digest-init.test.js +33 -0
  32. package/dist/services/digest/digest-llama-local.test.js +21 -0
  33. package/dist/services/digest/digest-pending.test.d.ts +1 -0
  34. package/dist/services/digest/digest-pending.test.js +192 -0
  35. package/dist/services/digest/digest-processor.test.d.ts +1 -0
  36. package/dist/services/digest/digest-processor.test.js +32 -0
  37. package/dist/services/digest/files.d.ts +6 -0
  38. package/dist/services/digest/files.js +45 -0
  39. package/dist/services/digest/model-registry.d.ts +2 -0
  40. package/dist/services/digest/model-registry.js +49 -0
  41. package/dist/services/digest/processor.d.ts +13 -0
  42. package/dist/services/digest/processor.js +188 -0
  43. package/dist/services/digest/providers/llama-local.d.ts +2 -0
  44. package/dist/services/digest/providers/llama-local.js +135 -0
  45. package/dist/services/digest/types.d.ts +117 -0
  46. package/dist/services/digest/types.js +6 -0
  47. package/dist/services/digest/worker.d.ts +2 -0
  48. package/dist/services/digest/worker.js +51 -0
  49. package/dist/{utils → services/integration}/credentials.js +1 -1
  50. package/dist/{utils/parser.js → services/integration/parser/adf.js} +3 -6
  51. package/dist/{memory → services/memory}/chunker.d.ts +0 -2
  52. package/dist/{memory → services/memory}/chunker.js +5 -7
  53. package/dist/services/memory/chunker.test.d.ts +1 -0
  54. package/dist/{memory/__tests__ → services/memory}/chunker.test.js +1 -34
  55. package/dist/services/memory/constants.d.ts +5 -0
  56. package/dist/services/memory/constants.js +13 -0
  57. package/dist/{memory → services/memory}/embedder.d.ts +3 -2
  58. package/dist/{memory → services/memory}/embedder.js +15 -6
  59. package/dist/services/memory/embedder.test.d.ts +1 -0
  60. package/dist/services/memory/embedder.test.js +13 -0
  61. package/dist/{memory → services/memory}/index.d.ts +1 -1
  62. package/dist/{memory → services/memory}/index.js +1 -1
  63. package/dist/{memory → services/memory}/indexer.d.ts +6 -2
  64. package/dist/{memory → services/memory}/indexer.js +15 -37
  65. package/dist/services/memory/indexer.test.d.ts +1 -0
  66. package/dist/{memory/__tests__ → services/memory}/indexer.test.js +11 -15
  67. package/dist/services/memory/memory.test.d.ts +1 -0
  68. package/dist/{tools/__tests__ → services/memory}/memory.test.js +82 -19
  69. package/dist/{memory → services/memory}/store.js +6 -18
  70. package/dist/services/memory/store.test.d.ts +1 -0
  71. package/dist/{memory/__tests__ → services/memory}/store.test.js +18 -5
  72. package/dist/{memory → services/memory}/types.d.ts +8 -2
  73. package/dist/services/memory/types.js +6 -0
  74. package/dist/utils/async.d.ts +1 -0
  75. package/dist/utils/async.js +15 -0
  76. package/dist/utils/files.d.ts +7 -0
  77. package/dist/utils/files.js +77 -0
  78. package/dist/utils/files.test.d.ts +1 -0
  79. package/dist/utils/files.test.js +81 -0
  80. package/dist/utils/hash.d.ts +1 -0
  81. package/dist/utils/hash.js +4 -0
  82. package/dist/utils/index.d.ts +6 -0
  83. package/dist/utils/index.js +6 -0
  84. package/dist/utils/json.d.ts +1 -0
  85. package/dist/utils/json.js +3 -0
  86. package/dist/utils/paths.d.ts +0 -1
  87. package/dist/utils/paths.js +1 -1
  88. package/dist/utils/temp-dir.test.d.ts +4 -0
  89. package/dist/utils/temp-dir.test.js +20 -0
  90. package/package.json +8 -6
  91. package/dist/memory/__tests__/embedder.test.js +0 -14
  92. package/dist/memory/types.js +0 -9
  93. package/dist/tools/handoffs.d.ts +0 -22
  94. package/dist/tools/memory.d.ts +0 -16
  95. /package/dist/{memory/__tests__/chunker.test.d.ts → cli/commands/cli-digest-pending.test.d.ts} +0 -0
  96. /package/dist/{memory/__tests__/embedder.test.d.ts → cli/commands/cli-memory.test.d.ts} +0 -0
  97. /package/dist/{kit-server.d.ts → entrypoints/server.d.ts} +0 -0
  98. /package/dist/{tools → mcp}/agent.d.ts +0 -0
  99. /package/dist/{tools → mcp}/integration.d.ts +0 -0
  100. /package/dist/{memory/__tests__/indexer.test.d.ts → services/digest/digest-background.test.d.ts} +0 -0
  101. /package/dist/{memory/__tests__/store.test.d.ts → services/digest/digest-init.test.d.ts} +0 -0
  102. /package/dist/{tools/__tests__/memory.test.d.ts → services/digest/digest-llama-local.test.d.ts} +0 -0
  103. /package/dist/{utils → services/integration}/credentials.d.ts +0 -0
  104. /package/dist/{utils/parser.d.ts → services/integration/parser/adf.d.ts} +0 -0
  105. /package/dist/{memory → services/memory}/store.d.ts +0 -0
@@ -0,0 +1,81 @@
1
+ import * as assert from 'node:assert/strict';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { afterEach, describe, test } from 'node:test';
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
+ const tempDirs = createTempDirTracker();
9
+ afterEach(() => {
10
+ tempDirs.cleanup();
11
+ });
12
+ function lockPath(workspace) {
13
+ return path.join(workspace, DIGEST_LOCKFILE_REL_PATH);
14
+ }
15
+ function lockDir(workspace) {
16
+ return path.dirname(lockPath(workspace));
17
+ }
18
+ describe('tryAcquireProcessLock', () => {
19
+ test('C1: no lockfile → creates it with current PID and returns true', () => {
20
+ const workspace = tempDirs.makeTempDir('lockfile-c1-');
21
+ const acquired = tryAcquireProcessLock(lockPath(workspace));
22
+ assert.equal(acquired, true);
23
+ const lockFile = lockPath(workspace);
24
+ const content = JSON.parse(fs.readFileSync(lockFile, 'utf8'));
25
+ assert.equal(content.pid, process.pid);
26
+ });
27
+ test('C2: lockfile with live foreign PID → returns false without modifying file', () => {
28
+ const workspace = tempDirs.makeTempDir('lockfile-c2-');
29
+ const lockFile = lockPath(workspace);
30
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
31
+ // Use process.pid as "live" pid (current process is definitely alive)
32
+ const livePid = process.pid;
33
+ fs.writeFileSync(lockFile, JSON.stringify({ pid: livePid }), 'utf8');
34
+ const originalContent = fs.readFileSync(lockFile, 'utf8');
35
+ const acquired = tryAcquireProcessLock(lockPath(workspace));
36
+ assert.equal(acquired, false);
37
+ // File must be unchanged
38
+ assert.equal(fs.readFileSync(lockFile, 'utf8'), originalContent);
39
+ });
40
+ test('C3: lockfile with dead PID (ESRCH) → deletes stale lock, creates new one, returns true', () => {
41
+ const workspace = tempDirs.makeTempDir('lockfile-c3-');
42
+ const lockFile = lockPath(workspace);
43
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
44
+ // PID 999999999 is virtually guaranteed to be dead
45
+ fs.writeFileSync(lockFile, JSON.stringify({ pid: 999999999 }), 'utf8');
46
+ const acquired = tryAcquireProcessLock(lockPath(workspace));
47
+ assert.equal(acquired, true);
48
+ const content = JSON.parse(fs.readFileSync(lockFile, 'utf8'));
49
+ assert.equal(content.pid, process.pid);
50
+ });
51
+ test('C4: concurrent callers — only one returns true (wx atomicity)', async () => {
52
+ const workspace = tempDirs.makeTempDir('lockfile-c4-');
53
+ // Call twice in the same tick; first wins, second sees EEXIST with live PID.
54
+ const r1 = tryAcquireProcessLock(lockPath(workspace));
55
+ const r2 = tryAcquireProcessLock(lockPath(workspace));
56
+ assert.equal(r1, true);
57
+ assert.equal(r2, false);
58
+ });
59
+ test('stale unparseable lockfile → treated as stale, returns true', () => {
60
+ const workspace = tempDirs.makeTempDir('lockfile-stale-');
61
+ const lockFile = lockPath(workspace);
62
+ fs.mkdirSync(lockDir(workspace), { recursive: true });
63
+ fs.writeFileSync(lockFile, 'not-json', 'utf8');
64
+ const acquired = tryAcquireProcessLock(lockPath(workspace));
65
+ assert.equal(acquired, true);
66
+ });
67
+ });
68
+ describe('releaseLock', () => {
69
+ test('C5: lockfile exists → deletes it', () => {
70
+ const workspace = tempDirs.makeTempDir('lockfile-c5-');
71
+ assert.equal(tryAcquireProcessLock(lockPath(workspace)), true);
72
+ const lockFile = lockPath(workspace);
73
+ assert.equal(fs.existsSync(lockFile), true);
74
+ releaseLock(lockPath(workspace));
75
+ assert.equal(fs.existsSync(lockFile), false);
76
+ });
77
+ test('C6: no lockfile → does not throw', () => {
78
+ const workspace = tempDirs.makeTempDir('lockfile-c6-');
79
+ assert.doesNotThrow(() => releaseLock(lockPath(workspace)));
80
+ });
81
+ });
@@ -0,0 +1 @@
1
+ export declare function sha256Hex(content: string): string;
@@ -0,0 +1,4 @@
1
+ import { createHash } from 'node:crypto';
2
+ export function sha256Hex(content) {
3
+ return createHash('sha256').update(content).digest('hex');
4
+ }
@@ -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';
@@ -0,0 +1 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,3 @@
1
+ export function isRecord(value) {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ }
@@ -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');
@@ -0,0 +1,4 @@
1
+ export declare function createTempDirTracker(): {
2
+ makeTempDir(prefix: string): string;
3
+ cleanup(): void;
4
+ };
@@ -0,0 +1,20 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ export function createTempDirTracker() {
5
+ const tempDirs = [];
6
+ return {
7
+ makeTempDir(prefix) {
8
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
9
+ tempDirs.push(tempDir);
10
+ return tempDir;
11
+ },
12
+ cleanup() {
13
+ while (tempDirs.length > 0) {
14
+ const tempDir = tempDirs.pop();
15
+ if (tempDir)
16
+ fs.rmSync(tempDir, { recursive: true, force: true });
17
+ }
18
+ },
19
+ };
20
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@hanhnd/agent-kit",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
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"
8
+ "agent-kit": "dist/server.js",
9
+ "cli": "dist/cli.js"
9
10
  },
10
11
  "files": [
11
12
  "dist",
@@ -20,13 +21,14 @@
20
21
  "directory": "mcp"
21
22
  },
22
23
  "scripts": {
23
- "build": "tsc && npm run bundle",
24
- "bundle": "esbuild src/kit-server.ts --bundle --platform=node --format=esm --outfile=dist/kit-server.js --external:node:* --external:better-sqlite3 --external:sqlite-vec --external:fastembed --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\"",
24
+ "build": "rm -rf dist && tsc && npm run bundle",
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);\"",
25
26
  "dev": "tsc --watch",
26
27
  "prepublishOnly": "npm run build",
27
- "test": "tsc && node --test $(find dist/src/memory/__tests__ dist/src/tools/__tests__ -name '*.test.js' 2>/dev/null | tr '\\n' ' ')"
28
+ "test": "tsc && node --test $(find dist -name '*.test.js' | tr '\\n' ' ')"
28
29
  },
29
30
  "dependencies": {
31
+ "node-llama-cpp": "^3.0.0",
30
32
  "@modelcontextprotocol/sdk": "^1.13.1",
31
33
  "better-sqlite3": "^11.0.0",
32
34
  "dedent": "^1.5.3",
@@ -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,9 +0,0 @@
1
- export const DEFAULT_MEMORY_CONFIG = {
2
- enabled: false,
3
- wikiDir: '',
4
- topK: 5,
5
- chunkSize: 1500,
6
- overlapLines: 2,
7
- embeddingModel: 'Xenova/bge-small-en-v1.5',
8
- vectorDimension: 384,
9
- };
@@ -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): 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
File without changes