aibridge-context 1.0.3 → 1.2.0

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.
package/README.md CHANGED
@@ -4,13 +4,28 @@
4
4
 
5
5
  Think of it as Git for AI context.
6
6
 
7
+ ## ⚠️ Public AI Access Warning
8
+
9
+ When GitHub sync is enabled, your project context becomes publicly accessible via a URL.
10
+
11
+ Do NOT use this tool with sensitive data.
12
+
7
13
  ## Quick Start
8
14
 
9
15
  ```bash
10
16
  npx aibridge-context init
17
+ npx aibridge-context link-github
11
18
  npx aibridge-context start
12
19
  ```
13
20
 
21
+ ## How It Works
22
+
23
+ 1. Tracks project changes
24
+ 2. Generates structured AI context
25
+ 3. Syncs to GitHub (optional)
26
+ 4. Creates a public URL
27
+ 5. AI tools read this URL for context
28
+
14
29
  ## Usage
15
30
 
16
31
  This package exposes a CLI command:
@@ -29,6 +44,7 @@ After installing globally, you can use:
29
44
 
30
45
  ```bash
31
46
  aibridge init
47
+ aibridge link-github
32
48
  ```
33
49
 
34
50
  ## Features
@@ -50,6 +66,7 @@ To use the local CLI in this repository:
50
66
 
51
67
  ```bash
52
68
  npx aibridge-context init
69
+ npx aibridge-context link-github
53
70
  npx aibridge-context start
54
71
  ```
55
72
 
@@ -57,6 +74,37 @@ If published to npm, the package exposes the `aibridge` binary.
57
74
 
58
75
  `ai-context` is supported as a legacy alias.
59
76
 
77
+ ## Using With AI
78
+
79
+ After enabling GitHub sync, use:
80
+
81
+ ```text
82
+ https://raw.githubusercontent.com/<user>/<repo>/main/.ai-context/state.json
83
+ ```
84
+
85
+ This URL always returns the latest project state.
86
+
87
+ Paste this into any AI:
88
+
89
+ ```text
90
+ Use this as source of truth:
91
+ https://raw.githubusercontent.com/<user>/<repo>/main/.ai-context/state.json
92
+ ```
93
+
94
+ You can also share:
95
+
96
+ ```text
97
+ https://raw.githubusercontent.com/<user>/<repo>/main/.ai-context/brain.txt
98
+ ```
99
+
100
+ Typical flow:
101
+
102
+ ```bash
103
+ npx aibridge-context init
104
+ aibridge link-github
105
+ npx aibridge-context start
106
+ ```
107
+
60
108
  ## Commands
61
109
 
62
110
  ### `aibridge init`
@@ -83,6 +131,10 @@ Default server port: `3333`
83
131
 
84
132
  Triggers a manual context refresh and optional git sync.
85
133
 
134
+ ### `aibridge link-github`
135
+
136
+ Prompts for a GitHub repository URL, links `origin`, pushes `main`, saves the repo URL to `.ai-context/config.json`, and enables public AI sync output.
137
+
86
138
  ## Generated files
87
139
 
88
140
  ### `.ai-context/state.json`
@@ -124,7 +176,10 @@ Default configuration:
124
176
  "gitSync": {
125
177
  "enabled": false,
126
178
  "push": true,
127
- "commitMessage": "auto: update AI context"
179
+ "commitMessage": "auto: update AI context",
180
+ "remote": "origin",
181
+ "branch": "main",
182
+ "repoUrl": ""
128
183
  }
129
184
  }
