@hanhnd/agent-kit 1.0.30 → 1.0.32

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 (81) hide show
  1. package/dist/__tests__/temp-dir.d.ts +4 -0
  2. package/dist/__tests__/temp-dir.js +20 -0
  3. package/dist/cli/index.d.ts +1 -0
  4. package/dist/cli/index.js +9 -0
  5. package/dist/cli/memory.d.ts +1 -0
  6. package/dist/cli/memory.js +77 -0
  7. package/dist/kit-cli.d.ts +2 -0
  8. package/dist/kit-cli.js +16205 -0
  9. package/dist/kit-server.js +677 -187
  10. package/dist/memory/__tests__/digest-llama-local.test.d.ts +1 -0
  11. package/dist/memory/__tests__/digest-llama-local.test.js +33 -0
  12. package/dist/memory/__tests__/digest-pending.test.d.ts +1 -0
  13. package/dist/memory/__tests__/digest-pending.test.js +164 -0
  14. package/dist/memory/__tests__/digest-processor.test.d.ts +1 -0
  15. package/dist/memory/__tests__/digest-processor.test.js +34 -0
  16. package/dist/memory/__tests__/digest-worker.test.d.ts +1 -0
  17. package/dist/memory/__tests__/digest-worker.test.js +46 -0
  18. package/dist/memory/__tests__/embedder.test.d.ts +1 -0
  19. package/dist/memory/__tests__/embedder.test.js +14 -0
  20. package/dist/memory/__tests__/indexer.test.js +7 -12
  21. package/dist/memory/__tests__/lockfile.test.d.ts +1 -0
  22. package/dist/memory/__tests__/lockfile.test.js +81 -0
  23. package/dist/memory/__tests__/store.test.js +15 -3
  24. package/dist/memory/chunker.js +3 -5
  25. package/dist/memory/constants.d.ts +5 -0
  26. package/dist/memory/constants.js +12 -0
  27. package/dist/memory/digest/constants.d.ts +14 -0
  28. package/dist/memory/digest/constants.js +15 -0
  29. package/dist/memory/digest/files.d.ts +7 -0
  30. package/dist/memory/digest/files.js +45 -0
  31. package/dist/memory/digest/model-registry.d.ts +6 -0
  32. package/dist/memory/digest/model-registry.js +48 -0
  33. package/dist/memory/digest/processor.d.ts +7 -0
  34. package/dist/memory/digest/processor.js +171 -0
  35. package/dist/memory/digest/providers/llama-local.d.ts +7 -0
  36. package/dist/memory/digest/providers/llama-local.js +136 -0
  37. package/dist/memory/digest/types.d.ts +85 -0
  38. package/dist/memory/digest/types.js +1 -0
  39. package/dist/memory/digest/worker.d.ts +3 -0
  40. package/dist/memory/digest/worker.js +51 -0
  41. package/dist/memory/embedder.d.ts +2 -0
  42. package/dist/memory/embedder.js +12 -4
  43. package/dist/memory/index.d.ts +1 -1
  44. package/dist/memory/index.js +1 -1
  45. package/dist/memory/indexer.d.ts +5 -2
  46. package/dist/memory/indexer.js +15 -37
  47. package/dist/memory/store.js +6 -18
  48. package/dist/memory/types.d.ts +2 -1
  49. package/dist/memory/types.js +1 -9
  50. package/dist/tools/__tests__/cli-digest-pending.test.d.ts +1 -0
  51. package/dist/tools/__tests__/cli-digest-pending.test.js +51 -0
  52. package/dist/tools/__tests__/cli-memory.test.d.ts +1 -0
  53. package/dist/tools/__tests__/cli-memory.test.js +22 -0
  54. package/dist/tools/__tests__/digest-init.test.d.ts +1 -0
  55. package/dist/tools/__tests__/digest-init.test.js +32 -0
  56. package/dist/tools/__tests__/memory.test.js +28 -6
  57. package/dist/tools/agent.js +2 -13
  58. package/dist/tools/config.d.ts +4 -4
  59. package/dist/tools/config.js +21 -13
  60. package/dist/tools/core.js +1 -3
  61. package/dist/tools/handoffs.js +1 -2
  62. package/dist/tools/integration.js +2 -8
  63. package/dist/tools/memory.d.ts +1 -1
  64. package/dist/tools/memory.js +29 -3
  65. package/dist/tools/security.js +2 -6
  66. package/dist/utils/args.d.ts +7 -0
  67. package/dist/utils/args.js +31 -0
  68. package/dist/utils/async.d.ts +1 -0
  69. package/dist/utils/async.js +15 -0
  70. package/dist/utils/credentials.d.ts +3 -3
  71. package/dist/utils/credentials.js +5 -7
  72. package/dist/utils/files.d.ts +8 -0
  73. package/dist/utils/files.js +77 -0
  74. package/dist/utils/hash.d.ts +1 -0
  75. package/dist/utils/hash.js +4 -0
  76. package/dist/utils/json.d.ts +2 -0
  77. package/dist/utils/json.js +13 -0
  78. package/dist/utils/parser.js +2 -6
  79. package/dist/utils/paths.d.ts +4 -0
  80. package/dist/utils/paths.js +6 -0
  81. package/package.json +7 -5
