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,73 @@
1
+ // Lightweight text/symbol index over source files (SWIPIUM-REQ-01 "All frameworks: build a
2
+ // lightweight text/symbol index over source files for feature queries"). Dependency-free: it
3
+ // extracts exported/declared symbol names + a small token bag per file so qa_app_map_query can
4
+ // rank source candidates without re-reading the tree. Persisted under .swipium/app-map.index/.
5
+ import { basename } from 'node:path';
6
+ import { rel, readTextSafe } from './fsWalk.js';
7
+ const SYMBOL_RES = [
8
+ /export\s+(?:default\s+)?(?:async\s+)?function\s+([A-Za-z0-9_]+)/g,
9
+ /export\s+(?:const|let|var)\s+([A-Za-z0-9_]+)/g,
10
+ /export\s+(?:default\s+)?class\s+([A-Za-z0-9_]+)/g,
11
+ /(?:^|\n)\s*(?:public\s+|final\s+|open\s+|abstract\s+)*(?:class|interface|object)\s+([A-Za-z0-9_]+)/g,
12
+ /struct\s+([A-Za-z0-9_]+)\s*:/g,
13
+ /(?:^|\n)\s*class\s+([A-Za-z0-9_]+)\s+extends\s+/g, // dart widgets
14
+ ];
15
+ function extractSymbols(text) {
16
+ const out = new Set();
17
+ for (const re of SYMBOL_RES) {
18
+ re.lastIndex = 0;
19
+ let m;
20
+ while ((m = re.exec(text)))
21
+ if (m[1])
22
+ out.add(m[1]);
23
+ }
24
+ return [...out].slice(0, 60);
25
+ }
26
+ function tokenize(text) {
27
+ const counts = new Map();
28
+ for (const m of text.matchAll(/[A-Za-z][A-Za-z0-9]{2,}/g)) {
29
+ // split camelCase into sub-words so "WeatherAnalysisScreen" matches "weather"/"analysis"
30
+ const word = m[0];
31
+ const parts = word.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase().split(/\s+/);
32
+ for (const p of parts)
33
+ if (p.length >= 3)
34
+ counts.set(p, (counts.get(p) ?? 0) + 1);
35
+ }
36
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 40).map(([t]) => t);
37
+ }
38
+ const STOP = new Set(['const', 'export', 'import', 'function', 'return', 'class', 'this', 'from', 'react', 'native', 'string', 'number', 'void', 'null', 'undefined', 'true', 'false', 'async', 'await']);
39
+ /** Build a code index from collected source files. Skips tests/specs and oversized files. */
40
+ export function buildCodeIndex(root, files, generatedAt) {
41
+ const out = [];
42
+ for (const f of files) {
43
+ const relPath = rel(root, f);
44
+ if (/\.(test|spec|stories)\./.test(basename(f)))
45
+ continue;
46
+ const text = readTextSafe(f);
47
+ if (!text || text.length > 400_000)
48
+ continue;
49
+ const symbols = extractSymbols(text);
50
+ const tokens = tokenize(text).filter((t) => !STOP.has(t));
51
+ if (!symbols.length && !tokens.length)
52
+ continue;
53
+ out.push({ file: relPath, symbols, tokens });
54
+ if (out.length >= 2000)
55
+ break;
56
+ }
57
+ return { schemaVersion: 1, generatedAt, files: out };
58
+ }
59
+ /** Score a file against query terms (symbol hits weigh more than token hits). */
60
+ export function scoreFile(entry, terms) {
61
+ let score = 0;
62
+ const symLower = entry.symbols.map((s) => s.toLowerCase());
63
+ for (const t of terms) {
64
+ if (symLower.some((s) => s.includes(t)))
65
+ score += 3;
66
+ if (entry.tokens.includes(t))
67
+ score += 1;
68
+ if (entry.file.toLowerCase().includes(t))
69
+ score += 2;
70
+ }
71
+ return score;
72
+ }
73
+ //# sourceMappingURL=codeIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeIndex.js","sourceRoot":"","sources":["../../src/appMap/codeIndex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ // Feature-NODE inference (SWIPIUM-REQ-01 FeatureNode). Complements featureIndex.ts (the lightweight
2
+ // code symbol/route index): this maps the static topology + library signals into candidate
3
+ // FeatureNodes for the AppKnowledgeMap. Inference is conservative — a feature backed by a single
4
+ // weak signal is a HYPOTHESIS, not a fact (Non-Goals § "Do not treat low-confidence feature
5
+ // inference as fact"). Runtime merge later enriches testCoverage + runtimeScreens; tickets scope.
6
+ import { combineConfidence } from './provenance.js';
7
+ // Ordered, lightweight semantic patterns matched against screen names/routes + source files.
8
+ const PATTERNS = [
9
+ { id: 'feature:auth', title: 'Authentication', objective: 'Sign in / sign up / sign out', re: /login|signin|sign-in|signup|sign-up|register|auth|password|forgot/i, risk: 'high' },
10
+ { id: 'feature:onboarding', title: 'Onboarding', objective: 'First-run welcome / tutorial', re: /onboard|welcome|intro|get-?started|walkthrough|tutorial/i, risk: 'low' },
11
+ { id: 'feature:paywall', title: 'Paywall / Subscription', objective: 'Purchase or subscribe', re: /paywall|subscribe|subscription|premium|upgrade|pricing|plans?|purchase|checkout|billing/i, risk: 'high' },
12
+ { id: 'feature:search', title: 'Search', objective: 'Search / discover content', re: /search|explore|discover|browse/i, risk: 'low' },
13
+ { id: 'feature:profile', title: 'Profile', objective: 'View / edit the user profile', re: /profile|account|\bme\b/i, risk: 'medium' },
14
+ { id: 'feature:settings', title: 'Settings', objective: 'Adjust app settings', re: /settings|preferences|config/i, risk: 'medium' },
15
+ { id: 'feature:notifications', title: 'Notifications', objective: 'View / manage notifications', re: /notification|alerts?|inbox/i, risk: 'low' },
16
+ { id: 'feature:create', title: 'Create / Add', objective: 'Create or add an item', re: /create|new|add|compose|post|upload/i, risk: 'medium' },
17
+ { id: 'feature:detail', title: 'Detail / View', objective: 'View an item detail', re: /detail|view|show|info/i, risk: 'low' },
18
+ { id: 'feature:checkout', title: 'Cart / Checkout', objective: 'Cart and checkout', re: /cart|checkout|order|payment|\bpay\b/i, risk: 'high' },
19
+ { id: 'feature:map', title: 'Map / Location', objective: 'Map or location features', re: /\bmap\b|location|nearby|geo/i, risk: 'low' },
20
+ { id: 'feature:media', title: 'Media', objective: 'Photos / video / camera', re: /camera|photo|video|gallery|media/i, risk: 'low' },
21
+ ];
22
+ export function inferFeatures(input) {
23
+ const { topo } = input;
24
+ const features = [];
25
+ for (const pat of PATTERNS) {
26
+ const screens = topo.screens.filter((s) => pat.re.test(s.name) || pat.re.test(s.route ?? '') || s.sourceFiles.some((f) => pat.re.test(f)));
27
+ if (!screens.length)
28
+ continue;
29
+ const sourceFiles = [...new Set(screens.flatMap((s) => s.sourceFiles))];
30
+ // signals: screen-name match + library corroboration for auth/paywall raise confidence to "fact".
31
+ const signals = [Math.min(0.85, 0.4 + 0.12 * screens.length)];
32
+ const reasons = [`matched ${screens.length} screen(s)`];
33
+ if (pat.id === 'feature:auth' && input.auth.libraries.length) {
34
+ signals.push(0.7);
35
+ reasons.push(`auth library: ${input.auth.libraries.join(', ')}`);
36
+ }
37
+ if (pat.id === 'feature:paywall' && input.paywalls.some((p) => p.libraries.length)) {
38
+ signals.push(0.7);
39
+ reasons.push('purchase/subscription library present');
40
+ }
41
+ if ((pat.id === 'feature:auth' || pat.id === 'feature:create' || pat.id === 'feature:search') && input.hasForms) {
42
+ signals.push(0.3);
43
+ reasons.push('form library present');
44
+ }
45
+ const confidence = combineConfidence(signals);
46
+ const corroborated = signals.length >= 2 || confidence >= 0.8;
47
+ features.push({
48
+ id: pat.id,
49
+ title: pat.title,
50
+ objective: pat.objective,
51
+ sourceFiles,
52
+ staticScreens: screens.map((s) => s.id),
53
+ runtimeScreens: [],
54
+ actions: [],
55
+ riskLevel: pat.risk,
56
+ testCoverage: 'none',
57
+ blockers: pat.id === 'feature:auth' ? ['Requires test credentials (fixture)'] : [],
58
+ status: corroborated ? 'fact' : 'hypothesis',
59
+ confidence,
60
+ reasons,
61
+ });
62
+ }
63
+ // Navigation is always a feature when there is more than one screen.
64
+ if (topo.screens.length > 1) {
65
+ features.push({
66
+ id: 'feature:navigation',
67
+ title: 'Navigation',
68
+ objective: "Move between the app's primary screens",
69
+ sourceFiles: [],
70
+ staticScreens: topo.screens.slice(0, 12).map((s) => s.id),
71
+ runtimeScreens: [],
72
+ actions: [],
73
+ riskLevel: 'low',
74
+ testCoverage: 'none',
75
+ blockers: [],
76
+ status: 'fact',
77
+ confidence: 0.9,
78
+ reasons: [`${topo.screens.length} screens, ${topo.edges.length} navigation edges`],
79
+ });
80
+ }
81
+ return features;
82
+ }
83
+ //# sourceMappingURL=featureModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureModel.js","sourceRoot":"","sources":["../../src/appMap/featureModel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ // SWIPIUM-REQ-02 / REQ-01 Fix Group 5 — apply first-run classifications to the durable app map.
2
+ // runFirstRun() emits AppMapPatch[] (per-screen purpose + auth/onboarding/paywall signals + observed
3
+ // transitions). Historically these were written ONLY as a detached session artifact. This module
4
+ // folds them into AppKnowledgeMap so a runtime login/onboarding/paywall screen durably updates the
5
+ // map's runtime topology + auth/onboarding/paywall models + provenance. PURE (mutates the passed map).
6
+ import { addProvenance, makeProvenance } from './provenance.js';
7
+ import { computeUnvisitedStaticScreens } from './runtimeMerge.js';
8
+ const AUTH_PURPOSES = new Set(['login', 'create_account', 'login_or_create_account', 'otp_or_email_verification']);
9
+ function findScreenBySignature(map, sig) {
10
+ if (!sig)
11
+ return undefined;
12
+ return map.runtimeTopology.screens.find((s) => s.signature === sig || s.uiSignature === sig || s.visualSignature === sig);
13
+ }
14
+ function defaultPlatform(map) {
15
+ if (map.project.platforms.length === 1)
16
+ return map.project.platforms[0];
17
+ return map.runtimeTopology.screens[0]?.platform ?? 'android';
18
+ }
19
+ function upsertPaywall(map, screenId, confidence) {
20
+ let pw = map.paywalls.find((f) => f.kind === 'paywall');
21
+ if (!pw) {
22
+ pw = { id: 'paywall', kind: 'paywall', present: true, signals: [], libraries: [], screens: [], confidence: 0 };
23
+ map.paywalls.push(pw);
24
+ }
25
+ pw.present = true;
26
+ pw.signals = [...new Set([...pw.signals, 'runtime_first_run'])];
27
+ if (!pw.screens.includes(screenId))
28
+ pw.screens.push(screenId);
29
+ pw.confidence = Math.max(pw.confidence, confidence);
30
+ }
31
+ /** Fold first-run classifications into the map's runtime topology + auth/onboarding/paywall models. */
32
+ export function applyFirstRunPatches(map, patches, at) {
33
+ const res = { updatedScreens: 0, newScreens: 0, authUpdated: false, onboardingUpdated: false, paywallUpdated: false };
34
+ const platform = defaultPlatform(map);
35
+ // Resolve the strongest static-screen link from a patch (Vision Gap Fix 2) against ids that actually
36
+ // exist in the static topology, so a runtime auth/onboarding screen durably links to its static id.
37
+ const staticIds = new Set(map.staticTopology.screens.map((s) => s.id));
38
+ const staticLinkOf = (p) => {
39
+ const links = (p.links ?? []).filter((l) => l.kind === 'staticScreen' && staticIds.has(l.id));
40
+ if (!links.length)
41
+ return undefined;
42
+ return links.reduce((best, l) => (l.confidence > best.confidence ? l : best), links[0]);
43
+ };
44
+ for (const p of patches) {
45
+ const staticLink = staticLinkOf(p);
46
+ let screen = findScreenBySignature(map, p.screenSignature);
47
+ if (screen) {
48
+ screen.purpose = p.purpose;
49
+ if (p.authState)
50
+ screen.authState = p.authState;
51
+ screen.lastSeen = at;
52
+ screen.lastArtifactUris = [...new Set([...(p.evidence ?? []), ...screen.lastArtifactUris])].slice(0, 10);
53
+ if (staticLink) {
54
+ screen.linkedStaticScreenId = staticLink.id;
55
+ screen.linkConfidence = Math.max(screen.linkConfidence ?? 0, staticLink.confidence);
56
+ screen.unmapped = false;
57
+ }
58
+ res.updatedScreens++;
59
+ }
60
+ else {
61
+ screen = {
62
+ id: `r${map.runtimeTopology.screens.length + 1}`,
63
+ signature: p.screenSignature,
64
+ platform,
65
+ purpose: p.purpose,
66
+ authState: p.authState,
67
+ lastArtifactUris: (p.evidence ?? []).slice(0, 10),
68
+ locatorReadiness: 'unknown',
69
+ firstSeen: at,
70
+ lastSeen: at,
71
+ visits: 1,
72
+ ...(staticLink ? { linkedStaticScreenId: staticLink.id, linkConfidence: staticLink.confidence, unmapped: false } : { unmapped: true }),
73
+ };
74
+ map.runtimeTopology.screens.push(screen);
75
+ res.newScreens++;
76
+ }
77
+ if (AUTH_PURPOSES.has(p.purpose)) {
78
+ map.auth.hasAuth = true;
79
+ map.auth.loginScreenSeen = true;
80
+ if (!map.auth.screens.includes(screen.id))
81
+ map.auth.screens.push(screen.id);
82
+ // Link the static screen too (Fix 2): the auth model lists both the runtime and static screen.
83
+ if (staticLink && !map.auth.screens.includes(staticLink.id))
84
+ map.auth.screens.push(staticLink.id);
85
+ map.auth.signals = [...new Set([...map.auth.signals, 'runtime_first_run'])];
86
+ map.auth.confidence = Math.max(map.auth.confidence, p.confidence);
87
+ res.authUpdated = true;
88
+ }
89
+ else if (p.purpose === 'onboarding') {
90
+ const ob = map.onboarding ?? { id: 'onboarding', kind: 'onboarding', present: false, signals: [], libraries: [], screens: [], confidence: 0 };
91
+ ob.present = true;
92
+ ob.signals = [...new Set([...ob.signals, 'runtime_first_run'])];
93
+ if (!ob.screens.includes(screen.id))
94
+ ob.screens.push(screen.id);
95
+ ob.confidence = Math.max(ob.confidence, p.confidence);
96
+ map.onboarding = ob;
97
+ res.onboardingUpdated = true;
98
+ }
99
+ else if (p.purpose === 'paywall') {
100
+ upsertPaywall(map, screen.id, p.confidence);
101
+ res.paywallUpdated = true;
102
+ }
103
+ }
104
+ // Observed transitions → runtime edges (best-effort; only when both endpoints resolve).
105
+ for (const p of patches) {
106
+ const fromSig = p.transition?.fromSignature;
107
+ if (!fromSig)
108
+ continue;
109
+ const from = findScreenBySignature(map, fromSig);
110
+ const to = findScreenBySignature(map, p.screenSignature);
111
+ if (!from || !to)
112
+ continue;
113
+ const exists = map.runtimeTopology.edges.find((e) => e.from === from.id && e.to === to.id && e.action.type === 'first_run_step');
114
+ if (!exists) {
115
+ map.runtimeTopology.edges.push({
116
+ from: from.id,
117
+ to: to.id,
118
+ action: { type: 'first_run_step', targetDescription: p.purpose },
119
+ outcome: p.transition?.outcome ?? 'changed_screen',
120
+ evidenceUris: (p.evidence ?? []).slice(0, 5),
121
+ observedCount: 1,
122
+ });
123
+ }
124
+ }
125
+ map.runtimeTopology.unvisitedStaticScreens = computeUnvisitedStaticScreens(map);
126
+ if (patches.length) {
127
+ addProvenance(map, makeProvenance('runtime', at, `First-run classifications: ${[...new Set(patches.map((p) => p.purpose))].slice(0, 6).join(', ')}`, { targetType: 'map' }));
128
+ }
129
+ return res;
130
+ }
131
+ //# sourceMappingURL=firstRunApply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firstRunApply.js","sourceRoot":"","sources":["../../src/appMap/firstRunApply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ // Bounded, dependency-free source-file walker shared by the static scanner and code index.
2
+ // Never throws on an unreadable dir; caps total files so a huge monorepo can't blow up a scan.
3
+ import { createHash } from 'node:crypto';
4
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
5
+ import { join, relative } from 'node:path';
6
+ const IGNORE_DIRS = new Set([
7
+ 'node_modules', '.git', '.swipium', 'build', 'dist', 'out', '.next', '.expo', 'Pods', 'DerivedData',
8
+ '.gradle', '.idea', 'vendor', 'coverage', '__pycache__', '.dart_tool', '.venv', 'venv', 'Carthage',
9
+ ]);
10
+ export function readTextSafe(path) {
11
+ try {
12
+ return readFileSync(path, 'utf8');
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ /** Recursively collect file paths under `root`, honoring ignore dirs + caps. Best-effort. */
19
+ export function walkFiles(root, opts = {}) {
20
+ const exts = opts.exts?.map((e) => e.toLowerCase());
21
+ const names = new Set(opts.alsoNames ?? []);
22
+ const maxFiles = opts.maxFiles ?? 4000;
23
+ const maxDepth = opts.maxDepth ?? 12;
24
+ const out = [];
25
+ const walk = (dir, depth) => {
26
+ if (out.length >= maxFiles || depth > maxDepth)
27
+ return;
28
+ let entries;
29
+ try {
30
+ entries = readdirSync(dir, { withFileTypes: true });
31
+ }
32
+ catch {
33
+ return;
34
+ }
35
+ for (const e of entries) {
36
+ if (out.length >= maxFiles)
37
+ return;
38
+ if (e.name.startsWith('.') && e.name !== '.well-known') {
39
+ // allow hidden files only if explicitly named
40
+ if (!names.has(e.name))
41
+ continue;
42
+ }
43
+ const full = join(dir, e.name);
44
+ if (e.isDirectory()) {
45
+ if (IGNORE_DIRS.has(e.name))
46
+ continue;
47
+ walk(full, depth + 1);
48
+ }
49
+ else if (e.isFile()) {
50
+ const lower = e.name.toLowerCase();
51
+ const extOk = !exts || exts.some((x) => lower.endsWith(x));
52
+ if (extOk || names.has(e.name))
53
+ out.push(full);
54
+ }
55
+ }
56
+ };
57
+ walk(root, 0);
58
+ return out;
59
+ }
60
+ export function fileHash(path) {
61
+ try {
62
+ const st = statSync(path);
63
+ if (!st.isFile())
64
+ return null;
65
+ const h = createHash('sha256').update(readFileSync(path)).digest('hex');
66
+ return { hash: `sha256:${h}`, mtimeMs: Math.round(st.mtimeMs) };
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ export function rel(root, path) {
73
+ return relative(root, path).split('\\').join('/');
74
+ }
75
+ //# sourceMappingURL=fsWalk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsWalk.js","sourceRoot":"","sources":["../../src/appMap/fsWalk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,227 @@
1
+ // SWIPIUM-REQ-08 — derive compact app-map issue summaries from the durable issue ledger.
2
+ //
3
+ // The issue ledger (`.swipium/issues-log.jsonl`) stays the source of truth. This module reads the
4
+ // issue index + events and attaches a small `AppMapIssueSummary` to the screens/features an issue is
5
+ // confidently associated with — counts + pointers only, never full events. Rebuilt on every app-map
6
+ // refresh, so deleting the issue index and rebuilding loses nothing once the map is refreshed.
7
+ //
8
+ // PURE w.r.t. the clock (now is injected). Reads the ledger via src/issues/store.
9
+ import { combineReleaseImpact, defaultReleaseImpact } from '../issues/schema.js';
10
+ import { getIndex, readEvents } from '../issues/store.js';
11
+ import { loadSuite } from '../testSuite/store.js';
12
+ /** Categorize a record into the summary buckets. A record can land in several derived buckets. */
13
+ function isOpen(r) {
14
+ return (r.state === 'open' || r.state === 'observed_again' || r.state === 'needs_triage') && r.category !== 'environment_noise';
15
+ }
16
+ function isRecurring(r) {
17
+ return r.state === 'reopened' || Boolean(r.lastRecurrenceMessage);
18
+ }
19
+ function isKnownNoise(r) {
20
+ return r.state === 'expected_environment_noise' || r.state === 'suppressed' || r.category === 'environment_noise';
21
+ }
22
+ const SEVERITY_RANK = { blocker: 5, high: 4, medium: 3, low: 2, info: 1 };
23
+ /** Build a compact issue summary from the subset of issue records mapped to a screen/feature. */
24
+ export function buildAppMapIssueSummary(records, now) {
25
+ const open = records.filter(isOpen);
26
+ const recurring = records.filter(isRecurring);
27
+ const hardGate = records.filter((r) => r.category === 'hard_gate');
28
+ const storeCompliance = records.filter((r) => r.category === 'store_compliance' || r.category === 'security_privacy');
29
+ const knownNoise = records.filter(isKnownNoise);
30
+ const improvement = records.filter((r) => r.category === 'improvement' || r.category === 'accessibility_readiness');
31
+ const fixed = records.filter((r) => r.state === 'fixed');
32
+ // Release impact rolls up non-suppressed, non-fixed, real-defect/gate/compliance records.
33
+ const impacts = records
34
+ .filter((r) => r.state !== 'suppressed' && r.state !== 'expected_environment_noise' && r.state !== 'fixed' && r.category !== 'environment_noise')
35
+ .map((r) => defaultReleaseImpact(r.category, r.severity));
36
+ const ids = (rs) => rs.map((r) => r.issueId);
37
+ const lastIssueSeenAt = records.reduce((max, r) => (!max || r.lastSeenAt > max ? r.lastSeenAt : max), undefined);
38
+ const topIssueIds = records
39
+ .slice()
40
+ .sort((a, b) => (SEVERITY_RANK[b.severity] ?? 0) - (SEVERITY_RANK[a.severity] ?? 0) || (b.lastSeenAt > a.lastSeenAt ? 1 : -1))
41
+ .slice(0, 5)
42
+ .map((r) => r.issueId);
43
+ return {
44
+ openIssueIds: ids(open),
45
+ recurringIssueIds: ids(recurring),
46
+ hardGateIssueIds: ids(hardGate),
47
+ storeComplianceIssueIds: ids(storeCompliance),
48
+ knownNoiseIssueIds: ids(knownNoise),
49
+ improvementIssueIds: ids(improvement),
50
+ fixedIssueIds: ids(fixed),
51
+ counts: {
52
+ open: open.length,
53
+ recurring: recurring.length,
54
+ hardGate: hardGate.length,
55
+ storeCompliance: storeCompliance.length,
56
+ knownNoise: knownNoise.length,
57
+ improvement: improvement.length,
58
+ fixed: fixed.length,
59
+ },
60
+ releaseImpact: combineReleaseImpact(impacts),
61
+ lastIssueSeenAt,
62
+ topIssueIds,
63
+ updatedAt: now,
64
+ };
65
+ }
66
+ /**
67
+ * Build per-issue screen/feature associations from the event log (mapping rules in REQ-08 order):
68
+ * 1. explicit links.appMapRefs (screenId/featureId)
69
+ * 2. observation.screenId matching a runtime/static screen id
70
+ * 3. observation.screenPurpose matching a runtime screen purpose
71
+ * Issues with no confident mapping stay project-level only (never attached to a random screen).
72
+ */
73
+ export function issueAssociations(root, map) {
74
+ const assoc = new Map();
75
+ const ensure = (id) => {
76
+ let a = assoc.get(id);
77
+ if (!a)
78
+ assoc.set(id, (a = { screenIds: new Set(), featureIds: new Set() }));
79
+ return a;
80
+ };
81
+ const runtimeIds = new Set(map.runtimeTopology.screens.map((s) => s.id));
82
+ const staticIds = new Set(map.staticTopology.screens.map((s) => s.id));
83
+ const purposeIndex = new Map(); // purpose(lower) → runtime screen ids
84
+ for (const s of map.runtimeTopology.screens) {
85
+ if (s.purpose) {
86
+ const key = s.purpose.toLowerCase();
87
+ purposeIndex.set(key, [...(purposeIndex.get(key) ?? []), s.id]);
88
+ }
89
+ }
90
+ for (const ev of readEvents(root)) {
91
+ const a = ensure(ev.issueId);
92
+ // 1. explicit app-map refs.
93
+ for (const ref of ev.links?.appMapRefs ?? []) {
94
+ if (ref.screenId)
95
+ a.screenIds.add(ref.screenId);
96
+ if (ref.featureId)
97
+ a.featureIds.add(ref.featureId);
98
+ }
99
+ const obs = ev.observation;
100
+ if (obs?.screenId) {
101
+ // 2. screen id that matches a known screen.
102
+ if (runtimeIds.has(obs.screenId) || staticIds.has(obs.screenId))
103
+ a.screenIds.add(obs.screenId);
104
+ }
105
+ // 3. screen purpose → runtime screens with that purpose.
106
+ if (obs?.screenPurpose) {
107
+ for (const sid of purposeIndex.get(obs.screenPurpose.toLowerCase()) ?? [])
108
+ a.screenIds.add(sid);
109
+ }
110
+ }
111
+ // Roll screen associations up to the features that contain those screens.
112
+ for (const f of map.features) {
113
+ const owned = new Set([...f.staticScreens, ...f.runtimeScreens]);
114
+ for (const [issueId, a] of assoc) {
115
+ if ([...a.screenIds].some((sid) => owned.has(sid)))
116
+ a.featureIds.add(f.id);
117
+ void issueId;
118
+ }
119
+ }
120
+ // 4. observation.workflow → test-suite case → feature. Read the persistent suite's COMPACT issue
121
+ // links (issue id + featureId only — never case history) so an issue attached only to a test case
122
+ // still shows up on the owning feature's summary (REQ-08 follow-up).
123
+ try {
124
+ const suite = loadSuite(root, map.appIdentity?.androidPackage ?? undefined);
125
+ for (const c of suite.cases) {
126
+ if (!c.featureId)
127
+ continue;
128
+ for (const ref of c.issueRefs ?? [])
129
+ ensure(ref.issueId).featureIds.add(c.featureId);
130
+ for (const run of c.history ?? [])
131
+ for (const link of run.issueLinks ?? [])
132
+ ensure(link.issueId).featureIds.add(c.featureId);
133
+ }
134
+ }
135
+ catch {
136
+ /* best-effort — suite is optional */
137
+ }
138
+ return assoc;
139
+ }
140
+ /**
141
+ * Attach derived issue summaries to the map's screens + features from the issue ledger. Clears stale
142
+ * summaries when an issue no longer maps to a node. The map keeps only counts + ids.
143
+ */
144
+ export function applyIssueSummariesToAppMap(map, root, now) {
145
+ const index = getIndex(root, now, map.appIdentity?.androidPackage ?? undefined);
146
+ const byId = new Map(index.records.map((r) => [r.issueId, r]));
147
+ if (index.records.length === 0) {
148
+ // No ledger yet — clear any stale summaries and return.
149
+ for (const s of map.runtimeTopology.screens)
150
+ delete s.issueSummary;
151
+ for (const s of map.staticTopology.screens)
152
+ delete s.issueSummary;
153
+ for (const f of map.features)
154
+ delete f.issueSummary;
155
+ return { screensWithIssues: 0, featuresWithIssues: 0 };
156
+ }
157
+ const assoc = issueAssociations(root, map);
158
+ const recordsForScreen = (screenId) => {
159
+ const out = [];
160
+ for (const [issueId, a] of assoc) {
161
+ if (a.screenIds.has(screenId)) {
162
+ const r = byId.get(issueId);
163
+ if (r)
164
+ out.push(r);
165
+ }
166
+ }
167
+ return out;
168
+ };
169
+ const recordsForFeature = (featureId) => {
170
+ const out = [];
171
+ for (const [issueId, a] of assoc) {
172
+ if (a.featureIds.has(featureId)) {
173
+ const r = byId.get(issueId);
174
+ if (r)
175
+ out.push(r);
176
+ }
177
+ }
178
+ return out;
179
+ };
180
+ let screensWithIssues = 0;
181
+ let featuresWithIssues = 0;
182
+ const applyTo = (node, recs) => {
183
+ if (recs.length === 0) {
184
+ delete node.issueSummary;
185
+ return false;
186
+ }
187
+ node.issueSummary = buildAppMapIssueSummary(recs, now);
188
+ return true;
189
+ };
190
+ for (const s of map.runtimeTopology.screens)
191
+ if (applyTo(s, recordsForScreen(s.id)))
192
+ screensWithIssues++;
193
+ for (const s of map.staticTopology.screens)
194
+ if (applyTo(s, recordsForScreen(s.id)))
195
+ screensWithIssues++;
196
+ for (const f of map.features) {
197
+ const recs = recordsForFeature(f.id);
198
+ if (recs.length === 0) {
199
+ delete f.issueSummary;
200
+ continue;
201
+ }
202
+ f.issueSummary = buildAppMapIssueSummary(recs, now);
203
+ featuresWithIssues++;
204
+ }
205
+ return { screensWithIssues, featuresWithIssues };
206
+ }
207
+ /** Structural validation for a persisted AppMapIssueSummary (best-effort; returns error strings). */
208
+ export function validateIssueSummary(s, where) {
209
+ const errs = [];
210
+ if (s == null)
211
+ return errs;
212
+ if (typeof s !== 'object')
213
+ return [`${where}: issueSummary is not an object`];
214
+ const o = s;
215
+ const arrays = ['openIssueIds', 'recurringIssueIds', 'hardGateIssueIds', 'storeComplianceIssueIds', 'knownNoiseIssueIds', 'improvementIssueIds', 'fixedIssueIds', 'topIssueIds'];
216
+ for (const k of arrays)
217
+ if (o[k] != null && !Array.isArray(o[k]))
218
+ errs.push(`${where}.${k} must be an array`);
219
+ if (o.counts != null && typeof o.counts !== 'object')
220
+ errs.push(`${where}.counts must be an object`);
221
+ if (o.releaseImpact != null && !['block', 'warn', 'pass'].includes(o.releaseImpact))
222
+ errs.push(`${where}.releaseImpact invalid`);
223
+ if (o.updatedAt != null && typeof o.updatedAt !== 'string')
224
+ errs.push(`${where}.updatedAt must be a string`);
225
+ return errs;
226
+ }
227
+ //# sourceMappingURL=issues.js.map