130
185
  ```
package/bin/cli.js CHANGED
@@ -2,10 +2,16 @@
2
2
  'use strict';
3
3
 
4
4
  const path = require('path');
5
+ const readline = require('readline/promises');
6
+ const { stdin, stdout } = require('process');
5
7
  const { initProject } = require('../core/init');
6
8
  const { startWatcher } = require('../core/watcher');
7
- const { loadRuntimeConfig, updateProjectState } = require('../core/stateManager');
8
- const { syncContextToGit } = require('../core/gitSync');
9
+ const {
10
+ loadRuntimeConfig,
11
+ updateProjectState,
12
+ updateRuntimeConfig
13
+ } = require('../core/stateManager');
14
+ const { linkGithubRepository, syncContextToGit } = require('../core/gitSync');
9
15
  const { startServer } = require('../server/server');
10
16
  const { createLogger } = require('../utils/logger');
11
17
 
@@ -28,7 +34,12 @@ async function run() {
28
34
 
29
35
  try {
30
36
  if (command === 'init') {
31
- await initProject(projectRoot, { logger });
37
+ await initProject(projectRoot, {
38
+ logger,
39
+ requestPublicSyncConsent: true,
40
+ promptForPublicSyncConsent: () =>
41
+ promptYesNo('[aibridge] Do you want to enable GitHub sync and public AI access? (y/n) ')
42
+ });
32
43
  return;
33
44
  }
34
45
 
@@ -51,14 +62,67 @@ async function run() {
51
62
  return;
52
63
  }
53
64
 
65
+ if (command === 'link-github') {
66
+ await initProject(projectRoot, { logger });
67
+ logger.warn('You are about to connect a GitHub repository.');
68
+ logger.info('This will:');
69
+ logger.info('* Push .ai-context to GitHub');
70
+ logger.info('* Make project context publicly accessible');
71
+ logger.info('* Allow AI systems to read your project state');
72
+
73
+ const shouldContinue = await promptYesNo('[aibridge] Continue? (y/n) ');
74
+
75
+ if (!shouldContinue) {
76
+ logger.info('GitHub linking cancelled. Public sync remains unchanged.');
77
+ return;
78
+ }
79
+
80
+ const repoUrl = process.argv[3] || (await promptForRepoUrl());
81
+
82
+ if (!repoUrl) {
83
+ logger.error('A GitHub repository URL is required.');
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+
88
+ const nextConfig = await updateRuntimeConfig(projectRoot, {
89
+ gitSync: {
90
+ enabled: true,
91
+ push: true,
92
+ repoUrl: repoUrl.trim()
93
+ }
94
+ });
95
+ const linkResult = await linkGithubRepository(projectRoot, repoUrl.trim(), logger);
96
+
97
+ if (!linkResult.ok) {
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+
102
+ await syncContextToGit(projectRoot, nextConfig.gitSync, logger);
103
+ return;
104
+ }
105
+
54
106
  if (command === 'start') {
55
107
  await initProject(projectRoot, { logger });
56
108
  const config = await loadRuntimeConfig(projectRoot);
109
+ const port = Number(process.env.AI_CONTEXT_PORT || config.port || 3333);
110
+ logger.info('Watching project for changes...');
57
111
  const serverHandle = await startServer({
58
112
  projectRoot,
59
- port: Number(process.env.AI_CONTEXT_PORT || config.port || 3333),
113
+ port,
60
114
  logger
61
115
  });
116
+ logger.info(`Local server: http://localhost:${port}`);
117
+
118
+ if (config.gitSync.enabled) {
119
+ logger.info('Auto-sync to GitHub is ENABLED');
120
+ logger.warn('Changes will be publicly available to AI');
121
+ } else {
122
+ logger.info('GitHub sync is DISABLED');
123
+ logger.info('Data is only available locally');
124
+ }
125
+
62
126
  const watcherHandle = await startWatcher(projectRoot, { logger });
63
127
 