@@ -0,0 +1,31 @@
1
+ export function parseArgs(args) {
2
+ const flags = new Map();
3
+ const positionals = [];
4
+ for (let index = 0; index < args.length; index += 1) {
5
+ const arg = args[index];
6
+ if (!arg.startsWith('--')) {
7
+ positionals.push(arg);
8
+ continue;
9
+ }
10
+ const key = arg.slice(2);
11
+ const next = args[index + 1];
12
+ if (!next || next.startsWith('--')) {
13
+ flags.set(key, true);
14
+ continue;
15
+ }
16
+ flags.set(key, next);
17
+ index += 1;
18
+ }
19
+ return { flags, positionals };
20
+ }
21
+ export function stringFlag(flags, key) {
22
+ const value = flags.get(key);
23
+ return typeof value === 'string' ? value : undefined;
24
+ }
25
+ export function numberFlag(flags, key, defaultValue) {
26
+ const value = Number(stringFlag(flags, key) ?? defaultValue);
27
+ if (!Number.isFinite(value)) {
28
+ throw new Error(`--${key} must be a finite number`);
29
+ }
30
+ return value;
31
+ }
@@ -0,0 +1 @@
1
+ export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, createError: () => Error): Promise<T>;
@@ -0,0 +1,15 @@
1
+ export async function withTimeout(promise, timeoutMs, createError) {
2
+ let timer;
3
+ const timeout = new Promise((_resolve, reject) => {
4
+ timer = setTimeout(() => {
5
+ reject(createError());
6
+ }, timeoutMs);
7
+ });
8
+ try {
9
+ return await Promise.race([promise, timeout]);
10
+ }
11
+ finally {
12
+ if (timer)
13
+ clearTimeout(timer);
14
+ }
15
+ }
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Credential loader — reads ~/.claude/credentials (INI format, like ~/.aws/credentials)
2
+ * Credential loader — reads ~/.agent-kit/credentials (INI format, like ~/.aws/credentials)
3
3
  *
4
4
  * Resolution order per key:
5
5
  * 1. process.env.KEY (explicit override / CI)
6
- * 2. ~/.claude/credentials [profile] section
6
+ * 2. ~/.agent-kit/credentials [profile] section
7
7
  * 3. undefined
8
8
  *
9
9
  * File format:
@@ -15,6 +15,6 @@
15
15
  */
16
16
  /**
17
17
  * Resolve a credential key using the priority chain:
18
- * process.env.KEY → ~/.claude/credentials [profile] → undefined
18
+ * process.env.KEY → ~/.agent-kit/credentials [profile] → undefined
19
19
  */
