prjct-cli 1.6.8 → 1.6.10

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 (38) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +46 -0
  3. package/core/ai-tools/registry.ts +2 -9
  4. package/core/bus/bus.ts +24 -0
  5. package/core/commands/planning.ts +3 -5
  6. package/core/infrastructure/agent-detector.ts +2 -2
  7. package/core/infrastructure/path-manager.ts +3 -17
  8. package/core/integrations/jira/client.ts +3 -77
  9. package/core/server/server.ts +2 -4
  10. package/core/server/sse.ts +115 -59
  11. package/core/services/context-generator.ts +22 -47
  12. package/core/services/diff-generator.ts +18 -43
  13. package/core/services/stack-detector.ts +4 -20
  14. package/core/services/sync-service.ts +35 -106
  15. package/core/services/sync-verifier.ts +17 -37
  16. package/core/services/watch-service.ts +20 -3
  17. package/core/types/citations.ts +22 -0
  18. package/core/types/commands.ts +10 -0
  19. package/core/types/diff.ts +41 -0
  20. package/core/types/errors.ts +111 -0
  21. package/core/types/index.ts +80 -0
  22. package/core/types/infrastructure.ts +14 -0
  23. package/core/types/jira.ts +51 -0
  24. package/core/types/logger.ts +17 -0
  25. package/core/types/output.ts +47 -0
  26. package/core/types/project-sync.ts +109 -0
  27. package/core/types/server.ts +28 -10
  28. package/core/types/services.ts +14 -0
  29. package/core/types/stack.ts +19 -0
  30. package/core/types/sync-verifier.ts +33 -0
  31. package/core/types/workflow.ts +23 -0
  32. package/core/utils/citations.ts +2 -16
  33. package/core/utils/error-messages.ts +5 -139
  34. package/core/utils/logger.ts +3 -11
  35. package/core/utils/output.ts +6 -45
  36. package/core/workflow/workflow-preferences.ts +14 -18
  37. package/dist/bin/prjct.mjs +137 -54
  38. package/package.json +1 -1
@@ -2020,6 +2020,13 @@ var init_logger = __esm({
2020
2020
  }
2021
2021
  });
2022
2022
 
2023
+ // core/types/server.ts
2024
+ var init_server = __esm({
2025
+ "core/types/server.ts"() {
2026
+ "use strict";
2027
+ }
2028
+ });
2029
+
2023
2030
  // core/constants/index.ts
2024
2031
  function getTimeout(key) {
2025
2032
  const envVar = `PRJCT_TIMEOUT_${key}`;
@@ -2183,24 +2190,12 @@ var init_branding = __esm({
2183
2190
  }
2184
2191
  });
2185
2192
 
2186
- // core/utils/error-messages.ts
2187
- function getError(code, overrides) {
2188
- const base = ERRORS[code];
2189
- return { ...base, ...overrides };
2190
- }
2191
- function createError(message, hint, options) {
2192
- return {
2193
- message,
2194
- hint,
2195
- ...options
2196
- };
2197
- }
2193
+ // core/types/errors.ts
2198
2194
  var ERRORS;
