@nex-ai/nex 0.1.7

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 (101) hide show
  1. package/README.md +228 -0
  2. package/dist/cli.d.ts +5 -0
  3. package/dist/cli.js +18 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/attribute.d.ts +4 -0
  6. package/dist/commands/attribute.js +75 -0
  7. package/dist/commands/attribute.js.map +1 -0
  8. package/dist/commands/config-cmd.d.ts +4 -0
  9. package/dist/commands/config-cmd.js +53 -0
  10. package/dist/commands/config-cmd.js.map +1 -0
  11. package/dist/commands/context.d.ts +4 -0
  12. package/dist/commands/context.js +135 -0
  13. package/dist/commands/context.js.map +1 -0
  14. package/dist/commands/insight.d.ts +4 -0
  15. package/dist/commands/insight.js +39 -0
  16. package/dist/commands/insight.js.map +1 -0
  17. package/dist/commands/integrate.d.ts +4 -0
  18. package/dist/commands/integrate.js +136 -0
  19. package/dist/commands/integrate.js.map +1 -0
  20. package/dist/commands/list-job.d.ts +4 -0
  21. package/dist/commands/list-job.js +41 -0
  22. package/dist/commands/list-job.js.map +1 -0
  23. package/dist/commands/list.d.ts +4 -0
  24. package/dist/commands/list.js +148 -0
  25. package/dist/commands/list.js.map +1 -0
  26. package/dist/commands/note.d.ts +4 -0
  27. package/dist/commands/note.js +77 -0
  28. package/dist/commands/note.js.map +1 -0
  29. package/dist/commands/object.d.ts +4 -0
  30. package/dist/commands/object.js +78 -0
  31. package/dist/commands/object.js.map +1 -0
  32. package/dist/commands/record.d.ts +4 -0
  33. package/dist/commands/record.js +126 -0
  34. package/dist/commands/record.js.map +1 -0
  35. package/dist/commands/register.d.ts +4 -0
  36. package/dist/commands/register.js +23 -0
  37. package/dist/commands/register.js.map +1 -0
  38. package/dist/commands/relationship.d.ts +4 -0
  39. package/dist/commands/relationship.js +80 -0
  40. package/dist/commands/relationship.js.map +1 -0
  41. package/dist/commands/scan.d.ts +4 -0
  42. package/dist/commands/scan.js +58 -0
  43. package/dist/commands/scan.js.map +1 -0
  44. package/dist/commands/search.d.ts +4 -0
  45. package/dist/commands/search.js +22 -0
  46. package/dist/commands/search.js.map +1 -0
  47. package/dist/commands/session.d.ts +4 -0
  48. package/dist/commands/session.js +31 -0
  49. package/dist/commands/session.js.map +1 -0
  50. package/dist/commands/setup.d.ts +10 -0
  51. package/dist/commands/setup.js +254 -0
  52. package/dist/commands/setup.js.map +1 -0
  53. package/dist/commands/task.d.ts +4 -0
  54. package/dist/commands/task.js +114 -0
  55. package/dist/commands/task.js.map +1 -0
  56. package/dist/index.d.ts +25 -0
  57. package/dist/index.js +68 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/lib/capture-filter.d.ts +9 -0
  60. package/dist/lib/capture-filter.js +14 -0
  61. package/dist/lib/capture-filter.js.map +1 -0
  62. package/dist/lib/client.d.ts +19 -0
  63. package/dist/lib/client.js +115 -0
  64. package/dist/lib/client.js.map +1 -0
  65. package/dist/lib/config.d.ts +34 -0
  66. package/dist/lib/config.js +59 -0
  67. package/dist/lib/config.js.map +1 -0
  68. package/dist/lib/context-format.d.ts +7 -0
  69. package/dist/lib/context-format.js +21 -0
  70. package/dist/lib/context-format.js.map +1 -0
  71. package/dist/lib/errors.d.ts +18 -0
  72. package/dist/lib/errors.js +30 -0
  73. package/dist/lib/errors.js.map +1 -0
  74. package/dist/lib/file-scanner.d.ts +38 -0
  75. package/dist/lib/file-scanner.js +178 -0
  76. package/dist/lib/file-scanner.js.map +1 -0
  77. package/dist/lib/installers.d.ts +19 -0
  78. package/dist/lib/installers.js +205 -0
  79. package/dist/lib/installers.js.map +1 -0
  80. package/dist/lib/output.d.ts +7 -0
  81. package/dist/lib/output.js +50 -0
  82. package/dist/lib/output.js.map +1 -0
  83. package/dist/lib/platform-detect.d.ts +16 -0
  84. package/dist/lib/platform-detect.js +188 -0
  85. package/dist/lib/platform-detect.js.map +1 -0
  86. package/dist/lib/project-config.d.ts +53 -0
  87. package/dist/lib/project-config.js +151 -0
  88. package/dist/lib/project-config.js.map +1 -0
  89. package/dist/lib/prompt.d.ts +4 -0
  90. package/dist/lib/prompt.js +21 -0
  91. package/dist/lib/prompt.js.map +1 -0
  92. package/dist/lib/rate-limiter.d.ts +13 -0
  93. package/dist/lib/rate-limiter.js +49 -0
  94. package/dist/lib/rate-limiter.js.map +1 -0
  95. package/dist/lib/recall-filter.d.ts +6 -0
  96. package/dist/lib/recall-filter.js +58 -0
  97. package/dist/lib/recall-filter.js.map +1 -0
  98. package/dist/lib/session-store.d.ts +15 -0
  99. package/dist/lib/session-store.js +62 -0
  100. package/dist/lib/session-store.js.map +1 -0
  101. package/package.json +32 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Configuration resolution: CLI flags > env vars > config file.
