commandmate 0.1.9 → 0.1.11

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 (140) hide show
  1. package/.env.example +8 -3
  2. package/.next/BUILD_ID +1 -1
  3. package/.next/app-build-manifest.json +11 -11
  4. package/.next/app-path-routes-manifest.json +1 -1
  5. package/.next/build-manifest.json +2 -2
  6. package/.next/cache/.tsbuildinfo +1 -1
  7. package/.next/cache/config.json +3 -3
  8. package/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/.next/cache/webpack/client-production/1.pack +0 -0
  10. package/.next/cache/webpack/client-production/2.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack +0 -0
  12. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  13. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  14. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  15. package/.next/cache/webpack/server-production/0.pack +0 -0
  16. package/.next/cache/webpack/server-production/index.pack +0 -0
  17. package/.next/next-server.js.nft.json +1 -1
  18. package/.next/prerender-manifest.json +1 -1
  19. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/_not-found.html +1 -1
  21. package/.next/server/app/_not-found.rsc +1 -1
  22. package/.next/server/app/api/external-apps/[id]/health/route.js +11 -12
  23. package/.next/server/app/api/external-apps/[id]/route.js +14 -15
  24. package/.next/server/app/api/external-apps/route.js +12 -13
  25. package/.next/server/app/api/hooks/claude-done/route.js +1 -1
  26. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  27. package/.next/server/app/api/repositories/clone/route.js +1 -1
  28. package/.next/server/app/api/repositories/route.js +1 -1
  29. package/.next/server/app/api/repositories/scan/route.js +1 -1
  30. package/.next/server/app/api/repositories/sync/route.js +1 -1
  31. package/.next/server/app/api/slash-commands.body +1 -1
  32. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  33. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  34. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  35. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  36. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  37. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  38. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  39. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  40. package/.next/server/app/api/worktrees/[id]/logs/route.js +7 -7
  41. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  42. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  43. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  44. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  45. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  46. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  47. package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
  48. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  49. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  50. package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
  51. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
  52. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
  53. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -1
  54. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  55. package/.next/server/app/api/worktrees/route.js +1 -1
  56. package/.next/server/app/index.html +2 -2
  57. package/.next/server/app/index.rsc +2 -2
  58. package/.next/server/app/page.js +1 -1
  59. package/.next/server/app/page_client-reference-manifest.js +1 -1
  60. package/.next/server/app/proxy/[...path]/route.js +12 -13
  61. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  62. package/.next/server/app/worktrees/[id]/page.js +5 -5
  63. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  64. package/.next/server/app/worktrees/[id]/simple-terminal/page_client-reference-manifest.js +1 -1
  65. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app-paths-manifest.json +10 -10
  67. package/.next/server/chunks/1318.js +4 -4
  68. package/.next/server/chunks/1528.js +1 -1
  69. package/.next/server/chunks/7425.js +162 -46
  70. package/.next/server/chunks/9723.js +1 -1
  71. package/.next/server/middleware-manifest.json +5 -5
  72. package/.next/server/pages/404.html +1 -1
  73. package/.next/server/pages/500.html +1 -1
  74. package/.next/server/server-reference-manifest.json +1 -1
  75. package/.next/server/src/middleware.js +2 -2
  76. package/.next/server/src/middleware.js.map +1 -1
  77. package/.next/static/chunks/app/{page-9cd00de9cc0abc43.js → page-fe35d61f14b90a51.js} +1 -1
  78. package/.next/static/chunks/app/worktrees/[id]/page-720605c2fb074444.js +1 -0
  79. package/.next/static/css/{e174aa24f94ce607.css → 376b339640084689.css} +1 -1
  80. package/.next/trace +5 -5
  81. package/dist/cli/commands/init.d.ts.map +1 -1
  82. package/dist/cli/commands/init.js +6 -4
  83. package/dist/cli/commands/start.d.ts +2 -0
  84. package/dist/cli/commands/start.d.ts.map +1 -1
  85. package/dist/cli/commands/start.js +64 -17
  86. package/dist/cli/commands/status.d.ts +4 -1
  87. package/dist/cli/commands/status.d.ts.map +1 -1
  88. package/dist/cli/commands/status.js +95 -6
  89. package/dist/cli/commands/stop.d.ts +2 -0
  90. package/dist/cli/commands/stop.d.ts.map +1 -1
  91. package/dist/cli/commands/stop.js +27 -10
  92. package/dist/cli/index.js +16 -2
  93. package/dist/cli/types/index.d.ts +20 -0
  94. package/dist/cli/types/index.d.ts.map +1 -1
  95. package/dist/cli/utils/daemon-factory.d.ts +105 -0
  96. package/dist/cli/utils/daemon-factory.d.ts.map +1 -0
  97. package/dist/cli/utils/daemon-factory.js +117 -0
  98. package/dist/cli/utils/daemon.d.ts.map +1 -1
  99. package/dist/cli/utils/daemon.js +4 -0
  100. package/dist/cli/utils/env-setup.d.ts +24 -12
  101. package/dist/cli/utils/env-setup.d.ts.map +1 -1
  102. package/dist/cli/utils/env-setup.js +64 -43
  103. package/dist/cli/utils/input-validators.d.ts +103 -0
  104. package/dist/cli/utils/input-validators.d.ts.map +1 -0
  105. package/dist/cli/utils/input-validators.js +163 -0
  106. package/dist/cli/utils/install-context.d.ts +53 -0
  107. package/dist/cli/utils/install-context.d.ts.map +1 -0
  108. package/dist/cli/utils/install-context.js +96 -0
  109. package/dist/cli/utils/pid-manager.d.ts +34 -0
  110. package/dist/cli/utils/pid-manager.d.ts.map +1 -1
  111. package/dist/cli/utils/pid-manager.js +43 -0
  112. package/dist/cli/utils/port-allocator.d.ts +108 -0
  113. package/dist/cli/utils/port-allocator.d.ts.map +1 -0
  114. package/dist/cli/utils/port-allocator.js +166 -0
  115. package/dist/cli/utils/resource-resolvers.d.ts +92 -0
  116. package/dist/cli/utils/resource-resolvers.d.ts.map +1 -0
  117. package/dist/cli/utils/resource-resolvers.js +175 -0
  118. package/dist/cli/utils/worktree-detector.d.ts +82 -0
  119. package/dist/cli/utils/worktree-detector.d.ts.map +1 -0
  120. package/dist/cli/utils/worktree-detector.js +221 -0
  121. package/dist/lib/errors.d.ts +111 -0
  122. package/dist/lib/errors.d.ts.map +1 -0
  123. package/dist/lib/errors.js +153 -0
  124. package/dist/server/server.js +3 -0
  125. package/dist/server/src/cli/utils/install-context.js +96 -0
  126. package/dist/server/src/config/system-directories.js +40 -0
  127. package/dist/server/src/lib/auto-yes-manager.js +325 -0
  128. package/dist/server/src/lib/auto-yes-resolver.js +34 -0
  129. package/dist/server/src/lib/cli-patterns.js +6 -1
  130. package/dist/server/src/lib/db-instance.js +12 -2
  131. package/dist/server/src/lib/db-migrations.js +143 -1
  132. package/dist/server/src/lib/db-path-resolver.js +99 -0
  133. package/dist/server/src/lib/db.js +63 -0
  134. package/dist/server/src/lib/env.js +52 -3
  135. package/dist/server/src/lib/worktrees.js +36 -1
  136. package/dist/server/src/types/external-apps.js +20 -0
  137. package/package.json +1 -1
  138. package/.next/static/chunks/app/worktrees/[id]/page-8c6676303b63fdaf.js +0 -1
  139. /package/.next/static/{ntEU_tKhyyZ-FVJS5Em3L → gRNW5YXY43KqCKbCdaJoJ}/_buildManifest.js +0 -0
  140. /package/.next/static/{ntEU_tKhyyZ-FVJS5Em3L → gRNW5YXY43KqCKbCdaJoJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * DaemonManager Factory
3
+ * Issue #136: Phase 3 - Task 3.1 - DaemonManager abstraction
4
+ *
5
+ * Provides Factory pattern for creating DaemonManager instances with
6
+ * issue-specific configurations while maintaining backward compatibility
7
+ * with existing DaemonManager(pidFilePath: string) constructor.
8
+ *
9
+ * MF-CONS-002: Backward compatibility with existing constructor maintained
10
+ * SF-002: Factory pattern for DaemonManager creation
11
+ */
12
+ import { DaemonManager } from './daemon';
13
+ import type { DaemonStatus, StartOptions } from '../types';
14
+ /**
15
+ * DaemonManager interface (abstraction)
16
+ * Defines the contract for daemon management operations
17
+ */
18
+ export interface IDaemonManager {
19
+ /**
20
+ * Start the daemon process
21
+ * @param options - Start options
22
+ * @returns Process ID of the started daemon
23
+ */
24
+ start(options: StartOptions): Promise<number>;
25
+ /**
26
+ * Stop the daemon process
27
+ * @param force - Use SIGKILL instead of SIGTERM
28
+ * @returns true if stopped successfully
29
+ */
30
+ stop(force?: boolean): Promise<boolean>;
31
+ /**
32
+ * Get daemon status
33
+ * @returns Status object or null if no PID file
34
+ */
35
+ getStatus(): Promise<DaemonStatus | null>;
36
+ /**
37
+ * Check if daemon is running
38
+ * @returns true if running
39
+ */
40
+ isRunning(): Promise<boolean>;
41
+ }
42
+ /**
43
+ * Configuration for DaemonManagerWrapper
44
+ */
45
+ export interface DaemonManagerConfig {
46
+ /** PID file path */
47
+ pidPath: string;
48
+ /** Environment file path */
49
+ envPath: string;
50
+ /** Database file path */
51
+ dbPath: string;
52
+ /** Issue number (undefined for main server) */
53
+ issueNo?: number;
54
+ }
55
+ /**
56
+ * Wrapper around existing DaemonManager to implement IDaemonManager
57
+ * MF-CONS-002: Uses existing DaemonManager(pidFilePath: string) internally
58
+ */
59
+ export declare class DaemonManagerWrapper implements IDaemonManager {
60
+ private innerManager;
61
+ private config;
62
+ constructor(innerManager: DaemonManager, config: DaemonManagerConfig);
63
+ start(options: StartOptions): Promise<number>;
64
+ stop(force?: boolean): Promise<boolean>;
65
+ getStatus(): Promise<DaemonStatus | null>;
66
+ isRunning(): Promise<boolean>;
67
+ /**
68
+ * Get configuration (for testing/debugging)
69
+ */
70
+ getConfig(): DaemonManagerConfig;
71
+ }
72
+ /**
73
+ * Factory for creating DaemonManager instances
74
+ * SF-002: Factory pattern implementation
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // Create manager for main server
79
+ * const factory = new DaemonManagerFactory();
80
+ * const mainManager = factory.create();
81
+ *
82
+ * // Create manager for worktree #135
83
+ * const worktreeManager = factory.create(135);
84
+ * ```
85
+ */
86
+ export declare class DaemonManagerFactory {
87
+ private pidResolver;
88
+ private dbResolver;
89
+ constructor();
90
+ /**
91
+ * Create a DaemonManager instance
92
+ * @param issueNo - Optional issue number for worktree-specific manager
93
+ * @returns IDaemonManager instance
94
+ */
95
+ create(issueNo?: number): IDaemonManager;
96
+ }
97
+ /**
98
+ * Get singleton factory instance
99
+ */
100
+ export declare function getDaemonManagerFactory(): DaemonManagerFactory;
101
+ /**
102
+ * Reset singleton factory (for testing)
103
+ */
104
+ export declare function resetDaemonManagerFactory(): void;
105
+ //# sourceMappingURL=daemon-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-factory.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9C;;;;OAIG;IACH,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAExC;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAE1C;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAsB;gBAExB,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB;IAK9D,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAW7C,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9C,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAIzC,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;IACH,SAAS,IAAI,mBAAmB;CAGjC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,UAAU,CAAiB;;IAOnC;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,cAAc;CAgBzC;AAOD;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAK9D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ /**
3
+ * DaemonManager Factory
4
+ * Issue #136: Phase 3 - Task 3.1 - DaemonManager abstraction
5
+ *
6
+ * Provides Factory pattern for creating DaemonManager instances with
7
+ * issue-specific configurations while maintaining backward compatibility
8
+ * with existing DaemonManager(pidFilePath: string) constructor.
9
+ *
10
+ * MF-CONS-002: Backward compatibility with existing constructor maintained
11
+ * SF-002: Factory pattern for DaemonManager creation
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.DaemonManagerFactory = exports.DaemonManagerWrapper = void 0;
15
+ exports.getDaemonManagerFactory = getDaemonManagerFactory;
16
+ exports.resetDaemonManagerFactory = resetDaemonManagerFactory;
17
+ const daemon_1 = require("./daemon");
18
+ const resource_resolvers_1 = require("./resource-resolvers");
19
+ const env_setup_1 = require("./env-setup");
20
+ /**
21
+ * Wrapper around existing DaemonManager to implement IDaemonManager
22
+ * MF-CONS-002: Uses existing DaemonManager(pidFilePath: string) internally
23
+ */
24
+ class DaemonManagerWrapper {
25
+ innerManager;
26
+ config;
27
+ constructor(innerManager, config) {
28
+ this.innerManager = innerManager;
29
+ this.config = config;
30
+ }
31
+ async start(options) {
32
+ // Set environment variables for the daemon process
33
+ // This allows the daemon to use the correct DB path for worktree
34
+ if (this.config.issueNo !== undefined) {
35
+ process.env.CM_DB_PATH = this.config.dbPath;
36
+ process.env.CM_ISSUE_NO = String(this.config.issueNo);
37
+ }
38
+ return this.innerManager.start(options);
39
+ }
40
+ async stop(force = false) {
41
+ return this.innerManager.stop(force);
42
+ }
43
+ async getStatus() {
44
+ return this.innerManager.getStatus();
45
+ }
46
+ async isRunning() {
47
+ return this.innerManager.isRunning();
48
+ }
49
+ /**
50
+ * Get configuration (for testing/debugging)
51
+ */
52
+ getConfig() {
53
+ return { ...this.config };
54
+ }
55
+ }
56
+ exports.DaemonManagerWrapper = DaemonManagerWrapper;
57
+ /**
58
+ * Factory for creating DaemonManager instances
59
+ * SF-002: Factory pattern implementation
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * // Create manager for main server
64
+ * const factory = new DaemonManagerFactory();
65
+ * const mainManager = factory.create();
66
+ *
67
+ * // Create manager for worktree #135
68
+ * const worktreeManager = factory.create(135);
69
+ * ```
70
+ */
71
+ class DaemonManagerFactory {
72
+ pidResolver;
73
+ dbResolver;
74
+ constructor() {
75
+ this.pidResolver = new resource_resolvers_1.PidPathResolver();
76
+ this.dbResolver = new resource_resolvers_1.DbPathResolver();
77
+ }
78
+ /**
79
+ * Create a DaemonManager instance
80
+ * @param issueNo - Optional issue number for worktree-specific manager
81
+ * @returns IDaemonManager instance
82
+ */
83
+ create(issueNo) {
84
+ const pidPath = this.pidResolver.resolve(issueNo);
85
+ const envPath = (0, env_setup_1.getEnvPath)(issueNo);
86
+ const dbPath = this.dbResolver.resolve(issueNo);
87
+ // MF-CONS-002: Use existing DaemonManager constructor
88
+ const innerManager = new daemon_1.DaemonManager(pidPath);
89
+ // Wrap with additional configuration
90
+ return new DaemonManagerWrapper(innerManager, {
91
+ pidPath,
92
+ envPath,
93
+ dbPath,
94
+ issueNo,
95
+ });
96
+ }
97
+ }
98
+ exports.DaemonManagerFactory = DaemonManagerFactory;
99
+ /**
100
+ * Singleton factory instance for convenience
101
+ */
102
+ let _factoryInstance = null;
103
+ /**
104
+ * Get singleton factory instance
105
+ */
106
+ function getDaemonManagerFactory() {
107
+ if (!_factoryInstance) {
108
+ _factoryInstance = new DaemonManagerFactory();
109
+ }
110
+ return _factoryInstance;
111
+ }
112
+ /**
113
+ * Reset singleton factory (for testing)
114
+ */
115
+ function resetDaemonManagerFactory() {
116
+ _factoryInstance = null;
117
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMtD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAY;gBAEd,WAAW,EAAE,MAAM;IAK/B;;;;;OAKG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA8EnD;;;;OAIG;IACG,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BpD;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6B/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;YACW,WAAW;CAiB1B"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMtD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAY;gBAEd,WAAW,EAAE,MAAM;IAK/B;;;;;OAKG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAmFnD;;;;OAIG;IACG,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BpD;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6B/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;YACW,WAAW;CAiB1B"}
@@ -56,6 +56,10 @@ class DaemonManager {
56
56
  if (options.port) {
57
57
  env.CM_PORT = String(options.port);
58
58
  }
59
+ // Issue #136: Set DB path for worktree servers
60
+ if (options.dbPath) {
61
+ env.CM_DB_PATH = options.dbPath;
62
+ }
59
63
  // Issue #125: Security warnings for external access (Stage 4 review: MF-2)
60
64
  const bindAddress = env.CM_BIND || '127.0.0.1';
61
65
  const authToken = env.CM_AUTH_TOKEN;
@@ -1,17 +1,21 @@
1
1
  /**
2
2
  * Environment Setup Utility
3
3
  * Issue #96: npm install CLI support
4
+ * Issue #136: DRY refactoring - isGlobalInstall and getConfigDir extracted to install-context.ts
4
5
  * Migrated from scripts/setup-env.sh
5
6
  */
6
7
  import { EnvConfig, EnvSetupOptions, ValidationResult } from '../types';
8
+ export { isGlobalInstall, getConfigDir } from './install-context';
7
9
  /**
8
10
  * Default environment configuration values
9
11
  * SF-4: DRY - Centralized defaults
12
+ *
13
+ * Issue #135: CM_DB_PATH removed - use getDefaultDbPath() instead
14
+ * for dynamic path resolution based on install type
10
15
  */
11
16
  export declare const ENV_DEFAULTS: {
12
17
  readonly CM_PORT: 3000;
13
18
  readonly CM_BIND: "127.0.0.1";
14
- readonly CM_DB_PATH: "./data/cm.db";
15
19
  readonly CM_LOG_LEVEL: "info";
16
20
  readonly CM_LOG_FORMAT: "text";
17
21
  };
@@ -20,19 +24,26 @@ export declare const ENV_DEFAULTS: {
20
24
  */
21
25
  export declare const DEFAULT_ROOT_DIR: string;
22
26
  /**
23
- * Check if running as global npm package
24
- * Issue #119: Determine .env location based on install type
27
+ * Get the default database path based on install type
28
+ * Issue #135: Dynamic DB path resolution
29
+ * Issue #136: Uses isGlobalInstall from install-context.ts
30
+ *
31
+ * For global installs: ~/.commandmate/data/cm.db
32
+ * For local installs: <cwd>/data/cm.db (as absolute path)
25
33
  *
26
- * @returns true if running as global npm package
34
+ * @returns Absolute path to the default database file
27
35
  */
28
- export declare function isGlobalInstall(): boolean;
36
+ export declare function getDefaultDbPath(): string;
29
37
  /**
30
38
  * Get the path to .env file based on install type
31
39
  * Issue #119: Global install uses ~/.commandmate/, local uses cwd
40
+ * Issue #136: Uses isGlobalInstall from install-context.ts
41
+ * Issue #136: Added issueNo parameter for worktree-specific .env files
32
42
  *
43
+ * @param issueNo - Optional issue number for worktree-specific .env
33
44
  * @returns Path to .env file
34
45
  */
35
- export declare function getEnvPath(): string;
46
+ export declare function getEnvPath(issueNo?: number): string;
36
47
  /**
37
48
  * Resolve path securely by resolving symlinks and verifying within allowed directory
38
49
  * Issue #125: Path traversal protection (OWASP A01:2021 - Broken Access Control)
@@ -44,20 +55,21 @@ export declare function getEnvPath(): string;
44
55
  */
45
56
  export declare function resolveSecurePath(targetPath: string, allowedBaseDir: string): string;
46
57
  /**
47
- * Get the config directory path
48
- * Issue #119: Returns ~/.commandmate for global, cwd for local
49
- * Issue #125: Added symlink resolution for security (path traversal protection)
58
+ * Get the PIDs directory path
59
+ * Issue #136: Centralized pids directory path resolution
50
60
  *
51
- * @returns Path to config directory (absolute, with symlinks resolved)
61
+ * @returns Path to pids directory
52
62
  */
53
- export declare function getConfigDir(): string;
63
+ export declare function getPidsDir(): string;
54
64
  /**
55
65
  * Get the PID file path based on install type
56
66
  * Issue #125: DRY principle - centralized PID file path resolution
67
+ * Issue #136: Uses getConfigDir from install-context.ts
57
68
  *
69
+ * @param issueNo - Optional issue number for worktree-specific PID file
58
70
  * @returns Path to PID file (uses getConfigDir for consistency)
59
71
  */
60
- export declare function getPidFilePath(): string;
72
+ export declare function getPidFilePath(issueNo?: number): string;
61
73
  /**
62
74
  * Sanitize input by removing control characters
63
75
  * SF-SEC-3: Input sanitization
@@ -1 +1 @@
1
- {"version":3,"file":"env-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/env-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EACL,SAAS,EACT,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAYzC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAcnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CASpF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAqBrC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,CAAC,EAAE,MAAM;IAI5B;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAiChB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY9C;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB;CAoCpD"}
1
+ {"version":3,"file":"env-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/env-setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,OAAO,EACL,SAAS,EACT,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AASlB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAElE;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;;;CAMf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBnD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CASpF;AAKD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAYvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,CAAC,EAAE,MAAM;IAI5B;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAiChB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY9C;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB;CAoCpD"}
@@ -2,14 +2,15 @@
2
2
  /**
3
3
  * Environment Setup Utility
4
4
  * Issue #96: npm install CLI support
5
+ * Issue #136: DRY refactoring - isGlobalInstall and getConfigDir extracted to install-context.ts
5
6
  * Migrated from scripts/setup-env.sh
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.EnvSetup = exports.DEFAULT_ROOT_DIR = exports.ENV_DEFAULTS = void 0;
9
- exports.isGlobalInstall = isGlobalInstall;
9
+ exports.EnvSetup = exports.DEFAULT_ROOT_DIR = exports.ENV_DEFAULTS = exports.getConfigDir = exports.isGlobalInstall = void 0;
10
+ exports.getDefaultDbPath = getDefaultDbPath;
10
11
  exports.getEnvPath = getEnvPath;
11
12
  exports.resolveSecurePath = resolveSecurePath;
12
- exports.getConfigDir = getConfigDir;
13
+ exports.getPidsDir = getPidsDir;
13
14
  exports.getPidFilePath = getPidFilePath;
14
15
  exports.sanitizeInput = sanitizeInput;
15
16
  exports.sanitizePath = sanitizePath;
@@ -19,14 +20,23 @@ const fs_1 = require("fs");
19
20
  const path_1 = require("path");
20
21
  const crypto_1 = require("crypto");
21
22
  const os_1 = require("os");
23
+ // Issue #136: Import from install-context.ts to avoid circular imports
24
+ // Re-export for backward compatibility
25
+ const install_context_1 = require("./install-context");
26
+ var install_context_2 = require("./install-context");
27
+ Object.defineProperty(exports, "isGlobalInstall", { enumerable: true, get: function () { return install_context_2.isGlobalInstall; } });
28
+ Object.defineProperty(exports, "getConfigDir", { enumerable: true, get: function () { return install_context_2.getConfigDir; } });
22
29
  /**
23
30
  * Default environment configuration values
24
31
  * SF-4: DRY - Centralized defaults
32
+ *
33
+ * Issue #135: CM_DB_PATH removed - use getDefaultDbPath() instead
34
+ * for dynamic path resolution based on install type
25
35
  */
26
36
  exports.ENV_DEFAULTS = {
27
37
  CM_PORT: 3000,
28
38
  CM_BIND: '127.0.0.1',
29
- CM_DB_PATH: './data/cm.db',
39
+ // CM_DB_PATH removed - Issue #135: use getDefaultDbPath() instead
30
40
  CM_LOG_LEVEL: 'info',
31
41
  CM_LOG_FORMAT: 'text',
32
42
  };
@@ -35,38 +45,51 @@ exports.ENV_DEFAULTS = {
35
45
  */
36
46
  exports.DEFAULT_ROOT_DIR = (0, path_1.join)((0, os_1.homedir)(), 'repos');
37
47
  /**
38
- * Check if running as global npm package
39
- * Issue #119: Determine .env location based on install type
48
+ * Get the default database path based on install type
49
+ * Issue #135: Dynamic DB path resolution
50
+ * Issue #136: Uses isGlobalInstall from install-context.ts
51
+ *
52
+ * For global installs: ~/.commandmate/data/cm.db
53
+ * For local installs: <cwd>/data/cm.db (as absolute path)
40
54
  *
41
- * @returns true if running as global npm package
55
+ * @returns Absolute path to the default database file
42
56
  */
43
- function isGlobalInstall() {
44
- // Check if running from global node_modules
45
- // Global installs typically have paths like:
46
- // - /usr/local/lib/node_modules/
47
- // - /Users/xxx/.npm-global/lib/node_modules/
48
- // - C:\Users\xxx\AppData\Roaming\npm\node_modules\
49
- const currentPath = (0, path_1.dirname)(__dirname);
50
- return (currentPath.includes('/lib/node_modules/') ||
51
- currentPath.includes('\\node_modules\\') ||
52
- currentPath.includes('/node_modules/commandmate'));
57
+ function getDefaultDbPath() {
58
+ if ((0, install_context_1.isGlobalInstall)()) {
59
+ return (0, path_1.join)((0, os_1.homedir)(), '.commandmate', 'data', 'cm.db');
60
+ }
61
+ // Use path module for absolute path resolution
62
+ const cwd = process.cwd();
63
+ return (0, path_1.join)(cwd, 'data', 'cm.db');
53
64
  }
54
65
  /**
55
66
  * Get the path to .env file based on install type
56
67
  * Issue #119: Global install uses ~/.commandmate/, local uses cwd
68
+ * Issue #136: Uses isGlobalInstall from install-context.ts
69
+ * Issue #136: Added issueNo parameter for worktree-specific .env files
57
70
  *
71
+ * @param issueNo - Optional issue number for worktree-specific .env
58
72
  * @returns Path to .env file
59
73
  */
60
- function getEnvPath() {
61
- if (isGlobalInstall()) {
74
+ function getEnvPath(issueNo) {
75
+ if ((0, install_context_1.isGlobalInstall)()) {
62
76
  const configDir = (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
63
77
  // Create config directory if it doesn't exist
64
78
  if (!(0, fs_1.existsSync)(configDir)) {
65
79
  (0, fs_1.mkdirSync)(configDir, { recursive: true, mode: 0o700 });
66
80
  }
81
+ // Issue #136: Worktree-specific .env file
82
+ if (issueNo !== undefined) {
83
+ const envsDir = (0, path_1.join)(configDir, 'envs');
84
+ if (!(0, fs_1.existsSync)(envsDir)) {
85
+ (0, fs_1.mkdirSync)(envsDir, { recursive: true, mode: 0o700 });
86
+ }
87
+ return (0, path_1.join)(envsDir, `${issueNo}.env`);
88
+ }
67
89
  return (0, path_1.join)(configDir, '.env');
68
90
  }
69
91
  // Local install - use current working directory
92
+ // Note: Worktree-specific .env not supported in local install mode
70
93
  return (0, path_1.join)(process.cwd(), '.env');
71
94
  }
72
95
  /**
@@ -86,40 +109,38 @@ function resolveSecurePath(targetPath, allowedBaseDir) {
86
109
  }
87
110
  return realPath;
88
111
  }
112
+ // Note: getConfigDir is now exported from install-context.ts
113
+ // The re-export above provides backward compatibility
89
114
  /**
90
- * Get the config directory path
91
- * Issue #119: Returns ~/.commandmate for global, cwd for local
92
- * Issue #125: Added symlink resolution for security (path traversal protection)
115
+ * Get the PIDs directory path
116
+ * Issue #136: Centralized pids directory path resolution
93
117
  *
94
- * @returns Path to config directory (absolute, with symlinks resolved)
118
+ * @returns Path to pids directory
95
119
  */
96
- function getConfigDir() {
97
- if (isGlobalInstall()) {
98
- const configDir = (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
99
- // Verify config directory is within home directory (security check)
100
- // Only validate if the directory exists (it may not exist yet during init)
101
- if ((0, fs_1.existsSync)(configDir)) {
102
- const realPath = (0, fs_1.realpathSync)(configDir);
103
- const realHome = (0, fs_1.realpathSync)((0, os_1.homedir)());
104
- if (!realPath.startsWith(realHome)) {
105
- throw new Error(`Security error: Config directory ${configDir} is outside home directory`);
106
- }
107
- return realPath;
108
- }
109
- return configDir;
110
- }
111
- // Local install - resolve symlinks in cwd
112
- const cwd = process.cwd();
113
- return (0, fs_1.realpathSync)(cwd);
120
+ function getPidsDir() {
121
+ const configDir = (0, install_context_1.getConfigDir)();
122
+ return (0, path_1.join)(configDir, 'pids');
114
123
  }
115
124
  /**
116
125
  * Get the PID file path based on install type
117
126
  * Issue #125: DRY principle - centralized PID file path resolution
127
+ * Issue #136: Uses getConfigDir from install-context.ts
118
128
  *
129
+ * @param issueNo - Optional issue number for worktree-specific PID file
119
130
  * @returns Path to PID file (uses getConfigDir for consistency)
120
131
  */
121
- function getPidFilePath() {
122
- return (0, path_1.join)(getConfigDir(), '.commandmate.pid');
132
+ function getPidFilePath(issueNo) {
133
+ const configDir = (0, install_context_1.getConfigDir)();
134
+ if (issueNo !== undefined) {
135
+ // Issue #136: Worktree-specific PID file in pids/ directory
136
+ const pidsDir = getPidsDir();
137
+ if (!(0, fs_1.existsSync)(pidsDir)) {
138
+ (0, fs_1.mkdirSync)(pidsDir, { recursive: true, mode: 0o700 });
139
+ }
140
+ return (0, path_1.join)(pidsDir, `${issueNo}.pid`);
141
+ }
142
+ // Default: main PID file for backward compatibility
143
+ return (0, path_1.join)(configDir, '.commandmate.pid');
123
144
  }
124
145
  /**
125
146
  * Sanitize input by removing control characters
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Input Validators
3
+ * Issue #136: Phase 1 - Foundation
4
+ *
5
+ * Provides input validation functions for worktree-related operations.
6
+ * These validators are critical for security (command injection prevention).
7
+ *
8
+ * @module input-validators
9
+ */
10
+ /**
11
+ * Maximum allowed issue number (2^31 - 1)
12
+ * NTH-SEC-002: Prevent integer overflow
13
+ */
14
+ export declare const MAX_ISSUE_NO = 2147483647;
15
+ /**
16
+ * Branch name whitelist pattern
17
+ * MF-SEC-001: Only allow safe characters to prevent command injection
18
+ * Allowed: a-z, A-Z, 0-9, underscore, hyphen, forward slash
19
+ */
20
+ export declare const BRANCH_NAME_PATTERN: RegExp;
21
+ /**
22
+ * Maximum branch name length
23
+ * Prevents DoS via overly long input
24
+ */
25
+ export declare const MAX_BRANCH_NAME_LENGTH = 255;
26
+ /**
27
+ * Validate issue number
28
+ * SEC-001: Strict positive integer validation
29
+ *
30
+ * @param issueNo - The issue number to validate
31
+ * @throws Error with code 'INVALID_ISSUE_NO' if not a valid integer
32
+ * @throws Error with code 'ISSUE_NO_OUT_OF_RANGE' if out of range
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * validateIssueNo(135); // OK
37
+ * validateIssueNo('135'); // throws INVALID_ISSUE_NO
38
+ * validateIssueNo(-1); // throws ISSUE_NO_OUT_OF_RANGE
39
+ * ```
40
+ */
41
+ export declare function validateIssueNo(issueNo: unknown): asserts issueNo is number;
42
+ /**
43
+ * Validate branch name
44
+ * MF-SEC-001: Whitelist validation to prevent command injection
45
+ *
46
+ * @param branchName - The branch name to validate
47
+ * @throws Error with code 'INVALID_BRANCH_NAME' if contains invalid characters
48
+ * @throws Error with code 'BRANCH_NAME_TOO_LONG' if exceeds max length
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * validateBranchName('feature/136-worktree'); // OK
53
+ * validateBranchName('feature`rm -rf /`'); // throws INVALID_BRANCH_NAME
54
+ * ```
55
+ */
56
+ export declare function validateBranchName(branchName: string): void;
57
+ /**
58
+ * Validate port number
59
+ * SEC-003: Port validation for worktree servers
60
+ *
61
+ * @param port - The port number to validate
62
+ * @param minPort - Minimum allowed port (default: 1024, non-privileged)
63
+ * @param maxPort - Maximum allowed port (default: 65535)
64
+ * @throws Error with code 'INVALID_PORT' if not a valid port number
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * validatePortNumber(3001); // OK
69
+ * validatePortNumber(80); // throws INVALID_PORT (privileged)
70
+ * ```
71
+ */
72
+ export declare function validatePortNumber(port: unknown, minPort?: number, maxPort?: number): asserts port is number;
73
+ /**
74
+ * Validation result interface for CLI commands
75
+ * Issue #136: Used by CLI commands for user-friendly error messages
76
+ */
77
+ export interface IssueValidationResult {
78
+ valid: boolean;
79
+ error?: string;
80
+ }
81
+ /**
82
+ * Type guard for checking if a value is a valid issue number
83
+ *
84
+ * @param value - Value to check
85
+ * @returns true if value is a valid issue number
86
+ */
87
+ export declare function isValidIssueNo(value: unknown): value is number;
88
+ /**
89
+ * Validate issue number and return result (for CLI commands)
90
+ * Issue #136: CLI-friendly validation that returns result instead of throwing
91
+ *
92
+ * @param issueNo - The issue number to validate
93
+ * @returns Validation result with error message if invalid
94
+ */
95
+ export declare function validateIssueNoResult(issueNo: unknown): IssueValidationResult;
96
+ /**
97
+ * Type guard for checking if a value is a valid branch name
98
+ *
99
+ * @param value - Value to check
100
+ * @returns true if value is a valid branch name
101
+ */
102
+ export declare function isValidBranchName(value: unknown): value is string;
103
+ //# sourceMappingURL=input-validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-validators.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/input-validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAsB,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAY3E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAQ3D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,MAAa,EACtB,OAAO,GAAE,MAAc,GACtB,OAAO,CAAC,IAAI,IAAI,MAAM,CAYxB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAO9D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,qBAAqB,CAe7E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAUjE"}