@dmsdc-ai/aigentry-brain 0.0.1

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 (136) hide show
  1. package/bin/aigentry-brain-mcp.mjs +17 -0
  2. package/bin/aigentry-brain-setup.mjs +17 -0
  3. package/bin/aigentry-brain.mjs +17 -0
  4. package/dist/audit/AuditTrail.d.ts +15 -0
  5. package/dist/audit/AuditTrail.js +43 -0
  6. package/dist/audit/AuditTrail.js.map +1 -0
  7. package/dist/backend/GitBackend.d.ts +27 -0
  8. package/dist/backend/GitBackend.js +201 -0
  9. package/dist/backend/GitBackend.js.map +1 -0
  10. package/dist/backend/SyncBackend.d.ts +13 -0
  11. package/dist/backend/SyncBackend.js +2 -0
  12. package/dist/backend/SyncBackend.js.map +1 -0
  13. package/dist/cli/AutoUpdater.d.ts +7 -0
  14. package/dist/cli/AutoUpdater.js +275 -0
  15. package/dist/cli/AutoUpdater.js.map +1 -0
  16. package/dist/cli/ConfigStore.d.ts +17 -0
  17. package/dist/cli/ConfigStore.js +50 -0
  18. package/dist/cli/ConfigStore.js.map +1 -0
  19. package/dist/cli/GhIntegration.d.ts +55 -0
  20. package/dist/cli/GhIntegration.js +192 -0
  21. package/dist/cli/GhIntegration.js.map +1 -0
  22. package/dist/cli/Prerequisites.d.ts +48 -0
  23. package/dist/cli/Prerequisites.js +182 -0
  24. package/dist/cli/Prerequisites.js.map +1 -0
  25. package/dist/cli/SetupWizard.d.ts +26 -0
  26. package/dist/cli/SetupWizard.js +407 -0
  27. package/dist/cli/SetupWizard.js.map +1 -0
  28. package/dist/cli/braincli.d.ts +2 -0
  29. package/dist/cli/braincli.js +260 -0
  30. package/dist/cli/braincli.js.map +1 -0
  31. package/dist/cli/setup.d.ts +25 -0
  32. package/dist/cli/setup.js +238 -0
  33. package/dist/cli/setup.js.map +1 -0
  34. package/dist/context/ConfidenceGuard.d.ts +11 -0
  35. package/dist/context/ConfidenceGuard.js +32 -0
  36. package/dist/context/ConfidenceGuard.js.map +1 -0
  37. package/dist/context/ContextBudgetPolicy.d.ts +21 -0
  38. package/dist/context/ContextBudgetPolicy.js +136 -0
  39. package/dist/context/ContextBudgetPolicy.js.map +1 -0
  40. package/dist/context/ContextPacker.d.ts +30 -0
  41. package/dist/context/ContextPacker.js +219 -0
  42. package/dist/context/ContextPacker.js.map +1 -0
  43. package/dist/context/ContextRestoreService.d.ts +39 -0
  44. package/dist/context/ContextRestoreService.js +134 -0
  45. package/dist/context/ContextRestoreService.js.map +1 -0
  46. package/dist/contract/BrainContract.d.ts +93 -0
  47. package/dist/contract/BrainContract.js +245 -0
  48. package/dist/contract/BrainContract.js.map +1 -0
  49. package/dist/core/ContentDedup.d.ts +43 -0
  50. package/dist/core/ContentDedup.js +145 -0
  51. package/dist/core/ContentDedup.js.map +1 -0
  52. package/dist/core/EntityGraph.d.ts +66 -0
  53. package/dist/core/EntityGraph.js +196 -0
  54. package/dist/core/EntityGraph.js.map +1 -0
  55. package/dist/core/EntrySchema.d.ts +46 -0
  56. package/dist/core/EntrySchema.js +4 -0
  57. package/dist/core/EntrySchema.js.map +1 -0
  58. package/dist/core/GraphStore.d.ts +16 -0
  59. package/dist/core/GraphStore.js +29 -0
  60. package/dist/core/GraphStore.js.map +1 -0
  61. package/dist/core/MemoryDecay.d.ts +49 -0
  62. package/dist/core/MemoryDecay.js +113 -0
  63. package/dist/core/MemoryDecay.js.map +1 -0
  64. package/dist/core/ProfileFormat.d.ts +38 -0
  65. package/dist/core/ProfileFormat.js +254 -0
  66. package/dist/core/ProfileFormat.js.map +1 -0
  67. package/dist/core/ProfileManager.d.ts +80 -0
  68. package/dist/core/ProfileManager.js +269 -0
  69. package/dist/core/ProfileManager.js.map +1 -0
  70. package/dist/core/SchemaMigration.d.ts +12 -0
  71. package/dist/core/SchemaMigration.js +34 -0
  72. package/dist/core/SchemaMigration.js.map +1 -0
  73. package/dist/crypto/AgeCrypto.d.ts +26 -0
  74. package/dist/crypto/AgeCrypto.js +101 -0
  75. package/dist/crypto/AgeCrypto.js.map +1 -0
  76. package/dist/index.d.ts +38 -0
  77. package/dist/index.js +30 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/mcp/BrainMcpServer.d.ts +13 -0
  80. package/dist/mcp/BrainMcpServer.js +223 -0
  81. package/dist/mcp/BrainMcpServer.js.map +1 -0
  82. package/dist/mcp/cli.d.ts +2 -0
  83. package/dist/mcp/cli.js +107 -0
  84. package/dist/mcp/cli.js.map +1 -0
  85. package/dist/metrics/ResumeMetrics.d.ts +20 -0
  86. package/dist/metrics/ResumeMetrics.js +46 -0
  87. package/dist/metrics/ResumeMetrics.js.map +1 -0
  88. package/dist/peers/PeerStore.d.ts +17 -0
  89. package/dist/peers/PeerStore.js +65 -0
  90. package/dist/peers/PeerStore.js.map +1 -0
  91. package/dist/policy/PolicyEngine.d.ts +16 -0
  92. package/dist/policy/PolicyEngine.js +70 -0
  93. package/dist/policy/PolicyEngine.js.map +1 -0
  94. package/dist/policy/PolicyEnvelope.d.ts +7 -0
  95. package/dist/policy/PolicyEnvelope.js +2 -0
  96. package/dist/policy/PolicyEnvelope.js.map +1 -0
  97. package/dist/policy/RetentionParser.d.ts +6 -0
  98. package/dist/policy/RetentionParser.js +48 -0
  99. package/dist/policy/RetentionParser.js.map +1 -0
  100. package/dist/shared/AtomicWrite.d.ts +1 -0
  101. package/dist/shared/AtomicWrite.js +11 -0
  102. package/dist/shared/AtomicWrite.js.map +1 -0
  103. package/dist/shared/Clock.d.ts +11 -0
  104. package/dist/shared/Clock.js +17 -0
  105. package/dist/shared/Clock.js.map +1 -0
  106. package/dist/shared/Config.d.ts +15 -0
  107. package/dist/shared/Config.js +67 -0
  108. package/dist/shared/Config.js.map +1 -0
  109. package/dist/shared/Encryption.d.ts +19 -0
  110. package/dist/shared/Encryption.js +47 -0
  111. package/dist/shared/Encryption.js.map +1 -0
  112. package/dist/shared/Logger.d.ts +12 -0
  113. package/dist/shared/Logger.js +40 -0
  114. package/dist/shared/Logger.js.map +1 -0
  115. package/dist/shared/Mutex.d.ts +7 -0
  116. package/dist/shared/Mutex.js +34 -0
  117. package/dist/shared/Mutex.js.map +1 -0
  118. package/dist/shared/SetupErrors.d.ts +31 -0
  119. package/dist/shared/SetupErrors.js +155 -0
  120. package/dist/shared/SetupErrors.js.map +1 -0
  121. package/dist/status/SyncStatusStore.d.ts +17 -0
  122. package/dist/status/SyncStatusStore.js +48 -0
  123. package/dist/status/SyncStatusStore.js.map +1 -0
  124. package/dist/sync/AutoCommitter.d.ts +17 -0
  125. package/dist/sync/AutoCommitter.js +68 -0
  126. package/dist/sync/AutoCommitter.js.map +1 -0
  127. package/dist/sync/ConflictResolver.d.ts +7 -0
  128. package/dist/sync/ConflictResolver.js +56 -0
  129. package/dist/sync/ConflictResolver.js.map +1 -0
  130. package/dist/sync/PushPullManager.d.ts +23 -0
  131. package/dist/sync/PushPullManager.js +155 -0
  132. package/dist/sync/PushPullManager.js.map +1 -0
  133. package/dist/sync/SyncEngine.d.ts +43 -0
  134. package/dist/sync/SyncEngine.js +145 -0
  135. package/dist/sync/SyncEngine.js.map +1 -0
  136. package/package.json +65 -0
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from 'node:child_process';
3
+ import { existsSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const root = join(__dirname, '..');
9
+ const distEntry = join(root, 'dist', 'mcp', 'cli.js');
10
+ const srcEntry = join(root, 'src', 'mcp', 'cli.ts');
11
+
12
+ if (existsSync(distEntry)) {
13
+ await import(distEntry);
14
+ } else {
15
+ const tsx = join(root, 'node_modules', '.bin', 'tsx');
16
+ execFileSync(tsx, [srcEntry, ...process.argv.slice(2)], { stdio: 'inherit' });
17
+ }
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from 'node:child_process';
3
+ import { existsSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const root = join(__dirname, '..');
9
+ const distEntry = join(root, 'dist', 'cli', 'setup.js');
10
+ const srcEntry = join(root, 'src', 'cli', 'setup.ts');
11
+
12
+ if (existsSync(distEntry)) {
13
+ await import(distEntry);
14
+ } else {
15
+ const tsx = join(root, 'node_modules', '.bin', 'tsx');
16
+ execFileSync(tsx, [srcEntry, ...process.argv.slice(2)], { stdio: 'inherit' });
17
+ }
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from 'node:child_process';
3
+ import { existsSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const root = join(__dirname, '..');
9
+ const distEntry = join(root, 'dist', 'cli', 'braincli.js');
10
+ const srcEntry = join(root, 'src', 'cli', 'braincli.ts');
11
+
12
+ if (existsSync(distEntry)) {
13
+ await import(distEntry);
14
+ } else {
15
+ const tsx = join(root, 'node_modules', '.bin', 'tsx');
16
+ execFileSync(tsx, [srcEntry, ...process.argv.slice(2)], { stdio: 'inherit' });
17
+ }
@@ -0,0 +1,15 @@
1
+ export type AuditAction = 'append' | 'erase' | 'query' | 'sync.pull' | 'sync.push';
2
+ export interface AuditEvent {
3
+ ts: string;
4
+ action: AuditAction;
5
+ entry_id?: string;
6
+ device_id: string;
7
+ detail?: Record<string, unknown>;
8
+ }
9
+ export declare class AuditTrail {
10
+ private filePath;
11
+ constructor(filePath: string);
12
+ log(event: AuditEvent): Promise<void>;
13
+ readAll(): Promise<AuditEvent[]>;
14
+ getFilePath(): string;
15
+ }
@@ -0,0 +1,43 @@
1
+ import { appendFile, readFile, mkdir } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ export class AuditTrail {
4
+ filePath;
5
+ constructor(filePath) {
6
+ this.filePath = filePath;
7
+ }
8
+ async log(event) {
9
+ await mkdir(dirname(this.filePath), { recursive: true });
10
+ const line = JSON.stringify(event) + '\n';
11
+ await appendFile(this.filePath, line, 'utf8');
12
+ }
13
+ async readAll() {
14
+ let content;
15
+ try {
16
+ content = await readFile(this.filePath, 'utf8');
17
+ }
18
+ catch (err) {
19
+ const e = err;
20
+ if (e.code === 'ENOENT') {
21
+ return [];
22
+ }
23
+ throw err;
24
+ }
25
+ const events = [];
26
+ for (const line of content.split('\n')) {
27
+ const trimmed = line.trim();
28
+ if (trimmed.length === 0)
29
+ continue;
30
+ try {
31
+ events.push(JSON.parse(trimmed));
32
+ }
33
+ catch {
34
+ // Skip malformed lines
35
+ }
36
+ }
37
+ return events;
38
+ }
39
+ getFilePath() {
40
+ return this.filePath;
41
+ }
42
+ }
43
+ //# sourceMappingURL=AuditTrail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditTrail.js","sourceRoot":"","sources":["../../src/audit/AuditTrail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,MAAM,OAAO,UAAU;IACb,QAAQ,CAAS;IAEzB,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QAC1C,MAAM,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA4B,CAAC;YACvC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxB,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACnC,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC,CAAC;YACjD,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,27 @@
1
+ import { type SimpleGit } from 'simple-git';
2
+ import type { SyncBackend } from './SyncBackend.js';
3
+ export declare class GitBackend implements SyncBackend {
4
+ private git;
5
+ private repoPath;
6
+ private branch;
7
+ private logger;
8
+ init(repoPath: string, remoteUrl?: string): Promise<void>;
9
+ private ensureGitignore;
10
+ pull(): Promise<void>;
11
+ /**
12
+ * TOFU (Trust-On-First-Use) multi-device recipient sync.
13
+ * After pull: if this device's key is not in recipients, add it and re-encrypt.
14
+ * Uses age-encryption npm — no sops binary needed.
15
+ */
16
+ syncRecipients(): Promise<void>;
17
+ commit(message: string): Promise<void>;
18
+ push(): Promise<void>;
19
+ fetch(): Promise<void>;
20
+ rebaseAbort(): Promise<void>;
21
+ hasChanges(): Promise<boolean>;
22
+ readFileAtRef(ref: string, filePath: string): Promise<string>;
23
+ resetToRef(ref: string): Promise<void>;
24
+ getGit(): SimpleGit;
25
+ getRepoPath(): string;
26
+ getBranch(): string;
27
+ }
@@ -0,0 +1,201 @@
1
+ import simpleGit from 'simple-git';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { createLogger } from '../shared/Logger.js';
6
+ import { readKeyFile, encryptBlock, decryptBlock, AgeDecryptError, } from '../crypto/AgeCrypto.js';
7
+ export class GitBackend {
8
+ git;
9
+ repoPath;
10
+ branch = 'main';
11
+ logger = createLogger('GitBackend');
12
+ async init(repoPath, remoteUrl) {
13
+ this.repoPath = repoPath;
14
+ const hasGitDir = existsSync(join(repoPath, '.git'));
15
+ if (!hasGitDir && remoteUrl) {
16
+ this.logger.info('Cloning remote repo', { remoteUrl, repoPath });
17
+ const parentGit = simpleGit();
18
+ await parentGit.clone(remoteUrl, repoPath, ['--depth', '1']);
19
+ this.git = simpleGit(repoPath);
20
+ await this.git.addConfig('user.email', 'brain@aigentry.local');
21
+ await this.git.addConfig('user.name', 'aigentry-brain');
22
+ }
23
+ else if (!hasGitDir) {
24
+ await mkdir(repoPath, { recursive: true });
25
+ this.git = simpleGit(repoPath);
26
+ await this.git.init();
27
+ await this.git.addConfig('user.email', 'brain@aigentry.local');
28
+ await this.git.addConfig('user.name', 'aigentry-brain');
29
+ }
30
+ else {
31
+ this.git = simpleGit(repoPath);
32
+ if (remoteUrl) {
33
+ try {
34
+ await this.git.addRemote('origin', remoteUrl);
35
+ }
36
+ catch {
37
+ this.logger.debug('Remote exists, updating URL', { remoteUrl });
38
+ await this.git.remote(['set-url', 'origin', remoteUrl]);
39
+ }
40
+ }
41
+ }
42
+ // Ensure .aigentry directory and .gitignore
43
+ const aigentryDir = join(repoPath, '.aigentry');
44
+ await mkdir(aigentryDir, { recursive: true });
45
+ await this.ensureGitignore(repoPath);
46
+ }
47
+ async ensureGitignore(repoPath) {
48
+ const gitignorePath = join(repoPath, '.gitignore');
49
+ const ignoreEntries = [
50
+ '.aigentry/sync-status.json',
51
+ '*.tmp',
52
+ '.DS_Store',
53
+ '*.yaml.bak',
54
+ ];
55
+ let existing = '';
56
+ if (existsSync(gitignorePath)) {
57
+ existing = await readFile(gitignorePath, 'utf8');
58
+ }
59
+ const missing = ignoreEntries.filter(e => !existing.includes(e));
60
+ if (missing.length > 0) {
61
+ const newContent = existing.trimEnd() + '\n' + missing.join('\n') + '\n';
62
+ await writeFile(gitignorePath, newContent, 'utf8');
63
+ }
64
+ }
65
+ async pull() {
66
+ try {
67
+ await this.git.pull('origin', this.branch, { '--rebase': 'true' });
68
+ // TOFU: sync recipients after pull
69
+ await this.syncRecipients();
70
+ }
71
+ catch (err) {
72
+ const remotes = await this.git.remote([]);
73
+ if (!remotes) {
74
+ this.logger.debug('No remote configured, skipping pull');
75
+ return;
76
+ }
77
+ this.logger.warn('Pull failed', { error: String(err) });
78
+ throw err;
79
+ }
80
+ }
81
+ /**
82
+ * TOFU (Trust-On-First-Use) multi-device recipient sync.
83
+ * After pull: if this device's key is not in recipients, add it and re-encrypt.
84
+ * Uses age-encryption npm — no sops binary needed.
85
+ */
86
+ async syncRecipients() {
87
+ const encJsonPath = join(this.repoPath, 'memory-profile.enc.json');
88
+ // Read local machine's public key
89
+ let localKeyPair;
90
+ try {
91
+ localKeyPair = readKeyFile();
92
+ }
93
+ catch {
94
+ // No age key on this machine — skip
95
+ return;
96
+ }
97
+ // Check if encrypted profile exists
98
+ if (!existsSync(encJsonPath))
99
+ return;
100
+ let encProfile;
101
+ try {
102
+ encProfile = JSON.parse(readFileSync(encJsonPath, 'utf-8'));
103
+ }
104
+ catch {
105
+ return;
106
+ }
107
+ // Skip if plaintext fallback or not age-block format
108
+ if (encProfile._aigentry?.format !== 'age-block')
109
+ return;
110
+ const recipients = encProfile._aigentry.recipients ?? [];
111
+ // Check if our key is already a recipient
112
+ if (recipients.includes(localKeyPair.recipient))
113
+ return;
114
+ // Add our key as a new recipient
115
+ this.logger.info('Adding local age key to recipients (TOFU)');
116
+ recipients.push(localKeyPair.recipient);
117
+ encProfile._aigentry.recipients = recipients;
118
+ // Try to re-encrypt all entries with updated recipients
119
+ try {
120
+ const reEncrypted = {};
121
+ for (const [id, ct] of Object.entries(encProfile.entries)) {
122
+ const plaintext = await decryptBlock(ct, localKeyPair.identity);
123
+ reEncrypted[id] = await encryptBlock(plaintext, recipients);
124
+ }
125
+ encProfile.entries = reEncrypted;
126
+ encProfile._aigentry.modified = new Date().toISOString();
127
+ this.logger.info('Re-encrypted entries with new recipient');
128
+ }
129
+ catch (err) {
130
+ if (err instanceof AgeDecryptError) {
131
+ // Cannot decrypt — we're a new device, entries were encrypted before our key was added.
132
+ // Just save updated recipients list. An existing device will re-encrypt on next sync.
133
+ this.logger.info('Cannot decrypt (new device) — saved recipient key. Waiting for existing device to re-encrypt.');
134
+ }
135
+ else {
136
+ this.logger.warn('Re-encryption failed', { error: String(err) });
137
+ return;
138
+ }
139
+ }
140
+ // Write updated profile
141
+ try {
142
+ await writeFile(encJsonPath, JSON.stringify(encProfile, null, 2), 'utf-8');
143
+ if (await this.hasChanges()) {
144
+ await this.commit('chore: add new device age key (TOFU)');
145
+ try {
146
+ await this.push();
147
+ this.logger.info('Pushed new device key to remote');
148
+ }
149
+ catch (pushErr) {
150
+ this.logger.debug('Could not push TOFU key (will sync later)', { error: String(pushErr) });
151
+ }
152
+ }
153
+ }
154
+ catch (err) {
155
+ this.logger.warn('Failed to save updated recipients', { error: String(err) });
156
+ }
157
+ }
158
+ async commit(message) {
159
+ await this.git.add('.');
160
+ try {
161
+ await this.git.commit(message);
162
+ }
163
+ catch {
164
+ this.logger.debug('Nothing to commit');
165
+ }
166
+ }
167
+ async push() {
168
+ await this.git.push(['-u', 'origin', this.branch]);
169
+ }
170
+ async fetch() {
171
+ await this.git.fetch('origin');
172
+ }
173
+ async rebaseAbort() {
174
+ try {
175
+ await this.git.rebase({ '--abort': null });
176
+ }
177
+ catch {
178
+ this.logger.debug('Not in rebase state, skipping abort');
179
+ }
180
+ }
181
+ async hasChanges() {
182
+ const status = await this.git.status();
183
+ return !status.isClean();
184
+ }
185
+ async readFileAtRef(ref, filePath) {
186
+ return this.git.show([`${ref}:${filePath}`]);
187
+ }
188
+ async resetToRef(ref) {
189
+ await this.git.reset(['--soft', ref]);
190
+ }
191
+ getGit() {
192
+ return this.git;
193
+ }
194
+ getRepoPath() {
195
+ return this.repoPath;
196
+ }
197
+ getBranch() {
198
+ return this.branch;
199
+ }
200
+ }
201
+ //# sourceMappingURL=GitBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitBackend.js","sourceRoot":"","sources":["../../src/backend/GitBackend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface SyncBackend {
2
+ init(repoPath: string, remoteUrl?: string): Promise<void>;
3
+ pull(): Promise<void>;
4
+ commit(message: string): Promise<void>;
5
+ push(): Promise<void>;
6
+ fetch(): Promise<void>;
7
+ rebaseAbort(): Promise<void>;
8
+ hasChanges(): Promise<boolean>;
9
+ readFileAtRef(ref: string, filePath: string): Promise<string>;
10
+ resetToRef(ref: string): Promise<void>;
11
+ getRepoPath(): string;
12
+ getBranch(): string;
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SyncBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncBackend.js","sourceRoot":"","sources":["../../src/backend/SyncBackend.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Check for updates and auto-install if available.
3
+ * Runs in background, never blocks the caller.
4
+ */
5
+ export declare function checkAndUpdate(options?: {
6
+ blocking?: boolean;
7
+ }): void;
@@ -0,0 +1,275 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, openSync, writeSync, closeSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { createLogger } from '../shared/Logger.js';
6
+ /** Write directly to terminal, bypassing npm's output suppression */
7
+ function log(msg) {
8
+ const data = msg + '\n';
9
+ for (const ttyPath of ['/dev/tty', 'CON']) {
10
+ try {
11
+ const fd = openSync(ttyPath, 'w');
12
+ writeSync(fd, data);
13
+ closeSync(fd);
14
+ return;
15
+ }
16
+ catch { /* try next */ }
17
+ }
18
+ process.stderr.write(data);
19
+ }
20
+ const logger = createLogger('AutoUpdater');
21
+ const PACKAGE_NAME = 'aigentry-brain';
22
+ const CACHE_FILE = join(homedir(), '.aigentry', '.update-cache.json');
23
+ const CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
24
+ function readCache() {
25
+ try {
26
+ if (!existsSync(CACHE_FILE))
27
+ return null;
28
+ return JSON.parse(readFileSync(CACHE_FILE, 'utf8'));
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ function writeCache(cache) {
35
+ try {
36
+ const dir = join(homedir(), '.aigentry');
37
+ mkdirSync(dir, { recursive: true });
38
+ writeFileSync(CACHE_FILE, JSON.stringify(cache), 'utf8');
39
+ }
40
+ catch {
41
+ // Best effort
42
+ }
43
+ }
44
+ function getCurrentVersion() {
45
+ try {
46
+ const raw = execSync(`npm list -g ${PACKAGE_NAME} --json --depth=0 2>/dev/null`, { encoding: 'utf8', timeout: 10000 });
47
+ const parsed = JSON.parse(raw);
48
+ return parsed.dependencies?.[PACKAGE_NAME]?.version ?? '0.0.0';
49
+ }
50
+ catch {
51
+ return '0.0.0';
52
+ }
53
+ }
54
+ /**
55
+ * Find the installation directory of aigentry-brain by reading MCP config.
56
+ * Returns the package root (parent of node_modules/aigentry-brain).
57
+ */
58
+ function findInstallDir() {
59
+ try {
60
+ const mcpConfigPath = join(homedir(), '.claude', '.mcp.json');
61
+ if (!existsSync(mcpConfigPath))
62
+ return null;
63
+ const mcpConfig = JSON.parse(readFileSync(mcpConfigPath, 'utf8'));
64
+ const cliPath = mcpConfig?.mcpServers?.['aigentry-brain']?.args?.[0];
65
+ if (!cliPath)
66
+ return null;
67
+ // cliPath can be:
68
+ // bin/aigentry-brain-mcp.mjs (new: bin wrapper)
69
+ // dist/mcp/cli.js (legacy: direct dist reference)
70
+ // In both cases, resolve up to the aigentry-brain package root,
71
+ // then up to the parent project root (if installed as dependency).
72
+ let brainRoot;
73
+ if (cliPath.includes('/bin/')) {
74
+ // bin/aigentry-brain-mcp.mjs → 1 level up to package root
75
+ brainRoot = join(cliPath, '..');
76
+ }
77
+ else {
78
+ // dist/mcp/cli.js → 3 levels up to package root
79
+ brainRoot = join(cliPath, '..', '..', '..');
80
+ }
81
+ // If this is inside node_modules, the parent project root is 2 levels up
82
+ if (brainRoot.includes('node_modules')) {
83
+ const projectRoot = join(brainRoot, '..', '..');
84
+ if (existsSync(join(projectRoot, 'package.json')))
85
+ return projectRoot;
86
+ }
87
+ // Otherwise brainRoot IS the project root (local dev)
88
+ if (existsSync(join(brainRoot, 'package.json')))
89
+ return brainRoot;
90
+ return null;
91
+ }
92
+ catch {
93
+ return null;
94
+ }
95
+ }
96
+ /**
97
+ * Check if aigentry-brain was installed from GitHub (not npm registry).
98
+ */
99
+ function isGitHubInstall() {
100
+ const installDir = findInstallDir();
101
+ if (!installDir)
102
+ return { isGithub: false, installDir: null };
103
+ try {
104
+ const pkgPath = join(installDir, 'package.json');
105
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
106
+ const dep = pkg.dependencies?.[PACKAGE_NAME] ?? '';
107
+ const isGithub = dep.includes('github:') || dep.includes('git+') || dep.includes('git://');
108
+ return { isGithub, installDir };
109
+ }
110
+ catch {
111
+ return { isGithub: false, installDir: null };
112
+ }
113
+ }
114
+ function compareVersions(a, b) {
115
+ const pa = a.split('.').map(Number);
116
+ const pb = b.split('.').map(Number);
117
+ for (let i = 0; i < 3; i++) {
118
+ if ((pa[i] ?? 0) > (pb[i] ?? 0))
119
+ return 1;
120
+ if ((pa[i] ?? 0) < (pb[i] ?? 0))
121
+ return -1;
122
+ }
123
+ return 0;
124
+ }
125
+ /**
126
+ * Check for updates and auto-install if available.
127
+ * Runs in background, never blocks the caller.
128
+ */
129
+ export function checkAndUpdate(options) {
130
+ // Skip in CI/test environments
131
+ if (process.env.CI || process.env.VITEST || process.env.NODE_ENV === 'test') {
132
+ return;
133
+ }
134
+ const cache = readCache();
135
+ const now = Date.now();
136
+ // Skip if checked recently
137
+ if (cache && (now - cache.lastCheck) < CHECK_INTERVAL_MS) {
138
+ return;
139
+ }
140
+ const doCheck = async () => {
141
+ try {
142
+ // Check if GitHub-based install
143
+ const { isGithub, installDir } = isGitHubInstall();
144
+ if (isGithub && installDir) {
145
+ // GitHub install: check latest commit hash
146
+ const latestHash = execSync('git ls-remote https://github.com/dmsdc-ai/aigentry-brain.git HEAD 2>/dev/null', { encoding: 'utf8', timeout: 15000 }).split('\t')[0]?.trim();
147
+ if (!latestHash) {
148
+ writeCache({ lastCheck: now, latestVersion: null });
149
+ return;
150
+ }
151
+ // Compare with installed commit
152
+ const installedPkgPath = join(installDir, 'node_modules', PACKAGE_NAME, 'package.json');
153
+ let needsUpdate = true;
154
+ try {
155
+ const installed = JSON.parse(readFileSync(installedPkgPath, 'utf8'));
156
+ // npm stores resolved git hash in _resolved field
157
+ if (installed._resolved?.includes(latestHash.slice(0, 7))) {
158
+ needsUpdate = false;
159
+ }
160
+ }
161
+ catch { /* assume needs update */ }
162
+ if (needsUpdate) {
163
+ writeCache({ lastCheck: now, latestVersion: latestHash.slice(0, 7) });
164
+ logger.info(`Updating ${PACKAGE_NAME} from GitHub`);
165
+ log(`[${PACKAGE_NAME}] Updating from GitHub...`);
166
+ try {
167
+ execSync(`npm install --install-links ${PACKAGE_NAME}@github:dmsdc-ai/aigentry-brain`, {
168
+ cwd: installDir,
169
+ encoding: 'utf8',
170
+ timeout: 120000,
171
+ stdio: 'pipe',
172
+ });
173
+ log(`[${PACKAGE_NAME}] Updated from GitHub ✅`);
174
+ }
175
+ catch (installErr) {
176
+ logger.warn('GitHub auto-update failed', { error: String(installErr) });
177
+ log(`[${PACKAGE_NAME}] Auto-update failed. Run manually in ${installDir}: npm install aigentry-brain@github:dmsdc-ai/aigentry-brain`);
178
+ }
179
+ }
180
+ else {
181
+ writeCache({ lastCheck: now, latestVersion: latestHash.slice(0, 7) });
182
+ }
183
+ }
184
+ else {
185
+ // npm registry install: original behavior
186
+ const latestRaw = execSync(`npm view ${PACKAGE_NAME} version 2>/dev/null`, {
187
+ encoding: 'utf8',
188
+ timeout: 15000,
189
+ }).trim();
190
+ writeCache({ lastCheck: now, latestVersion: latestRaw });
191
+ const currentVersion = getCurrentVersion();
192
+ if (compareVersions(latestRaw, currentVersion) > 0) {
193
+ logger.info(`Updating ${PACKAGE_NAME}: ${currentVersion} → ${latestRaw}`);
194
+ log(`[${PACKAGE_NAME}] Updating to v${latestRaw}...`);
195
+ try {
196
+ execSync(`npm install -g ${PACKAGE_NAME}@${latestRaw}`, {
197
+ encoding: 'utf8',
198
+ timeout: 120000,
199
+ stdio: 'pipe',
200
+ });
201
+ log(`[${PACKAGE_NAME}] Updated to v${latestRaw} ✅`);
202
+ }
203
+ catch (installErr) {
204
+ logger.warn('Auto-update install failed', { error: String(installErr) });
205
+ log(`[${PACKAGE_NAME}] Auto-update failed. Run manually: npm install -g ${PACKAGE_NAME}`);
206
+ }
207
+ }
208
+ }
209
+ }
210
+ catch {
211
+ // Network error, npm down, etc. — silently skip
212
+ writeCache({ lastCheck: now, latestVersion: null });
213
+ }
214
+ };
215
+ if (options?.blocking) {
216
+ // For CLI usage: run synchronously
217
+ try {
218
+ const { isGithub, installDir } = isGitHubInstall();
219
+ if (isGithub && installDir) {
220
+ const latestHash = execSync('git ls-remote https://github.com/dmsdc-ai/aigentry-brain.git HEAD 2>/dev/null', { encoding: 'utf8', timeout: 15000 }).split('\t')[0]?.trim();
221
+ if (latestHash) {
222
+ const installedPkgPath = join(installDir, 'node_modules', PACKAGE_NAME, 'package.json');
223
+ let needsUpdate = true;
224
+ try {
225
+ const installed = JSON.parse(readFileSync(installedPkgPath, 'utf8'));
226
+ if (installed._resolved?.includes(latestHash.slice(0, 7)))
227
+ needsUpdate = false;
228
+ }
229
+ catch { /* assume needs update */ }
230
+ if (needsUpdate) {
231
+ log(`[${PACKAGE_NAME}] Updating from GitHub...`);
232
+ try {
233
+ execSync(`npm install --install-links ${PACKAGE_NAME}@github:dmsdc-ai/aigentry-brain`, {
234
+ cwd: installDir, encoding: 'utf8', timeout: 120000, stdio: 'pipe',
235
+ });
236
+ log(`[${PACKAGE_NAME}] Updated from GitHub ✅`);
237
+ }
238
+ catch {
239
+ log(`[${PACKAGE_NAME}] Auto-update failed. Run manually in ${installDir}: npm install aigentry-brain@github:dmsdc-ai/aigentry-brain`);
240
+ }
241
+ }
242
+ writeCache({ lastCheck: now, latestVersion: latestHash.slice(0, 7) });
243
+ }
244
+ }
245
+ else {
246
+ const latestRaw = execSync(`npm view ${PACKAGE_NAME} version 2>/dev/null`, {
247
+ encoding: 'utf8',
248
+ timeout: 15000,
249
+ }).trim();
250
+ writeCache({ lastCheck: now, latestVersion: latestRaw });
251
+ const currentVersion = getCurrentVersion();
252
+ if (compareVersions(latestRaw, currentVersion) > 0) {
253
+ log(`[${PACKAGE_NAME}] Updating to v${latestRaw}...`);
254
+ try {
255
+ execSync(`npm install -g ${PACKAGE_NAME}@${latestRaw}`, {
256
+ encoding: 'utf8', timeout: 120000, stdio: 'pipe',
257
+ });
258
+ log(`[${PACKAGE_NAME}] Updated to v${latestRaw} ✅`);
259
+ }
260
+ catch {
261
+ log(`[${PACKAGE_NAME}] Auto-update failed. Run manually: npm install -g ${PACKAGE_NAME}`);
262
+ }
263
+ }
264
+ }
265
+ }
266
+ catch {
267
+ writeCache({ lastCheck: now, latestVersion: null });
268
+ }
269
+ }
270
+ else {
271
+ // For MCP server: run in background, don't block
272
+ doCheck().catch(() => { });
273
+ }
274
+ }
275
+ //# sourceMappingURL=AutoUpdater.js.map