@gowelle/stint-agent 1.2.22 → 1.2.23

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-TQHWJWBZ.js";
5
+ } from "./chunk-ZUQTJV35.js";
6
6
  import {
7
7
  authService
8
- } from "./chunk-7H6J2KCA.js";
8
+ } from "./chunk-WQUVXZWM.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-LTVAFGVL.js";
4
+ import "./chunk-WQUVXZWM.js";
5
+ export {
6
+ apiService
7
+ };
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  apiService
3
- } from "./chunk-KMYPMLEH.js";
3
+ } from "./chunk-LTVAFGVL.js";
4
4
  import {
5
5
  gitService,
6
6
  projectService
7
- } from "./chunk-TQHWJWBZ.js";
7
+ } from "./chunk-ZUQTJV35.js";
8
8
  import {
9
9
  authService,
10
10
  config,
11
11
  logger
12
- } from "./chunk-7H6J2KCA.js";
12
+ } from "./chunk-WQUVXZWM.js";
13
13
 
14
14
  // src/utils/notify.ts
15
15
  import notifier from "node-notifier";
@@ -549,11 +549,29 @@ var WebSocketServiceImpl = class {
549
549
  logger.info("websocket", `Subscribing to private channel: ${channel}`);
550
550
  const privateChannel = this.echo.private(channel);
551
551
  writeStatus({ channel });
552
- privateChannel.listen(".commit.approved", (data) => {
552
+ privateChannel.listen(".commit.approved", async (data) => {
553
553
  logger.info("websocket", `Commit approved: ${data.pendingCommit.id}`);
554
554
  writeStatus({ lastEvent: "commit.approved", lastEventTime: (/* @__PURE__ */ new Date()).toISOString() });
555
+ let commit = data.pendingCommit;
556
+ if (commit.has_large_files) {
557
+ try {
558
+ logger.info("websocket", `Commit ${commit.id} marked as large, fetching full details...`);
559
+ const { apiService: apiService2 } = await import("./api-GSYJMF33.js");
560
+ const fullCommit = await apiService2.getCommit(commit.id);
561
+ commit = {
562
+ ...commit,
563
+ files: fullCommit.files,
564
+ has_large_files: false
565
+ // Clear flag as we now have the files
566
+ };
567
+ logger.success("websocket", `Fetched full details for commit ${commit.id}`);
568
+ } catch (error) {
569
+ logger.error("websocket", `Failed to fetch full commit details for ${commit.id}`, error);
570
+ }
571
+ }
555
572
  this.commitApprovedHandlers.forEach(
556
- (handler) => handler(data.pendingCommit, data.pendingCommit.project)
573
+ (handler) => handler(commit, data.pendingCommit.project)
574
+ // Use the potentially updated commit object
557
575
  );
558
576
  }).listen(".commit.pending", (data) => {
559
577
  logger.info("websocket", `Commit pending: ${data.pendingCommit.id}`);
@@ -2,7 +2,7 @@ import {
2
2
  authService,
3
3
  config,
4
4
  logger
5
- } from "./chunk-7H6J2KCA.js";
5
+ } from "./chunk-WQUVXZWM.js";
6
6
 
7
7
  // src/utils/circuit-breaker.ts
8
8
  var CircuitBreaker = class {
@@ -98,7 +98,7 @@ var CircuitBreaker = class {
98
98
  };
99
99
 
100
100
  // src/services/api.ts
101
- var AGENT_VERSION = "1.2.22";
101
+ var AGENT_VERSION = "1.2.23";
102
102
  var ApiServiceImpl = class {
103
103
  sessionId = null;
104
104
  circuitBreaker = new CircuitBreaker({
@@ -272,6 +272,30 @@ var ApiServiceImpl = class {
272
272
  logger.info("api", `Found ${commits.length} pending commits`);
273
273
  return commits;
274
274
  }
275
+ /**
276
+ * Get a specific commit by ID
277
+ * @param commitId - Commit ID
278
+ * @returns The pending commit details
279
+ */
280
+ async getCommit(commitId) {
281
+ logger.info("api", `Fetching commit ${commitId}`);
282
+ const response = await this.request(`/api/agent/commits/${commitId}`);
283
+ const item = response.data;
284
+ const projectId = item.project_id || item.projectId;
285
+ const createdAt = item.created_at || item.createdAt;
286
+ const hasLargeFiles = item.has_large_files || item.hasLargeFiles;
287
+ if (!projectId || !createdAt) {
288
+ throw new Error(`Invalid commit data received from API: ${JSON.stringify(item)}`);
289
+ }
290
+ return {
291
+ id: item.id,
292
+ projectId,
293
+ message: item.message,
294
+ files: item.files,
295
+ has_large_files: hasLargeFiles,
296
+ createdAt
297
+ };
298
+ }
275
299
  /**
276
300
  * Mark a commit as successfully executed
277
301
  * @param commitId - Commit ID
@@ -308,7 +308,7 @@ var AuthServiceImpl = class {
308
308
  return null;
309
309
  }
310
310
  try {
311
- const { apiService } = await import("./api-U7WJAW3E.js");
311
+ const { apiService } = await import("./api-GSYJMF33.js");
312
312
  const user = await apiService.getCurrentUser();
313
313
  logger.info("auth", `Token validated for user: ${user.email}`);
314
314
  return user;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  config,
3
3
  logger
4
- } from "./chunk-7H6J2KCA.js";
4
+ } from "./chunk-WQUVXZWM.js";
5
5
 
6
6
  // src/services/git.ts
7
7
  import simpleGit from "simple-git";
@@ -3,20 +3,20 @@ import {
3
3
  commitQueue,
4
4
  notify,
5
5
  websocketService
6
- } from "../chunk-ZNBNEPPK.js";
6
+ } from "../chunk-BPDL5KWL.js";
7
7
  import {
8
8
  apiService
9
- } from "../chunk-KMYPMLEH.js";
9
+ } from "../chunk-LTVAFGVL.js";
10
10
  import {
11
11
  gitService,
12
12
  projectService,
13
13
  removePidFile,
14
14
  writePidFile
15
- } from "../chunk-TQHWJWBZ.js";
15
+ } from "../chunk-ZUQTJV35.js";
16
16
  import {
17
17
  authService,
18
18
  logger
19
- } from "../chunk-7H6J2KCA.js";
19
+ } from "../chunk-WQUVXZWM.js";
20
20
 
21
21
  // src/daemon/runner.ts
22
22
  import "dotenv/config";
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  commitQueue,
4
4
  websocketService
5
- } from "./chunk-ZNBNEPPK.js";
5
+ } from "./chunk-BPDL5KWL.js";
6
6
  import {
7
7
  apiService
8
- } from "./chunk-KMYPMLEH.js";
8
+ } from "./chunk-LTVAFGVL.js";
9
9
  import {
10
10
  getPidFilePath,
11
11
  gitService,
@@ -14,14 +14,14 @@ import {
14
14
  projectService,
15
15
  spawnDetached,
16
16
  validatePidFile
17
- } from "./chunk-TQHWJWBZ.js";
17
+ } from "./chunk-ZUQTJV35.js";
18
18
  import {
19
19
  __commonJS,
20
20
  __toESM,
21
21
  authService,
22
22
  config,
23
23
  logger
24
- } from "./chunk-7H6J2KCA.js";
24
+ } from "./chunk-WQUVXZWM.js";
25
25
 
26
26
  // node_modules/semver/internal/constants.js
27
27
  var require_constants = __commonJS({
@@ -1956,7 +1956,7 @@ var require_semver2 = __commonJS({
1956
1956
  // src/index.ts
1957
1957
  import "dotenv/config";
1958
1958
  import { Command } from "commander";
1959
- import chalk14 from "chalk";
1959
+ import chalk15 from "chalk";
1960
1960
 
1961
1961
  // src/commands/login.ts
1962
1962
  import open from "open";
@@ -2552,7 +2552,7 @@ function registerStatusCommand(program2) {
2552
2552
  try {
2553
2553
  const { render } = await import("ink");
2554
2554
  const { createElement } = await import("react");
2555
- const { StatusDashboard } = await import("./StatusDashboard-LYZL3IQH.js");
2555
+ const { StatusDashboard } = await import("./StatusDashboard-NDXVTKKO.js");
2556
2556
  render(createElement(StatusDashboard, { cwd }));
2557
2557
  return;
2558
2558
  } catch (error) {
@@ -4153,20 +4153,222 @@ function registerDoctorCommand(program2) {
4153
4153
  });
4154
4154
  }
4155
4155
 
4156
+ // src/commands/config.ts
4157
+ import chalk14 from "chalk";
4158
+ import path6 from "path";
4159
+ import os6 from "os";
4160
+ var ALLOWED_KEYS = [
4161
+ "apiUrl",
4162
+ "wsUrl",
4163
+ "reverbAppKey",
4164
+ "notifications.enabled"
4165
+ ];
4166
+ var SENSITIVE_KEYS = ["token"];
4167
+ function isAllowedKey(key) {
4168
+ return ALLOWED_KEYS.includes(key);
4169
+ }
4170
+ function isSensitiveKey(key) {
4171
+ return SENSITIVE_KEYS.includes(key);
4172
+ }
4173
+ function getNestedValue(obj, path7) {
4174
+ const parts = path7.split(".");
4175
+ let current = obj;
4176
+ for (const part of parts) {
4177
+ if (current === null || current === void 0 || typeof current !== "object") {
4178
+ return void 0;
4179
+ }
4180
+ current = current[part];
4181
+ }
4182
+ return current;
4183
+ }
4184
+ function setNestedValue(obj, path7, value) {
4185
+ const parts = path7.split(".");
4186
+ let current = obj;
4187
+ for (let i = 0; i < parts.length - 1; i++) {
4188
+ const part = parts[i];
4189
+ if (!(part in current) || typeof current[part] !== "object") {
4190
+ current[part] = {};
4191
+ }
4192
+ current = current[part];
4193
+ }
4194
+ current[parts[parts.length - 1]] = value;
4195
+ }
4196
+ function formatValue(value) {
4197
+ if (value === void 0 || value === null) {
4198
+ return chalk14.gray("(not set)");
4199
+ }
4200
+ if (typeof value === "boolean") {
4201
+ return value ? chalk14.green("true") : chalk14.red("false");
4202
+ }
4203
+ if (typeof value === "object") {
4204
+ return chalk14.cyan(JSON.stringify(value));
4205
+ }
4206
+ return chalk14.white(String(value));
4207
+ }
4208
+ function getConfigPath() {
4209
+ const configDir = path6.join(os6.homedir(), ".config", "stint");
4210
+ return path6.join(configDir, "config.json");
4211
+ }
4212
+ function registerConfigCommand(program2) {
4213
+ const configCmd = program2.command("config").description("Manage agent configuration");
4214
+ configCmd.command("get <key>").description("Get a configuration value").action((key) => {
4215
+ try {
4216
+ if (isSensitiveKey(key)) {
4217
+ console.log(chalk14.yellow(`
4218
+ \u26A0 Cannot read sensitive key "${key}"`));
4219
+ console.log(chalk14.gray('Use "stint whoami" to check authentication status.\n'));
4220
+ return;
4221
+ }
4222
+ const allConfig = config.getAll();
4223
+ const value = getNestedValue(allConfig, key);
4224
+ if (value === void 0) {
4225
+ console.log(chalk14.yellow(`
4226
+ \u26A0 Key "${key}" is not set.
4227
+ `));
4228
+ console.log(chalk14.gray("Available keys:"));
4229
+ ALLOWED_KEYS.forEach((k) => console.log(chalk14.gray(` - ${k}`)));
4230
+ console.log();
4231
+ } else {
4232
+ console.log(`
4233
+ ${chalk14.bold(key)}: ${formatValue(value)}
4234
+ `);
4235
+ }
4236
+ logger.debug("config", `Get config key: ${key}`);
4237
+ } catch (error) {
4238
+ logger.error("config", "Failed to get config", error);
4239
+ console.error(chalk14.red(`
4240
+ \u2716 Error: ${error.message}
4241
+ `));
4242
+ }
4243
+ });
4244
+ configCmd.command("set <key> <value>").description("Set a configuration value").action((key, value) => {
4245
+ try {
4246
+ if (isSensitiveKey(key)) {
4247
+ console.log(chalk14.red(`
4248
+ \u2716 Cannot set sensitive key "${key}"`));
4249
+ console.log(chalk14.gray('Use "stint login" to set authentication.\n'));
4250
+ return;
4251
+ }
4252
+ if (!isAllowedKey(key)) {
4253
+ console.log(chalk14.yellow(`
4254
+ \u26A0 Unknown key "${key}"`));
4255
+ console.log(chalk14.gray("Allowed keys:"));
4256
+ ALLOWED_KEYS.forEach((k) => console.log(chalk14.gray(` - ${k}`)));
4257
+ console.log();
4258
+ return;
4259
+ }
4260
+ let parsedValue = value;
4261
+ if (value.toLowerCase() === "true") {
4262
+ parsedValue = true;
4263
+ } else if (value.toLowerCase() === "false") {
4264
+ parsedValue = false;
4265
+ }
4266
+ if (key.includes(".")) {
4267
+ const allConfig = config.getAll();
4268
+ setNestedValue(allConfig, key, parsedValue);
4269
+ const topKey = key.split(".")[0];
4270
+ config.set(topKey, allConfig[topKey]);
4271
+ } else {
4272
+ config.set(key, parsedValue);
4273
+ }
4274
+ console.log(chalk14.green(`
4275
+ \u2713 Set ${key} = ${formatValue(parsedValue)}
4276
+ `));
4277
+ logger.success("config", `Set config key: ${key} = ${value}`);
4278
+ } catch (error) {
4279
+ logger.error("config", "Failed to set config", error);
4280
+ console.error(chalk14.red(`
4281
+ \u2716 Error: ${error.message}
4282
+ `));
4283
+ }
4284
+ });
4285
+ configCmd.command("list").description("List all configuration values").action(() => {
4286
+ try {
4287
+ const allConfig = config.getAll();
4288
+ console.log(chalk14.bold("\n\u{1F4CB} Configuration:\n"));
4289
+ console.log(chalk14.gray("\u2500".repeat(50)));
4290
+ for (const key of ALLOWED_KEYS) {
4291
+ const value = getNestedValue(allConfig, key);
4292
+ console.log(`${chalk14.cyan(key.padEnd(25))} ${formatValue(value)}`);
4293
+ }
4294
+ console.log(chalk14.gray("\u2500".repeat(50)));
4295
+ console.log(`${chalk14.cyan("token".padEnd(25))} ${chalk14.yellow("[REDACTED]")}`);
4296
+ console.log(chalk14.gray("\u2500".repeat(50)));
4297
+ console.log(`${chalk14.gray("machineId".padEnd(25))} ${chalk14.gray(allConfig.machineId)}`);
4298
+ console.log(`${chalk14.gray("machineName".padEnd(25))} ${chalk14.gray(allConfig.machineName)}`);
4299
+ console.log();
4300
+ logger.debug("config", "Listed config");
4301
+ } catch (error) {
4302
+ logger.error("config", "Failed to list config", error);
4303
+ console.error(chalk14.red(`
4304
+ \u2716 Error: ${error.message}
4305
+ `));
4306
+ }
4307
+ });
4308
+ configCmd.command("path").description("Show the configuration file path").action(() => {
4309
+ const configPath = getConfigPath();
4310
+ console.log(`
4311
+ ${chalk14.bold("Config file:")} ${chalk14.cyan(configPath)}
4312
+ `);
4313
+ logger.debug("config", `Config path: ${configPath}`);
4314
+ });
4315
+ configCmd.command("reset").description("Reset configuration to defaults (keeps token)").option("--force", "Skip confirmation prompt").action(async (options) => {
4316
+ try {
4317
+ if (!options.force) {
4318
+ console.log(chalk14.yellow("\n\u26A0 This will reset all configuration to defaults."));
4319
+ console.log(chalk14.gray("Your authentication token will be preserved.\n"));
4320
+ const readline = await import("readline");
4321
+ const rl = readline.createInterface({
4322
+ input: process.stdin,
4323
+ output: process.stdout
4324
+ });
4325
+ const answer = await new Promise((resolve) => {
4326
+ rl.question(chalk14.bold("Are you sure? (y/N) "), resolve);
4327
+ });
4328
+ rl.close();
4329
+ if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
4330
+ console.log(chalk14.gray("\nReset cancelled.\n"));
4331
+ return;
4332
+ }
4333
+ }
4334
+ const token = config.getToken();
4335
+ for (const key of ALLOWED_KEYS) {
4336
+ if (key === "notifications.enabled") {
4337
+ config.set("notifications", { enabled: true });
4338
+ } else {
4339
+ if (key === "apiUrl") config.set("apiUrl", "https://stint.codes");
4340
+ if (key === "wsUrl") config.set("wsUrl", "wss://stint.codes/reverb");
4341
+ if (key === "reverbAppKey") config.set("reverbAppKey", "wtn6tu6lirfv6yflujk7");
4342
+ }
4343
+ }
4344
+ if (token) {
4345
+ config.setToken(token);
4346
+ }
4347
+ console.log(chalk14.green("\n\u2713 Configuration reset to defaults.\n"));
4348
+ logger.success("config", "Reset config to defaults");
4349
+ } catch (error) {
4350
+ logger.error("config", "Failed to reset config", error);
4351
+ console.error(chalk14.red(`
4352
+ \u2716 Error: ${error.message}
4353
+ `));
4354
+ }
4355
+ });
4356
+ }
4357
+
4156
4358
  // src/index.ts
4157
- var AGENT_VERSION = "1.2.22";
4359
+ var AGENT_VERSION = "1.2.23";
4158
4360
  var program = new Command();
4159
4361
  program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-v, --version", "output the current version").addHelpText("after", `
4160
- ${chalk14.bold("Examples:")}
4161
- ${chalk14.cyan("$")} stint login ${chalk14.gray("# Authenticate with Stint")}
4162
- ${chalk14.cyan("$")} stint install ${chalk14.gray("# Install agent to run on startup")}
4163
- ${chalk14.cyan("$")} stint link ${chalk14.gray("# Link current directory to a project")}
4164
- ${chalk14.cyan("$")} stint daemon start ${chalk14.gray("# Start background daemon")}
4165
- ${chalk14.cyan("$")} stint status ${chalk14.gray("# Check status")}
4166
- ${chalk14.cyan("$")} stint commits ${chalk14.gray("# List pending commits")}
4362
+ ${chalk15.bold("Examples:")}
4363
+ ${chalk15.cyan("$")} stint login ${chalk15.gray("# Authenticate with Stint")}
4364
+ ${chalk15.cyan("$")} stint install ${chalk15.gray("# Install agent to run on startup")}
4365
+ ${chalk15.cyan("$")} stint link ${chalk15.gray("# Link current directory to a project")}
4366
+ ${chalk15.cyan("$")} stint daemon start ${chalk15.gray("# Start background daemon")}
4367
+ ${chalk15.cyan("$")} stint status ${chalk15.gray("# Check status")}
4368
+ ${chalk15.cyan("$")} stint commits ${chalk15.gray("# List pending commits")}
4167
4369
 
4168
- ${chalk14.bold("Documentation:")}
4169
- For more information, visit: ${chalk14.blue("https://stint.codes/docs")}
4370
+ ${chalk15.bold("Documentation:")}
4371
+ For more information, visit: ${chalk15.blue("https://stint.codes/docs")}
4170
4372
  `);
4171
4373
  registerLoginCommand(program);
4172
4374
  registerLogoutCommand(program);
@@ -4181,6 +4383,7 @@ registerInstallCommand(program);
4181
4383
  registerUninstallCommand(program);
4182
4384
  registerUpdateCommand(program);
4183
4385
  registerDoctorCommand(program);
4386
+ registerConfigCommand(program);
4184
4387
  program.exitOverride();
4185
4388
  try {
4186
4389
  await program.parseAsync(process.argv);
@@ -4188,7 +4391,7 @@ try {
4188
4391
  const commanderError = error;
4189
4392
  if (commanderError.code !== "commander.help" && commanderError.code !== "commander.version" && commanderError.code !== "commander.helpDisplayed") {
4190
4393
  logger.error("cli", "Command execution failed", error);
4191
- console.error(chalk14.red(`
4394
+ console.error(chalk15.red(`
4192
4395
  \u2716 Error: ${error.message}
4193
4396
  `));
4194
4397
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gowelle/stint-agent",
3
- "version": "1.2.22",
3
+ "version": "1.2.23",
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-KMYPMLEH.js";
4
- import "./chunk-7H6J2KCA.js";
5
- export {
6
- apiService
7
- };