20
20
  export declare function getCredential(key: string): string | undefined;
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Credential loader — reads ~/.claude/credentials (INI format, like ~/.aws/credentials)
2
+ * Credential loader — reads ~/.agent-kit/credentials (INI format, like ~/.aws/credentials)
3
3
  *
4
4
  * Resolution order per key:
5
5
  * 1. process.env.KEY (explicit override / CI)
6
- * 2. ~/.claude/credentials [profile] section
6
+ * 2. ~/.agent-kit/credentials [profile] section
7
7
  * 3. undefined
8
8
  *
9
9
  * File format:
@@ -14,9 +14,7 @@
14
14
  * Active profile: KIT_PROFILE env var (defaults to "default")
15
15
  */
16
16
  import * as fs from 'fs';
17
- import * as os from 'os';
18
- import * as path from 'path';
19
- const CREDENTIALS_FILE = path.join(os.homedir(), '.claude', 'credentials');
17
+ import { CREDENTIALS_FILE } from './paths.js';
20
18
  let cachedCredentials = null;
21
19
  /**
22
20
  * Parse a simple INI file into a map of profiles.
@@ -47,7 +45,7 @@ function parseIni(content) {
47
45
  return result;
48
46
  }
49
47
  /**
50
- * Load credentials from ~/.claude/credentials for the active profile.
48
+ * Load credentials from ~/.agent-kit/credentials for the active profile.
51
49
  * Result is cached for the lifetime of the MCP server process.
52
50
  */
