@skillsmith/core 0.4.14 → 0.4.15

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 (214) hide show
  1. package/README.md +2 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/api/client.d.ts +1 -0
  4. package/dist/src/api/client.d.ts.map +1 -1
  5. package/dist/src/api/client.health.d.ts +26 -0
  6. package/dist/src/api/client.health.d.ts.map +1 -0
  7. package/dist/src/api/client.health.js +74 -0
  8. package/dist/src/api/client.health.js.map +1 -0
  9. package/dist/src/api/client.js +3 -51
  10. package/dist/src/api/client.js.map +1 -1
  11. package/dist/src/db/createDatabase.d.ts +9 -1
  12. package/dist/src/db/createDatabase.d.ts.map +1 -1
  13. package/dist/src/db/createDatabase.js +9 -1
  14. package/dist/src/db/createDatabase.js.map +1 -1
  15. package/dist/src/db/drivers/sqljsDriver.d.ts.map +1 -1
  16. package/dist/src/db/drivers/sqljsDriver.js +5 -2
  17. package/dist/src/db/drivers/sqljsDriver.js.map +1 -1
  18. package/dist/src/db/migrations/v5b-change-type.d.ts +19 -0
  19. package/dist/src/db/migrations/v5b-change-type.d.ts.map +1 -0
  20. package/dist/src/db/migrations/v5b-change-type.js +22 -0
  21. package/dist/src/db/migrations/v5b-change-type.js.map +1 -0
  22. package/dist/src/db/migrations/v6-advisories.d.ts +32 -0
  23. package/dist/src/db/migrations/v6-advisories.d.ts.map +1 -0
  24. package/dist/src/db/migrations/v6-advisories.js +53 -0
  25. package/dist/src/db/migrations/v6-advisories.js.map +1 -0
  26. package/dist/src/db/migrations/v7-compatibility.d.ts +21 -0
  27. package/dist/src/db/migrations/v7-compatibility.d.ts.map +1 -0
  28. package/dist/src/db/migrations/v7-compatibility.js +23 -0
  29. package/dist/src/db/migrations/v7-compatibility.js.map +1 -0
  30. package/dist/src/db/migrations/v8-co-installs.d.ts +21 -0
  31. package/dist/src/db/migrations/v8-co-installs.d.ts.map +1 -0
  32. package/dist/src/db/migrations/v8-co-installs.js +33 -0
  33. package/dist/src/db/migrations/v8-co-installs.js.map +1 -0
  34. package/dist/src/db/schema.d.ts +5 -16
  35. package/dist/src/db/schema.d.ts.map +1 -1
  36. package/dist/src/db/schema.js +37 -22
  37. package/dist/src/db/schema.js.map +1 -1
  38. package/dist/src/exports/repositories.d.ts +5 -0
  39. package/dist/src/exports/repositories.d.ts.map +1 -1
  40. package/dist/src/exports/repositories.js +17 -0
  41. package/dist/src/exports/repositories.js.map +1 -1
  42. package/dist/src/exports/types.d.ts +1 -1
  43. package/dist/src/exports/types.d.ts.map +1 -1
  44. package/dist/src/exports/types.js.map +1 -1
  45. package/dist/src/indexer/SkillParser.d.ts +2 -0
  46. package/dist/src/indexer/SkillParser.d.ts.map +1 -1
  47. package/dist/src/indexer/SkillParser.js.map +1 -1
  48. package/dist/src/learning/PatternStore.d.ts +0 -2
  49. package/dist/src/learning/PatternStore.d.ts.map +1 -1
  50. package/dist/src/learning/PatternStore.helpers.d.ts +19 -1
  51. package/dist/src/learning/PatternStore.helpers.d.ts.map +1 -1
  52. package/dist/src/learning/PatternStore.helpers.js +51 -0
  53. package/dist/src/learning/PatternStore.helpers.js.map +1 -1
  54. package/dist/src/learning/PatternStore.js +5 -37
  55. package/dist/src/learning/PatternStore.js.map +1 -1
  56. package/dist/src/repositories/AdvisoryRepository.d.ts +80 -0
  57. package/dist/src/repositories/AdvisoryRepository.d.ts.map +1 -0
  58. package/dist/src/repositories/AdvisoryRepository.js +128 -0
  59. package/dist/src/repositories/AdvisoryRepository.js.map +1 -0
  60. package/dist/src/repositories/AdvisoryRepository.test.d.ts +6 -0
  61. package/dist/src/repositories/AdvisoryRepository.test.d.ts.map +1 -0
  62. package/dist/src/repositories/AdvisoryRepository.test.js +149 -0
  63. package/dist/src/repositories/AdvisoryRepository.test.js.map +1 -0
  64. package/dist/src/repositories/CoInstallRepository.d.ts +68 -0
  65. package/dist/src/repositories/CoInstallRepository.d.ts.map +1 -0
  66. package/dist/src/repositories/CoInstallRepository.js +122 -0
  67. package/dist/src/repositories/CoInstallRepository.js.map +1 -0
  68. package/dist/src/repositories/SkillRepository.d.ts.map +1 -1
  69. package/dist/src/repositories/SkillRepository.js +16 -5
  70. package/dist/src/repositories/SkillRepository.js.map +1 -1
  71. package/dist/src/services/SearchService.helpers.d.ts.map +1 -1
  72. package/dist/src/services/SearchService.helpers.js +4 -0
  73. package/dist/src/services/SearchService.helpers.js.map +1 -1
  74. package/dist/src/services/SearchService.types.d.ts +1 -0
  75. package/dist/src/services/SearchService.types.d.ts.map +1 -1
  76. package/dist/src/services/TaskRunner.d.ts +5 -81
  77. package/dist/src/services/TaskRunner.d.ts.map +1 -1
  78. package/dist/src/services/TaskRunner.js +7 -68
  79. package/dist/src/services/TaskRunner.js.map +1 -1
  80. package/dist/src/services/TaskRunner.process.d.ts +33 -0
  81. package/dist/src/services/TaskRunner.process.d.ts.map +1 -0
  82. package/dist/src/services/TaskRunner.process.js +70 -0
  83. package/dist/src/services/TaskRunner.process.js.map +1 -0
  84. package/dist/src/services/TaskRunner.types.d.ts +76 -0
  85. package/dist/src/services/TaskRunner.types.d.ts.map +1 -0
  86. package/dist/src/services/TaskRunner.types.js +22 -0
  87. package/dist/src/services/TaskRunner.types.js.map +1 -0
  88. package/dist/src/services/__tests__/TaskRunner.process.test.d.ts +13 -0
  89. package/dist/src/services/__tests__/TaskRunner.process.test.d.ts.map +1 -0
  90. package/dist/src/services/__tests__/TaskRunner.process.test.js +91 -0
  91. package/dist/src/services/__tests__/TaskRunner.process.test.js.map +1 -0
  92. package/dist/src/services/quarantine/QuarantineService.d.ts +3 -24
  93. package/dist/src/services/quarantine/QuarantineService.d.ts.map +1 -1
  94. package/dist/src/services/quarantine/QuarantineService.js +8 -205
  95. package/dist/src/services/quarantine/QuarantineService.js.map +1 -1
  96. package/dist/src/services/quarantine/QuarantineService.multiapproval.d.ts +57 -0
  97. package/dist/src/services/quarantine/QuarantineService.multiapproval.d.ts.map +1 -0
  98. package/dist/src/services/quarantine/QuarantineService.multiapproval.js +211 -0
  99. package/dist/src/services/quarantine/QuarantineService.multiapproval.js.map +1 -0
  100. package/dist/src/session/SessionManager.d.ts +2 -33
  101. package/dist/src/session/SessionManager.d.ts.map +1 -1
  102. package/dist/src/session/SessionManager.js +14 -238
  103. package/dist/src/session/SessionManager.js.map +1 -1
  104. package/dist/src/session/SessionManager.memory.d.ts +67 -0
  105. package/dist/src/session/SessionManager.memory.d.ts.map +1 -0
  106. package/dist/src/session/SessionManager.memory.js +262 -0
  107. package/dist/src/session/SessionManager.memory.js.map +1 -0
  108. package/dist/src/sync/SyncEngine.d.ts +13 -1
  109. package/dist/src/sync/SyncEngine.d.ts.map +1 -1
  110. package/dist/src/sync/SyncEngine.js +50 -1
  111. package/dist/src/sync/SyncEngine.js.map +1 -1
  112. package/dist/src/testing/MultiLLMProvider.d.ts +5 -6
  113. package/dist/src/testing/MultiLLMProvider.d.ts.map +1 -1
  114. package/dist/src/testing/MultiLLMProvider.js +18 -130
  115. package/dist/src/testing/MultiLLMProvider.js.map +1 -1
  116. package/dist/src/testing/MultiLLMProvider.metrics.d.ts +33 -0
  117. package/dist/src/testing/MultiLLMProvider.metrics.d.ts.map +1 -0
  118. package/dist/src/testing/MultiLLMProvider.metrics.js +87 -0
  119. package/dist/src/testing/MultiLLMProvider.metrics.js.map +1 -0
  120. package/dist/src/testing/MultiLLMProvider.selection.d.ts +77 -0
  121. package/dist/src/testing/MultiLLMProvider.selection.d.ts.map +1 -0
  122. package/dist/src/testing/MultiLLMProvider.selection.js +151 -0
  123. package/dist/src/testing/MultiLLMProvider.selection.js.map +1 -0
  124. package/dist/src/types/skill.d.ts +10 -0
  125. package/dist/src/types/skill.d.ts.map +1 -1
  126. package/dist/src/types.d.ts +30 -0
  127. package/dist/src/types.d.ts.map +1 -1
  128. package/dist/src/versioning/change-classifier.d.ts +38 -0
  129. package/dist/src/versioning/change-classifier.d.ts.map +1 -0
  130. package/dist/src/versioning/change-classifier.js +187 -0
  131. package/dist/src/versioning/change-classifier.js.map +1 -0
  132. package/dist/src/versioning/change-classifier.test.d.ts +6 -0
  133. package/dist/src/versioning/change-classifier.test.d.ts.map +1 -0
  134. package/dist/src/versioning/change-classifier.test.js +275 -0
  135. package/dist/src/versioning/change-classifier.test.js.map +1 -0
  136. package/dist/src/versioning/update-risk.d.ts +50 -0
  137. package/dist/src/versioning/update-risk.d.ts.map +1 -0
  138. package/dist/src/versioning/update-risk.js +80 -0
  139. package/dist/src/versioning/update-risk.js.map +1 -0
  140. package/dist/src/versioning/update-risk.test.d.ts +6 -0
  141. package/dist/src/versioning/update-risk.test.d.ts.map +1 -0
  142. package/dist/src/versioning/update-risk.test.js +200 -0
  143. package/dist/src/versioning/update-risk.test.js.map +1 -0
  144. package/dist/tests/AuditLogger.edge-cases.test.d.ts +10 -0
  145. package/dist/tests/AuditLogger.edge-cases.test.d.ts.map +1 -0
  146. package/dist/tests/AuditLogger.edge-cases.test.js +183 -0
  147. package/dist/tests/AuditLogger.edge-cases.test.js.map +1 -0
  148. package/dist/tests/CacheManager.test.d.ts +9 -0
  149. package/dist/tests/CacheManager.test.d.ts.map +1 -0
  150. package/dist/tests/CacheManager.test.js +163 -0
  151. package/dist/tests/CacheManager.test.js.map +1 -0
  152. package/dist/tests/GitHubIndexer.edge-cases.test.d.ts +10 -0
  153. package/dist/tests/GitHubIndexer.edge-cases.test.d.ts.map +1 -0
  154. package/dist/tests/GitHubIndexer.edge-cases.test.js +255 -0
  155. package/dist/tests/GitHubIndexer.edge-cases.test.js.map +1 -0
  156. package/dist/tests/SearchService.test.js +71 -0
  157. package/dist/tests/SearchService.test.js.map +1 -1
  158. package/dist/tests/SkillVersionRepository.test.d.ts +0 -11
  159. package/dist/tests/SkillVersionRepository.test.d.ts.map +1 -1
  160. package/dist/tests/SkillVersionRepository.test.js +131 -194
  161. package/dist/tests/SkillVersionRepository.test.js.map +1 -1
  162. package/dist/tests/api/client.health.test.d.ts +15 -0
  163. package/dist/tests/api/client.health.test.d.ts.map +1 -0
  164. package/dist/tests/api/client.health.test.js +111 -0
  165. package/dist/tests/api/client.health.test.js.map +1 -0
  166. package/dist/tests/db/betterSqlite3Driver.test.d.ts +8 -0
  167. package/dist/tests/db/betterSqlite3Driver.test.d.ts.map +1 -0
  168. package/dist/tests/db/betterSqlite3Driver.test.js +88 -0
  169. package/dist/tests/db/betterSqlite3Driver.test.js.map +1 -0
  170. package/dist/tests/db/database-abstraction.test.js +12 -0
  171. package/dist/tests/db/database-abstraction.test.js.map +1 -1
  172. package/dist/tests/db/schema-migrations.test.d.ts +10 -0
  173. package/dist/tests/db/schema-migrations.test.d.ts.map +1 -0
  174. package/dist/tests/db/schema-migrations.test.js +134 -0
  175. package/dist/tests/db/schema-migrations.test.js.map +1 -0
  176. package/dist/tests/db/sqljsDriver.test.d.ts +9 -0
  177. package/dist/tests/db/sqljsDriver.test.d.ts.map +1 -0
  178. package/dist/tests/db/sqljsDriver.test.js +75 -0
  179. package/dist/tests/db/sqljsDriver.test.js.map +1 -0
  180. package/dist/tests/helpers/database.d.ts +32 -0
  181. package/dist/tests/helpers/database.d.ts.map +1 -0
  182. package/dist/tests/helpers/database.js +54 -0
  183. package/dist/tests/helpers/database.js.map +1 -0
  184. package/dist/tests/learning/PatternStore.helpers.test.d.ts +17 -0
  185. package/dist/tests/learning/PatternStore.helpers.test.d.ts.map +1 -0
  186. package/dist/tests/learning/PatternStore.helpers.test.js +301 -0
  187. package/dist/tests/learning/PatternStore.helpers.test.js.map +1 -0
  188. package/dist/tests/repositories/CoInstallRepository.test.d.ts +9 -0
  189. package/dist/tests/repositories/CoInstallRepository.test.d.ts.map +1 -0
  190. package/dist/tests/repositories/CoInstallRepository.test.js +126 -0
  191. package/dist/tests/repositories/CoInstallRepository.test.js.map +1 -0
  192. package/dist/tests/routing/LanguageRouter.test.d.ts +9 -0
  193. package/dist/tests/routing/LanguageRouter.test.d.ts.map +1 -0
  194. package/dist/tests/routing/LanguageRouter.test.js +150 -0
  195. package/dist/tests/routing/LanguageRouter.test.js.map +1 -0
  196. package/dist/tests/session/SessionManager.memory.test.d.ts +11 -0
  197. package/dist/tests/session/SessionManager.memory.test.d.ts.map +1 -0
  198. package/dist/tests/session/SessionManager.memory.test.js +219 -0
  199. package/dist/tests/session/SessionManager.memory.test.js.map +1 -0
  200. package/dist/tests/sync/SyncEngine.test.js +32 -18
  201. package/dist/tests/sync/SyncEngine.test.js.map +1 -1
  202. package/dist/tests/testing/MultiLLMProvider.metrics.test.d.ts +13 -0
  203. package/dist/tests/testing/MultiLLMProvider.metrics.test.d.ts.map +1 -0
  204. package/dist/tests/testing/MultiLLMProvider.metrics.test.js +149 -0
  205. package/dist/tests/testing/MultiLLMProvider.metrics.test.js.map +1 -0
  206. package/dist/tests/testing/MultiLLMProvider.selection.test.d.ts +15 -0
  207. package/dist/tests/testing/MultiLLMProvider.selection.test.d.ts.map +1 -0
  208. package/dist/tests/testing/MultiLLMProvider.selection.test.js +249 -0
  209. package/dist/tests/testing/MultiLLMProvider.selection.test.js.map +1 -0
  210. package/dist/tests/unit/quarantine-query-builder.test.d.ts +10 -0
  211. package/dist/tests/unit/quarantine-query-builder.test.d.ts.map +1 -0
  212. package/dist/tests/unit/quarantine-query-builder.test.js +157 -0
  213. package/dist/tests/unit/quarantine-query-builder.test.js.map +1 -0
  214. package/package.json +1 -1
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Multi-Approval Workflow for MALICIOUS Severity Quarantine
3
+ * @module @skillsmith/core/services/quarantine/QuarantineService.multiapproval
4
+ * @see SMI-2277: Persist multi-approval state to database
5
+ * @see SMI-2741: Split from QuarantineService.ts to meet 500-line standard
6
+ *
7
+ * Handles the multi-approval workflow required for MALICIOUS severity skills.
8
+ * MALICIOUS severity requires multiple independent reviewers to approve before
9
+ * a skill can be unquarantined, preventing single-reviewer compromise.
10
+ */
11
+ import type { QuarantineRepository } from '../../repositories/quarantine/index.js';
12
+ import type { ApprovalRepository } from '../../repositories/quarantine/ApprovalRepository.js';
13
+ import type { AuditLogger } from '../../security/AuditLogger.js';
14
+ import type { AuthenticatedSession, AuthenticatedReviewInput, AuthenticatedReviewResult, MultiApprovalStatus } from './types.js';
15
+ /**
16
+ * Number of approvals required for MALICIOUS severity reviews
17
+ */
18
+ export declare const MALICIOUS_APPROVAL_COUNT = 2;
19
+ /**
20
+ * Multi-approval timeout in milliseconds (24 hours)
21
+ */
22
+ export declare const MULTI_APPROVAL_TIMEOUT_MS: number;
23
+ /**
24
+ * Handle approval for MALICIOUS severity skills
25
+ *
26
+ * MALICIOUS severity requires multiple reviewers to approve
27
+ * before a skill can be unquarantined. This prevents single
28
+ * reviewer compromise from allowing malicious skills.
29
+ *
30
+ * Approval state is persisted to the database (SMI-2277) so
31
+ * pending approvals survive service restarts.
32
+ *
33
+ * @param session - Authenticated session
34
+ * @param quarantineId - Quarantine entry ID
35
+ * @param skillId - Skill ID
36
+ * @param input - Review input
37
+ * @param repository - Quarantine repository
38
+ * @param approvalRepository - Approval repository
39
+ * @param auditLogger - Audit logger
40
+ * @returns Review result with multi-approval status
41
+ */
42
+ export declare function handleMaliciousApproval(session: AuthenticatedSession, quarantineId: string, skillId: string, input: AuthenticatedReviewInput, repository: QuarantineRepository, approvalRepository: ApprovalRepository, auditLogger: AuditLogger): AuthenticatedReviewResult;
43
+ /**
44
+ * Build a MultiApprovalStatus from database rows
45
+ *
46
+ * Converts persisted approval entries into the MultiApprovalStatus
47
+ * interface expected by consumers.
48
+ */
49
+ export declare function buildMultiApprovalStatus(quarantineId: string, approvals: Array<{
50
+ reviewerId: string;
51
+ reviewerEmail: string;
52
+ createdAt: string;
53
+ completedAt: string | null;
54
+ reason: string | null;
55
+ isComplete: boolean;
56
+ }>): MultiApprovalStatus;
57
+ //# sourceMappingURL=QuarantineService.multiapproval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuarantineService.multiapproval.d.ts","sourceRoot":"","sources":["../../../../src/services/quarantine/QuarantineService.multiapproval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAA;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAA;AAC7F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,mBAAmB,EAEpB,MAAM,YAAY,CAAA;AAGnB;;GAEG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAsB,CAAA;AAE5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,oBAAoB,EAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,wBAAwB,EAC/B,UAAU,EAAE,oBAAoB,EAChC,kBAAkB,EAAE,kBAAkB,EACtC,WAAW,EAAE,WAAW,GACvB,yBAAyB,CAoK3B;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,KAAK,CAAC;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAC,GACD,mBAAmB,CAoBrB"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @fileoverview Multi-Approval Workflow for MALICIOUS Severity Quarantine
3
+ * @module @skillsmith/core/services/quarantine/QuarantineService.multiapproval
4
+ * @see SMI-2277: Persist multi-approval state to database
5
+ * @see SMI-2741: Split from QuarantineService.ts to meet 500-line standard
6
+ *
7
+ * Handles the multi-approval workflow required for MALICIOUS severity skills.
8
+ * MALICIOUS severity requires multiple independent reviewers to approve before
9
+ * a skill can be unquarantined, preventing single-reviewer compromise.
10
+ */
11
+ import { QuarantineServiceError, requirePermission } from './types.js';
12
+ /**
13
+ * Number of approvals required for MALICIOUS severity reviews
14
+ */
15
+ export const MALICIOUS_APPROVAL_COUNT = 2;
16
+ /**
17
+ * Multi-approval timeout in milliseconds (24 hours)
18
+ */
19
+ export const MULTI_APPROVAL_TIMEOUT_MS = 24 * 60 * 60 * 1000;
20
+ /**
21
+ * Handle approval for MALICIOUS severity skills
22
+ *
23
+ * MALICIOUS severity requires multiple reviewers to approve
24
+ * before a skill can be unquarantined. This prevents single
25
+ * reviewer compromise from allowing malicious skills.
26
+ *
27
+ * Approval state is persisted to the database (SMI-2277) so
28
+ * pending approvals survive service restarts.
29
+ *
30
+ * @param session - Authenticated session
31
+ * @param quarantineId - Quarantine entry ID
32
+ * @param skillId - Skill ID
33
+ * @param input - Review input
34
+ * @param repository - Quarantine repository
35
+ * @param approvalRepository - Approval repository
36
+ * @param auditLogger - Audit logger
37
+ * @returns Review result with multi-approval status
38
+ */
39
+ export function handleMaliciousApproval(session, quarantineId, skillId, input, repository, approvalRepository, auditLogger) {
40
+ // Require elevated permission for MALICIOUS review
41
+ requirePermission(session, 'quarantine:review_malicious');
42
+ // Check if this reviewer already approved (database-backed)
43
+ if (approvalRepository.hasReviewerApproved(quarantineId, session.userId)) {
44
+ // Retrieve existing approval for error details
45
+ const existingApprovals = approvalRepository.getPendingApprovals(quarantineId);
46
+ const existing = existingApprovals.find((a) => a.reviewerId === session.userId);
47
+ throw new QuarantineServiceError('You have already approved this entry', 'ALREADY_REVIEWED', {
48
+ quarantineId,
49
+ previousApprovalAt: existing?.createdAt ?? 'unknown',
50
+ });
51
+ }
52
+ // Check for approval timeout
53
+ const startTime = approvalRepository.getWorkflowStartTime(quarantineId);
54
+ if (startTime) {
55
+ const timeSinceStart = Date.now() - new Date(startTime).getTime();
56
+ if (timeSinceStart > MULTI_APPROVAL_TIMEOUT_MS) {
57
+ // Capture existing approvals before clearing for audit
58
+ const expiredApprovals = approvalRepository.getPendingApprovals(quarantineId);
59
+ // Reset approval workflow
60
+ approvalRepository.clearApprovals(quarantineId);
61
+ // Log timeout event so cleared reviewer work is auditable
62
+ auditLogger.log({
63
+ event_type: 'quarantine_multi_approval_timeout',
64
+ actor: 'system',
65
+ resource: skillId,
66
+ action: 'timeout',
67
+ result: 'success',
68
+ metadata: {
69
+ quarantineId,
70
+ timeoutMs: MULTI_APPROVAL_TIMEOUT_MS,
71
+ expiredApprovals: expiredApprovals.map((a) => ({
72
+ reviewerId: a.reviewerId,
73
+ email: a.reviewerEmail,
74
+ approvedAt: a.createdAt,
75
+ })),
76
+ triggeredBy: {
77
+ userId: session.userId,
78
+ email: session.email,
79
+ },
80
+ },
81
+ });
82
+ throw new QuarantineServiceError('Multi-approval workflow timed out. Please start again.', 'INVALID_INPUT', { quarantineId, timeoutMs: MULTI_APPROVAL_TIMEOUT_MS });
83
+ }
84
+ }
85
+ // Record this approval in the database
86
+ approvalRepository.recordApproval({
87
+ skillId: quarantineId,
88
+ reviewerId: session.userId,
89
+ reviewerEmail: session.email,
90
+ decision: 'approved',
91
+ reason: input.reviewNotes,
92
+ requiredApprovals: MALICIOUS_APPROVAL_COUNT,
93
+ });
94
+ // Get current approval count and all pending approvals
95
+ const pendingApprovals = approvalRepository.getPendingApprovals(quarantineId);
96
+ const approvalCount = pendingApprovals.filter((a) => a.decision === 'approved').length;
97
+ // Build the multi-approval status from database state
98
+ const approvalStatus = buildMultiApprovalStatus(quarantineId, pendingApprovals);
99
+ // Log the approval
100
+ auditLogger.log({
101
+ event_type: 'quarantine_multi_approval',
102
+ actor: 'reviewer',
103
+ resource: skillId,
104
+ action: 'approve',
105
+ result: 'success',
106
+ metadata: {
107
+ quarantineId,
108
+ approvalNumber: approvalCount,
109
+ requiredApprovals: MALICIOUS_APPROVAL_COUNT,
110
+ reviewer: {
111
+ userId: session.userId,
112
+ email: session.email,
113
+ },
114
+ },
115
+ });
116
+ // Check if we have enough approvals
117
+ if (approvalCount >= MALICIOUS_APPROVAL_COUNT) {
118
+ // Mark approvals as complete in database
119
+ approvalRepository.markComplete(quarantineId);
120
+ approvalStatus.isComplete = true;
121
+ approvalStatus.completedAt = new Date();
122
+ // Perform the actual review
123
+ const approverEmails = pendingApprovals
124
+ .filter((a) => a.decision === 'approved')
125
+ .map((a) => a.reviewerEmail);
126
+ const reviewResult = repository.review(quarantineId, {
127
+ reviewedBy: approverEmails.join(', '),
128
+ reviewStatus: 'approved',
129
+ reviewNotes: `Multi-approval complete: ${approvalCount} reviewers approved. ${input.reviewNotes || ''}`,
130
+ });
131
+ // Log completion
132
+ auditLogger.log({
133
+ event_type: 'quarantine_multi_approval_complete',
134
+ actor: 'reviewer',
135
+ resource: skillId,
136
+ action: 'complete',
137
+ result: 'success',
138
+ metadata: {
139
+ quarantineId,
140
+ approvals: pendingApprovals
141
+ .filter((a) => a.decision === 'approved')
142
+ .map((a) => ({
143
+ reviewerId: a.reviewerId,
144
+ email: a.reviewerEmail,
145
+ approvedAt: a.createdAt,
146
+ })),
147
+ },
148
+ });
149
+ return {
150
+ success: true,
151
+ approved: true,
152
+ skillId,
153
+ severity: 'MALICIOUS',
154
+ canImport: reviewResult?.canImport ?? false,
155
+ warnings: [
156
+ 'MALICIOUS skill approved through multi-approval workflow',
157
+ `Approved by: ${approverEmails.join(', ')}`,
158
+ ],
159
+ reviewedBy: {
160
+ userId: session.userId,
161
+ email: session.email,
162
+ displayName: session.displayName,
163
+ },
164
+ multiApprovalStatus: approvalStatus,
165
+ };
166
+ }
167
+ // Need more approvals
168
+ return {
169
+ success: true,
170
+ approved: false,
171
+ skillId,
172
+ severity: 'MALICIOUS',
173
+ canImport: false,
174
+ warnings: [
175
+ `Multi-approval in progress: ${approvalCount}/${MALICIOUS_APPROVAL_COUNT} approvals received`,
176
+ `Requires ${MALICIOUS_APPROVAL_COUNT - approvalCount} more approval(s)`,
177
+ ],
178
+ reviewedBy: {
179
+ userId: session.userId,
180
+ email: session.email,
181
+ displayName: session.displayName,
182
+ },
183
+ multiApprovalStatus: approvalStatus,
184
+ };
185
+ }
186
+ /**
187
+ * Build a MultiApprovalStatus from database rows
188
+ *
189
+ * Converts persisted approval entries into the MultiApprovalStatus
190
+ * interface expected by consumers.
191
+ */
192
+ export function buildMultiApprovalStatus(quarantineId, approvals) {
193
+ const currentApprovals = approvals.map((a) => ({
194
+ reviewerId: a.reviewerId,
195
+ reviewerEmail: a.reviewerEmail,
196
+ approvedAt: new Date(a.createdAt),
197
+ notes: a.reason ?? undefined,
198
+ }));
199
+ const startedAt = approvals.length > 0 ? new Date(approvals[0].createdAt) : new Date();
200
+ const isComplete = approvals.some((a) => a.isComplete);
201
+ const completedEntry = approvals.find((a) => a.completedAt);
202
+ return {
203
+ quarantineId,
204
+ requiredApprovals: MALICIOUS_APPROVAL_COUNT,
205
+ currentApprovals,
206
+ isComplete,
207
+ startedAt,
208
+ completedAt: completedEntry ? new Date(completedEntry.completedAt) : undefined,
209
+ };
210
+ }
211
+ //# sourceMappingURL=QuarantineService.multiapproval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuarantineService.multiapproval.js","sourceRoot":"","sources":["../../../../src/services/quarantine/QuarantineService.multiapproval.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  * Session Manager for Claude-Flow Memory Integration
3
3
  * SMI-641: Session ID Storage in Claude-Flow Memory
