swipium 1.0.0

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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/appMap/automationLink.js +74 -0
  4. package/dist/appMap/automationLink.js.map +1 -0
  5. package/dist/appMap/build.js +193 -0
  6. package/dist/appMap/build.js.map +1 -0
  7. package/dist/appMap/codeIndex.js +73 -0
  8. package/dist/appMap/codeIndex.js.map +1 -0
  9. package/dist/appMap/featureModel.js +83 -0
  10. package/dist/appMap/featureModel.js.map +1 -0
  11. package/dist/appMap/firstRunApply.js +131 -0
  12. package/dist/appMap/firstRunApply.js.map +1 -0
  13. package/dist/appMap/fsWalk.js +75 -0
  14. package/dist/appMap/fsWalk.js.map +1 -0
  15. package/dist/appMap/issues.js +227 -0
  16. package/dist/appMap/issues.js.map +1 -0
  17. package/dist/appMap/migrations.js +87 -0
  18. package/dist/appMap/migrations.js.map +1 -0
  19. package/dist/appMap/prelaunch.js +66 -0
  20. package/dist/appMap/prelaunch.js.map +1 -0
  21. package/dist/appMap/projectRegistry.js +70 -0
  22. package/dist/appMap/projectRegistry.js.map +1 -0
  23. package/dist/appMap/provenance.js +52 -0
  24. package/dist/appMap/provenance.js.map +1 -0
  25. package/dist/appMap/query.js +118 -0
  26. package/dist/appMap/query.js.map +1 -0
  27. package/dist/appMap/runtimeMerge.js +207 -0
  28. package/dist/appMap/runtimeMerge.js.map +1 -0
  29. package/dist/appMap/schema.js +65 -0
  30. package/dist/appMap/schema.js.map +1 -0
  31. package/dist/appMap/screenMatch.js +75 -0
  32. package/dist/appMap/screenMatch.js.map +1 -0
  33. package/dist/appMap/staticScan.js +614 -0
  34. package/dist/appMap/staticScan.js.map +1 -0
  35. package/dist/appMap/store.js +173 -0
  36. package/dist/appMap/store.js.map +1 -0
  37. package/dist/appMap/tsAstScan.js +184 -0
  38. package/dist/appMap/tsAstScan.js.map +1 -0
  39. package/dist/artifacts/bundletool.js +199 -0
  40. package/dist/artifacts/bundletool.js.map +1 -0
  41. package/dist/artifacts/resolve.js +388 -0
  42. package/dist/artifacts/resolve.js.map +1 -0
  43. package/dist/automationGen/appiumModel.js +129 -0
  44. package/dist/automationGen/appiumModel.js.map +1 -0
  45. package/dist/automationGen/ciEmitter.js +80 -0
  46. package/dist/automationGen/ciEmitter.js.map +1 -0
  47. package/dist/automationGen/jsEmitter.js +440 -0
  48. package/dist/automationGen/jsEmitter.js.map +1 -0
  49. package/dist/automationGen/packagePatch.js +56 -0
  50. package/dist/automationGen/packagePatch.js.map +1 -0
  51. package/dist/automationGen/projectProfile.js +317 -0
  52. package/dist/automationGen/projectProfile.js.map +1 -0
  53. package/dist/automationGen/pythonEmitter.js +386 -0
  54. package/dist/automationGen/pythonEmitter.js.map +1 -0
  55. package/dist/automationGen/readmeEmitter.js +66 -0
  56. package/dist/automationGen/readmeEmitter.js.map +1 -0
  57. package/dist/automationGen/suitePlan.js +94 -0
  58. package/dist/automationGen/suitePlan.js.map +1 -0
  59. package/dist/automationGen/validation.js +150 -0
  60. package/dist/automationGen/validation.js.map +1 -0
  61. package/dist/build/parseBuildLog.js +119 -0
  62. package/dist/build/parseBuildLog.js.map +1 -0
  63. package/dist/build/plan.js +150 -0
  64. package/dist/build/plan.js.map +1 -0
  65. package/dist/ci/preflight.js +85 -0
  66. package/dist/ci/preflight.js.map +1 -0
  67. package/dist/cli/init.js +105 -0
  68. package/dist/cli/init.js.map +1 -0
  69. package/dist/cli/scan.js +85 -0
  70. package/dist/cli/scan.js.map +1 -0
  71. package/dist/cli/suite.js +85 -0
  72. package/dist/cli/suite.js.map +1 -0
  73. package/dist/cli/verify.js +62 -0
  74. package/dist/cli/verify.js.map +1 -0
  75. package/dist/consent/consent.js +43 -0
  76. package/dist/consent/consent.js.map +1 -0
  77. package/dist/context/detect.js +156 -0
  78. package/dist/context/detect.js.map +1 -0
  79. package/dist/context/findApps.js +198 -0
  80. package/dist/context/findApps.js.map +1 -0
  81. package/dist/context/projectRoot.js +41 -0
  82. package/dist/context/projectRoot.js.map +1 -0
  83. package/dist/context/scan.js +167 -0
  84. package/dist/context/scan.js.map +1 -0
  85. package/dist/core/target.js +115 -0
  86. package/dist/core/target.js.map +1 -0
  87. package/dist/core/targetPlan.js +140 -0
  88. package/dist/core/targetPlan.js.map +1 -0
  89. package/dist/drivers/DirectDriver.js +228 -0
  90. package/dist/drivers/DirectDriver.js.map +1 -0
  91. package/dist/drivers/Driver.js +4 -0
  92. package/dist/drivers/Driver.js.map +1 -0
  93. package/dist/drivers/SimctlDriver.js +127 -0
  94. package/dist/drivers/SimctlDriver.js.map +1 -0
  95. package/dist/drivers/WdaDriver.js +250 -0
  96. package/dist/drivers/WdaDriver.js.map +1 -0
  97. package/dist/explore/candidates.js +93 -0
  98. package/dist/explore/candidates.js.map +1 -0
  99. package/dist/explore/graph.js +116 -0
  100. package/dist/explore/graph.js.map +1 -0
  101. package/dist/explore/memory.js +35 -0
  102. package/dist/explore/memory.js.map +1 -0
  103. package/dist/explore/planner.js +105 -0
  104. package/dist/explore/planner.js.map +1 -0
  105. package/dist/explore/policy.js +85 -0
  106. package/dist/explore/policy.js.map +1 -0
  107. package/dist/explore/runner.js +475 -0
  108. package/dist/explore/runner.js.map +1 -0
  109. package/dist/explore/signatures.js +35 -0
  110. package/dist/explore/signatures.js.map +1 -0
  111. package/dist/explore/suite.js +55 -0
  112. package/dist/explore/suite.js.map +1 -0
  113. package/dist/featureTesting/executionBootstrap.js +140 -0
  114. package/dist/featureTesting/executionBootstrap.js.map +1 -0
  115. package/dist/firstRun/authStateMachine.js +83 -0
  116. package/dist/firstRun/authStateMachine.js.map +1 -0
  117. package/dist/firstRun/classifyScreen.js +201 -0
  118. package/dist/firstRun/classifyScreen.js.map +1 -0
  119. package/dist/firstRun/firstRunPlanner.js +207 -0
  120. package/dist/firstRun/firstRunPlanner.js.map +1 -0
  121. package/dist/firstRun/firstRunRunner.js +331 -0
  122. package/dist/firstRun/firstRunRunner.js.map +1 -0
  123. package/dist/firstRun/generatedDataPolicy.js +215 -0
  124. package/dist/firstRun/generatedDataPolicy.js.map +1 -0
  125. package/dist/firstRun/inputPlanner.js +67 -0
  126. package/dist/firstRun/inputPlanner.js.map +1 -0
  127. package/dist/firstRun/onboardingStateMachine.js +46 -0
  128. package/dist/firstRun/onboardingStateMachine.js.map +1 -0
  129. package/dist/firstRun/paywallPolicy.js +54 -0
  130. package/dist/firstRun/paywallPolicy.js.map +1 -0
  131. package/dist/firstRun/types.js +7 -0
  132. package/dist/firstRun/types.js.map +1 -0
  133. package/dist/fixtures/catalog.js +131 -0
  134. package/dist/fixtures/catalog.js.map +1 -0
  135. package/dist/flows/discover.js +18 -0
  136. package/dist/flows/discover.js.map +1 -0
  137. package/dist/flows/generate.js +211 -0
  138. package/dist/flows/generate.js.map +1 -0
  139. package/dist/flows/lint.js +97 -0
  140. package/dist/flows/lint.js.map +1 -0
  141. package/dist/flows/pack.js +68 -0
  142. package/dist/flows/pack.js.map +1 -0
  143. package/dist/flows/run.js +738 -0
  144. package/dist/flows/run.js.map +1 -0
  145. package/dist/flows/schema.js +240 -0
  146. package/dist/flows/schema.js.map +1 -0
  147. package/dist/flows/seedExec.js +108 -0
  148. package/dist/flows/seedExec.js.map +1 -0
  149. package/dist/flows/templates.js +155 -0
  150. package/dist/flows/templates.js.map +1 -0
  151. package/dist/flows/waitGuards.js +12 -0
  152. package/dist/flows/waitGuards.js.map +1 -0
  153. package/dist/index.js +33 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/ios/signing.js +182 -0
  156. package/dist/ios/signing.js.map +1 -0
  157. package/dist/issues/classify.js +186 -0
  158. package/dist/issues/classify.js.map +1 -0
  159. package/dist/issues/fingerprint.js +130 -0
  160. package/dist/issues/fingerprint.js.map +1 -0
  161. package/dist/issues/index.js +240 -0
  162. package/dist/issues/index.js.map +1 -0
  163. package/dist/issues/metrics.js +155 -0
  164. package/dist/issues/metrics.js.map +1 -0
  165. package/dist/issues/recurrence.js +193 -0
  166. package/dist/issues/recurrence.js.map +1 -0
  167. package/dist/issues/report.js +110 -0
  168. package/dist/issues/report.js.map +1 -0
  169. package/dist/issues/reportBridge.js +119 -0
  170. package/dist/issues/reportBridge.js.map +1 -0
  171. package/dist/issues/schema.js +90 -0
  172. package/dist/issues/schema.js.map +1 -0
  173. package/dist/issues/sourceRevision.js +108 -0
  174. package/dist/issues/sourceRevision.js.map +1 -0
  175. package/dist/issues/store.js +155 -0
  176. package/dist/issues/store.js.map +1 -0
  177. package/dist/lib/android.js +278 -0
  178. package/dist/lib/android.js.map +1 -0
  179. package/dist/lib/commandTemplate.js +55 -0
  180. package/dist/lib/commandTemplate.js.map +1 -0
  181. package/dist/lib/coordSpace.js +23 -0
  182. package/dist/lib/coordSpace.js.map +1 -0
  183. package/dist/lib/device.js +87 -0
  184. package/dist/lib/device.js.map +1 -0
  185. package/dist/lib/gitignore.js +22 -0
  186. package/dist/lib/gitignore.js.map +1 -0
  187. package/dist/lib/image.js +97 -0
  188. package/dist/lib/image.js.map +1 -0
  189. package/dist/lib/logger.js +8 -0
  190. package/dist/lib/logger.js.map +1 -0
  191. package/dist/lib/metroState.js +45 -0
  192. package/dist/lib/metroState.js.map +1 -0
  193. package/dist/lib/needsInput.js +201 -0
  194. package/dist/lib/needsInput.js.map +1 -0
  195. package/dist/lib/png.js +103 -0
  196. package/dist/lib/png.js.map +1 -0
  197. package/dist/lib/redact.js +21 -0
  198. package/dist/lib/redact.js.map +1 -0
  199. package/dist/lib/result.js +87 -0
  200. package/dist/lib/result.js.map +1 -0
  201. package/dist/lib/schemaHash.js +65 -0
  202. package/dist/lib/schemaHash.js.map +1 -0
  203. package/dist/lib/sensitive.js +13 -0
  204. package/dist/lib/sensitive.js.map +1 -0
  205. package/dist/lib/simctl.js +149 -0
  206. package/dist/lib/simctl.js.map +1 -0
  207. package/dist/lib/spawn.js +144 -0
  208. package/dist/lib/spawn.js.map +1 -0
  209. package/dist/lib/wda.js +347 -0
  210. package/dist/lib/wda.js.map +1 -0
  211. package/dist/lib/wdaConfig.js +69 -0
  212. package/dist/lib/wdaConfig.js.map +1 -0
  213. package/dist/lib/wdaTune.js +58 -0
  214. package/dist/lib/wdaTune.js.map +1 -0
  215. package/dist/oracle/auth.js +22 -0
  216. package/dist/oracle/auth.js.map +1 -0
  217. package/dist/oracle/failures.js +193 -0
  218. package/dist/oracle/failures.js.map +1 -0
  219. package/dist/oracle/health.js +123 -0
  220. package/dist/oracle/health.js.map +1 -0
  221. package/dist/oracle/record.js +36 -0
  222. package/dist/oracle/record.js.map +1 -0
  223. package/dist/orchestration/envelope.js +52 -0
  224. package/dist/orchestration/envelope.js.map +1 -0
  225. package/dist/orchestration/goal.js +98 -0
  226. package/dist/orchestration/goal.js.map +1 -0
  227. package/dist/plan/plan.js +124 -0
  228. package/dist/plan/plan.js.map +1 -0
  229. package/dist/prompts/index.js +63 -0
  230. package/dist/prompts/index.js.map +1 -0
  231. package/dist/report/artifactManifest.js +44 -0
  232. package/dist/report/artifactManifest.js.map +1 -0
  233. package/dist/report/coverage.js +60 -0
  234. package/dist/report/coverage.js.map +1 -0
  235. package/dist/report/evidence.js +84 -0
  236. package/dist/report/evidence.js.map +1 -0
  237. package/dist/report/export.js +447 -0
  238. package/dist/report/export.js.map +1 -0
  239. package/dist/report/flake.js +61 -0
  240. package/dist/report/flake.js.map +1 -0
  241. package/dist/report/history.js +564 -0
  242. package/dist/report/history.js.map +1 -0
  243. package/dist/report/policy.js +98 -0
  244. package/dist/report/policy.js.map +1 -0
  245. package/dist/report/qaLevel.js +96 -0
  246. package/dist/report/qaLevel.js.map +1 -0
  247. package/dist/report/readiness.js +213 -0
  248. package/dist/report/readiness.js.map +1 -0
  249. package/dist/report/summary.js +42 -0
  250. package/dist/report/summary.js.map +1 -0
  251. package/dist/report/testCatalog.js +93 -0
  252. package/dist/report/testCatalog.js.map +1 -0
  253. package/dist/report/timing.js +37 -0
  254. package/dist/report/timing.js.map +1 -0
  255. package/dist/server.js +180 -0
  256. package/dist/server.js.map +1 -0
  257. package/dist/services/automationGenerate.js +60 -0
  258. package/dist/services/automationGenerate.js.map +1 -0
  259. package/dist/services/build.js +66 -0
  260. package/dist/services/build.js.map +1 -0
  261. package/dist/services/preflight.js +51 -0
  262. package/dist/services/preflight.js.map +1 -0
  263. package/dist/services/prepareAndroid.js +183 -0
  264. package/dist/services/prepareAndroid.js.map +1 -0
  265. package/dist/services/prepareIos.js +162 -0
  266. package/dist/services/prepareIos.js.map +1 -0
  267. package/dist/services/report.js +537 -0
  268. package/dist/services/report.js.map +1 -0
  269. package/dist/services/smoke.js +120 -0
  270. package/dist/services/smoke.js.map +1 -0
  271. package/dist/services/suiteGenerate.js +123 -0
  272. package/dist/services/suiteGenerate.js.map +1 -0
  273. package/dist/services/testSuiteKnowledge.js +150 -0
  274. package/dist/services/testSuiteKnowledge.js.map +1 -0
  275. package/dist/session/attach.js +47 -0
  276. package/dist/session/attach.js.map +1 -0
  277. package/dist/session/progress.js +56 -0
  278. package/dist/session/progress.js.map +1 -0
  279. package/dist/session/store.js +329 -0
  280. package/dist/session/store.js.map +1 -0
  281. package/dist/snapshot/overlays.js +132 -0
  282. package/dist/snapshot/overlays.js.map +1 -0
  283. package/dist/snapshot/parse.js +204 -0
  284. package/dist/snapshot/parse.js.map +1 -0
  285. package/dist/snapshot/present.js +12 -0
  286. package/dist/snapshot/present.js.map +1 -0
  287. package/dist/snapshot/settle.js +36 -0
  288. package/dist/snapshot/settle.js.map +1 -0
  289. package/dist/state/profile.js +318 -0
  290. package/dist/state/profile.js.map +1 -0
  291. package/dist/suite/compile.js +176 -0
  292. package/dist/suite/compile.js.map +1 -0
  293. package/dist/suite/lint.js +45 -0
  294. package/dist/suite/lint.js.map +1 -0
  295. package/dist/suite/pom.js +285 -0
  296. package/dist/suite/pom.js.map +1 -0
  297. package/dist/suite/testcase.js +87 -0
  298. package/dist/suite/testcase.js.map +1 -0
  299. package/dist/testSuite/generator.js +222 -0
  300. package/dist/testSuite/generator.js.map +1 -0
  301. package/dist/testSuite/history.js +44 -0
  302. package/dist/testSuite/history.js.map +1 -0
  303. package/dist/testSuite/issueLinks.js +96 -0
  304. package/dist/testSuite/issueLinks.js.map +1 -0
  305. package/dist/testSuite/merge.js +190 -0
  306. package/dist/testSuite/merge.js.map +1 -0
  307. package/dist/testSuite/schema.js +86 -0
  308. package/dist/testSuite/schema.js.map +1 -0
  309. package/dist/testSuite/store.js +116 -0
  310. package/dist/testSuite/store.js.map +1 -0
  311. package/dist/testSuite/traceability.js +55 -0
  312. package/dist/testSuite/traceability.js.map +1 -0
  313. package/dist/tools/act.js +457 -0
  314. package/dist/tools/act.js.map +1 -0
  315. package/dist/tools/agent.js +225 -0
  316. package/dist/tools/agent.js.map +1 -0
  317. package/dist/tools/appMap.js +317 -0
  318. package/dist/tools/appMap.js.map +1 -0
  319. package/dist/tools/assertVisual.js +74 -0
  320. package/dist/tools/assertVisual.js.map +1 -0
  321. package/dist/tools/automationGenerate.js +394 -0
  322. package/dist/tools/automationGenerate.js.map +1 -0
  323. package/dist/tools/capabilities.js +114 -0
  324. package/dist/tools/capabilities.js.map +1 -0
  325. package/dist/tools/clearOverlay.js +150 -0
  326. package/dist/tools/clearOverlay.js.map +1 -0
  327. package/dist/tools/detectContext.js +41 -0
  328. package/dist/tools/detectContext.js.map +1 -0
  329. package/dist/tools/doctor.js +116 -0
  330. package/dist/tools/doctor.js.map +1 -0
  331. package/dist/tools/explore.js +289 -0
  332. package/dist/tools/explore.js.map +1 -0
  333. package/dist/tools/firstRun.js +136 -0
  334. package/dist/tools/firstRun.js.map +1 -0
  335. package/dist/tools/flow.js +331 -0
  336. package/dist/tools/flow.js.map +1 -0
  337. package/dist/tools/flowGenerate.js +55 -0
  338. package/dist/tools/flowGenerate.js.map +1 -0
  339. package/dist/tools/getArtifact.js +39 -0
  340. package/dist/tools/getArtifact.js.map +1 -0
  341. package/dist/tools/health.js +41 -0
  342. package/dist/tools/health.js.map +1 -0
  343. package/dist/tools/ios.js +492 -0
  344. package/dist/tools/ios.js.map +1 -0
  345. package/dist/tools/jobs.js +20 -0
  346. package/dist/tools/jobs.js.map +1 -0
  347. package/dist/tools/network.js +50 -0
  348. package/dist/tools/network.js.map +1 -0
  349. package/dist/tools/note.js +69 -0
  350. package/dist/tools/note.js.map +1 -0
  351. package/dist/tools/plan.js +49 -0
  352. package/dist/tools/plan.js.map +1 -0
  353. package/dist/tools/prepareIosTarget.js +99 -0
  354. package/dist/tools/prepareIosTarget.js.map +1 -0
  355. package/dist/tools/prepareTarget.js +257 -0
  356. package/dist/tools/prepareTarget.js.map +1 -0
  357. package/dist/tools/report.js +42 -0
  358. package/dist/tools/report.js.map +1 -0
  359. package/dist/tools/screenRecord.js +24 -0
  360. package/dist/tools/screenRecord.js.map +1 -0
  361. package/dist/tools/screenshot.js +63 -0
  362. package/dist/tools/screenshot.js.map +1 -0
  363. package/dist/tools/smoke.js +39 -0
  364. package/dist/tools/smoke.js.map +1 -0
  365. package/dist/tools/snapshot.js +129 -0
  366. package/dist/tools/snapshot.js.map +1 -0
  367. package/dist/tools/startSession.js +169 -0
  368. package/dist/tools/startSession.js.map +1 -0
  369. package/dist/tools/state.js +87 -0
  370. package/dist/tools/state.js.map +1 -0
  371. package/dist/tools/suite.js +412 -0
  372. package/dist/tools/suite.js.map +1 -0
  373. package/dist/tools/testThis.js +774 -0
  374. package/dist/tools/testThis.js.map +1 -0
  375. package/dist/tools/wda.js +477 -0
  376. package/dist/tools/wda.js.map +1 -0
  377. package/dist/version.js +62 -0
  378. package/dist/version.js.map +1 -0
  379. package/dist/visual/ocr.js +72 -0
  380. package/dist/visual/ocr.js.map +1 -0
  381. package/dist/visual/provider.js +75 -0
  382. package/dist/visual/provider.js.map +1 -0
  383. package/docs/README.md +19 -0
  384. package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
  385. package/docs/mcp-server.md +135 -0
  386. package/docs/tools.md +130 -0
  387. package/package.json +70 -0