64
128
  const shutdown = async (signal) => {
@@ -97,16 +161,47 @@ async function run() {
97
161
  function printHelp() {
98
162
  console.log(`aibridge-context
99
163
 
100
- Usage:
101
- aibridge init
102
- aibridge start
103
- aibridge update
104
-
105
164
  Commands:
106
- init Create .ai-context and initialize AI context files
107
- start Start the watcher and local server on port 3333
108
- update Trigger a manual state update
165
+ init Initialize AI context (with optional public sync)
166
+ link-github Connect GitHub for public AI access
167
+ start Start watcher and server
168
+ update Manually update context
169
+
170
+ Description:
171
+ This tool creates an AI-readable version of your project and can expose it via a public URL for AI tools.
109
172
  `);
110
173
  }
111
174
 
175
+ async function promptForRepoUrl() {
176
+ const rl = readline.createInterface({
177
+ input: stdin,
178
+ output: stdout
179
+ });
180
+
181
+ try {
182
+ const response = await rl.question('[aibridge] GitHub repository URL: ');
183
+ return response.trim();
184
+ } finally {
185
+ rl.close();
186
+ }
187
+ }
188
+
189
+ async function promptYesNo(question) {
190
+ if (!stdin.isTTY || !stdout.isTTY) {
191
+ return false;
192
+ }
193
+
194
+ const rl = readline.createInterface({
195
+ input: stdin,
196
+ output: stdout
197
+ });
198
+
199
+ try {
200
+ const response = await rl.question(question);
201
+ return response.trim().toLowerCase() === 'y';
202
+ } finally {
203
+ rl.close();
204
+ }
205
+ }
206
+
112
207
  run();
package/core/gitSync.js CHANGED
@@ -29,13 +29,42 @@ async function isGitRepository(projectRoot) {
29
29
 
30
30
  async function hasRemote(projectRoot) {
31
31
  try {
32
- const result = await runGit(projectRoot, ['remote']);
32
+ const result = await runGit(projectRoot, ['remote', 'get-url', 'origin']);
33
33
  return result.stdout.trim().length > 0;
34
34
  } catch (error) {
35
35
  return false;
36
36
  }
37
37
  }
38
38
 
39
+ async function getRemoteOriginUrl(projectRoot) {
40
+ try {
41
+ const result = await runGit(projectRoot, ['remote', 'get-url', 'origin']);
42
+ return result.stdout.trim();
43
+ } catch (error) {
44
+ return '';
45
+ }
46
+ }
47
+
48
+ async function getCurrentBranch(projectRoot) {
49
+ try {
50
+ const result = await runGit(projectRoot, ['branch', '--show-current']);
51
+ return result.stdout.trim();
52
+ } catch (error) {
53
+ return '';
54
+ }
55
+ }
56
+
57
+ async function ensureMainBranch(projectRoot) {
58
+ const currentBranch = await getCurrentBranch(projectRoot);
59
+
60
+ if (currentBranch === 'main') {
61
+ return 'main';
62
+ }
63
+
64
+ await runGit(projectRoot, ['branch', '-M', 'main']);
65
+ return 'main';
66
+ }
67
+
39
68
  async function hasStagedContextChanges(projectRoot) {
40
69
  try {
41
70
  await runGit(projectRoot, ['diff', '--cached', '--quiet', '--', '.ai-context']);
@@ -45,12 +74,159 @@ async function hasStagedContextChanges(projectRoot) {
45
74
  }
46
75
  }
47
76
 
77
+ function formatGitError(error) {
78
+ const stderr = typeof error.stderr === 'string' ? error.stderr.trim() : '';
79
+ const stdout = typeof error.stdout === 'string' ? error.stdout.trim() : '';
80
+ const message = stderr || stdout || error.message || 'Unknown git error.';
81
+ return message.split('\n')[0];
82
+ }
83
+
84
+ async function ensureGitInitialized(projectRoot, logger) {
85
+ const repositoryReady = await isGitRepository(projectRoot);
86
+
87
+ if (repositoryReady) {
88
+ return {
89
+ initialized: false
90
+ };
91
+ }
92
+
93
+ try {
94
+ await runGit(projectRoot, ['init']);
95
+ await runGit(projectRoot, ['add', '.']);
96
+ try {
97
+ await runGit(projectRoot, ['commit', '-m', 'initial commit']);
98
+ } catch (error) {
99
+ if (!/nothing to commit/i.test(error.stderr || error.message)) {
100
+ throw error;
101
+ }
102
+ }
103
+
104
+ await ensureMainBranch(projectRoot);
105
+
106
+ if (logger) {
107
+ logger.info('Git initialized');
108
+ }
109
+
110
+ return {
111
+ initialized: true
112
+ };
113
+ } catch (error) {
114
+ if (logger) {
115
+ logger.warn(`Git initialization failed gracefully: ${formatGitError(error)}`);
116
+ }
117
+
118
+ return {
119
+ initialized: false,
120
+ error: error.message
121
+ };
122
+ }
123
+ }
124
+
125
+ function parseGitHubRepo(repoUrl) {
126
+ if (!repoUrl) {
127
+ return null;
128
+ }
129
+
130
+ const cleanedUrl = repoUrl.trim().replace(/\.git$/, '');
131
+ let match = cleanedUrl.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)$/i);
132
+
133
+ if (!match) {
134
+ match = cleanedUrl.match(/^git@github\.com:([^/]+)\/([^/]+)$/i);
135
+ }
136
+
137
+ if (!match) {
138
+ return null;
139
+ }
140
+
141
+ return {
142
+ owner: match[1],
143
+ repo: match[2]
144
+ };
145
+ }
146
+
147
+ function buildPublicAiUrls(repoUrl, branch) {
148
+ const parsedRepo = parseGitHubRepo(repoUrl);
149
+
150
+ if (!parsedRepo) {
151
+ return null;
152
+ }
153
+
154
+ const baseUrl = `https://raw.githubusercontent.com/${parsedRepo.owner}/${parsedRepo.repo}/${branch}`;
155
+
156
+ return {
157
+ stateUrl: `${baseUrl}/.ai-context/state.json`,
158
+ brainUrl: `${baseUrl}/.ai-context/brain.txt`
159
+ };
160
+ }
161
+
162
+ function logMissingRemoteInstructions(logger) {
163
+ if (!logger) {
164
+ return;
165
+ }
166
+
167
+ logger.warn('GitHub remote not found.');
168
+ logger.info('Run:');
169
+ logger.info('git remote add origin <repo-url>');
170
+ logger.info('git push -u origin main');
171
+ }
172
+
173
+ function logPublicAiEndpoints(logger, urls) {
174
+ if (!logger || !urls) {
175
+ return;
176
+ }
177
+
178
+ logger.info('\u2705 AI Context Synced Successfully');
179
+ logger.info('\u{1F310} Public AI Endpoint:');
180
+ logger.info(urls.stateUrl);
181
+ logger.info('\u{1F9E0} AI Instructions Endpoint:');
182
+ logger.info(urls.brainUrl);
183
+ logger.warn('\u26A0\uFE0F IMPORTANT:');
184
+ logger.warn('This data is PUBLIC. Anyone with this link can access it.');
185
+ logger.info('\u{1F916} To use with AI:');
186
+ logger.info('"Use this URL as the source of truth for my project."');
187
+ }
188
+
189
+ async function linkGithubRepository(projectRoot, repoUrl, logger) {
190
+ const normalizedRepoUrl = repoUrl.trim();
191
+ await ensureGitInitialized(projectRoot, logger);
192
+
193
+ try {
194
+ const existingRemoteUrl = await getRemoteOriginUrl(projectRoot);
195
+
196
+ if (!existingRemoteUrl) {
197
+ await runGit(projectRoot, ['remote', 'add', 'origin', normalizedRepoUrl]);
198
+ } else if (existingRemoteUrl !== normalizedRepoUrl) {
199
+ await runGit(projectRoot, ['remote', 'set-url', 'origin', normalizedRepoUrl]);
200
+ }
201
+
202
+ await ensureMainBranch(projectRoot);
203
+ await runGit(projectRoot, ['push', '-u', 'origin', 'main']);
204
+
205
+ return {
206
+ ok: true,
207
+ urls: buildPublicAiUrls(normalizedRepoUrl, 'main')
208
+ };
209
+ } catch (error) {
210
+ if (logger) {
211
+ logger.warn(`GitHub link failed gracefully: ${formatGitError(error)}`);
212
+ }
213
+
214
+ return {
215
+ ok: false,
216
+ error: error.message
217
+ };
218
+ }
219
+ }
220
+
48
221
  async function syncContextToGit(projectRoot, config, logger) {
49
222
  const settings = Object.assign(
50
223
  {
51
224
  enabled: false,
52
225
  push: true,
53
- commitMessage: 'auto: update AI context'
226
+ commitMessage: 'auto: update AI context',
227
+ remote: 'origin',
228
+ branch: 'main',
229
+ repoUrl: ''
54
230
  },
55
231
  config
56
232
  );
@@ -76,10 +252,25 @@ async function syncContextToGit(projectRoot, config, logger) {
76
252
  }
77
253
 
78
254
  try {
79
- await runGit(projectRoot, ['add', '.ai-context']);
255
+ const branchName = await ensureMainBranch(projectRoot);
256
+ const remoteUrl = (await getRemoteOriginUrl(projectRoot)) || settings.repoUrl;
257
+
258
+ if (!remoteUrl) {
259
+ logMissingRemoteInstructions(logger);
260
+ return {
261
+ skipped: true,
262
+ reason: 'missing_remote'
263
+ };
264
+ }
265
+
266
+ await runGit(projectRoot, ['add', '-f', '.ai-context']);
80
267
 
81
268
  const hasChanges = await hasStagedContextChanges(projectRoot);
82
269
  if (!hasChanges) {
270
+ if (logger) {
271
+ logger.info('No .ai-context changes to sync.');
272
+ }
273
+
83
274
  return {
84
275
  skipped: true,
85
276
  reason: 'no_changes'
@@ -92,9 +283,7 @@ async function syncContextToGit(projectRoot, config, logger) {
92
283
  const remoteExists = await hasRemote(projectRoot);
93
284
 
94
285
  if (!remoteExists) {
95
- if (logger) {
96
- logger.warn('Git sync committed locally, but no remote is configured for push.');
97
- }
286
+ logMissingRemoteInstructions(logger);
98
287
 
99
288
  return {
100
289
  ok: true,
@@ -102,20 +291,20 @@ async function syncContextToGit(projectRoot, config, logger) {
102
291
  };
103
292
  }
104
293
 
105
- await runGit(projectRoot, ['push']);
294
+ await runGit(projectRoot, ['push', '-u', settings.remote || 'origin', branchName]);
106
295
  }
107
296
 
108
- if (logger) {
109
- logger.info('Synced .ai-context changes to git.');
110
- }
297
+ const urls = buildPublicAiUrls(remoteUrl, branchName);
298
+ logPublicAiEndpoints(logger, urls);
111
299
 
112
300
  return {
113
301
  ok: true,
114
- pushed: Boolean(settings.push)
302
+ pushed: Boolean(settings.push),
303
+ urls
115
304
  };
116
305
  } catch (error) {
117
306
  if (logger) {
118
- logger.warn(`Git sync failed gracefully: ${error.message}`);
307
+ logger.warn(`Git sync failed gracefully: ${formatGitError(error)}`);
119
308
  }
120
309
 
121
310
  return {
@@ -126,6 +315,10 @@ async function syncContextToGit(projectRoot, config, logger) {
126
315
  }
127
316
 
128
317
  module.exports = {
318
+ buildPublicAiUrls,
319
+ ensureGitInitialized,
320
+ getRemoteOriginUrl,
129
321
  isGitRepository,
322
+ linkGithubRepository,
130
323
  syncContextToGit
131
324
  };
package/core/init.js CHANGED
@@ -11,12 +11,22 @@ const {
11
11
  getContextPaths,
12
12
  readJsonFile,
13
13
  renderTemplate,
14
+ updateRuntimeConfig,
14
15
  writeJsonAtomic,
15
16
  writeTextAtomic
16
17
  } = require('./stateManager');
18
+ const { ensureGitInitialized } = require('./gitSync');
17
19
 
18
20
  async function initProject(projectRoot, options) {
19
- const settings = Object.assign({ logger: null, force: false }, options);
21
+ const settings = Object.assign(
22
+ {
23
+ logger: null,
24
+ force: false,
25
+ requestPublicSyncConsent: false,
26
+ promptForPublicSyncConsent: null
27
+ },
28
+ options
29
+ );
20
30
  const logger = settings.logger;
21
31
  const contextDir = await ensureContextDirectory(projectRoot);
22
32
  const paths = getContextPaths(projectRoot);
@@ -34,6 +44,7 @@ async function initProject(projectRoot, options) {
34
44
  const existingChangelog = await readJsonFile(paths.changelogFile, null);
35
45
  const templateState = JSON.parse(stateTemplate);
36
46
  const templateChangelog = JSON.parse(changelogTemplate);
47
+ let enableGitSync = false;
37
48
 
38
49
  const initialState = Object.assign({}, templateState, existingState || createDefaultState(projectRoot), {
39
50
  project: metadata.project,
@@ -60,18 +71,21 @@ async function initProject(projectRoot, options) {
60
71
  await writeTextAtomic(paths.contextFile, initialContext);
61
72
  }
62
73
 
63
- if (!existingConfig) {
64
- await writeJsonAtomic(paths.configFile, {
65
- port: 3333,
66
- debounceMs: 600,
67
- gitSync: {
68
- enabled: false,
69
- push: true,
70
- commitMessage: 'auto: update AI context'
71
- }
72
- });
74
+ if (!existingConfig && settings.requestPublicSyncConsent) {
75
+ enableGitSync = await requestPublicSyncConsent(
76
+ logger,
77
+ settings.promptForPublicSyncConsent
78
+ );
73
79
  }
74
80
 
81
+ await updateRuntimeConfig(projectRoot, existingConfig ? null : {
82
+ gitSync: {
83
+ enabled: enableGitSync
84
+ }
85
+ });
86
+
87
+ await ensureGitInitialized(projectRoot, logger);
88
+
75
89
  if (logger) {
76
90
  logger.info(`Initialized AI context in ${contextDir}`);
77
91
  }
@@ -82,6 +96,29 @@ async function initProject(projectRoot, options) {
82
96
  };
83
97
  }
84
98
 
99
+ async function requestPublicSyncConsent(logger, promptForPublicSyncConsent) {
100
+ if (logger) {
101
+ logger.warn('This tool can make parts of your project publicly accessible for AI tools.');
102
+ logger.info('It will:');
103
+ logger.info('* Track project changes');
104
+ logger.info('* Generate AI-readable context');
105
+ logger.info('* Optionally sync to GitHub');
106
+ logger.info('* Create a PUBLIC URL accessible by AI systems');
107
+ logger.warn('WARNING:');
108
+ logger.warn('Anyone with the URL can read this data.');
109
+ }
110
+
111
+ if (typeof promptForPublicSyncConsent !== 'function') {
112
+ if (logger) {
113
+ logger.info('GitHub sync will remain disabled until you explicitly enable it.');
114
+ }
115
+
116
+ return false;
117
+ }
118
+
119
+ return Boolean(await promptForPublicSyncConsent());
120
+ }
121
+
85
122
  async function fileExists(filePath) {
86
123
  try {
87
124
  await fsp.access(filePath);
@@ -14,7 +14,10 @@ const DEFAULT_CONFIG = {
14
14
  gitSync: {
15
15
  enabled: false,
16
16
  push: true,
17
- commitMessage: 'auto: update AI context'
17
+ commitMessage: 'auto: update AI context',
18
+ remote: 'origin',
19
+ branch: 'main',
20
+ repoUrl: ''
18
21
  }
19
22
  };
20
23
 
@@ -181,6 +184,16 @@ async function loadRuntimeConfig(projectRoot) {
181
184
  return deepMerge(DEFAULT_CONFIG, userConfig);
182
185
  }
183
186
 
187
+ async function updateRuntimeConfig(projectRoot, updates) {
188
+ const { configFile } = getContextPaths(projectRoot);
189
+ const currentConfig = await readJsonFile(configFile, {});
190
+ const mergedCurrentConfig = deepMerge(DEFAULT_CONFIG, currentConfig);
191
+ const nextConfig = deepMerge(mergedCurrentConfig, updates || {});
192
+
193
+ await writeJsonAtomic(configFile, nextConfig);
194
+ return nextConfig;
195
+ }
196
+
184
197
  async function updateProjectState(projectRoot, changeEvent, options) {
185
198
  const settings = Object.assign(
186
199
  {
@@ -321,6 +334,7 @@ module.exports = {
321
334
  loadRuntimeConfig,
322
335
  readJsonFile,
323
336
  renderTemplate,
337
+ updateRuntimeConfig,
324
338
  updateProjectState,
325
339
  writeJsonAtomic,
326
340
  writeTextAtomic
package/index.js CHANGED
@@ -2,15 +2,28 @@
2
2
 
3
3
  const { initProject } = require('./core/init');
4
4
  const { startWatcher } = require('./core/watcher');
5
- const { updateProjectState, loadRuntimeConfig } = require('./core/stateManager');
5
+ const {
6
+ updateProjectState,
7
+ loadRuntimeConfig,
8
+ updateRuntimeConfig
9
+ } = require('./core/stateManager');
6
10
  const { startServer } = require('./server/server');
7
- const { syncContextToGit } = require('./core/gitSync');
11
+ const {
12
+ buildPublicAiUrls,
13
+ ensureGitInitialized,
14
+ linkGithubRepository,
15
+ syncContextToGit
16
+ } = require('./core/gitSync');
8
17
 
9
18
  module.exports = {
19
+ buildPublicAiUrls,
20
+ ensureGitInitialized,
10
21
  initProject,
22
+ linkGithubRepository,
11
23
  startWatcher,
12
24
  updateProjectState,
13
25
  loadRuntimeConfig,
26
+ updateRuntimeConfig,
14
27
  startServer,
15
28
  syncContextToGit
16
29
  };
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "aibridge-context",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "description": "Zero-config CLI and library for generating AI-readable project context, serving it locally, and syncing it with git.",
5
5
  "main": "./index.js",
6
6
  "bin": {
7
+ "aibridge-context": "./bin/cli.js",
7
8
  "aibridge": "./bin/cli.js",
8
9
  "ai-context": "./bin/cli.js"
9
10
  },
package/server/server.js CHANGED
@@ -22,10 +22,6 @@ async function startServer(options) {
22
22
  instance.on('error', reject);
23
23
  });
24
24
 
25
- if (settings.logger) {
26
- settings.logger.info(`AI context server is running on http://localhost:${settings.port}`);
27
- }
28
-
29
25
  return {
30
26
  app,
31
27
  server,