@gowelle/stint-agent 1.2.43 → 1.2.45

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.
@@ -2,10 +2,10 @@ import {
2
2
  gitService,
3
3
  projectService,
4
4
  validatePidFile
5
- } from "./chunk-IYPRVBYG.js";
5
+ } from "./chunk-UFU7YWGS.js";
6
6
  import {
7
7
  authService
8
- } from "./chunk-H7MANPCF.js";
8
+ } from "./chunk-65VAEI4L.js";
9
9
 
10
10
  // src/components/StatusDashboard.tsx
11
11
  import { useState, useEffect } from "react";
@@ -0,0 +1,7 @@
1
+ import {
2
+ apiService
3
+ } from "./chunk-RS22EJ47.js";
4
+ import "./chunk-65VAEI4L.js";
5
+ export {
6
+ apiService
7
+ };
@@ -346,7 +346,7 @@ var AuthServiceImpl = class {
346
346
  return null;
347
347
  }
348
348
  try {
349
- const { apiService } = await import("./api-7EO4NO7A.js");
349
+ const { apiService } = await import("./api-JGS7AMNS.js");
350
350
  const user = await apiService.getCurrentUser();
351
351
  logger.info("auth", `Token validated for user: ${user.email}`);
352
352
  return user;
@@ -1,23 +1,241 @@
1
1
  import {
2
2
  apiService
3
- } from "./chunk-XWCVS4R6.js";
3
+ } from "./chunk-RS22EJ47.js";
4
4
  import {
5
5
  gitService,
6
6
  projectService
7
- } from "./chunk-IYPRVBYG.js";
7
+ } from "./chunk-UFU7YWGS.js";
8
8
  import {
9
9
  authService,
10
10
  config,
11
11
  logger
12
- } from "./chunk-H7MANPCF.js";
12
+ } from "./chunk-65VAEI4L.js";
13
+
14
+ // src/services/package-detector.ts
15
+ import fs from "fs";
16
+ import path from "path";
17
+ var PackageDetectorService = class {
18
+ /**
19
+ * Detect all package types in a project directory
20
+ */
21
+ async detectAll(projectPath) {
22
+ const packages = [];
23
+ try {
24
+ const npmInfo = await this.detectNpm(projectPath);
25
+ if (npmInfo) packages.push(npmInfo);
26
+ const composerInfo = await this.detectComposer(projectPath);
27
+ if (composerInfo) packages.push(composerInfo);
28
+ const cargoInfo = await this.detectCargo(projectPath);
29
+ if (cargoInfo) packages.push(cargoInfo);
30
+ const pipInfo = await this.detectPip(projectPath);
31
+ if (pipInfo) packages.push(pipInfo);
32
+ const goInfo = await this.detectGo(projectPath);
33
+ if (goInfo) packages.push(goInfo);
34
+ const gemInfo = await this.detectGem(projectPath);
35
+ if (gemInfo) packages.push(gemInfo);
36
+ if (packages.length > 0) {
37
+ logger.info(
38
+ "package-detector",
39
+ `Detected ${packages.length} package type(s): ${packages.map((p) => p.type).join(", ")}`
40
+ );
41
+ }
42
+ return packages;
43
+ } catch (error) {
44
+ logger.error(
45
+ "package-detector",
46
+ "Error detecting packages",
47
+ error
48
+ );
49
+ return packages;
50
+ }
51
+ }
52
+ /**
53
+ * Detect npm package (package.json)
54
+ */
55
+ async detectNpm(projectPath) {
56
+ const manifestPath = path.join(projectPath, "package.json");
57
+ if (!fs.existsSync(manifestPath)) {
58
+ return null;
59
+ }
60
+ try {
61
+ const content = fs.readFileSync(manifestPath, "utf8");
62
+ const pkg = JSON.parse(content);
63
+ const scripts = pkg.scripts ? Object.keys(pkg.scripts) : [];
64
+ return {
65
+ type: "npm",
66
+ name: pkg.name || "unknown",
67
+ version: pkg.version || "0.0.0",
68
+ manifestPath,
69
+ scripts,
70
+ hasPublishConfig: !!pkg.publishConfig
71
+ };
72
+ } catch (error) {
73
+ logger.debug(
74
+ "package-detector",
75
+ `Failed to parse package.json: ${error.message}`
76
+ );
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Detect composer package (composer.json)
82
+ */
83
+ async detectComposer(projectPath) {
84
+ const manifestPath = path.join(projectPath, "composer.json");
85
+ if (!fs.existsSync(manifestPath)) {
86
+ return null;
87
+ }
88
+ try {
89
+ const content = fs.readFileSync(manifestPath, "utf8");
90
+ const pkg = JSON.parse(content);
91
+ return {
92
+ type: "composer",
93
+ name: pkg.name || "unknown",
94
+ version: pkg.version || "0.0.0",
95
+ manifestPath
96
+ };
97
+ } catch (error) {
98
+ logger.debug(
99
+ "package-detector",
100
+ `Failed to parse composer.json: ${error.message}`
101
+ );
102
+ return null;
103
+ }
104
+ }
105
+ /**
106
+ * Detect cargo package (Cargo.toml)
107
+ */
108
+ async detectCargo(projectPath) {
109
+ const manifestPath = path.join(projectPath, "Cargo.toml");
110
+ if (!fs.existsSync(manifestPath)) {
111
+ return null;
112
+ }
113
+ try {
114
+ const content = fs.readFileSync(manifestPath, "utf8");
115
+ const nameMatch = content.match(/^\s*name\s*=\s*["']([^"']+)["']/m);
116
+ const versionMatch = content.match(/^\s*version\s*=\s*["']([^"']+)["']/m);
117
+ return {
118
+ type: "cargo",
119
+ name: nameMatch ? nameMatch[1] : "unknown",
120
+ version: versionMatch ? versionMatch[1] : "0.0.0",
121
+ manifestPath
122
+ };
123
+ } catch (error) {
124
+ logger.debug(
125
+ "package-detector",
126
+ `Failed to parse Cargo.toml: ${error.message}`
127
+ );
128
+ return null;
129
+ }
130
+ }
131
+ /**
132
+ * Detect pip package (pyproject.toml or setup.py)
133
+ */
134
+ async detectPip(projectPath) {
135
+ const pyprojectPath = path.join(projectPath, "pyproject.toml");
136
+ if (fs.existsSync(pyprojectPath)) {
137
+ try {
138
+ const content = fs.readFileSync(pyprojectPath, "utf8");
139
+ const nameMatch = content.match(
140
+ /\[project\][\s\S]*?name\s*=\s*["']([^"']+)["']/
141
+ );
142
+ const versionMatch = content.match(
143
+ /\[project\][\s\S]*?version\s*=\s*["']([^"']+)["']/
144
+ );
145
+ const poetryNameMatch = content.match(
146
+ /\[tool\.poetry\][\s\S]*?name\s*=\s*["']([^"']+)["']/
147
+ );
148
+ const poetryVersionMatch = content.match(
149
+ /\[tool\.poetry\][\s\S]*?version\s*=\s*["']([^"']+)["']/
150
+ );
151
+ return {
152
+ type: "pip",
153
+ name: nameMatch?.[1] || poetryNameMatch?.[1] || "unknown",
154
+ version: versionMatch?.[1] || poetryVersionMatch?.[1] || "0.0.0",
155
+ manifestPath: pyprojectPath
156
+ };
157
+ } catch (error) {
158
+ logger.debug(
159
+ "package-detector",
160
+ `Failed to parse pyproject.toml: ${error.message}`
161
+ );
162
+ }
163
+ }
164
+ const setupPyPath = path.join(projectPath, "setup.py");
165
+ if (fs.existsSync(setupPyPath)) {
166
+ return {
167
+ type: "pip",
168
+ name: "unknown",
169
+ version: "0.0.0",
170
+ manifestPath: setupPyPath
171
+ };
172
+ }
173
+ return null;
174
+ }
175
+ /**
176
+ * Detect go module (go.mod)
177
+ */
178
+ async detectGo(projectPath) {
179
+ const manifestPath = path.join(projectPath, "go.mod");
180
+ if (!fs.existsSync(manifestPath)) {
181
+ return null;
182
+ }
183
+ try {
184
+ const content = fs.readFileSync(manifestPath, "utf8");
185
+ const moduleMatch = content.match(/^module\s+(\S+)/m);
186
+ return {
187
+ type: "go",
188
+ name: moduleMatch ? moduleMatch[1] : "unknown",
189
+ version: "0.0.0",
190
+ // Go modules use git tags for versioning
191
+ manifestPath
192
+ };
193
+ } catch (error) {
194
+ logger.debug(
195
+ "package-detector",
196
+ `Failed to parse go.mod: ${error.message}`
197
+ );
198
+ return null;
199
+ }
200
+ }
201
+ /**
202
+ * Detect gem package (*.gemspec)
203
+ */
204
+ async detectGem(projectPath) {
205
+ try {
206
+ const files = fs.readdirSync(projectPath);
207
+ const gemspecFile = files.find((f) => f.endsWith(".gemspec"));
208
+ if (!gemspecFile) {
209
+ return null;
210
+ }
211
+ const manifestPath = path.join(projectPath, gemspecFile);
212
+ const content = fs.readFileSync(manifestPath, "utf8");
213
+ const nameMatch = content.match(/\.name\s*=\s*["']([^"']+)["']/);
214
+ const versionMatch = content.match(/\.version\s*=\s*["']([^"']+)["']/);
215
+ return {
216
+ type: "gem",
217
+ name: nameMatch ? nameMatch[1] : gemspecFile.replace(".gemspec", ""),
218
+ version: versionMatch ? versionMatch[1] : "0.0.0",
219
+ manifestPath
220
+ };
221
+ } catch (error) {
222
+ logger.debug(
223
+ "package-detector",
224
+ `Failed to detect gemspec: ${error.message}`
225
+ );
226
+ return null;
227
+ }
228
+ }
229
+ };
230
+ var packageDetector = new PackageDetectorService();
13
231
 
14
232
  // src/utils/notify.ts
15
233
  import notifier from "node-notifier";
16
- import path from "path";
234
+ import path2 from "path";
17
235
  import { fileURLToPath } from "url";
18
236
  var __filename = fileURLToPath(import.meta.url);
19
- var __dirname = path.dirname(__filename);
20
- var DEFAULT_ICON = path.resolve(__dirname, "../assets/logo.png");
237
+ var __dirname = path2.dirname(__filename);
238
+ var DEFAULT_ICON = path2.resolve(__dirname, "../assets/logo.png");
21
239
  function notify(options) {
22
240
  if (!config.areNotificationsEnabled()) {
23
241
  logger.debug("notify", "Notifications disabled, skipping notification");
@@ -587,9 +805,9 @@ Run "git pull --rebase" to resolve.`,
587
805
  */
588
806
  findProjectPath(projectId) {
589
807
  const allProjects = projectService.getAllLinkedProjects();
590
- for (const [path3, linkedProject] of Object.entries(allProjects)) {
808
+ for (const [path4, linkedProject] of Object.entries(allProjects)) {
591
809
  if (linkedProject.projectId === projectId) {
592
- return path3;
810
+ return path4;
593
811
  }
594
812
  }
595
813
  return null;
@@ -612,10 +830,10 @@ var commitQueue = new CommitQueueProcessor();
612
830
  // src/services/websocket.ts
613
831
  import Echo from "laravel-echo";
614
832
  import Pusher from "pusher-js";
615
- import fs from "fs";
833
+ import fs2 from "fs";
616
834
  import os from "os";
617
- import path2 from "path";
618
- var STATUS_FILE_PATH = path2.join(
835
+ import path3 from "path";
836
+ var STATUS_FILE_PATH = path3.join(
619
837
  os.homedir(),
620
838
  ".config",
621
839
  "stint",
@@ -623,19 +841,19 @@ var STATUS_FILE_PATH = path2.join(
623
841
  );
624
842
  function writeStatus(update) {
625
843
  try {
626
- const dir = path2.dirname(STATUS_FILE_PATH);
627
- if (!fs.existsSync(dir)) {
628
- fs.mkdirSync(dir, { recursive: true });
844
+ const dir = path3.dirname(STATUS_FILE_PATH);
845
+ if (!fs2.existsSync(dir)) {
846
+ fs2.mkdirSync(dir, { recursive: true });
629
847
  }
630
848
  let status = { websocket: { connected: false } };
631
- if (fs.existsSync(STATUS_FILE_PATH)) {
849
+ if (fs2.existsSync(STATUS_FILE_PATH)) {
632
850
  try {
633
- status = JSON.parse(fs.readFileSync(STATUS_FILE_PATH, "utf8"));
851
+ status = JSON.parse(fs2.readFileSync(STATUS_FILE_PATH, "utf8"));
634
852
  } catch {
635
853
  }
636
854
  }
637
855
  status.websocket = { ...status.websocket, ...update };
638
- fs.writeFileSync(STATUS_FILE_PATH, JSON.stringify(status, null, 2));
856
+ fs2.writeFileSync(STATUS_FILE_PATH, JSON.stringify(status, null, 2));
639
857
  } catch {
640
858
  }
641
859
  }
@@ -941,7 +1159,7 @@ var WebSocketServiceImpl = class {
941
1159
  "websocket",
942
1160
  `Commit ${commit.id} marked as large, fetching full details...`
943
1161
  );
944
- const { apiService: apiService2 } = await import("./api-7EO4NO7A.js");
1162
+ const { apiService: apiService2 } = await import("./api-JGS7AMNS.js");
945
1163
  const fullCommit = await apiService2.getCommit(commit.id);
946
1164
  commit = {
947
1165
  ...commit,
@@ -1147,6 +1365,7 @@ var WebSocketServiceImpl = class {
1147
1365
  var websocketService = new WebSocketServiceImpl();
1148
1366
 
1149
1367
  export {
1368
+ packageDetector,
1150
1369
  notify,
1151
1370
  commitQueue,
1152
1371
  websocketService
@@ -2,7 +2,7 @@ import {
2
2
  authService,
3
3
  config,
4
4
  logger
5
- } from "./chunk-H7MANPCF.js";
5
+ } from "./chunk-65VAEI4L.js";
6
6
 
7
7
  // src/utils/circuit-breaker.ts
8
8
  var CircuitBreaker = class {
@@ -100,7 +100,7 @@ var CircuitBreaker = class {
100
100
  };
101
101
 
102
102
  // src/services/api.ts
103
- var AGENT_VERSION = "1.2.43";
103
+ var AGENT_VERSION = "1.2.45";
104
104
  var ApiServiceImpl = class {
105
105
  sessionId = null;
106
106
  circuitBreaker = new CircuitBreaker({
@@ -411,8 +411,10 @@ var ApiServiceImpl = class {
411
411
  * @param projectId - Project ID
412
412
  * @param data - Repository information (path, remote URL, branches)
413
413
  * @param changedFiles - Optional array of changed files for commit file selection
414
+ * @param packageInfo - Optional array of detected package types
415
+ * @param fileTree - Optional array of all files in the project
414
416
  */
415
- async syncProject(projectId, data, changedFiles) {
417
+ async syncProject(projectId, data, changedFiles, packageInfo, fileTree) {
416
418
  logger.info("api", `Syncing project ${projectId}`);
417
419
  return this.withRetry(async () => {
418
420
  const payload = {
@@ -425,13 +427,20 @@ var ApiServiceImpl = class {
425
427
  if (changedFiles && changedFiles.length > 0) {
426
428
  payload.changed_files = changedFiles;
427
429
  }
430
+ if (packageInfo && packageInfo.length > 0) {
431
+ payload.package_info = packageInfo;
432
+ }
433
+ if (fileTree && fileTree.length > 0) {
434
+ payload.file_tree = fileTree;
435
+ }
428
436
  const response = await this.request(`/api/agent/projects/${projectId}/sync`, {
429
437
  method: "POST",
430
438
  body: JSON.stringify(payload)
431
439
  });
440
+ const packageTypes = packageInfo?.map((p) => p.type).join(", ") || "none";
432
441
  logger.success(
433
442
  "api",
434
- `Project ${projectId} synced (${changedFiles?.length ?? 0} changed files)`
443
+ `Project ${projectId} synced (changed: ${changedFiles?.length ?? 0}, tree: ${fileTree?.length ?? 0}, pkgs: ${packageTypes})`
435
444
  );
436
445
  return {
437
446
  auto_sync: response.auto_sync
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  config,
3
3
  logger
4
- } from "./chunk-H7MANPCF.js";
4
+ } from "./chunk-65VAEI4L.js";
5
5
 
6
6
  // src/services/git.ts
7
7
  import simpleGit from "simple-git";
@@ -285,6 +285,30 @@ var GitServiceImpl = class {
285
285
  return null;
286
286
  }
287
287
  }
288
+ /**
289
+ * Get list of all tracked files in the repository
290
+ * @param path - Repository path
291
+ * @returns Array of file paths relative to repo root
292
+ */
293
+ async getFileTree(path3) {
294
+ try {
295
+ const git = this.getGit(path3);
296
+ const tracked = await git.raw(["ls-files"]);
297
+ const untracked = await git.raw([
298
+ "ls-files",
299
+ "--others",
300
+ "--exclude-standard"
301
+ ]);
302
+ const files = [
303
+ ...tracked.split("\n").filter(Boolean),
304
+ ...untracked.split("\n").filter(Boolean)
305
+ ];
306
+ return [...new Set(files)].sort();
307
+ } catch (error) {
308
+ logger.error("git", `Failed to get file tree in ${path3}`, error);
309
+ return [];
310
+ }
311
+ }
288
312
  };
289
313
  var gitService = new GitServiceImpl();
290
314
 
@@ -2,21 +2,22 @@
2
2
  import {
3
3
  commitQueue,
4
4
  notify,
5
+ packageDetector,
5
6
  websocketService
6
- } from "../chunk-KGDXQOLB.js";
7
+ } from "../chunk-IPK6ZV6I.js";
7
8
  import {
8
9
  apiService
9
- } from "../chunk-XWCVS4R6.js";
10
+ } from "../chunk-RS22EJ47.js";
10
11
  import {
11
12
  gitService,
12
13
  projectService,
13
14
  removePidFile,
14
15
  writePidFile
15
- } from "../chunk-IYPRVBYG.js";
16
+ } from "../chunk-UFU7YWGS.js";
16
17
  import {
17
18
  authService,
18
19
  logger
19
- } from "../chunk-H7MANPCF.js";
20
+ } from "../chunk-65VAEI4L.js";
20
21
 
21
22
  // src/daemon/runner.ts
22
23
  import "dotenv/config";
@@ -190,10 +191,12 @@ var FileWatcher = class {
190
191
  }
191
192
  const repoInfo = await gitService.getRepoInfo(projectPath);
192
193
  const changedFiles = await gitService.getChangedFiles(projectPath);
194
+ const packageInfo = await packageDetector.detectAll(projectPath);
193
195
  const response = await apiService.syncProject(
194
196
  projectId,
195
197
  repoInfo,
196
- changedFiles
198
+ changedFiles,
199
+ packageInfo
197
200
  );
198
201
  if (response.auto_sync) {
199
202
  this.updateProjectSettings(projectId, response.auto_sync);
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  commitQueue,
4
+ packageDetector,
4
5
  websocketService
5
- } from "./chunk-KGDXQOLB.js";
6
+ } from "./chunk-IPK6ZV6I.js";
6
7
  import {
7
8
  apiService
8
- } from "./chunk-XWCVS4R6.js";
9
+ } from "./chunk-RS22EJ47.js";
9
10
  import {
10
11
  getPidFilePath,
11
12
  gitService,
@@ -14,14 +15,14 @@ import {
14
15
  projectService,
15
16
  spawnDetached,
16
17
  validatePidFile
17
- } from "./chunk-IYPRVBYG.js";
18
+ } from "./chunk-UFU7YWGS.js";
18
19
  import {
19
20
  __commonJS,
20
21
  __toESM,
21
22
  authService,
22
23
  config,
23
24
  logger
24
- } from "./chunk-H7MANPCF.js";
25
+ } from "./chunk-65VAEI4L.js";
25
26
 
26
27
  // node_modules/semver/internal/constants.js
27
28
  var require_constants = __commonJS({
@@ -2657,7 +2658,7 @@ function registerStatusCommand(program2) {
2657
2658
  try {
2658
2659
  const { render } = await import("ink");
2659
2660
  const { createElement } = await import("react");
2660
- const { StatusDashboard } = await import("./StatusDashboard-QOFG2BEM.js");
2661
+ const { StatusDashboard } = await import("./StatusDashboard-H4POEKO4.js");
2661
2662
  render(createElement(StatusDashboard, { cwd }));
2662
2663
  return;
2663
2664
  } catch (error) {
@@ -2883,13 +2884,19 @@ function registerSyncCommand(program2) {
2883
2884
  const repoInfo = await gitService.getRepoInfo(cwd);
2884
2885
  spinner.text = "Getting changed files...";
2885
2886
  const changedFiles = await gitService.getChangedFiles(cwd);
2887
+ spinner.text = "Detecting package types...";
2888
+ const packageInfo = await packageDetector.detectAll(cwd);
2889
+ spinner.text = "Scanning file tree...";
2890
+ const fileTree = await gitService.getFileTree(cwd);
2886
2891
  spinner.text = "Preparing sync payload...";
2887
2892
  const syncSpinner = ora7("Connecting to server...").start();
2888
2893
  try {
2889
2894
  await apiService.syncProject(
2890
2895
  linkedProject.projectId,
2891
2896
  repoInfo,
2892
- changedFiles
2897
+ changedFiles,
2898
+ packageInfo,
2899
+ fileTree
2893
2900
  );
2894
2901
  syncSpinner.succeed("Server sync completed");
2895
2902
  } catch (error) {
@@ -2904,6 +2911,13 @@ function registerSyncCommand(program2) {
2904
2911
  console.log(
2905
2912
  `${chalk7.bold("Changed:")} ${changedFiles.length} files synced for commit selection`
2906
2913
  );
2914
+ if (packageInfo.length > 0) {
2915
+ const pkgTypes = packageInfo.map((p) => `${p.type} (${p.name}@${p.version})`).join(", ");
2916
+ console.log(`${chalk7.bold("Packages:")} ${pkgTypes}`);
2917
+ }
2918
+ console.log(
2919
+ `${chalk7.bold("File Tree:")} ${fileTree.length} files indexed`
2920
+ );
2907
2921
  console.log(`${chalk7.bold("Project ID:")} ${linkedProject.projectId}`);
2908
2922
  console.log(`${chalk7.bold("Branch:")} ${repoInfo.currentBranch}`);
2909
2923
  console.log(
@@ -4928,7 +4942,7 @@ Tasks for project ${chalk15.cyan(linkedProject.projectId)}`
4928
4942
  });
4929
4943
 
4930
4944
  // src/index.ts
4931
- var AGENT_VERSION = "1.2.43";
4945
+ var AGENT_VERSION = "1.2.45";
4932
4946
  var program = new Command2();
4933
4947
  program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-v, --version", "output the current version").addHelpText(
4934
4948
  "after",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gowelle/stint-agent",
3
- "version": "1.2.43",
3
+ "version": "1.2.45",
4
4
  "description": "Local agent for Stint - Project Assistant",
5
5
  "author": "Gowelle John <gowelle.john@icloud.com>",
6
6
  "license": "MIT",
@@ -1,7 +0,0 @@
1
- import {
2
- apiService
3
- } from "./chunk-XWCVS4R6.js";
4
- import "./chunk-H7MANPCF.js";
5
- export {
6
- apiService
7
- };