3
+ * Base URL is hardcoded to production (NEX_DEV_URL escape hatch for local dev).
4
+ */
5
+ export declare const CONFIG_PATH: string;
6
+ export declare const BASE_URL: string;
7
+ export declare const API_BASE: string;
8
+ export declare const REGISTER_URL: string;
9
+ export interface NexConfig {
10
+ api_key?: string;
11
+ workspace_id?: string;
12
+ workspace_slug?: string;
13
+ default_format?: string;
14
+ default_timeout?: number;
15
+ [key: string]: unknown;
16
+ }
17
+ export declare function loadConfig(): NexConfig;
18
+ export declare function saveConfig(config: NexConfig): void;
19
+ /**
20
+ * Resolve API key from: flag > env > config file.
21
+ */
22
+ export declare function resolveApiKey(flagValue?: string): string | undefined;
23
+ /**
24
+ * Resolve output format from: flag > config file > default.
25
+ */
26
+ export declare function resolveFormat(flagValue?: string): string;
27
+ /**
28
+ * Resolve timeout from: flag > config file > default.
29
+ */
30
+ export declare function resolveTimeout(flagValue?: string): number;
31
+ /**
32
+ * Persist registration data to config file.
33
+ */
34
+ export declare function persistRegistration(data: Record<string, unknown>): void;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Configuration resolution: CLI flags > env vars > config file.
3
+ * Base URL is hardcoded to production (NEX_DEV_URL escape hatch for local dev).
4
+ */
5
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
6
+ import { join, dirname } from "node:path";
7
+ import { homedir } from "node:os";
8
+ export const CONFIG_PATH = join(homedir(), ".nex", "config.json");
9
+ export const BASE_URL = process.env.NEX_DEV_URL ?? "https://app.nex.ai";
10
+ export const API_BASE = `${BASE_URL}/api/developers`;
11
+ export const REGISTER_URL = `${BASE_URL}/api/v1/agents/register`;
12
+ export function loadConfig() {
13
+ try {
14
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
15
+ return JSON.parse(raw);
16
+ }
17
+ catch {
18
+ return {};
19
+ }
20
+ }
21
+ export function saveConfig(config) {
22
+ mkdirSync(dirname(CONFIG_PATH), { recursive: true });
23
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
24
+ }
25
+ /**
26
+ * Resolve API key from: flag > env > config file.
27
+ */
28
+ export function resolveApiKey(flagValue) {
29
+ return flagValue || process.env.NEX_API_KEY || loadConfig().api_key || undefined;
30
+ }
31
+ /**
32
+ * Resolve output format from: flag > config file > default.
33
+ */
34
+ export function resolveFormat(flagValue) {
35
+ return flagValue || loadConfig().default_format || "json";
36
+ }
37
+ /**
38
+ * Resolve timeout from: flag > config file > default.
39
+ */
40
+ export function resolveTimeout(flagValue) {
41
+ if (flagValue)
42
+ return parseInt(flagValue, 10);
43
+ return loadConfig().default_timeout ?? 120_000;
44
+ }
45
+ /**
46
+ * Persist registration data to config file.
47
+ */
48
+ export function persistRegistration(data) {
49
+ const existing = loadConfig();
50
+ if (typeof data.api_key === "string")
51
+ existing.api_key = data.api_key;
52
+ if (typeof data.workspace_id === "string" || typeof data.workspace_id === "number") {
53
+ existing.workspace_id = String(data.workspace_id);
54
+ }
55
+ if (typeof data.workspace_slug === "string")
56
+ existing.workspace_slug = data.workspace_slug;
57
+ saveConfig(existing);
58
+ }
59
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,oBAAoB,CAAC;AACxE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,QAAQ,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,QAAQ,yBAAyB,CAAC;AAWjE,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC9C,OAAO,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU,EAAE,CAAC,OAAO,IAAI,SAAS,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC9C,OAAO,SAAS,IAAI,UAAU,EAAE,CAAC,cAAc,IAAI,MAAM,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAkB;IAC/C,IAAI,SAAS;QAAE,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC9C,OAAO,UAAU,EAAE,CAAC,eAAe,IAAI,OAAO,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA6B;IAC/D,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;QAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IACtE,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QACnF,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;QAAE,QAAQ,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;IAC3F,UAAU,CAAC,QAAQ,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface NexRecallResult {
2
+ answer: string;
3
+ entityCount: number;
4
+ sessionId?: string;
5
+ }
6
+ export declare function formatNexContext(result: NexRecallResult): string;
7
+ export declare function stripNexContext(text: string): string;
@@ -0,0 +1,21 @@
1
+ const OPEN_TAG = "<nex-context>";
2
+ const CLOSE_TAG = "</nex-context>";
3
+ export function formatNexContext(result) {
4
+ const parts = [
5
+ OPEN_TAG,
6
+ "The following is relevant context from the user's knowledge base. Use it to inform your response, but do not mention this block directly.",
7
+ ];
8
+ if (result.entityCount > 0) {
9
+ parts.push(`[${result.entityCount} related entities found]`);
10
+ }
11
+ parts.push("");
12
+ parts.push(result.answer);
13
+ parts.push(CLOSE_TAG);
14
+ return parts.join("\n");
15
+ }
16
+ export function stripNexContext(text) {
17
+ let result = text.replace(/<nex-context>[\s\S]*?<\/nex-context>/g, "");
18
+ result = result.replace(/<nex-context>[\s\S]*/g, "");
19
+ return result.trim();
20
+ }
21
+ //# sourceMappingURL=context-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-format.js","sourceRoot":"","sources":["../../src/lib/context-format.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,eAAe,CAAC;AACjC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAQnC,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,MAAM,KAAK,GAAa;QACtB,QAAQ;QACR,2IAA2I;KAC5I,CAAC;IACF,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,0BAA0B,CAAC,CAAC;IAC/D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,uCAAuC,EAAE,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Error types for Nex CLI.
3
+ * Exit codes: 0 = success, 1 = general error, 2 = auth error.
4
+ */
5
+ export declare class AuthError extends Error {
6
+ exitCode: number;
7
+ constructor(message?: string);
8
+ }
9
+ export declare class RateLimitError extends Error {
10
+ exitCode: number;
11
+ retryAfterMs: number;
12
+ constructor(retryAfterMs?: number);
13
+ }
14
+ export declare class ServerError extends Error {
15
+ exitCode: number;
16
+ status: number;
17
+ constructor(status: number, body?: string);
18
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Error types for Nex CLI.
3
+ * Exit codes: 0 = success, 1 = general error, 2 = auth error.
4
+ */
5
+ export class AuthError extends Error {
6
+ exitCode = 2;
7
+ constructor(message = "No API key configured. Run 'nex register' or set NEX_API_KEY.") {
8
+ super(message);
9
+ this.name = "AuthError";
10
+ }
11
+ }
12
+ export class RateLimitError extends Error {
13
+ exitCode = 1;
14
+ retryAfterMs;
15
+ constructor(retryAfterMs = 60_000) {
16
+ super(`Rate limited — retry after ${Math.ceil(retryAfterMs / 1000)}s`);
17
+ this.name = "RateLimitError";
18
+ this.retryAfterMs = retryAfterMs;
19
+ }
20
+ }
21
+ export class ServerError extends Error {
22
+ exitCode = 1;
23
+ status;
24
+ constructor(status, body) {
25
+ super(`Nex API error ${status}${body ? `: ${body}` : ""}`);
26
+ this.name = "ServerError";
27
+ this.status = status;
28
+ }
29
+ }
30
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAC3B,QAAQ,GAAG,CAAC,CAAC;IAEpB,YAAY,OAAO,GAAG,+DAA+D;QACnF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,KAAK;IAChC,QAAQ,GAAG,CAAC,CAAC;IACb,YAAY,CAAS;IAE5B,YAAY,YAAY,GAAG,MAAM;QAC/B,KAAK,CAAC,8BAA8B,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC7B,QAAQ,GAAG,CAAC,CAAC;IACb,MAAM,CAAS;IAEtB,YAAY,MAAc,EAAE,IAAa;QACvC,KAAK,CAAC,iBAAiB,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * File scanner — discovers text files, tracks changes via content hash,
3
+ * and ingests new/changed files into Nex via POST /v1/context/text.
4
+ *
5
+ * Manifest stored at ~/.nex/file-scan-manifest.json.
6
+ */
7
+ export interface ManifestEntry {
8
+ hash: string;
9
+ size: number;
10
+ scanned_at: string;
11
+ }
12
+ export interface Manifest {
13
+ version: number;
14
+ files: Record<string, ManifestEntry>;
15
+ }
16
+ export interface ScanOptions {
17
+ extensions: string[];
18
+ maxFiles: number;
19
+ depth: number;
20
+ force: boolean;
21
+ dryRun: boolean;
22
+ }
23
+ export interface ScanResult {
24
+ scanned: number;
25
+ skipped: number;
26
+ errors: number;
27
+ files: Array<{
28
+ path: string;
29
+ status: "ingested" | "skipped" | "error";
30
+ reason?: string;
31
+ }>;
32
+ }
33
+ export declare const MANIFEST_PATH: string;
34
+ export declare function loadScanConfig(overrides?: Partial<ScanOptions>): ScanOptions;
35
+ export declare function isScanEnabled(): boolean;
36
+ export declare function loadManifest(): Manifest;
37
+ export declare function saveManifest(manifest: Manifest): void;
38
+ export declare function scanFiles(dir: string, opts: ScanOptions, ingestFn: (content: string, context: string) => Promise<unknown>): Promise<ScanResult>;
@@ -0,0 +1,178 @@
1
+ /**
2
+ * File scanner — discovers text files, tracks changes via content hash,
3
+ * and ingests new/changed files into Nex via POST /v1/context/text.
4
+ *
5
+ * Manifest stored at ~/.nex/file-scan-manifest.json.
6
+ */
7
+ import { createHash } from "node:crypto";
8
+ import { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from "node:fs";
9
+ import { join, extname, resolve, dirname } from "node:path";
10
+ import { homedir } from "node:os";
11
+ // --- Constants ---
12
+ export const MANIFEST_PATH = join(homedir(), ".nex", "file-scan-manifest.json");
13
+ const DEFAULT_EXTENSIONS = [
14
+ // Documents
15
+ ".md", ".txt", ".rtf", ".html", ".htm",
16
+ // Data / config
17
+ ".csv", ".tsv", ".json", ".yaml", ".yml", ".toml", ".xml",
18
+ // Code / scripts
19
+ ".js", ".ts", ".jsx", ".tsx", ".py", ".rb", ".go", ".rs", ".java",
20
+ ".sh", ".bash", ".zsh", ".fish",
21
+ // Markup / notes
22
+ ".org", ".rst", ".adoc", ".tex", ".log",
23
+ // Config / CI
24
+ ".env", ".ini", ".cfg", ".conf", ".properties",
25
+ ];
26
+ const SKIP_DIRS = new Set([
27
+ "node_modules", ".git", "dist", "build", ".next", "__pycache__", ".venv",
28
+ ".cache", ".turbo", "coverage", ".nyc_output",
29
+ ]);
30
+ // --- Config from env ---
31
+ export function loadScanConfig(overrides) {
32
+ const envEnabled = process.env.NEX_SCAN_ENABLED;
33
+ if (envEnabled === "false" || envEnabled === "0") {
34
+ // Caller should check this separately; config still resolves
35
+ }
36
+ const envExts = process.env.NEX_SCAN_EXTENSIONS;
37
+ const extensions = overrides?.extensions
38
+ ?? (envExts ? envExts.split(",").map((e) => e.trim()) : DEFAULT_EXTENSIONS);
39
+ const envMaxFiles = process.env.NEX_SCAN_MAX_FILES;
40
+ const maxFiles = overrides?.maxFiles
41
+ ?? (envMaxFiles ? parseInt(envMaxFiles, 10) : 5);
42
+ const envDepth = process.env.NEX_SCAN_DEPTH;
43
+ const depth = overrides?.depth
44
+ ?? (envDepth ? parseInt(envDepth, 10) : 20);
45
+ return {
46
+ extensions,
47
+ maxFiles,
48
+ depth,
49
+ force: overrides?.force ?? false,
50
+ dryRun: overrides?.dryRun ?? false,
51
+ };
52
+ }
53
+ export function isScanEnabled() {
54
+ const v = process.env.NEX_SCAN_ENABLED;
55
+ return v !== "false" && v !== "0";
56
+ }
57
+ // --- Manifest ---
58
+ export function loadManifest() {
59
+ try {
60
+ const raw = readFileSync(MANIFEST_PATH, "utf-8");
61
+ const data = JSON.parse(raw);
62
+ if (data.version === 1 && typeof data.files === "object")
63
+ return data;
64
+ }
65
+ catch {
66
+ // missing or corrupt
67
+ }
68
+ return { version: 1, files: {} };
69
+ }
70
+ export function saveManifest(manifest) {
71
+ mkdirSync(dirname(MANIFEST_PATH), { recursive: true });
72
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
73
+ }
74
+ function discoverFiles(dir, extensions, maxDepth, currentDepth = 0) {
75
+ if (currentDepth > maxDepth)
76
+ return [];
77
+ const results = [];
78
+ let entries;
79
+ try {
80
+ entries = readdirSync(dir);
81
+ }
82
+ catch {
83
+ return results;
84
+ }
85
+ for (const entry of entries) {
86
+ if (entry.startsWith(".") && SKIP_DIRS.has(entry))
87
+ continue;
88
+ if (SKIP_DIRS.has(entry))
89
+ continue;
90
+ const fullPath = join(dir, entry);
91
+ let stat;
92
+ try {
93
+ stat = statSync(fullPath);
94
+ }
95
+ catch {
96
+ continue;
97
+ }
98
+ if (stat.isDirectory()) {
99
+ results.push(...discoverFiles(fullPath, extensions, maxDepth, currentDepth + 1));
100
+ }
101
+ else if (stat.isFile() && extensions.has(extname(entry).toLowerCase())) {
102
+ results.push({ path: fullPath, size: stat.size, mtime: stat.mtimeMs });
103
+ }
104
+ }
105
+ return results;
106
+ }
107
+ // --- Hashing ---
108
+ function hashFile(filePath) {
109
+ const content = readFileSync(filePath);
110
+ return "sha256-" + createHash("sha256").update(content).digest("hex");
111
+ }
112
+ // --- Scanner ---
113
+ export async function scanFiles(dir, opts, ingestFn) {
114
+ const absDir = resolve(dir);
115
+ const extSet = new Set(opts.extensions.map((e) => (e.startsWith(".") ? e : `.${e}`).toLowerCase()));
116
+ // Discover files
117
+ const discovered = discoverFiles(absDir, extSet, opts.depth);
118
+ // Sort by mtime descending (newest first), cap at maxFiles
119
+ discovered.sort((a, b) => b.mtime - a.mtime);
120
+ const candidates = discovered.slice(0, opts.maxFiles);
121
+ const manifest = opts.force ? { version: 1, files: {} } : loadManifest();
122
+ const result = { scanned: 0, skipped: 0, errors: 0, files: [] };
123
+ for (const file of candidates) {
124
+ const hash = hashFile(file.path);
125
+ const existing = manifest.files[file.path];
126
+ // Skip if hash matches (already ingested)
127
+ if (existing && existing.hash === hash && !opts.force) {
128
+ result.skipped++;
129
+ result.files.push({ path: file.path, status: "skipped", reason: "unchanged" });
130
+ continue;
131
+ }
132
+ if (opts.dryRun) {
133
+ result.scanned++;
134
+ result.files.push({
135
+ path: file.path,
136
+ status: "ingested",
137
+ reason: existing ? "changed" : "new",
138
+ });
139
+ continue;
140
+ }
141
+ // Read and ingest
142
+ try {
143
+ const content = readFileSync(file.path, "utf-8");
144
+ if (!content.trim()) {
145
+ result.skipped++;
146
+ result.files.push({ path: file.path, status: "skipped", reason: "empty" });
147
+ continue;
148
+ }
149
+ await ingestFn(content, `file-scan:${file.path}`);
150
+ // Update manifest
151
+ manifest.files[file.path] = {
152
+ hash,
153
+ size: file.size,
154
+ scanned_at: new Date().toISOString(),
155
+ };
156
+ result.scanned++;
157
+ result.files.push({
158
+ path: file.path,
159
+ status: "ingested",
160
+ reason: existing ? "changed" : "new",
161
+ });
162
+ }
163
+ catch (err) {
164
+ result.errors++;
165
+ result.files.push({
166
+ path: file.path,
167
+ status: "error",
168
+ reason: err instanceof Error ? err.message : String(err),
169
+ });
170
+ }
171
+ }
172
+ // Persist manifest (unless dry-run)
173
+ if (!opts.dryRun) {
174
+ saveManifest(manifest);
175
+ }
176
+ return result;
177
+ }
178
+ //# sourceMappingURL=file-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-scanner.js","sourceRoot":"","sources":["../../src/lib/file-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Platform-specific installers for Nex MCP server and Claude Code plugin.
3
+ *
4
+ * - Generic MCP installer handles 9/12 platforms (same JSON mcpServers format)
5
+ * - Claude Code installer handles hooks + slash commands
6
+ * - Zed installer uses context_servers instead of mcpServers
7
+ * - Continue.dev writes YAML config
8
+ */
9
+ import type { Platform } from "./platform-detect.js";
10
+ export declare function installMcpServer(platform: Platform, apiKey: string): {
11
+ installed: boolean;
12
+ configPath: string;
13
+ };
14
+ export declare function installClaudeCodePlugin(pluginDir?: string): {
15
+ installed: boolean;
16
+ hooksAdded: string[];
17
+ commandsLinked: string[];
18
+ };
19
+ export declare function syncApiKeyToMcpConfig(apiKey: string): void;
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Platform-specific installers for Nex MCP server and Claude Code plugin.
3
+ *
4
+ * - Generic MCP installer handles 9/12 platforms (same JSON mcpServers format)
5
+ * - Claude Code installer handles hooks + slash commands
6
+ * - Zed installer uses context_servers instead of mcpServers
7
+ * - Continue.dev writes YAML config
8
+ */
9
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, symlinkSync, readdirSync } from "node:fs";
10
+ import { join, dirname, resolve } from "node:path";
11
+ import { homedir } from "node:os";
12
+ import { fileURLToPath } from "node:url";
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const MCP_SERVER_ENTRY = {
16
+ command: "npx",
17
+ args: ["-y", "@nex-crm/mcp-server"],
18
+ env: {},
19
+ };
20
+ // --- Generic MCP Installer ---
21
+ function readJsonFile(path) {
22
+ try {
23
+ const raw = readFileSync(path, "utf-8");
24
+ return JSON.parse(raw);
25
+ }
26
+ catch {
27
+ return {};
28
+ }
29
+ }
30
+ function writeJsonFile(path, data) {
31
+ mkdirSync(dirname(path), { recursive: true });
32
+ writeFileSync(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
33
+ }
34
+ export function installMcpServer(platform, apiKey) {
35
+ const entry = {
36
+ ...MCP_SERVER_ENTRY,
37
+ env: { NEX_API_KEY: apiKey },
38
+ };
39
+ if (platform.configFormat === "zed") {
40
+ return installZedMcp(platform.configPath, entry);
41
+ }
42
+ if (platform.configFormat === "continue") {
43
+ return installContinueMcp(platform.configPath, apiKey);
44
+ }
45
+ // Standard JSON format (Cursor, Claude Desktop, VS Code, Windsurf, Cline, Kilo Code, OpenCode)
46
+ const config = readJsonFile(platform.configPath);
47
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
48
+ config.mcpServers = {};
49
+ }
50
+ config.mcpServers.nex = entry;
51
+ writeJsonFile(platform.configPath, config);
52
+ return { installed: true, configPath: platform.configPath };
53
+ }
54
+ function installZedMcp(configPath, entry) {
55
+ const config = readJsonFile(configPath);
56
+ if (!config.context_servers || typeof config.context_servers !== "object") {
57
+ config.context_servers = {};
58
+ }
59
+ config.context_servers.nex = {
60
+ command: { path: entry.command, args: entry.args, env: entry.env },
61
+ };
62
+ writeJsonFile(configPath, config);
63
+ return { installed: true, configPath };
64
+ }
65
+ function installContinueMcp(configPath, apiKey) {
66
+ // Continue.dev can also accept JSON in a separate mcpServers config
67
+ // Write a simple JSON file alongside the YAML
68
+ const mcpPath = configPath.replace("config.yaml", "mcp.json");
69
+ const config = readJsonFile(mcpPath);
70
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
71
+ config.mcpServers = {};
72
+ }
73
+ config.mcpServers.nex = {
74
+ ...MCP_SERVER_ENTRY,
75
+ env: { NEX_API_KEY: apiKey },
76
+ };
77
+ writeJsonFile(mcpPath, config);
78
+ return { installed: true, configPath: mcpPath };
79
+ }
80
+ export function installClaudeCodePlugin(pluginDir) {
81
+ const home = homedir();
82
+ const claudeDir = join(home, ".claude");
83
+ const settingsPath = join(claudeDir, "settings.json");
84
+ // Resolve plugin directory — find it relative to the CLI package
85
+ const resolvedPluginDir = pluginDir ?? findPluginDir();
86
+ if (!resolvedPluginDir) {
87
+ return { installed: false, hooksAdded: [], commandsLinked: [] };
88
+ }
89
+ // 1. Read existing settings.json
90
+ let settings = {};
91
+ try {
92
+ const raw = readFileSync(settingsPath, "utf-8");
93
+ settings = JSON.parse(raw);
94
+ }
95
+ catch {
96
+ // Start fresh
97
+ }
98
+ if (!settings.hooks) {
99
+ settings.hooks = {};
100
+ }
101
+ const hooksAdded = [];
102
+ const distDir = join(resolvedPluginDir, "dist");
103
+ // 2. Add hooks (idempotent — check if nex hooks already exist)
104
+ const hookDefs = [
105
+ {
106
+ event: "SessionStart",
107
+ script: join(distDir, "auto-session-start.js"),
108
+ timeout: 120000,
109
+ statusMessage: "Loading knowledge context...",
110
+ },
111
+ {
112
+ event: "UserPromptSubmit",
113
+ script: join(distDir, "auto-recall.js"),
114
+ timeout: 10000,
115
+ statusMessage: "Recalling relevant memories...",
116
+ },
117
+ {
118
+ event: "Stop",
119
+ script: join(distDir, "auto-capture.js"),
120
+ timeout: 10000,
121
+ async: true,
122
+ },
123
+ ];
124
+ for (const def of hookDefs) {
125
+ if (!settings.hooks[def.event]) {
126
+ settings.hooks[def.event] = [];
127
+ }
128
+ const groups = settings.hooks[def.event];
129
+ const alreadyInstalled = groups.some((g) => g.hooks.some((h) => h.command.includes("nex") || h.command.includes("auto-recall") || h.command.includes("auto-capture") || h.command.includes("auto-session-start")));
130
+ if (!alreadyInstalled) {
131
+ const hookEntry = {
132
+ type: "command",
133
+ command: `node ${def.script}`,
134
+ timeout: def.timeout,
135
+ };
136
+ if (def.statusMessage)
137
+ hookEntry.statusMessage = def.statusMessage;
138
+ if (def.async)
139
+ hookEntry.async = true;
140
+ groups.push({ matcher: "", hooks: [hookEntry] });
141
+ hooksAdded.push(def.event);
142
+ }
143
+ }
144
+ // 3. Write settings.json
145
+ mkdirSync(claudeDir, { recursive: true });
146
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
147
+ // 4. Symlink slash commands
148
+ const commandsLinked = [];
149
+ const commandsDir = join(claudeDir, "commands");
150
+ const sourceCommandsDir = join(resolvedPluginDir, "commands");
151
+ if (existsSync(sourceCommandsDir)) {
152
+ mkdirSync(commandsDir, { recursive: true });
153
+ try {
154
+ const entries = readdirSync(sourceCommandsDir);
155
+ for (const entry of entries) {
156
+ if (!entry.endsWith(".md"))
157
+ continue;
158
+ const target = join(commandsDir, entry);
159
+ const source = join(sourceCommandsDir, entry);
160
+ if (!existsSync(target)) {
161
+ try {
162
+ symlinkSync(source, target, "file");
163
+ commandsLinked.push(entry);
164
+ }
165
+ catch {
166
+ // May fail if file already exists as regular file — skip
167
+ }
168
+ }
169
+ }
170
+ }
171
+ catch {
172
+ // Commands dir read failed — non-critical
173
+ }
174
+ }
175
+ return { installed: true, hooksAdded, commandsLinked };
176
+ }
177
+ /**
178
+ * Find the claude-code-plugin directory relative to the CLI install.
179
+ * Looks for it as a sibling package in the monorepo.
180
+ */
181
+ function findPluginDir() {
182
+ // Try common locations
183
+ const candidates = [
184
+ // Sibling in monorepo (development)
185
+ resolve(__dirname, "..", "..", "..", "claude-code-plugin"),
186
+ // npm global install (node_modules sibling)
187
+ resolve(__dirname, "..", "..", "..", "..", "@nex-crm", "claude-code-nex-plugin"),
188
+ // Relative to cli package
189
+ resolve(__dirname, "..", "..", "claude-code-plugin"),
190
+ ];
191
+ for (const candidate of candidates) {
192
+ if (existsSync(join(candidate, "package.json"))) {
193
+ return candidate;
194
+ }
195
+ }
196
+ return undefined;
197
+ }
198
+ // --- Sync API key to ~/.nex-mcp.json ---
199
+ export function syncApiKeyToMcpConfig(apiKey) {
200
+ const mcpConfigPath = join(homedir(), ".nex-mcp.json");
201
+ const config = readJsonFile(mcpConfigPath);
202
+ config.api_key = apiKey;
203
+ writeJsonFile(mcpConfigPath, config);
204
+ }
205
+ //# sourceMappingURL=installers.js.map