@@ -0,0 +1,12 @@
1
+ export const DEFAULT_SELECTOR_WAIT_MS = 8000;
2
+ /** Build the Flow V2 wait guard that should precede a generated selector action. */
3
+ export function waitForVisibleGuard(selector, timeoutMs = DEFAULT_SELECTOR_WAIT_MS) {
4
+ const id = selector.match(/^id\s*=\s*(.+)$/i)?.[1];
5
+ if (id)
6
+ return { waitForVisible: { id, timeoutMs } };
7
+ const accessibilityId = selector.match(/^accessibility id\s*=\s*(.+)$/i)?.[1];
8
+ if (accessibilityId)
9
+ return { waitForVisible: { 'accessibility id': accessibilityId, timeoutMs } };
10
+ return { waitForVisible: { text: selector, timeoutMs } };
11
+ }
12
+ //# sourceMappingURL=waitGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitGuards.js","sourceRoot":"","sources":["../../src/flows/waitGuards.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAE7C,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,SAAS,GAAG,wBAAwB;IACxF,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,IAAI,EAAE;QAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;IAErD,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,gCAAgC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9E,IAAI,eAAe;QAAE,OAAO,EAAE,cAAc,EAAE,EAAE,kBAAkB,EAAE,eAAe,EAAE,SAAS,EAAE,EAAE,CAAC;IAEnG,OAAO,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC;AAC3D,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ // Entry point. Default = run as the stdio MCP server. `init <client>` = setup helper.
3
+ import { startServer } from './server.js';
4
+ import { runInit } from './cli/init.js';
5
+ import { runVerify } from './cli/verify.js';
6
+ import { runScan } from './cli/scan.js';
7
+ import { runSuite } from './cli/suite.js';
8
+ import { log } from './lib/logger.js';
9
+ async function main() {
10
+ const [, , cmd, ...rest] = process.argv;
11
+ if (cmd === 'init') {
12
+ await runInit(rest);
13
+ return;
14
+ }
15
+ if (cmd === 'scan') {
16
+ await runScan(rest);
17
+ return;
18
+ }
19
+ if (cmd === 'suite') {
20
+ await runSuite(rest);
21
+ return;
22
+ }
23
+ if (cmd === 'verify') {
24
+ await runVerify();
25
+ return;
26
+ }
27
+ await startServer();
28
+ }
29
+ main().catch((err) => {
30
+ log('error', 'fatal', { err: String(err?.stack ?? err) });
31
+ process.exit(1);
32
+ });
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,sFAAsF;AAEtF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrB,MAAM,SAAS,EAAE,CAAC;QAClB,OAAO;IACT,CAAC;IACD,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,182 @@
1
+ import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { basename, extname, join } from 'node:path';
4
+ import { run, runBinary } from '../lib/spawn.js';
5
+ function firstMatch(text, re) {
6
+ return text.match(re)?.[1]?.trim() ?? null;
7
+ }
8
+ function arrayValues(text, key) {
9
+ const keyIndex = text.indexOf(`<key>${key}</key>`);
10
+ if (keyIndex < 0)
11
+ return [];
12
+ const array = text.slice(keyIndex).match(/<array>([\s\S]*?)<\/array>/)?.[1] ?? '';
13
+ return [...array.matchAll(/<string>([^<]+)<\/string>/g)].map((m) => m[1].trim()).filter(Boolean);
14
+ }
15
+ function dictStringValue(text, key) {
16
+ const idx = text.indexOf(`<key>${key}</key>`);
17
+ if (idx < 0)
18
+ return null;
19
+ return text.slice(idx).match(/<string>([^<]+)<\/string>/)?.[1]?.trim() ?? null;
20
+ }
21
+ function entitlements(text) {
22
+ const idx = text.indexOf('<key>Entitlements</key>');
23
+ if (idx < 0)
24
+ return {};
25
+ const dict = text.slice(idx).match(/<dict>([\s\S]*?)<\/dict>/)?.[1] ?? '';
26
+ const out = {};
27
+ const re = /<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g;
28
+ for (const match of dict.matchAll(re))
29
+ out[match[1]] = match[2];
30
+ return out;
31
+ }
32
+ export function parseCodesignDetails(text) {
33
+ const authorityCount = [...text.matchAll(/^Authority=/gm)].length;
34
+ const signature = firstMatch(text, /^Signature=(.+)$/m);
35
+ return {
36
+ identifier: firstMatch(text, /^Identifier=(.+)$/m),
37
+ teamIdentifier: firstMatch(text, /^TeamIdentifier=(.+)$/m),
38
+ authorityCount,
39
+ signed: !!signature && !/adhoc/i.test(signature) && authorityCount > 0,
40
+ };
41
+ }
42
+ export function parseMobileProvisionPlist(text) {
43
+ const appIdentifier = entitlements(text)['application-identifier'] ?? dictStringValue(text, 'ApplicationIdentifierPrefix');
44
+ const bundleId = appIdentifier?.includes('.') ? appIdentifier.split('.').slice(1).join('.') : null;
45
+ return {
46
+ teamIds: arrayValues(text, 'TeamIdentifier'),
47
+ applicationIdentifier: appIdentifier ?? null,
48
+ bundleId,
49
+ expirationDate: firstMatch(text, /<key>ExpirationDate<\/key>\s*<date>([^<]+)<\/date>/),
50
+ provisionedDevices: text.includes('<key>ProvisionedDevices</key>') ? arrayValues(text, 'ProvisionedDevices') : null,
51
+ entitlements: entitlements(text),
52
+ };
53
+ }
54
+ /** PURE: the CFBundleSupportedPlatforms array from an Info.plist's XML text. */
55
+ export function parseSupportedPlatforms(plistText) {
56
+ return arrayValues(plistText, 'CFBundleSupportedPlatforms');
57
+ }
58
+ /**
59
+ * PURE: classify a .app's build destination from its CFBundleSupportedPlatforms. A simulator .app
60
+ * lists "iPhoneSimulator"; a device build lists "iPhoneOS". Unknown when neither is present.
61
+ */
62
+ export function destinationFromPlatforms(platforms) {
63
+ const p = platforms.map((x) => x.toLowerCase());
64
+ if (p.some((x) => x.includes('simulator')))
65
+ return 'simulator';
66
+ if (p.some((x) => x === 'iphoneos' || x.includes('iphoneos')))
67
+ return 'device';
68
+ return 'unknown';
69
+ }
70
+ /** Read a .app bundle's build destination from Info.plist (best-effort; 'unknown' on any failure). */
71
+ export function appBuildDestination(appPath) {
72
+ try {
73
+ const plist = join(appPath, 'Info.plist');
74
+ if (!existsSync(plist))
75
+ return 'unknown';
76
+ return destinationFromPlatforms(parseSupportedPlatforms(readFileSync(plist, 'utf8')));
77
+ }
78
+ catch {
79
+ return 'unknown';
80
+ }
81
+ }
82
+ function findExtractedApp(dir) {
83
+ const payload = join(dir, 'Payload');
84
+ if (!existsSync(payload))
85
+ return null;
86
+ for (const name of readdirSync(payload)) {
87
+ const full = join(payload, name);
88
+ if (name.endsWith('.app') && statSync(full).isDirectory())
89
+ return full;
90
+ }
91
+ return null;
92
+ }
93
+ async function materializeApp(path) {
94
+ if (path.endsWith('.app'))
95
+ return { appPath: path, artifactType: 'iphoneos-app', missing: [] };
96
+ if (extname(path).toLowerCase() !== '.ipa')
97
+ return { appPath: null, artifactType: 'unknown', missing: [`unsupported iOS artifact extension: ${basename(path)}`] };
98
+ const dir = mkdtempSync(join(tmpdir(), 'swipium-ipa-'));
99
+ const unzip = await run('unzip', ['-q', path, '-d', dir], { timeoutMs: 30000 });
100
+ if (unzip.code !== 0) {
101
+ rmSync(dir, { recursive: true, force: true });
102
+ return { appPath: null, artifactType: 'ipa', missing: [`could not extract ipa: ${unzip.stderr.trim() || `exit ${unzip.code}`}`] };
103
+ }
104
+ return { appPath: findExtractedApp(dir), cleanup: dir, artifactType: 'ipa', missing: [] };
105
+ }
106
+ export async function inspectIosSigningArtifact(path, opts = {}) {
107
+ const missing = [];
108
+ const warnings = [];
109
+ if (!existsSync(path)) {
110
+ return { checked: true, artifactPath: path, artifactType: 'unknown', appPath: null, embeddedProvisionPresent: false, simulatorBuildSuspected: false, codesign: null, mobileProvision: null, requestedUdid: opts.requestedUdid ?? null, ready: false, missing: ['artifact path does not exist'], warnings };
111
+ }
112
+ if (process.platform !== 'darwin') {
113
+ return { checked: false, artifactPath: path, artifactType: path.endsWith('.ipa') ? 'ipa' : path.endsWith('.app') ? 'iphoneos-app' : 'unknown', appPath: null, embeddedProvisionPresent: false, simulatorBuildSuspected: false, codesign: null, mobileProvision: null, requestedUdid: opts.requestedUdid ?? null, ready: false, missing: ['iOS signing inspection requires macOS codesign/security tools'], warnings };
114
+ }
115
+ const materialized = await materializeApp(path);
116
+ missing.push(...materialized.missing);
117
+ let codesign = null;
118
+ let mobileProvision = null;
119
+ let embeddedProvisionPresent = false;
120
+ try {
121
+ if (materialized.appPath) {
122
+ const provisionPath = join(materialized.appPath, 'embedded.mobileprovision');
123
+ embeddedProvisionPresent = existsSync(provisionPath);
124
+ const sign = await run('codesign', ['-dv', '--verbose=4', materialized.appPath], { timeoutMs: 15000 });
125
+ codesign = parseCodesignDetails(`${sign.stdout}\n${sign.stderr}`);
126
+ if (sign.code !== 0 || !codesign.signed)
127
+ missing.push('codesign verification did not prove a non-ad-hoc signed app');
128
+ if (!embeddedProvisionPresent) {
129
+ missing.push('embedded.mobileprovision is missing');
130
+ }
131
+ else {
132
+ const cms = await runBinary('security', ['cms', '-D', '-i', provisionPath], { timeoutMs: 15000 });
133
+ if (cms.code !== 0)
134
+ missing.push('embedded.mobileprovision could not be decoded');
135
+ else
136
+ mobileProvision = parseMobileProvisionPlist(cms.stdout.toString('utf8'));
137
+ }
138
+ }
139
+ else if (!missing.length) {
140
+ missing.push('could not find .app inside artifact');
141
+ }
142
+ }
143
+ finally {
144
+ if (materialized.cleanup)
145
+ rmSync(materialized.cleanup, { recursive: true, force: true });
146
+ }
147
+ if (opts.expectedBundleId && mobileProvision?.bundleId && mobileProvision.bundleId !== opts.expectedBundleId) {
148
+ missing.push(`provisioned bundle id ${mobileProvision.bundleId} does not match expected ${opts.expectedBundleId}`);
149
+ }
150
+ if (codesign?.teamIdentifier && mobileProvision?.teamIds.length && !mobileProvision.teamIds.includes(codesign.teamIdentifier)) {
151
+ missing.push('codesign team identifier does not match provisioning profile team');
152
+ }
153
+ if (opts.requestedUdid && mobileProvision?.provisionedDevices && !mobileProvision.provisionedDevices.includes(opts.requestedUdid)) {
154
+ missing.push(`provisioning profile does not include requested device UDID ${opts.requestedUdid}`);
155
+ }
156
+ if (!opts.requestedUdid && mobileProvision?.provisionedDevices?.length)
157
+ warnings.push('provisioning profile has device UDIDs; pass a device UDID to verify this artifact is provisioned for the target hardware');
158
+ if (mobileProvision?.expirationDate) {
159
+ const expiresAt = Date.parse(mobileProvision.expirationDate);
160
+ if (!Number.isNaN(expiresAt) && expiresAt < Date.now()) {
161
+ missing.push(`embedded provisioning profile expired on ${mobileProvision.expirationDate}`);
162
+ }
163
+ }
164
+ const simulatorBuildSuspected = !!materialized.appPath && !embeddedProvisionPresent;
165
+ if (simulatorBuildSuspected)
166
+ missing.push('no embedded.mobileprovision: this looks like a simulator .app, not a signed device build');
167
+ return {
168
+ checked: true,
169
+ artifactPath: path,
170
+ artifactType: materialized.artifactType,
171
+ appPath: materialized.appPath,
172
+ embeddedProvisionPresent,
173
+ simulatorBuildSuspected,
174
+ codesign,
175
+ mobileProvision,
176
+ requestedUdid: opts.requestedUdid ?? null,
177
+ ready: missing.length === 0,
178
+ missing,
179
+ warnings,
180
+ };
181
+ }
182
+ //# sourceMappingURL=signing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/ios/signing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ // SWIPIUM Issue Log — policy-trained issue classifier (SWIPIUM-REQ-07 "Classifier Rules").
2
+ //
3
+ // Runs AFTER raw health/log extraction and BEFORE report rendering. Turns a normalized observation
4
+ // into a category + severity + owner + release impact, distinguishing real product defects from
5
+ // expected simulator / StoreKit / Google Play Billing / RevenueCat noise, hard gates, and readiness
6
+ // improvements. Built-in rules encode the spec's taxonomy; an optional `.swipium/issues/policy.json`
7
+ // can ADD or OVERRIDE rules. PURE — no clock, no fs.
8
+ import { defaultReleaseImpact } from './schema.js';
9
+ const OWNER_BY_CATEGORY = {
10
+ app_bug: 'app',
11
+ blocker_app_bug: 'app',
12
+ environment_noise: 'test_env',
13
+ expected_gate: 'test_env',
14
+ hard_gate: 'test_env',
15
+ improvement: 'app',
16
+ missing_test_data: 'test_env',
17
+ mcp_limitation: 'mcp',
18
+ security_privacy: 'app',
19
+ store_compliance: 'app',
20
+ accessibility_readiness: 'app',
21
+ };
22
+ function haystack(obs) {
23
+ return [
24
+ obs.title,
25
+ obs.summary,
26
+ obs.failureCode,
27
+ obs.exception?.message,
28
+ obs.exception?.type,
29
+ obs.subsystem,
30
+ obs.packageName,
31
+ obs.visibleText,
32
+ ]
33
+ .filter(Boolean)
34
+ .join(' ')
35
+ .toLowerCase();
36
+ }
37
+ function ruleMatches(rule, obs, ctx) {
38
+ const m = rule.match;
39
+ const hay = haystack(obs);
40
+ if (m.failureCode && (!obs.failureCode || !m.failureCode.includes(obs.failureCode)))
41
+ return false;
42
+ if (m.messageIncludes && !m.messageIncludes.some((s) => hay.includes(s.toLowerCase())))
43
+ return false;
44
+ if (m.environment && (!ctx.environment || !m.environment.includes(ctx.environment)))
45
+ return false;
46
+ if (m.httpStatus && (obs.http?.status == null || !m.httpStatus.includes(obs.http.status)))
47
+ return false;
48
+ if (m.subsystem && (!obs.subsystem || !m.subsystem.includes(obs.subsystem)))
49
+ return false;
50
+ if (m.screenPurpose && (!obs.screenPurpose || !m.screenPurpose.includes(obs.screenPurpose)))
51
+ return false;
52
+ return true;
53
+ }
54
+ function fromRule(rule, reason) {
55
+ const category = rule.category;
56
+ const severity = rule.severity;
57
+ return {
58
+ category,
59
+ severity,
60
+ owner: rule.owner ?? OWNER_BY_CATEGORY[category],
61
+ confidence: 0.9,
62
+ reason,
63
+ releaseImpact: rule.releaseImpact ?? defaultReleaseImpact(category, severity),
64
+ };
65
+ }
66
+ const BILLING_SUBSYSTEMS = new Set(['revenuecat', 'storekit', 'google_play_billing', 'billing']);
67
+ /** Built-in classifier: returns the most specific classification for an observation. */
68
+ export function classifyObservation(obs, ctx = {}) {
69
+ const hay = haystack(obs);
70
+ const env = ctx.environment ?? 'unknown';
71
+ const isSim = env === 'simulator' || env === 'emulator';
72
+ // --- 0. Authoritative override: the caller already classified (e.g. a mobile-audit check) ---
73
+ if (ctx.forceCategory) {
74
+ const category = ctx.forceCategory;
75
+ const severity = ctx.severityHint ?? 'medium';
76
+ return { category, severity, owner: OWNER_BY_CATEGORY[category], confidence: 0.95, reason: 'classified by the observing audit check', releaseImpact: defaultReleaseImpact(category, severity) };
77
+ }
78
+ // --- 1. User-supplied policy rules win first (most specific intent) ---
79
+ const pol = ctx.policy?.classifiers;
80
+ if (pol) {
81
+ for (const bucket of [pol.blockers, pol.hardGates, pol.environmentNoise, pol.improvements, pol.rules]) {
82
+ for (const rule of bucket ?? []) {
83
+ if (ruleMatches(rule, obs, ctx))
84
+ return fromRule(rule, `policy rule "${rule.name}"`);
85
+ }
86
+ }
87
+ }
88
+ // --- 2. Hard gates (stop the workflow, not the run; not an app bug by themselves) ---
89
+ if (/\botp\b|one-?time|mfa|2fa|verification code|magic link/.test(hay)) {
90
+ return mk('hard_gate', 'medium', 'OTP/MFA challenge requires a real user code — workflow gated, not an app bug');
91
+ }
92
+ if (obs.screenPurpose === 'paywall' && /hard paywall|no free|purchase required|must subscribe/.test(hay)) {
93
+ return mk('hard_gate', 'medium', 'Hard paywall with no permitted test path — recorded without purchase');
94
+ }
95
+ // --- 3. Expected environment noise (sim/emulator billing/store + explicit offline) ---
96
+ if (ctx.expectedOffline && /no internet|offline|no connection|network unavailable/.test(hay)) {
97
+ return mk('environment_noise', 'info', 'Network unavailable during an explicit offline test — expected');
98
+ }
99
+ if (obs.subsystem && BILLING_SUBSYSTEMS.has(obs.subsystem) && isSim && !ctx.realDevicePurchaseFlow) {
100
+ return mk('environment_noise', 'info', `${obs.subsystem} warning on ${env} — sandbox/simulator noise, not a product defect`);
101
+ }
102
+ if (/revenuecat/.test(hay) && /sandbox/.test(hay) && isSim) {
103
+ return mk('environment_noise', 'info', 'RevenueCat sandbox warning on simulator/emulator — expected');
104
+ }
105
+ if (/storekit/.test(hay) && /(sandbox|test|simulator)/.test(hay) && isSim) {
106
+ return mk('environment_noise', 'info', 'StoreKit sandbox/test warning on simulator — expected');
107
+ }
108
+ if (/billing_unavailable|billing service unavailable|billing.*unavailable/.test(hay) && env === 'emulator' && !ctx.realDevicePurchaseFlow) {
109
+ return mk('environment_noise', 'info', 'Google Play billing unavailable on emulator — environment, not an app bug');
110
+ }
111
+ if (/missing.*(product|offering|sku)/.test(hay) && isSim && !ctx.realDevicePurchaseFlow) {
112
+ return mk('environment_noise', 'info', 'Missing production purchase products in a local simulator run — expected');
113
+ }
114
+ // --- 4. Real billing/entitlement failure on device or during release-gate purchase ---
115
+ if ((obs.subsystem && BILLING_SUBSYSTEMS.has(obs.subsystem)) ||
116
+ /checkout|subscription|entitlement|purchase/.test(hay)) {
117
+ if (ctx.realDevicePurchaseFlow || env === 'device') {
118
+ return mk('app_bug', 'high', 'Checkout/subscription/entitlement failure on a real device or release-gate purchase flow');
119
+ }
120
+ }
121
+ // --- 5. App defects: React/JS/native + crashes ---
122
+ const fc = obs.failureCode;
123
+ if (fc === 'REDBOX' || /red\s?box/.test(hay))
124
+ return mk('blocker_app_bug', 'blocker', 'React Native RedBox — fatal JS/runtime error');
125
+ if (fc === 'NATIVE_CRASH' || /native crash|sigsegv|sigabrt/.test(hay))
126
+ return mk('blocker_app_bug', 'blocker', 'Fatal native crash');
127
+ if (fc === 'ANR' || /\banr\b|not responding/.test(hay))
128
+ return mk('blocker_app_bug', 'blocker', 'Application not responding (ANR)');
129
+ if (fc === 'ERROR_BOUNDARY' || /error boundary/.test(hay))
130
+ return mk('app_bug', 'high', 'Error boundary fallback shown during a normal workflow');
131
+ if (obs.exception?.type || /unhandled (js )?exception|typeerror|referenceerror|cannot read propert/.test(hay)) {
132
+ return mk('app_bug', 'high', 'Unhandled JS exception during a user workflow');
133
+ }
134
+ if (/(module|package).*(not found|resolution failed|cannot find)|unable to resolve module|import error/.test(hay)) {
135
+ return mk('app_bug', 'high', 'Package import / module resolution failure');
136
+ }
137
+ // --- 6. HTTP / API rules ---
138
+ const status = obs.http?.status;
139
+ if (status != null) {
140
+ if (status >= 500)
141
+ return mk('app_bug', 'high', `HTTP ${status} from app-owned backend`, 'backend');
142
+ if (status === 404 || status === 410)
143
+ return mk('app_bug', 'high', `HTTP ${status} for an app route/content endpoint that should exist`, 'backend');
144
+ if ((status === 401 || status === 403) && !ctx.authNegativeTest) {
145
+ return mk('app_bug', 'high', `HTTP ${status} with invalid/missing/expired app token (not an auth-negative test)`, 'backend');
146
+ }
147
+ }
148
+ // --- 7. Missing assets / routes ---
149
+ if (/missing (required )?(asset|route)|asset not found|404 not found/.test(hay)) {
150
+ return mk('app_bug', 'medium', 'Missing required asset or route');
151
+ }
152
+ // --- 8. Improvements / readiness (non-blocking) ---
153
+ if (fc === 'MISSING_DURABLE_LOCATOR' ||
154
+ fc === 'COORDINATE_ONLY_FLOW' ||
155
+ /accessibility id|missing testid|unstable locator|no durable locator/.test(hay)) {
156
+ return mk('accessibility_readiness', 'low', 'Missing accessibility IDs / unstable locators — readiness improvement, not a blocker');
157
+ }
158
+ if (fc === 'LOGBOX' || /logbox|console warning|non-fatal warning|slow network|missing (empty|loading|error) state/.test(hay)) {
159
+ return mk('improvement', 'low', 'Non-fatal warning / readiness gap — precaution, not a blocker');
160
+ }
161
+ // --- 9. Privacy / store-compliance & missing test data ---
162
+ if (/privacy policy|terms of service|account deletion|delete account|data deletion|manage subscription|restore purchase/.test(hay)) {
163
+ return mk('store_compliance', 'high', 'Store-compliance surface (privacy/terms/account-deletion/subscription) issue');
164
+ }
165
+ if (fc === 'MISSING_TEST_DATA' || fc === 'AUTH_GATE' || fc === 'MISSING_FIXTURE' || /no test (data|account)|fixture missing/.test(hay)) {
166
+ return mk('missing_test_data', 'medium', 'Required test data / fixture missing — provide it, not an app bug');
167
+ }
168
+ // --- 10. Fallback ---
169
+ // Honor a caller-supplied category (e.g. an explicit qa_note category) when no built-in rule
170
+ // matched — this is how hard-gate / store-compliance / improvement notes still land correctly.
171
+ if (ctx.categoryHint) {
172
+ return mk(ctx.categoryHint, ctx.severityHint ?? 'medium', `classified from caller-supplied category "${ctx.categoryHint}"`);
173
+ }
174
+ return mk('mcp_limitation', 'low', 'Unclassified observation — recorded for triage');
175
+ function mk(category, severity, reason, owner) {
176
+ return {
177
+ category,
178
+ severity,
179
+ owner: owner ?? OWNER_BY_CATEGORY[category],
180
+ confidence: 0.85,
181
+ reason,
182
+ releaseImpact: defaultReleaseImpact(category, severity),
183
+ };
184
+ }
185
+ }
186
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/issues/classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ // SWIPIUM Issue Log — stable fingerprinting (SWIPIUM-REQ-07 "Fingerprinting Rules").
2
+ //
3
+ // A fingerprint must be STABLE across sessions, timestamps, artifact paths, and random ids, but
4
+ // SPECIFIC enough not to merge unrelated defects. We build a normalized token list from the
5
+ // meaningful signals (failure code/category, platform, screen, route, exception type + top frame,
6
+ // HTTP route template + status, package, billing subsystem, normalized visible text) and hash it.
7
+ //
8
+ // Explicitly EXCLUDED (per spec): session id, screenshot/artifact paths, exact timestamps, random
9
+ // ids / emails / UUIDs / tokens / device ids / request ids, line numbers (unless disambiguating),
10
+ // and full stack traces. PURE — no clock, no fs.
11
+ import { createHash } from 'node:crypto';
12
+ /** Replace volatile tokens (timestamps, uuids, emails, ids, tokens) with stable placeholders. */
13
+ export function scrubVolatile(text) {
14
+ return text
15
+ .replace(/\d{4}-\d{2}-\d{2}(?:[t ]\d{2}:\d{2}:\d{2}(?:\.\d+)?z?)?/gi, ':ts') // ISO date/datetime
16
+ .replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, ':uuid') // UUID
17
+ .replace(/[\w.+-]+@[\w-]+\.[\w.-]+/g, ':email') // email
18
+ .replace(/\bBearer\s+[\w.\-]+/gi, ':token')
19
+ // Any token containing a digit is treated as a volatile id (session id, request id, hash,
20
+ // numeric id, hex). Status codes / version-like signals travel through structural fields, not
21
+ // free text, so over-scrubbing free text here is safe and maximizes fingerprint stability.
22
+ .replace(/\b[\w-]*\d[\w.-]*\b/gi, ':id')
23
+ .replace(/\s+/g, ' ')
24
+ .trim();
25
+ }
26
+ /** Normalize a URL/endpoint to a route template: drop host, replace id-ish path segments. */
27
+ export function normalizeRoute(rawUrl) {
28
+ let path = rawUrl;
29
+ // strip scheme + host
30
+ path = path.replace(/^[a-z]+:\/\/[^/]+/i, '');
31
+ // strip query/fragment
32
+ path = path.replace(/[?#].*$/, '');
33
+ const segs = path.split('/').map((seg) => {
34
+ if (!seg)
35
+ return seg;
36
+ if (/^\d+$/.test(seg))
37
+ return ':id'; // numeric id
38
+ if (/[a-f0-9]{8}-[a-f0-9]{4}-/i.test(seg))
39
+ return ':id'; // uuid-ish
40
+ if (/^[0-9a-f]{16,}$/i.test(seg))
41
+ return ':id'; // hex id
42
+ if (/\d/.test(seg) && /[a-z]/i.test(seg) && seg.length > 12)
43
+ return ':id'; // mixed long token
44
+ return seg.toLowerCase();
45
+ });
46
+ return segs.join('/') || '/';
47
+ }
48
+ /** Normalize an exception message: drop the "(reading 'x')" detail into a stable shape and scrub. */
49
+ export function normalizeException(type, message, topFrame) {
50
+ const parts = [];
51
+ if (type)
52
+ parts.push(type);
53
+ if (message) {
54
+ let m = message.toLowerCase();
55
+ // "Cannot read properties of undefined (reading 'map')" → "cannot_read_property map"
56
+ const reading = m.match(/cannot read propert(?:y|ies) of \w+ \(reading '([^']+)'\)/);
57
+ if (reading) {
58
+ m = `cannot_read_property ${reading[1]}`;
59
+ }
60
+ else {
61
+ m = scrubVolatile(m).replace(/[^a-z0-9 _]/g, ' ').replace(/\s+/g, ' ').trim();
62
+ // keep it short — a few meaningful words
63
+ m = m.split(' ').slice(0, 6).join(' ');
64
+ }
65
+ parts.push(m);
66
+ }
67
+ if (topFrame) {
68
+ // keep the file/function name, strip line:col numbers
69
+ const frame = topFrame.replace(/:\d+(:\d+)?$/, '').replace(/^at\s+/, '').trim();
70
+ parts.push(frame.split(/[\\/]/).pop() ?? frame);
71
+ }
72
+ return parts.join(' ').trim();
73
+ }
74
+ /** Build the ordered, normalized token list that defines an issue's identity. */
75
+ export function fingerprintTokens(input) {
76
+ const tokens = [];
77
+ const obs = input.observation ?? {};
78
+ if (input.failureCode)
79
+ tokens.push(`code:${input.failureCode.toLowerCase()}`);
80
+ else if (input.category)
81
+ tokens.push(`cat:${input.category}`);
82
+ if (input.platform && input.platform !== 'unknown')
83
+ tokens.push(`plat:${input.platform}`);
84
+ if (input.appId)
85
+ tokens.push(`app:${input.appId}`);
86
+ // Screen identity: prefer a stable app-map screen id / route, fall back to purpose.
87
+ if (obs.screenId)
88
+ tokens.push(`screen:${obs.screenId.toLowerCase()}`);
89
+ else if (obs.route)
90
+ tokens.push(`route:${normalizeRoute(obs.route)}`);
91
+ else if (obs.screenPurpose)
92
+ tokens.push(`purpose:${obs.screenPurpose.toLowerCase()}`);
93
+ if (obs.workflow)
94
+ tokens.push(`flow:${obs.workflow.toLowerCase().replace(/\s+/g, '_')}`);
95
+ if (obs.exception && (obs.exception.type || obs.exception.message || obs.exception.topFrame)) {
96
+ const ex = normalizeException(obs.exception.type, obs.exception.message, obs.exception.topFrame);
97
+ if (ex)
98
+ tokens.push(`exc:${ex}`);
99
+ }
100
+ if (obs.http && (obs.http.routeTemplate || obs.http.status != null)) {
101
+ const method = (obs.http.method ?? 'GET').toUpperCase();
102
+ const route = obs.http.routeTemplate ? normalizeRoute(obs.http.routeTemplate) : '';
103
+ tokens.push(`http:${method} ${route} status=${obs.http.status ?? ''}`.trim());
104
+ }
105
+ if (obs.packageName)
106
+ tokens.push(`pkg:${obs.packageName.toLowerCase()}`);
107
+ if (obs.subsystem)
108
+ tokens.push(`sub:${obs.subsystem.toLowerCase()}`);
109
+ // Only include visible text when there's no stronger structural signal (exception/http).
110
+ const hasStructural = Boolean(obs.exception || obs.http || obs.screenId || obs.route);
111
+ if (obs.visibleText && !hasStructural) {
112
+ const norm = scrubVolatile(obs.visibleText.toLowerCase()).split(' ').slice(0, 10).join(' ');
113
+ if (norm)
114
+ tokens.push(`text:${norm}`);
115
+ }
116
+ return tokens;
117
+ }
118
+ /** A short hex digest of the tokens, prefixed `sha256:` (matches the spec's example shape). */
119
+ export function fingerprint(input) {
120
+ const tokens = fingerprintTokens(input);
121
+ const basis = tokens.join('|');
122
+ const digest = createHash('sha256').update(basis).digest('hex');
123
+ return `sha256:${digest.slice(0, 32)}`;
124
+ }
125
+ /** Derive a short, stable issue id from a fingerprint (iss_<8 hex>). */
126
+ export function issueIdFromFingerprint(fp) {
127
+ const hex = fp.replace(/^sha256:/, '');
128
+ return `iss_${hex.slice(0, 8)}`;
129
+ }
130
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/issues/fingerprint.ts"],"names":[],"mappings":"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"}