53
51
  function loadCredentials() {
@@ -79,7 +77,7 @@ function loadCredentials() {
79
77
  }
80
78
  /**
81
79
  * Resolve a credential key using the priority chain:
82
- * process.env.KEY → ~/.claude/credentials [profile] → undefined
80
+ * process.env.KEY → ~/.agent-kit/credentials [profile] → undefined
83
81
  */
84
82
  export function getCredential(key) {
85
83
  if (process.env[key]) {
@@ -0,0 +1,8 @@
1
+ export declare function atomicWriteTextFile(filePath: string, content: string): void;
2
+ export declare function atomicWriteJsonFile(filePath: string, value: unknown): void;
3
+ export declare function tryWriteFileExclusive(filePath: string, content: string): boolean;
4
+ export declare function acquireLock(lockPath: string, timeoutMs: number, retryMs: number): Promise<boolean>;
5
+ export declare function releaseLock(lockPath: string, opts?: {
6
+ ignoreErrors?: boolean;
7
+ }): void;
8
+ export declare function tryAcquireProcessLock(lockPath: string): boolean;
@@ -0,0 +1,77 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ export function atomicWriteTextFile(filePath, content) {
4
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
5
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
6
+ fs.writeFileSync(tempPath, content, 'utf8');
7
+ fs.renameSync(tempPath, filePath);
8
+ }
9
+ export function atomicWriteJsonFile(filePath, value) {
10
+ atomicWriteTextFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
11
+ }
12
+ export function tryWriteFileExclusive(filePath, content) {
13
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
14
+ try {
15
+ fs.writeFileSync(filePath, content, { flag: 'wx' });
16
+ return true;
17
+ }
18
+ catch (err) {
19
+ if (err.code === 'EEXIST')
20
+ return false;
21
+ throw err;
22
+ }
23
+ }
24
+ export async function acquireLock(lockPath, timeoutMs, retryMs) {
25
+ const deadline = Date.now() + timeoutMs;
26
+ while (Date.now() < deadline) {
27
+ try {
28
+ if (tryWriteFileExclusive(lockPath, String(process.pid)))
29
+ return true;
30
+ }
31
+ catch {
32
+ // Preserve fail-open retry behavior for transient lock-file write errors.
33
+ }
34
+ await new Promise((r) => setTimeout(r, retryMs));
35
+ }
36
+ return false;
37
+ }
38
+ export function releaseLock(lockPath, opts = {}) {
39
+ try {
40
+ fs.unlinkSync(lockPath);
41
+ }
42
+ catch (err) {
43
+ if (opts.ignoreErrors || err.code === 'ENOENT')
44
+ return;
45
+ throw err;
46
+ }
47
+ }
48
+ export function tryAcquireProcessLock(lockPath) {
49
+ const lockContent = JSON.stringify({ pid: process.pid });
50
+ if (tryWriteFileExclusive(lockPath, lockContent))
51
+ return true;
52
+ let pid;
53
+ try {
54
+ const raw = fs.readFileSync(lockPath, 'utf8');
55
+ pid = JSON.parse(raw).pid;
56
+ }
57
+ catch {
58
+ // Unparseable lockfiles are treated as stale.
59
+ }
60
+ if (pid !== undefined) {
61
+ try {
62
+ process.kill(pid, 0);
63
+ return false;
64
+ }
65
+ catch (err) {
66
+ if (err.code !== 'ESRCH')
67
+ return false;
68
+ }
69
+ }
70
+ try {
71
+ fs.unlinkSync(lockPath);
72
+ }
73
+ catch {
74
+ // Ignore if another process already removed the stale lock.
75
+ }
76
+ return tryWriteFileExclusive(lockPath, lockContent);
77
+ }
@@ -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,2 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
2
+ export declare function readJsonObjectFile(filePath: string): Record<string, unknown>;
@@ -0,0 +1,13 @@
1
+ import * as fs from 'node:fs';
2
+ export function isRecord(value) {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ }
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
+ }
@@ -17,8 +17,7 @@ export function adfToMarkdown(adf) {
17
17
  }
18
18
  case 'heading': {
19
19
  const level = node.attrs?.level || 1;
20
- result +=
21
- '#'.repeat(level) + ' ' + renderNodes(node.content, listDepth, node.type) + '\n\n';
20
+ result += '#'.repeat(level) + ' ' + renderNodes(node.content, listDepth, node.type) + '\n\n';
22
21
  break;
23
22
  }
24
23
  case 'text': {
@@ -61,10 +60,7 @@ export function adfToMarkdown(adf) {
61
60
  break;
62
61
  }
63
62
  case 'blockquote':
64
- result +=
65
- '> ' +
66
- renderNodes(node.content, listDepth, node.type).trim().replace(/\n/g, '\n> ') +
67
- '\n\n';
63
+ result += '> ' + renderNodes(node.content, listDepth, node.type).trim().replace(/\n/g, '\n> ') + '\n\n';
68
64
  break;
69
65
  case 'codeBlock':
70
66
  result += `\`\`\`${node.attrs?.language || ''}\n${renderNodes(node.content, listDepth, node.type).trim()}\n\`\`\`\n\n`;
@@ -0,0 +1,4 @@
1
+ export declare const AGENT_KIT_HOME: string;
2
+ export declare const CREDENTIALS_FILE: string;
3
+ export declare const MODEL_CACHE_DIR: string;
4
+ export declare const FASTEMBED_CACHE_DIR: string;
@@ -0,0 +1,6 @@
1
+ import * as os from 'os';
2
+ import * as path from 'path';
3
+ export const AGENT_KIT_HOME = path.join(os.homedir(), '.agent-kit');
4
+ export const CREDENTIALS_FILE = path.join(AGENT_KIT_HOME, 'credentials');
5
+ export const MODEL_CACHE_DIR = path.join(AGENT_KIT_HOME, 'cache', 'models');
6
+ export const FASTEMBED_CACHE_DIR = path.join(MODEL_CACHE_DIR, 'fastembed');
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@hanhnd/agent-kit",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "Agent Kit MCP server for software development agent workflows",
5
5
  "type": "module",
6
6
  "main": "dist/kit-server.js",
7
7
  "bin": {
8
- "agent-kit": "dist/kit-server.js"
8
+ "agent-kit": "dist/kit-server.js",
9
+ "agent-kit-cli": "dist/kit-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/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
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 src/memory/__tests__ src/tools/__tests__ -name '*.test.ts' | sed 's#^src/#dist/#; s#\\.ts$#.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",