2199
- var init_error_messages = __esm({
2200
- "core/utils/error-messages.ts"() {
2195
+ var init_errors2 = __esm({
2196
+ "core/types/errors.ts"() {
2201
2197
  "use strict";
2202
2198
  ERRORS = {
2203
- // Project errors
2204
2199
  NO_PROJECT: {
2205
2200
  message: "No prjct project found in this directory",
2206
2201
  hint: "Run 'prjct init' to set up a new project",
@@ -2221,7 +2216,6 @@ var init_error_messages = __esm({
2221
2216
  hint: "Check JSON syntax or delete .prjct/ and run init again",
2222
2217
  file: ".prjct/prjct.config.json"
2223
2218
  },
2224
- // Git errors
2225
2219
  GIT_NOT_FOUND: {
2226
2220
  message: "Git repository not detected",
2227
2221
  hint: "Run 'git init' first, then 'prjct init'"
@@ -2242,7 +2236,6 @@ var init_error_messages = __esm({
2242
2236
  message: "Git operation failed",
2243
2237
  hint: "Check git status and resolve any conflicts"
2244
2238
  },
2245
- // Auth errors
2246
2239
  GH_NOT_AUTHENTICATED: {
2247
2240
  message: "GitHub CLI not authenticated",
2248
2241
  hint: "Run 'gh auth login' to authenticate",
@@ -2256,7 +2249,6 @@ var init_error_messages = __esm({
2256
2249
  message: "Linear API error",
2257
2250
  hint: "Check your API key or network connection"
2258
2251
  },
2259
- // Task errors
2260
2252
  NO_ACTIVE_TASK: {
2261
2253
  message: "No active task",
2262
2254
  hint: `Start a task with 'p. task "description"'`
@@ -2265,12 +2257,10 @@ var init_error_messages = __esm({
2265
2257
  message: "A task is already in progress",
2266
2258
  hint: "Complete it with 'p. done' or pause with 'p. pause'"
2267
2259
  },
2268
- // Sync errors
2269
2260
  SYNC_FAILED: {
2270
2261
  message: "Project sync failed",
2271
2262
  hint: "Check file permissions and try again"
2272
2263
  },
2273
- // Ship errors
2274
2264
  NOTHING_TO_SHIP: {
2275
2265
  message: "Nothing to ship",
2276
2266
  hint: "Make some changes first, then run ship"
@@ -2279,7 +2269,6 @@ var init_error_messages = __esm({
2279
2269
  message: "Failed to create pull request",
2280
2270
  hint: "Check GitHub auth and remote configuration"
2281
2271
  },
2282
- // Provider errors
2283
2272
  NO_AI_PROVIDER: {
2284
2273
  message: "No AI provider detected",
2285
2274
  hint: "Install Claude Code or Gemini CLI, then run 'prjct start'",
@@ -2289,7 +2278,6 @@ var init_error_messages = __esm({
2289
2278
  message: "AI provider not configured for prjct",
2290
2279
  hint: "Run 'prjct start' to configure your provider"
2291
2280
  },
2292
- // Command errors
2293
2281
  UNKNOWN_COMMAND: {
2294
2282
  message: "Unknown command",
2295
2283
  hint: "Run 'prjct --help' to see available commands"
@@ -2298,12 +2286,31 @@ var init_error_messages = __esm({
2298
2286
  message: "Missing required parameter",
2299
2287
  hint: "Check command usage below"
2300
2288
  },
2301
- // Generic
2302
2289
  UNKNOWN: {
2303
2290
  message: "An unexpected error occurred",
2304
2291
  hint: "Check the error details and try again"
2305
2292
  }
2306
2293
  };
2294
+ }
2295
+ });
2296
+
2297
+ // core/utils/error-messages.ts
2298
+ function getError(code, overrides) {
2299
+ const base = ERRORS[code];
2300
+ return { ...base, ...overrides };
2301
+ }
2302
+ function createError(message, hint, options) {
2303
+ return {
2304
+ message,
2305
+ hint,
2306
+ ...options
2307
+ };
2308
+ }
2309
+ var init_error_messages = __esm({
2310
+ "core/utils/error-messages.ts"() {
2311
+ "use strict";
2312
+ init_errors2();
2313
+ init_errors2();
2307
2314
  __name(getError, "getError");
2308
2315
  __name(createError, "createError");
2309
2316
  }
@@ -13320,9 +13327,11 @@ var init_types3 = __esm({
13320
13327
  "use strict";
13321
13328
  init_agentic();
13322
13329
  init_bus();
13330
+ init_errors2();
13323
13331
  init_fs();
13324
13332
  init_integrations();
13325
13333
  init_memory();
13334
+ init_server();
13326
13335
  }
13327
13336
  });
13328
13337
 
@@ -22952,13 +22961,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
22952
22961
  projectPath: this.projectPath,
22953
22962
  globalPath: this.globalPath
22954
22963
  });
22955
- return generator.generate(
22956
- { branch: git.branch, commits: git.commits },
22957
- stats,
22958
- commands,
22959
- agents,
22960
- sources
22961
- );
22964
+ return generator.generate(git, stats, commands, agents, sources);
22962
22965
  }
22963
22966
  // ==========================================================================
22964
22967
  // PROJECT.JSON UPDATE
@@ -23750,6 +23753,8 @@ var init_watch_service = __esm({
23750
23753
  };
23751
23754
  isRunning = false;
23752
23755
  syncCount = 0;
23756
+ sigintHandler = null;
23757
+ sigtermHandler = null;
23753
23758
  /**
23754
23759
  * Start watching for file changes
23755
23760
  */
@@ -23780,8 +23785,12 @@ var init_watch_service = __esm({
23780
23785
  }
23781
23786
  });
23782
23787
  this.watcher.on("add", (filePath) => this.handleChange("add", filePath)).on("change", (filePath) => this.handleChange("change", filePath)).on("unlink", (filePath) => this.handleChange("unlink", filePath)).on("error", (error) => this.handleError(error));
23783
- process.on("SIGINT", () => this.stop());
23784
- process.on("SIGTERM", () => this.stop());
23788
+ if (this.sigintHandler) process.off("SIGINT", this.sigintHandler);
23789
+ if (this.sigtermHandler) process.off("SIGTERM", this.sigtermHandler);
23790
+ this.sigintHandler = () => this.stop();
23791
+ this.sigtermHandler = () => this.stop();
23792
+ process.on("SIGINT", this.sigintHandler);
23793
+ process.on("SIGTERM", this.sigtermHandler);
23785
23794
  return { success: true };
23786
23795
  }
23787
23796
  /**
@@ -23801,6 +23810,15 @@ var init_watch_service = __esm({
23801
23810
  await this.watcher.close();
23802
23811
  this.watcher = null;
23803
23812
  }
23813
+ if (this.sigintHandler) {
23814
+ process.off("SIGINT", this.sigintHandler);
23815
+ this.sigintHandler = null;
23816
+ }
23817
+ if (this.sigtermHandler) {
23818
+ process.off("SIGTERM", this.sigtermHandler);
23819
+ this.sigtermHandler = null;
23820
+ }
23821
+ this.pendingChanges.clear();
23804
23822
  this.isRunning = false;
23805
23823
  process.exit(0);
23806
23824
  }
@@ -28646,7 +28664,7 @@ var require_package = __commonJS({
28646
28664
  "package.json"(exports, module) {
28647
28665
  module.exports = {
28648
28666
  name: "prjct-cli",
28649
- version: "1.6.8",
28667
+ version: "1.6.10",
28650
28668
  description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
28651
28669
  main: "core/index.ts",
28652
28670
  bin: {
@@ -29665,9 +29683,47 @@ function createExtendedRoutes() {
29665
29683
  __name(createExtendedRoutes, "createExtendedRoutes");
29666
29684
 
29667
29685
  // core/server/sse.ts
29686
+ init_server();
29668
29687
  import { streamSSE } from "hono/streaming";
29688
+ var MAX_CLIENT_TTL_MS = 60 * 60 * 1e3;
29689
+ var REAPER_INTERVAL_MS = 5 * 60 * 1e3;
29690
+ var HEARTBEAT_INTERVAL_MS = 3e4;
29669
29691
  function createSSEManager() {
29670
29692
  const clients = /* @__PURE__ */ new Map();
29693
+ let reaperInterval = null;
29694
+ function removeClient(clientId) {
29695
+ const entry = clients.get(clientId);
29696
+ if (!entry) return;
29697
+ clearInterval(entry.heartbeatInterval);
29698
+ clearTimeout(entry.ttlTimeout);
29699
+ entry.abortController.abort();
29700
+ clients.delete(clientId);
29701
+ }
29702
+ __name(removeClient, "removeClient");
29703
+ function startReaper() {
29704
+ if (reaperInterval) return;
29705
+ reaperInterval = setInterval(() => {
29706
+ const now = Date.now();
29707
+ for (const [id, entry] of clients) {
29708
+ const connectedMs = now - new Date(entry.client.connectedAt).getTime();
29709
+ if (connectedMs > MAX_CLIENT_TTL_MS) {
29710
+ removeClient(id);
29711
+ }
29712
+ }
29713
+ }, REAPER_INTERVAL_MS);
29714
+ if (reaperInterval && typeof reaperInterval === "object" && "unref" in reaperInterval) {
29715
+ reaperInterval.unref();
29716
+ }
29717
+ }
29718
+ __name(startReaper, "startReaper");
29719
+ function stopReaper() {
29720
+ if (reaperInterval) {
29721
+ clearInterval(reaperInterval);
29722
+ reaperInterval = null;
29723
+ }
29724
+ }
29725
+ __name(stopReaper, "stopReaper");
29726
+ startReaper();
29671
29727
  return {
29672
29728
  /**
29673
29729
  * Handle a new SSE connection
@@ -29675,8 +29731,11 @@ function createSSEManager() {
29675
29731
  handleConnection(c) {
29676
29732
  return streamSSE(c, async (stream) => {
29677
29733
  const clientId = crypto.randomUUID();
29734
+ const connectedAt = (/* @__PURE__ */ new Date()).toISOString();
29735
+ const abortController = new AbortController();
29678
29736
  const client = {
29679
29737
  id: clientId,
29738
+ connectedAt,
29680
29739
  send: /* @__PURE__ */ __name((event, data) => {
29681
29740
  stream.writeSSE({
29682
29741
  event,
@@ -29684,34 +29743,47 @@ function createSSEManager() {
29684
29743
  });
29685
29744
  }, "send"),
29686
29745
  close: /* @__PURE__ */ __name(() => {
29687
- clients.delete(clientId);
29746
+ removeClient(clientId);
29688
29747
  }, "close")
29689
29748
  };
29690
- clients.set(clientId, client);
29749
+ const heartbeatInterval = setInterval(async () => {
29750
+ try {
29751
+ await stream.writeSSE({
29752
+ event: "heartbeat",
29753
+ data: JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString() })
29754
+ });
29755
+ } catch {
29756
+ removeClient(clientId);
29757
+ }
29758
+ }, HEARTBEAT_INTERVAL_MS);
29759
+ const ttlTimeout = setTimeout(() => {
29760
+ removeClient(clientId);
29761
+ }, MAX_CLIENT_TTL_MS);
29762
+ if (typeof heartbeatInterval === "object" && "unref" in heartbeatInterval) {
29763
+ heartbeatInterval.unref();
29764
+ }
29765
+ if (typeof ttlTimeout === "object" && "unref" in ttlTimeout) {
29766
+ ttlTimeout.unref();
29767
+ }
29768
+ clients.set(clientId, {
29769
+ client,
29770
+ heartbeatInterval,
29771
+ ttlTimeout,
29772
+ abortController
29773
+ });
29691
29774
  await stream.writeSSE({
29692
29775
  event: "connected",
29693
29776
  data: JSON.stringify({
29694
29777
  clientId,
29695
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
29778
+ timestamp: connectedAt,
29696
29779
  message: "Connected to prjct-cli server"
29697
29780
  })
29698
29781
  });
29699
- const heartbeat = setInterval(async () => {
29700
- try {
29701
- await stream.writeSSE({
29702
- event: "heartbeat",
29703
- data: JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString() })
29704
- });
29705
- } catch (_error) {
29706
- clearInterval(heartbeat);
29707
- clients.delete(clientId);
29708
- }
29709
- }, 3e4);
29710
29782
  stream.onAbort(() => {
29711
- clearInterval(heartbeat);
29712
- clients.delete(clientId);
29783
+ removeClient(clientId);
29713
29784
  });
29714
- await new Promise(() => {
29785
+ await new Promise((resolve) => {
29786
+ abortController.signal.addEventListener("abort", () => resolve(), { once: true });
29715
29787
  });
29716
29788
  });
29717
29789
  },
@@ -29724,11 +29796,11 @@ function createSSEManager() {
29724
29796
  data,
29725
29797
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
29726
29798
  };
29727
- for (const client of clients.values()) {
29799
+ for (const [id, entry] of clients) {
29728
29800
  try {
29729
- client.send(event, message);
29730
- } catch (_error) {
29731
- clients.delete(client.id);
29801
+ entry.client.send(event, message);
29802
+ } catch {
29803
+ removeClient(id);
29732
29804
  }
29733
29805
  }
29734
29806
  },
@@ -29737,6 +29809,16 @@ function createSSEManager() {
29737
29809
  */
29738
29810
  getClientCount() {
29739
29811
  return clients.size;
29812
+ },
29813
+ /**
29814
+ * Shut down all clients and stop the reaper.
29815
+ * Called on server stop.
29816
+ */
29817
+ shutdown() {
29818
+ stopReaper();
29819
+ for (const id of [...clients.keys()]) {
29820
+ removeClient(id);
29821
+ }
29740
29822
  }
29741
29823
  };
29742
29824
  }
@@ -29818,6 +29900,7 @@ function createServer(config) {
29818
29900
  console.log(` Dashboard: http://localhost:${port}`);
29819
29901
  },
29820
29902
  stop() {
29903
+ sseManager.shutdown();
29821
29904
  if (server) {
29822
29905
  server.stop();
29823
29906
  server = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "description": "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
5
5
  "main": "core/index.ts",
6
6
  "bin": {