4
4
  * SMI-1518: V3 API Migration - Use direct API calls instead of spawn
5
+ * SMI-2741: Split to meet 500-line standard
5
6
  *
6
7
  * Manages session lifecycle with persistent storage in claude-flow memory
7
8
  * to enable context restoration across sessions.
@@ -10,6 +11,7 @@ import type { SessionData, Checkpoint } from './SessionContext.js';
10
11
  import type { CommandExecutor, SessionOptions } from './SessionManager.types.js';
11
12
  export type { CommandExecutor, MemoryResult, SessionOptions } from './SessionManager.types.js';
12
13
  export { DefaultCommandExecutor } from './SessionManager.helpers.js';
14
+ export { storeMemoryEntry, retrieveMemoryEntry, deleteMemoryEntry, runPreTaskHook, runPostTaskHook, } from './SessionManager.memory.js';
13
15
  /**
14
16
  * Session Manager for claude-flow memory integration
15
17
  *
@@ -85,38 +87,5 @@ export declare class SessionManager {
85
87
  * Clear the current session pointer
86
88
  */
87
89
  private clearCurrentSession;
88
- /**
89
- * Store data in claude-flow memory
90
- *
91
- * SMI-674: Uses spawn() with argument array to prevent command injection
92
- * SMI-1518: V3 API Migration - Use direct storeEntry() when available
93
- */
94
- private storeMemory;
95
- /**
96
- * Retrieve data from claude-flow memory
97
- *
98
- * SMI-674: Uses spawn() with argument array to prevent command injection
99
- * SMI-1518: V3 API Migration - Use direct getEntry() when available
100
- */
101
- private retrieveMemory;
102
- /**
103
- * Delete data from claude-flow memory
104
- *
105
- * SMI-674: Uses spawn() with argument array to prevent command injection
106
- * SMI-1518: V3 API Migration - Use callMCPTool('memory/delete') when available
107
- */
108
- private deleteMemory;
109
- /**
110
- * Run pre-task hook
111
- * SMI-674: Uses spawn() with argument array to prevent command injection
112
- * SMI-1518: V3 API Migration - Use callMCPTool('hooks/pre-task') when available
113
- */
114
- private runPreTaskHook;
115
- /**
116
- * Run post-task hook
117
- * SMI-674: Uses spawn() with argument array to prevent command injection
118
- * SMI-1518: V3 API Migration - Use callMCPTool('hooks/post-task') when available
119
- */
120
- private runPostTaskHook;
121
90
  }
122
91
  //# sourceMappingURL=SessionManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../../src/session/SessionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAGlE,OAAO,KAAK,EAAE,eAAe,EAAgB,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAe9F,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAEpE;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,cAAc,CAA2B;IAEjD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAmC;gBAE1C,QAAQ,CAAC,EAAE,eAAe;IAItC;;;OAGG;YACW,QAAQ;IAiBtB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACG,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BtE;;;;;OAKG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoDhE;;;OAGG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAezD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC;;OAEG;IACH,iBAAiB,IAAI,WAAW,GAAG,IAAI;IAIvC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAehE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAenD;;OAEG;YACW,YAAY;IAM1B;;OAEG;YACW,iBAAiB;IAI/B;;OAEG;YACW,mBAAmB;IAIjC;;;;;OAKG;YACW,WAAW;IA4CzB;;;;;OAKG;YACW,cAAc;IAgD5B;;;;;OAKG;YACW,YAAY;IA4C1B;;;;OAIG;YACW,cAAc;IAwC5B;;;;OAIG;YACW,eAAe;CA6B9B"}
1
+ {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../../src/session/SessionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAGlE,OAAO,KAAK,EAAE,eAAe,EAAgB,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAgB9F,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,4BAA4B,CAAA;AAEnC;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,cAAc,CAA2B;IAEjD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAmC;gBAE1C,QAAQ,CAAC,EAAE,eAAe;IAItC;;;OAGG;YACW,QAAQ;IAiBtB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACG,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BtE;;;;;OAKG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqDhE;;;OAGG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAezD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC;;OAEG;IACH,iBAAiB,IAAI,WAAW,GAAG,IAAI;IAIvC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAehE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAenD;;OAEG;YACW,YAAY;IAM1B;;OAEG;YACW,iBAAiB;IAI/B;;OAEG;YACW,mBAAmB;CAGlC"}
@@ -2,6 +2,7 @@
2
2
  * Session Manager for Claude-Flow Memory Integration
3
3
  * SMI-641: Session ID Storage in Claude-Flow Memory
4
4
  * SMI-1518: V3 API Migration - Use direct API calls instead of spawn
5
+ * SMI-2741: Split to meet 500-line standard
5
6
  *
6
7
  * Manages session lifecycle with persistent storage in claude-flow memory
7
8
  * to enable context restoration across sessions.
@@ -9,8 +10,11 @@
9
10
  import { randomUUID } from 'node:crypto';
10
11
  import { sanitizeSessionData } from './SessionManager.types.js';
11
12
  // Import helpers
12
- import { getClaudeFlowMemory, getClaudeFlowMcp, MEMORY_KEYS, USE_V3_API, MEMORY_NAMESPACE, validateMemoryKey, DefaultCommandExecutor, } from './SessionManager.helpers.js';
13
+ import { MEMORY_KEYS, DefaultCommandExecutor } from './SessionManager.helpers.js';
14
+ // SMI-2741: Memory and hook operations extracted to companion file
15
+ import { storeMemoryEntry, retrieveMemoryEntry, deleteMemoryEntry, runPreTaskHook, runPostTaskHook, } from './SessionManager.memory.js';
13
16
  export { DefaultCommandExecutor } from './SessionManager.helpers.js';
17
+ export { storeMemoryEntry, retrieveMemoryEntry, deleteMemoryEntry, runPreTaskHook, runPostTaskHook, } from './SessionManager.memory.js';
14
18
  /**
15
19
  * Session Manager for claude-flow memory integration
16
20
  *
@@ -80,7 +84,7 @@ export class SessionManager {
80
84
  await this.setCurrentSession(sessionId);
81
85
  // Run pre-task hook if description provided
82
86
  if (options.description) {
83
- await this.runPreTaskHook(options.description);
87
+ await runPreTaskHook(options.description, this.executor);
84
88
  }
85
89
  this.currentSession = session;
86
90
  return session;
@@ -103,7 +107,7 @@ export class SessionManager {
103
107
  memoryKey: `${MEMORY_KEYS.CHECKPOINT_PREFIX}${this.currentSession.sessionId}/${Date.now()}`,
104
108
  };
105
109
  // SMI-676: Store checkpoint data FIRST (before updating session)
106
- const checkpointResult = await this.storeMemory(checkpoint.memoryKey, JSON.stringify(checkpoint));
110
+ const checkpointResult = await storeMemoryEntry(checkpoint.memoryKey, JSON.stringify(checkpoint), this.executor);
107
111
  if (!checkpointResult.success) {
108
112
  throw new Error(`Failed to store checkpoint: ${checkpointResult.error}`);
109
113
  }
@@ -125,7 +129,7 @@ export class SessionManager {
125
129
  this.currentSession.checkpoints = previousCheckpoints;
126
130
  this.currentSession.lastActivity = previousLastActivity;
127
131
  // Clean up the checkpoint from memory
128
- await this.deleteMemory(checkpoint.memoryKey);
132
+ await deleteMemoryEntry(checkpoint.memoryKey, this.executor);
129
133
  throw err;
130
134
  }
131
135
  return checkpoint;
@@ -158,7 +162,7 @@ export class SessionManager {
158
162
  this.currentSession.lastActivity = new Date().toISOString();
159
163
  await this.storeSession(this.currentSession);
160
164
  // Run post-task hook
161
- await this.runPostTaskHook(this.currentSession.sessionId);
165
+ await runPostTaskHook(this.currentSession.sessionId, this.executor);
162
166
  // Clear current session pointer
163
167
  await this.clearCurrentSession();
164
168
  this.currentSession = null;
@@ -174,7 +178,7 @@ export class SessionManager {
174
178
  */
175
179
  async getSession(sessionId) {
176
180
  const memoryKey = `${MEMORY_KEYS.SESSION_PREFIX}${sessionId}`;
177
- const result = await this.retrieveMemory(memoryKey);
181
+ const result = await retrieveMemoryEntry(memoryKey, this.executor);
178
182
  if (!result.success || !result.data) {
179
183
  return null;
180
184
  }
@@ -189,7 +193,7 @@ export class SessionManager {
189
193
  * Get the ID of the current session from memory
190
194
  */
191
195
  async getCurrentSessionId() {
192
- const result = await this.retrieveMemory(MEMORY_KEYS.CURRENT);
196
+ const result = await retrieveMemoryEntry(MEMORY_KEYS.CURRENT, this.executor);
193
197
  if (!result.success || !result.data) {
194
198
  return null;
195
199
  }
@@ -207,247 +211,19 @@ export class SessionManager {
207
211
  async storeSession(session) {
208
212
  const memoryKey = `${MEMORY_KEYS.SESSION_PREFIX}${session.sessionId}`;
209
213
  const sanitized = sanitizeSessionData(session);
210
- return this.storeMemory(memoryKey, JSON.stringify(sanitized));
214
+ return storeMemoryEntry(memoryKey, JSON.stringify(sanitized), this.executor);
211
215
  }
212
216
  /**
213
217
  * Set the current session pointer
214
218
  */
215
219
  async setCurrentSession(sessionId) {
216
- return this.storeMemory(MEMORY_KEYS.CURRENT, JSON.stringify({ sessionId }));
220
+ return storeMemoryEntry(MEMORY_KEYS.CURRENT, JSON.stringify({ sessionId }), this.executor);
217
221
  }
218
222
  /**
219
223
  * Clear the current session pointer
220
224
  */
221
225
  async clearCurrentSession() {
222
- return this.deleteMemory(MEMORY_KEYS.CURRENT);
223
- }
224
- /**
225
- * Store data in claude-flow memory
226
- *
227
- * SMI-674: Uses spawn() with argument array to prevent command injection
228
- * SMI-1518: V3 API Migration - Use direct storeEntry() when available
229
- */
230
- async storeMemory(key, value) {
231
- if (!validateMemoryKey(key)) {
232
- return { success: false, error: 'Invalid memory key' };
233
- }
234
- // SMI-1518, SMI-1609: Try V3 direct API first if enabled
235
- if (USE_V3_API) {
236
- try {
237
- const memoryModule = await getClaudeFlowMemory();
238
- if (memoryModule?.storeEntry) {
239
- const result = await memoryModule.storeEntry({
240
- key,
241
- value,
242
- namespace: MEMORY_NAMESPACE,
243
- });
244
- if (result.success) {
245
- return { success: true };
246
- }
247
- console.warn(`V3 storeEntry failed: ${result.error}, falling back to spawn`);
248
- }
249
- }
250
- catch (error) {
251
- console.warn(`V3 storeEntry exception: ${error}, falling back to spawn`);
252
- }
253
- }
254
- try {
255
- const args = ['claude-flow', 'memory', 'store', '--key', key, '--value', value];
256
- if (this.executor.spawn) {
257
- await this.executor.spawn('npx', args);
258
- }
259
- else {
260
- const escapedValue = value.replace(/'/g, "'\\''");
261
- const command = `npx claude-flow memory store --key "${key}" --value '${escapedValue}'`;
262
- await this.executor.execute(command);
263
- }
264
- return { success: true };
265
- }
266
- catch (error) {
267
- return {
268
- success: false,
269
- error: error instanceof Error ? error.message : String(error),
270
- };
271
- }
272
- }
273
- /**
274
- * Retrieve data from claude-flow memory
275
- *
276
- * SMI-674: Uses spawn() with argument array to prevent command injection
277
- * SMI-1518: V3 API Migration - Use direct getEntry() when available
278
- */
279
- async retrieveMemory(key) {
280
- if (!validateMemoryKey(key)) {
281
- return { success: false, error: 'Invalid memory key' };
282
- }
283
- // SMI-1518, SMI-1609: Try V3 direct API first if enabled
284
- if (USE_V3_API) {
285
- try {
286
- const memoryModule = await getClaudeFlowMemory();
287
- if (memoryModule?.getEntry) {
288
- const result = await memoryModule.getEntry({
289
- key,
290
- namespace: MEMORY_NAMESPACE,
291
- });
292
- if (result.success && result.found && result.entry) {
293
- return { success: true, data: result.entry.content };
294
- }
295
- if (result.success && !result.found) {
296
- return { success: false, error: 'Key not found' };
297
- }
298
- console.warn(`V3 getEntry failed: ${result.error}, falling back to spawn`);
299
- }
300
- }
301
- catch (error) {
302
- console.warn(`V3 getEntry exception: ${error}, falling back to spawn`);
303
- }
304
- }
305
- try {
306
- const args = ['claude-flow', 'memory', 'get', '--key', key];
307
- let stdout;
308
- if (this.executor.spawn) {
309
- const result = await this.executor.spawn('npx', args);
310
- stdout = result.stdout;
311
- }
312
- else {
313
- const command = `npx claude-flow memory get --key "${key}"`;
314
- const result = await this.executor.execute(command);
315
- stdout = result.stdout;
316
- }
317
- return { success: true, data: stdout.trim() };
318
- }
319
- catch (error) {
320
- return {
321
- success: false,
322
- error: error instanceof Error ? error.message : String(error),
323
- };
324
- }
325
- }
326
- /**
327
- * Delete data from claude-flow memory
328
- *
329
- * SMI-674: Uses spawn() with argument array to prevent command injection
330
- * SMI-1518: V3 API Migration - Use callMCPTool('memory/delete') when available
331
- */
332
- async deleteMemory(key) {
333
- if (!validateMemoryKey(key)) {
334
- return { success: false, error: 'Invalid memory key' };
335
- }
336
- // SMI-1518, SMI-1609: Try V3 MCP API first if enabled
337
- if (USE_V3_API) {
338
- try {
339
- const mcpModule = await getClaudeFlowMcp();
340
- if (mcpModule?.callMCPTool) {
341
- const result = (await mcpModule.callMCPTool('memory/delete', { key }));
342
- if (result.success) {
343
- return { success: true };
344
- }
345
- console.warn(`V3 memory/delete failed, falling back to spawn`);
346
- }
347
- }
348
- catch (error) {
349
- const mcpModule = await getClaudeFlowMcp();
350
- const MCPClientError = mcpModule?.MCPClientError;
351
- if (!MCPClientError || !(error instanceof MCPClientError)) {
352
- console.warn(`V3 memory/delete exception: ${error}, falling back to spawn`);
353
- }
354
- }
355
- }
356
- try {
357
- const args = ['claude-flow', 'memory', 'delete', '--key', key];
358
- if (this.executor.spawn) {
359
- await this.executor.spawn('npx', args);
360
- }
361
- else {
362
- const command = `npx claude-flow memory delete --key "${key}"`;
363
- await this.executor.execute(command);
364
- }
365
- return { success: true };
366
- }
367
- catch {
368
- // Ignore delete errors (key may not exist)
369
- return { success: true };
370
- }
371
- }
372
- /**
373
- * Run pre-task hook
374
- * SMI-674: Uses spawn() with argument array to prevent command injection
375
- * SMI-1518: V3 API Migration - Use callMCPTool('hooks/pre-task') when available
376
- */
377
- async runPreTaskHook(description) {
378
- // SMI-1518, SMI-1609: Try V3 MCP API first if enabled
379
- if (USE_V3_API) {
380
- try {
381
- const mcpModule = await getClaudeFlowMcp();
382
- if (mcpModule?.callMCPTool) {
383
- await mcpModule.callMCPTool('hooks/pre-task', {
384
- description,
385
- memoryKey: 'session/current',
386
- });
387
- return;
388
- }
389
- }
390
- catch {
391
- // V3 API not available or failed, fall back to spawn
392
- }
393
- }
394
- try {
395
- const args = [
396
- 'claude-flow',
397
- 'hooks',
398
- 'pre-task',
399
- '--description',
400
- description,
401
- '--memory-key',
402
- 'session/current',
403
- ];
404
- if (this.executor.spawn) {
405
- await this.executor.spawn('npx', args);
406
- }
407
- else {
408
- const escapedDesc = description.replace(/'/g, "'\\''");
409
- const command = `npx claude-flow hooks pre-task --description '${escapedDesc}' --memory-key "session/current"`;
410
- await this.executor.execute(command);
411
- }
412
- }
413
- catch {
414
- // Hooks are optional, don't fail if they don't work
415
- }
416
- }
417
- /**
418
- * Run post-task hook
419
- * SMI-674: Uses spawn() with argument array to prevent command injection
420
- * SMI-1518: V3 API Migration - Use callMCPTool('hooks/post-task') when available
421
- */
422
- async runPostTaskHook(taskId) {
423
- // SMI-1518, SMI-1609: Try V3 MCP API first if enabled
424
- if (USE_V3_API) {
425
- try {
426
- const mcpModule = await getClaudeFlowMcp();
427
- if (mcpModule?.callMCPTool) {
428
- await mcpModule.callMCPTool('hooks/post-task', {
429
- taskId,
430
- });
431
- return;
432
- }
433
- }
434
- catch {
435
- // V3 API not available or failed, fall back to spawn
436
- }
437
- }
438
- try {
439
- const args = ['claude-flow', 'hooks', 'post-task', '--task-id', taskId];
440
- if (this.executor.spawn) {
441
- await this.executor.spawn('npx', args);
442
- }
443
- else {
444
- const command = `npx claude-flow hooks post-task --task-id "${taskId}"`;
445
- await this.executor.execute(command);
446
- }
447
- }
448
- catch {
449
- // Hooks are optional, don't fail if they don't work
450
- }
226
+ return deleteMemoryEntry(MEMORY_KEYS.CURRENT, this.executor);
451
227
  }
452
228
  }
453
229
  //# sourceMappingURL=SessionManager.js.map