@dailephd/my-dev-kit-lab 0.4.5 → 0.4.7

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 (263) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/README.md +43 -3
  3. package/dist/scripts/cli.js +9 -0
  4. package/dist/src/audits/core/typescriptJavaScriptAnalyzer.js +30 -12
  5. package/dist/src/browser/index.js +2 -0
  6. package/dist/src/browser/playwrightRuntime.js +74 -0
  7. package/dist/src/browser/types.js +10 -0
  8. package/dist/src/cli/help.js +376 -0
  9. package/dist/src/cli/index.js +2 -0
  10. package/dist/src/cli/runLabCli.js +257 -0
  11. package/dist/src/commands/runAuditCommand.js +132 -0
  12. package/dist/src/commands/runControlledExperimentCommand.js +7 -3
  13. package/dist/{scripts/experiments/describeExperiment.js → src/commands/runExperimentDescribeCommand.js} +14 -10
  14. package/dist/{scripts/experiments/listExperiments.js → src/commands/runExperimentListCommand.js} +3 -6
  15. package/dist/{scripts/experiments/runExperiment.js → src/commands/runExperimentRunCommand.js} +80 -22
  16. package/dist/src/commands/runFinalDemoCommand.js +2 -3
  17. package/dist/src/commands/runSecurityValidationCommand.js +271 -0
  18. package/dist/src/commands/runTutorialRunCommand.js +170 -0
  19. package/dist/src/commands/runTutorialValidateCommand.js +138 -0
  20. package/dist/src/core/processTree.js +52 -0
  21. package/dist/src/core/resolveCommand.js +34 -0
  22. package/dist/src/core/runMeasuredCommand.js +39 -31
  23. package/dist/src/runtime/index.js +4 -0
  24. package/dist/src/runtime/labExecutionContext.js +22 -0
  25. package/dist/src/runtime/managedProcess.js +380 -0
  26. package/dist/src/runtime/packageResource.js +22 -0
  27. package/dist/src/runtime/packageRoot.js +37 -0
  28. package/dist/src/screenshot/captureReportScreenshot.js +30 -27
  29. package/dist/src/securityValidation/packageChecks/requiredPackageContents.js +14 -1
  30. package/dist/src/tutorial/index.js +16 -0
  31. package/dist/src/tutorial/loadTutorialContracts.js +60 -0
  32. package/dist/src/tutorial/markdownTutorialWriter.js +53 -0
  33. package/dist/src/tutorial/runTutorial.js +465 -0
  34. package/dist/src/tutorial/scenarioValidation.js +383 -0
  35. package/dist/src/tutorial/subtitleWriter.js +88 -0
  36. package/dist/src/tutorial/targetContractValidation.js +212 -0
  37. package/dist/src/tutorial/tutorialActions.js +110 -0
  38. package/dist/src/tutorial/tutorialArtifacts.js +176 -0
  39. package/dist/src/tutorial/tutorialAssertions.js +249 -0
  40. package/dist/src/tutorial/tutorialCursor.js +149 -0
  41. package/dist/src/tutorial/tutorialLocators.js +37 -0
  42. package/dist/src/tutorial/tutorialManifest.js +74 -0
  43. package/dist/src/tutorial/tutorialOverlay.js +180 -0
  44. package/dist/src/tutorial/tutorialPaths.js +86 -0
  45. package/dist/src/tutorial/tutorialSession.js +398 -0
  46. package/dist/src/tutorial/types.js +48 -0
  47. package/dist/src/tutorial/validationPrimitives.js +141 -0
  48. package/examples/tutorial-browser/index.html +47 -0
  49. package/examples/tutorial-browser/prepare.mjs +14 -0
  50. package/examples/tutorial-browser/scenario.json +17 -0
  51. package/examples/tutorial-browser/server.mjs +14 -0
  52. package/package.json +13 -9
  53. package/dist/scripts/audits/runAudit.js +0 -135
  54. package/dist/scripts/build-gallery.js +0 -3
  55. package/dist/scripts/capture-demo-report.js +0 -3
  56. package/dist/scripts/evaluate-token-savings.js +0 -2
  57. package/dist/scripts/generate-experiment-plots.js +0 -3
  58. package/dist/scripts/generate-prompt-variants.js +0 -2
  59. package/dist/scripts/render-experiment-report.js +0 -2
  60. package/dist/scripts/report-context-integrity-smoke.js +0 -70
  61. package/dist/scripts/run-agent-prompt.js +0 -2
  62. package/dist/scripts/run-controlled-experiment.js +0 -2
  63. package/dist/scripts/run-lab-demo.js +0 -5
  64. package/dist/scripts/run-visualization-demos.js +0 -3
  65. package/dist/scripts/security/resolveToolRoot.js +0 -16
  66. package/dist/scripts/security/runCodeql.js +0 -58
  67. package/dist/scripts/security/runDependencyChecks.js +0 -58
  68. package/dist/scripts/security/runFuzzSmoke.js +0 -29
  69. package/dist/scripts/security/runPackageChecks.js +0 -57
  70. package/dist/scripts/security/runSemgrep.js +0 -64
  71. package/dist/scripts/security/validate.js +0 -266
  72. package/dist/scripts/verify-benchmarks.js +0 -202
  73. package/examples/demo-report-input.json +0 -78
  74. package/examples/lab-demo-cases.json +0 -35
  75. package/examples/real-agent-campaign-cases.json +0 -118
  76. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/debug/res/xml/ambiguous_backup_rules.xml +0 -4
  77. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/ambiguous_backup_rules.xml +0 -4
  78. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/backup_rules.xml +0 -5
  79. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/broad_backup_rules.xml +0 -4
  80. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/data_extraction_rules.xml +0 -10
  81. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/unsupported_domain_rules.xml +0 -4
  82. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-b/src/main/res/xml/malformed_backup_rules.xml +0 -4
  83. package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-b/src/main/res/xml/unsupported_root.xml +0 -4
  84. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/debug/res/xml/ambiguous_config.xml +0 -4
  85. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/ambiguous_config.xml +0 -4
  86. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/base_cleartext_false.xml +0 -8
  87. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/broad_and_duplicate_domains.xml +0 -8
  88. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/empty_domain.xml +0 -6
  89. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/malformed_pin.xml +0 -11
  90. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/network_security_config.xml +0 -26
  91. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-b/src/main/res/xml/malformed_network_security_config.xml +0 -6
  92. package/tests/fixtures/android/advanced-security-fixtures/network-security/module-b/src/main/res/xml/unsupported_root.xml +0 -4
  93. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-dynamic.gradle +0 -7
  94. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-false.gradle +0 -9
  95. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-true.gradle +0 -13
  96. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/kotlin-release-debuggable-false.gradle.kts +0 -7
  97. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/kotlin-release-debuggable-true.gradle.kts +0 -10
  98. package/tests/fixtures/android/advanced-security-fixtures/release-configuration/missing-release-build-type.gradle.kts +0 -7
  99. package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/debug/res/xml/network_security_config.xml +0 -8
  100. package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/main/res/xml/backup_rules.xml +0 -4
  101. package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/main/res/xml/network_security_config.xml +0 -8
  102. package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-b/src/main/res/xml/malformed_network_security_config.xml +0 -7
  103. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/SampleActivity.java +0 -8
  104. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/SampleActivity.kt +0 -9
  105. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/build.gradle +0 -11
  106. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/build.gradle.kts +0 -11
  107. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/google-services.json +0 -16
  108. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/local.properties +0 -3
  109. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates-bounds/module/binary.properties +0 -0
  110. package/tests/fixtures/android/advanced-security-fixtures/secret-candidates-bounds/module/oversized.json +0 -1
  111. package/tests/fixtures/android/advanced-security-fixtures/signing-configuration/app/fake-release-keystore.jks +0 -1
  112. package/tests/fixtures/android/advanced-security-fixtures/signing-configuration/build/generated-fake.keystore +0 -1
  113. package/tests/fixtures/android/compose-app/app/build.gradle.kts +0 -21
  114. package/tests/fixtures/android/compose-app/app/src/main/AndroidManifest.xml +0 -22
  115. package/tests/fixtures/android/compose-app/app/src/main/java/com/example/composeapp/MainActivity.kt +0 -11
  116. package/tests/fixtures/android/compose-app/build.gradle.kts +0 -4
  117. package/tests/fixtures/android/compose-app/gradle/wrapper/gradle-wrapper.properties +0 -4
  118. package/tests/fixtures/android/compose-app/settings.gradle.kts +0 -2
  119. package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/build.gradle.kts +0 -3
  120. package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/gradle/libs.versions.toml +0 -5
  121. package/tests/fixtures/android/gradle-metadata-fixtures/comment-safety.gradle.kts +0 -21
  122. package/tests/fixtures/android/gradle-metadata-fixtures/dynamic-values.gradle.kts +0 -17
  123. package/tests/fixtures/android/gradle-metadata-fixtures/groovy-literal.gradle +0 -23
  124. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-malformed.properties +0 -4
  125. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-missing-url.properties +0 -3
  126. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-with-checksum.properties +0 -5
  127. package/tests/fixtures/android/java-app/app/build.gradle +0 -16
  128. package/tests/fixtures/android/java-app/app/src/main/AndroidManifest.xml +0 -19
  129. package/tests/fixtures/android/java-app/app/src/main/java/com/example/javaapp/MainActivity.java +0 -4
  130. package/tests/fixtures/android/java-app/build.gradle +0 -3
  131. package/tests/fixtures/android/java-app/gradle/wrapper/gradle-wrapper.properties +0 -4
  132. package/tests/fixtures/android/java-app/settings.gradle +0 -2
  133. package/tests/fixtures/android/library/build.gradle.kts +0 -3
  134. package/tests/fixtures/android/library/gradle/wrapper/gradle-wrapper.properties +0 -4
  135. package/tests/fixtures/android/library/mylibrary/build.gradle.kts +0 -13
  136. package/tests/fixtures/android/library/mylibrary/src/main/AndroidManifest.xml +0 -2
  137. package/tests/fixtures/android/library/settings.gradle.kts +0 -2
  138. package/tests/fixtures/android/manifest-audit-fixtures/incomplete-intent-filter.xml +0 -14
  139. package/tests/fixtures/android/manifest-audit-fixtures/malformed-exported.xml +0 -10
  140. package/tests/fixtures/android/manifest-audit-fixtures/malformed.xml +0 -5
  141. package/tests/fixtures/android/manifest-audit-fixtures/missing-application.xml +0 -7
  142. package/tests/fixtures/android/manifest-audit-fixtures/missing-component-name.xml +0 -11
  143. package/tests/fixtures/android/manifest-audit-fixtures/permission-coverage.xml +0 -29
  144. package/tests/fixtures/android/manifest-audit-fixtures/risky-components.xml +0 -62
  145. package/tests/fixtures/android/manifest-audit-fixtures/risky-deep-links.xml +0 -45
  146. package/tests/fixtures/android/manifest-audit-fixtures/unresolved-placeholder.xml +0 -14
  147. package/tests/fixtures/android/manifest-audit-fixtures/unusual-namespace-prefix.xml +0 -11
  148. package/tests/fixtures/android/multi-module/app/build.gradle.kts +0 -22
  149. package/tests/fixtures/android/multi-module/app/src/androidTest/java/com/example/multimodule/app/ExampleInstrumentedTest.kt +0 -3
  150. package/tests/fixtures/android/multi-module/app/src/main/AndroidManifest.xml +0 -11
  151. package/tests/fixtures/android/multi-module/app/src/test/java/com/example/multimodule/app/ExampleUnitTest.kt +0 -3
  152. package/tests/fixtures/android/multi-module/build.gradle.kts +0 -5
  153. package/tests/fixtures/android/multi-module/core/build.gradle.kts +0 -14
  154. package/tests/fixtures/android/multi-module/core/src/main/AndroidManifest.xml +0 -2
  155. package/tests/fixtures/android/multi-module/feature-login/build.gradle.kts +0 -18
  156. package/tests/fixtures/android/multi-module/feature-login/src/main/AndroidManifest.xml +0 -2
  157. package/tests/fixtures/android/multi-module/gradle/libs.versions.toml +0 -8
  158. package/tests/fixtures/android/multi-module/gradle/wrapper/gradle-wrapper.properties +0 -4
  159. package/tests/fixtures/android/multi-module/settings.gradle.kts +0 -4
  160. package/tests/fixtures/android/non-android-gradle/build.gradle.kts +0 -3
  161. package/tests/fixtures/android/non-android-gradle/core/build.gradle.kts +0 -3
  162. package/tests/fixtures/android/non-android-gradle/core/src/main/java/com/example/core/Core.java +0 -4
  163. package/tests/fixtures/android/non-android-gradle/gradle/wrapper/gradle-wrapper.properties +0 -4
  164. package/tests/fixtures/android/non-android-gradle/settings.gradle.kts +0 -2
  165. package/tests/fixtures/android/partial/app/build.gradle.kts +0 -7
  166. package/tests/fixtures/android/partial/settings.gradle.kts +0 -2
  167. package/tests/fixtures/android/xml-view-app/app/build.gradle.kts +0 -17
  168. package/tests/fixtures/android/xml-view-app/app/src/main/AndroidManifest.xml +0 -31
  169. package/tests/fixtures/android/xml-view-app/app/src/main/kotlin/com/example/xmlviewapp/MainActivity.kt +0 -7
  170. package/tests/fixtures/android/xml-view-app/app/src/main/res/layout/activity_main.xml +0 -4
  171. package/tests/fixtures/android/xml-view-app/build.gradle.kts +0 -4
  172. package/tests/fixtures/android/xml-view-app/gradle/wrapper/gradle-wrapper.properties +0 -4
  173. package/tests/fixtures/android/xml-view-app/settings.gradle.kts +0 -2
  174. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/README.md +0 -16
  175. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/build.gradle.kts +0 -4
  176. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/src/main/java/com/example/Widget.java +0 -7
  177. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/src/main/kotlin/com/example/Gadget.kt +0 -7
  178. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/README.md +0 -10
  179. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/build/Main.class +0 -1
  180. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/dist/index.js +0 -1
  181. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/generated/schema.ts +0 -1
  182. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/src/index.ts +0 -3
  183. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/vendor/lib.py +0 -2
  184. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/README.md +0 -10
  185. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/build.gradle.kts +0 -8
  186. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/settings.gradle.kts +0 -1
  187. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/main/java/com/example/FooService.java +0 -7
  188. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/main/kotlin/com/example/BarService.kt +0 -7
  189. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/test/java/com/example/FooServiceTest.java +0 -8
  190. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/test/kotlin/com/example/BarServiceTest.kt +0 -8
  191. package/tests/fixtures/audits/mixed-language/mixed-python-ts/README.md +0 -8
  192. package/tests/fixtures/audits/mixed-language/mixed-python-ts/src/app.py +0 -7
  193. package/tests/fixtures/audits/mixed-language/mixed-python-ts/src/index.ts +0 -3
  194. package/tests/fixtures/audits/mixed-language/mixed-python-ts/tests/test_app.py +0 -5
  195. package/tests/fixtures/audits/mixed-language/mixed-ts-js/README.md +0 -7
  196. package/tests/fixtures/audits/mixed-language/mixed-ts-js/src/helper.js +0 -5
  197. package/tests/fixtures/audits/mixed-language/mixed-ts-js/src/index.ts +0 -3
  198. package/tests/fixtures/audits/mixed-language/mixed-ts-js/tests/index.sample.ts +0 -5
  199. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/README.md +0 -10
  200. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/build.gradle.kts +0 -4
  201. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/pytests/test_app.py +0 -5
  202. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/app.py +0 -2
  203. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/helper.js +0 -5
  204. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/index.ts +0 -3
  205. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/main/java/com/example/Multiplier.java +0 -7
  206. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/main/kotlin/com/example/Divider.kt +0 -7
  207. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/derived/run-integrity-evidence.json +0 -99
  208. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-audit.json +0 -1585
  209. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-capsule.json +0 -11455
  210. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/00-request.txt +0 -1
  211. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/architecture-context-packet.txt +0 -82
  212. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/behavior-model.txt +0 -104
  213. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/final-report.txt +0 -41
  214. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-context-packet.txt +0 -114
  215. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-report.txt +0 -92
  216. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/judge-report.txt +0 -34
  217. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/pseudocode-packet.txt +0 -244
  218. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/request-brief.txt +0 -40
  219. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-context-packet.txt +0 -93
  220. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-implementation-report.txt +0 -69
  221. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-strategy-packet.txt +0 -354
  222. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/verification-report.txt +0 -85
  223. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/derived/run-integrity-evidence.json +0 -98
  224. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-audit.json +0 -1169
  225. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-request.json +0 -29
  226. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-audit.json +0 -1494
  227. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-capsule.json +0 -11364
  228. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-request.json +0 -33
  229. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/test-request.json +0 -74
  230. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/architecture-context-retrieval-report.txt +0 -58
  231. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/implementation-context-retrieval-report.txt +0 -75
  232. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/test-context-retrieval-report.txt +0 -84
  233. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/run.json +0 -62
  234. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/my-dev-kit-version.txt +0 -1
  235. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/orchestrator-version.txt +0 -1
  236. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/corrected-replay-manifest.json +0 -19
  237. package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/failed-run-manifest.json +0 -56
  238. package/tests/fixtures/fake-adversarial-cli.js +0 -152
  239. package/tests/fixtures/fake-my-dev-kit-cli.js +0 -83
  240. package/tests/fixtures/full-workflow-library/complete-v1.0.0.json +0 -24
  241. package/tests/fixtures/full-workflow-library/future-minor-v1.1.0-additive.json +0 -25
  242. package/tests/fixtures/stage-context-expectations/complete-v1.0.0.json +0 -230
  243. package/tests/fixtures/stage-context-expectations/future-minor-v1.1.0-additive.json +0 -232
  244. package/tests/fixtures/stage-context-expectations/invalid/malformed-json.txt +0 -1
  245. package/tests/fixtures/stage-context-expectations/invalid/non-object-root.json +0 -1
  246. package/tests/fixtures/stage-context-expectations/minimal-v1.0.0.json +0 -18
  247. package/tests/fixtures/upstream-artifacts/invalid/malformed-json.txt +0 -1
  248. package/tests/fixtures/upstream-artifacts/invalid/non-object-root.json +0 -1
  249. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/complete-v1.0.0.json +0 -504
  250. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/future-minor-v1.1.0-additive.json +0 -955
  251. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/complete-v1.0.0.json +0 -190
  252. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/future-minor-v1.1.0-additive.json +0 -327
  253. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/PROVENANCE.txt +0 -18
  254. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/context-capsule/complete-v1.0.0.json +0 -556
  255. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/retrieval-audit-record/complete-v1.0.0.json +0 -238
  256. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/PROVENANCE.txt +0 -13
  257. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/context-capsule.json +0 -7874
  258. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/retrieval-audit-record.json +0 -1076
  259. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/complete-v1.0.0.json +0 -160
  260. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/future-minor-v1.1.0-additive.json +0 -186
  261. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/PROVENANCE.txt +0 -31
  262. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/ready-pass-final-pass.json +0 -132
  263. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/refresh-required-need-context.json +0 -146
@@ -0,0 +1,465 @@
1
+ import { stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { launchChromium } from "../browser/index.js";
4
+ import { runMeasuredCommand } from "../core/runMeasuredCommand.js";
5
+ import { startManagedProcess } from "../runtime/managedProcess.js";
6
+ import { loadTutorialScenario, loadTutorialTargetContract } from "./loadTutorialContracts.js";
7
+ import { describeTargetIdMismatch, tutorialTargetIdsMatch } from "./targetContractValidation.js";
8
+ import { buildTutorialRunPaths, createTutorialRunDirectories, generateTutorialRunId } from "./tutorialPaths.js";
9
+ import { closeTutorialSession, executeTutorialSteps, openTutorialSession } from "./tutorialSession.js";
10
+ import { buildTutorialArtifactPaths, finalizeTutorialVideo, writeTextArtifact } from "./tutorialArtifacts.js";
11
+ import { buildSubtitleCues, renderSrt, renderVtt } from "./subtitleWriter.js";
12
+ import { renderTutorialMarkdown } from "./markdownTutorialWriter.js";
13
+ import { buildTutorialManifest, renderTutorialManifest } from "./tutorialManifest.js";
14
+ import { TARGET_ROOT_PLACEHOLDER, TUTORIAL_RUN_RESULT_SCHEMA_VERSION } from "./types.js";
15
+ export async function runTutorial(options) {
16
+ const startedAtMs = Date.now();
17
+ const startedAt = new Date(startedAtMs).toISOString();
18
+ const warnings = [];
19
+ const cleanupErrors = [];
20
+ const finish = (status, extra = {}) => {
21
+ const endedAtMs = Date.now();
22
+ return {
23
+ schemaVersion: TUTORIAL_RUN_RESULT_SCHEMA_VERSION,
24
+ status,
25
+ startedAt,
26
+ endedAt: new Date(endedAtMs).toISOString(),
27
+ durationMs: endedAtMs - startedAtMs,
28
+ steps: [],
29
+ artifacts: { screenshots: [] },
30
+ warnings,
31
+ cleanupErrors,
32
+ ...extra
33
+ };
34
+ };
35
+ // ---- 1. Contracts -------------------------------------------------------
36
+ const loadedScenario = await loadTutorialScenario(options.context.invocationCwd, options.scenarioPath);
37
+ if (!loadedScenario.ok) {
38
+ return finish("scenario-invalid", { error: loadedScenario.errors.join("\n") });
39
+ }
40
+ const { scenario } = loadedScenario.value;
41
+ const loadedTarget = await loadTutorialTargetContract(options.context.invocationCwd, options.targetContractPath);
42
+ if (!loadedTarget.ok) {
43
+ return finish("target-invalid", {
44
+ scenarioId: scenario.id,
45
+ error: loadedTarget.errors.join("\n")
46
+ });
47
+ }
48
+ const { targetContract, contractRoot } = loadedTarget.value;
49
+ // ---- 2. Identity --------------------------------------------------------
50
+ // Checked before any directory is created, any command runs, or any process
51
+ // starts, so a mismatched pair costs nothing but a comparison.
52
+ if (!tutorialTargetIdsMatch(scenario.targetId, targetContract.id)) {
53
+ return finish("target-mismatch", {
54
+ scenarioId: scenario.id,
55
+ targetId: targetContract.id,
56
+ error: describeTargetIdMismatch(scenario.targetId, targetContract.id)
57
+ });
58
+ }
59
+ // ---- 3. Run directory ---------------------------------------------------
60
+ const runId = (options.generateRunId ?? generateTutorialRunId)();
61
+ const paths = buildTutorialRunPaths({
62
+ workspaceRoot: options.context.workspaceRoot,
63
+ invocationCwd: options.context.invocationCwd,
64
+ scenarioId: scenario.id,
65
+ runId,
66
+ outDir: options.outDir
67
+ });
68
+ const identity = { scenarioId: scenario.id, targetId: targetContract.id, runId, paths };
69
+ try {
70
+ await createTutorialRunDirectories(paths);
71
+ }
72
+ catch (error) {
73
+ // No run layout, so no artifacts and no manifest are possible or expected.
74
+ return finish("prepare-failed", {
75
+ ...identity,
76
+ error: `Tutorial run directory could not be created at ${paths.runRoot}: ${messageOf(error)}`
77
+ });
78
+ }
79
+ /**
80
+ * Ends a run that failed before step execution produced anything recordable.
81
+ *
82
+ * The run layout exists, so a manifest is still written: it reports the real
83
+ * failure and marks every tutorial artifact as skipped rather than pretending
84
+ * one was produced. The failure status is never replaced by an artifact
85
+ * status -- an early failure is not a video problem.
86
+ */
87
+ const finishBeforeArtifacts = async (status, error, reason) => {
88
+ const skipped = (kind) => ({
89
+ kind,
90
+ status: "skipped",
91
+ error: reason
92
+ });
93
+ const artifacts = {
94
+ video: skipped("video"),
95
+ srt: skipped("srt"),
96
+ vtt: skipped("vtt"),
97
+ markdown: skipped("markdown"),
98
+ screenshots: []
99
+ };
100
+ const endedAtMs = Date.now();
101
+ const manifest = buildTutorialManifest({
102
+ scenario,
103
+ targetContract,
104
+ run: {
105
+ id: runId,
106
+ status,
107
+ startedAt,
108
+ endedAt: new Date(endedAtMs).toISOString(),
109
+ durationMs: endedAtMs - startedAtMs
110
+ },
111
+ steps: [],
112
+ artifacts: [artifacts.video, artifacts.srt, artifacts.vtt, artifacts.markdown],
113
+ warnings,
114
+ cleanupErrors
115
+ });
116
+ artifacts.manifest = await writeTextArtifact({
117
+ kind: "manifest",
118
+ runRoot: paths.runRoot,
119
+ filePath: buildTutorialArtifactPaths(paths).manifest,
120
+ contents: renderTutorialManifest(manifest)
121
+ });
122
+ if (artifacts.manifest.status === "failed") {
123
+ warnings.push(artifacts.manifest.error ?? "Tutorial manifest could not be written.");
124
+ }
125
+ return finish(status, { ...identity, artifacts, error });
126
+ };
127
+ // ---- 4. Prepare ---------------------------------------------------------
128
+ const prepareResult = await runPrepare(targetContract, contractRoot, paths);
129
+ if (prepareResult) {
130
+ return finishBeforeArtifacts("prepare-failed", prepareResult, "Tutorial preparation failed before any recording started.");
131
+ }
132
+ // ---- 5. Processes + readiness ------------------------------------------
133
+ const started = [];
134
+ const startup = await startTargetProcesses(targetContract, contractRoot, paths, started);
135
+ if (startup) {
136
+ cleanupErrors.push(...(await stopProcessesInReverse(started)));
137
+ return finishBeforeArtifacts(startup.status, startup.error, "Target processes did not become ready, so no recording started.");
138
+ }
139
+ // ---- 6. Browser ---------------------------------------------------------
140
+ const launch = await (options.launchBrowser ?? launchChromium)({ headless: true });
141
+ if (launch.status !== "launched") {
142
+ cleanupErrors.push(...(await stopProcessesInReverse(started)));
143
+ const status = launch.status === "unavailable" ? "browser-unavailable" : "browser-failed";
144
+ const error = launch.status === "unavailable"
145
+ ? `Tutorial browser runtime is unavailable (${launch.reason}): ${launch.error}`
146
+ : `Tutorial browser failed to launch: ${launch.error}`;
147
+ return finishBeforeArtifacts(status, error, "Tutorial recording never started because the browser was not available.");
148
+ }
149
+ const browser = launch.browser;
150
+ // ---- 7. Session + steps -------------------------------------------------
151
+ const artifactPaths = buildTutorialArtifactPaths(paths);
152
+ let steps = [];
153
+ let screenshots = [];
154
+ let primaryStatus = "passed";
155
+ let primaryError;
156
+ let videoRecordingStarted = false;
157
+ let videoRecord;
158
+ const opened = await openTutorialSession(browser, {
159
+ viewport: scenario.browser.viewport,
160
+ recordVideoDir: artifactPaths.videoTempDir
161
+ });
162
+ if (!opened.ok) {
163
+ primaryStatus = "browser-failed";
164
+ primaryError = opened.error;
165
+ }
166
+ else {
167
+ videoRecordingStarted = true;
168
+ const execution = await executeTutorialSteps({
169
+ page: opened.session.page,
170
+ scenario,
171
+ applicationUrl: targetContract.applicationUrl,
172
+ targetRoot: paths.targetRoot,
173
+ visuals: true,
174
+ paths,
175
+ ...(options.sleep ? { sleep: options.sleep } : {})
176
+ });
177
+ steps = execution.steps;
178
+ screenshots = execution.screenshots;
179
+ warnings.push(...execution.visualWarnings);
180
+ if (execution.failedStepId !== undefined) {
181
+ primaryStatus = "step-failed";
182
+ primaryError = execution.error;
183
+ }
184
+ // Playwright finalizes a recording only on page close, so the session is
185
+ // closed before the video is saved. A failed tutorial still gets its video.
186
+ cleanupErrors.push(...(await closeTutorialSession(opened.session)));
187
+ const finalized = await finalizeTutorialVideo({
188
+ video: opened.session.video,
189
+ runRoot: paths.runRoot,
190
+ videoPath: artifactPaths.video,
191
+ videoTempDir: artifactPaths.videoTempDir
192
+ });
193
+ videoRecord = finalized.record;
194
+ warnings.push(...finalized.warnings);
195
+ }
196
+ // ---- 8. Browser cleanup -------------------------------------------------
197
+ // Browser resources are released before the processes they were talking to.
198
+ const browserCloseError = await closeQuietly(() => browser.close());
199
+ if (browserCloseError) {
200
+ cleanupErrors.push(`Tutorial browser close failed: ${browserCloseError}`);
201
+ }
202
+ // ---- 9. Artifacts -------------------------------------------------------
203
+ if (!videoRecord) {
204
+ videoRecord = {
205
+ kind: "video",
206
+ status: "skipped",
207
+ error: "Tutorial recording never started, so no canonical WebM was expected."
208
+ };
209
+ }
210
+ const cues = buildSubtitleCues({ scenario, steps });
211
+ const srtRecord = await writeTextArtifact({
212
+ kind: "srt",
213
+ runRoot: paths.runRoot,
214
+ filePath: artifactPaths.srt,
215
+ contents: renderSrt(cues)
216
+ });
217
+ const vttRecord = await writeTextArtifact({
218
+ kind: "vtt",
219
+ runRoot: paths.runRoot,
220
+ filePath: artifactPaths.vtt,
221
+ contents: renderVtt(cues)
222
+ });
223
+ const markdownRecord = await writeTextArtifact({
224
+ kind: "markdown",
225
+ runRoot: paths.runRoot,
226
+ filePath: artifactPaths.markdown,
227
+ contents: renderTutorialMarkdown({ scenario, steps, screenshots })
228
+ });
229
+ // ---- 10. Process cleanup ------------------------------------------------
230
+ cleanupErrors.push(...(await stopProcessesInReverse(started)));
231
+ // ---- 11. Final status ---------------------------------------------------
232
+ // Precedence for an otherwise-passing run, most specific first: a missing
233
+ // required video, then any other failed required artifact, then cleanup.
234
+ // A real execution failure is never replaced by an artifact problem.
235
+ const artifactFailures = [videoRecord, srtRecord, vttRecord, markdownRecord, ...screenshots].filter((record) => record.status === "failed");
236
+ const videoFailed = videoRecord.status === "failed" || (videoRecordingStarted && videoRecord.status === "skipped");
237
+ const nonVideoArtifactFailed = artifactFailures.some((record) => record.kind !== "video");
238
+ let finalStatus = primaryStatus;
239
+ let finalError = primaryError;
240
+ if (primaryStatus === "passed") {
241
+ if (videoFailed) {
242
+ finalStatus = "video-finalization-failed";
243
+ finalError = videoRecord.error ?? "Canonical tutorial video could not be finalized.";
244
+ }
245
+ else if (nonVideoArtifactFailed) {
246
+ finalStatus = "artifact-failed";
247
+ finalError = artifactFailures
248
+ .filter((record) => record.kind !== "video")
249
+ .map((record) => record.error ?? `${record.kind} artifact failed`)
250
+ .join("; ");
251
+ }
252
+ }
253
+ else {
254
+ // Artifact problems are recorded but must not mask the real failure.
255
+ for (const record of artifactFailures) {
256
+ warnings.push(record.error ?? `${record.kind} artifact failed`);
257
+ }
258
+ }
259
+ // ---- 12. Manifest -------------------------------------------------------
260
+ const allArtifacts = [
261
+ videoRecord,
262
+ srtRecord,
263
+ vttRecord,
264
+ markdownRecord,
265
+ ...screenshots,
266
+ ...collectProcessLogRecords(targetContract, paths)
267
+ ];
268
+ const manifestEndedAtMs = Date.now();
269
+ const manifest = buildTutorialManifest({
270
+ scenario,
271
+ targetContract,
272
+ run: {
273
+ id: runId,
274
+ status: finalStatus,
275
+ startedAt,
276
+ endedAt: new Date(manifestEndedAtMs).toISOString(),
277
+ durationMs: manifestEndedAtMs - startedAtMs
278
+ },
279
+ steps,
280
+ artifacts: allArtifacts,
281
+ warnings,
282
+ cleanupErrors
283
+ });
284
+ const manifestRecord = await writeTextArtifact({
285
+ kind: "manifest",
286
+ runRoot: paths.runRoot,
287
+ filePath: artifactPaths.manifest,
288
+ contents: renderTutorialManifest(manifest)
289
+ });
290
+ if (manifestRecord.status === "failed") {
291
+ if (finalStatus === "passed") {
292
+ finalStatus = "artifact-failed";
293
+ finalError = manifestRecord.error;
294
+ }
295
+ else {
296
+ warnings.push(manifestRecord.error ?? "Tutorial manifest could not be written.");
297
+ }
298
+ }
299
+ const artifacts = {
300
+ video: videoRecord,
301
+ srt: srtRecord,
302
+ vtt: vttRecord,
303
+ markdown: markdownRecord,
304
+ manifest: manifestRecord,
305
+ screenshots
306
+ };
307
+ // A cleanup failure only downgrades an otherwise-clean run, because "passed"
308
+ // would misreport a leaked resource.
309
+ if (finalStatus === "passed" && cleanupErrors.length > 0) {
310
+ return finish("cleanup-failed", {
311
+ ...identity,
312
+ steps,
313
+ artifacts,
314
+ error: `Tutorial run completed but cleanup failed: ${cleanupErrors.join("; ")}`
315
+ });
316
+ }
317
+ return finish(finalStatus, {
318
+ ...identity,
319
+ steps,
320
+ artifacts,
321
+ ...(finalError !== undefined ? { error: finalError } : {})
322
+ });
323
+ }
324
+ /**
325
+ * Managed-process log paths are known from the contract and the run layout, so
326
+ * they are recorded from structured data rather than by scanning the directory.
327
+ */
328
+ function collectProcessLogRecords(targetContract, paths) {
329
+ const records = [];
330
+ for (const declared of targetContract.processes) {
331
+ records.push({
332
+ kind: "stdout-log",
333
+ id: declared.id,
334
+ status: "written",
335
+ path: `logs/processes/${declared.id}.stdout.txt`
336
+ });
337
+ records.push({
338
+ kind: "stderr-log",
339
+ id: declared.id,
340
+ status: "written",
341
+ path: `logs/processes/${declared.id}.stderr.txt`
342
+ });
343
+ }
344
+ return records;
345
+ }
346
+ /** Returns an error message when prepare failed, otherwise undefined. */
347
+ async function runPrepare(targetContract, contractRoot, paths) {
348
+ const prepareLogDir = path.join(paths.logsRoot, "prepare");
349
+ const measured = await runMeasuredCommand({
350
+ commandId: "prepare",
351
+ executable: targetContract.prepare.executable,
352
+ args: expandPlaceholders(targetContract.prepare.args ?? [], paths.targetRoot),
353
+ cwd: contractRoot,
354
+ outDir: prepareLogDir,
355
+ env: expandEnvPlaceholders(targetContract.prepare.env, paths.targetRoot),
356
+ timeoutMs: undefined
357
+ });
358
+ if (!measured.ok || measured.exitCode !== 0) {
359
+ const detail = measured.error ?? `exit code ${String(measured.exitCode)}`;
360
+ return `Tutorial prepare command exited with ${detail}. See ${measured.stdoutPath} and ${measured.stderrPath}.`;
361
+ }
362
+ // The prepare command is the only thing allowed to populate targetRoot, so its
363
+ // success is not enough -- the directory it promised must actually be there.
364
+ try {
365
+ const stats = await stat(paths.targetRoot);
366
+ if (!stats.isDirectory()) {
367
+ return `Tutorial prepare command succeeded but ${paths.targetRoot} is not a directory.`;
368
+ }
369
+ }
370
+ catch {
371
+ return `Tutorial prepare command succeeded but did not create the target directory ${paths.targetRoot}.`;
372
+ }
373
+ return undefined;
374
+ }
375
+ async function startTargetProcesses(targetContract, contractRoot, paths, started) {
376
+ for (const declared of targetContract.processes) {
377
+ let handle;
378
+ try {
379
+ handle = await startManagedProcess({
380
+ id: declared.id,
381
+ executable: declared.executable,
382
+ args: expandPlaceholders(declared.args ?? [], paths.targetRoot),
383
+ cwd: resolveProcessCwd(declared, contractRoot, paths),
384
+ outDir: path.join(paths.logsRoot, "processes"),
385
+ env: expandEnvPlaceholders(declared.env, paths.targetRoot)
386
+ });
387
+ }
388
+ catch (error) {
389
+ return {
390
+ status: "process-start-failed",
391
+ error: `Managed process ${JSON.stringify(declared.id)} failed to start: ${messageOf(error)}`
392
+ };
393
+ }
394
+ started.push(handle);
395
+ const readiness = await handle.waitForReadiness(declared.readiness);
396
+ if (readiness.status !== "ready") {
397
+ return {
398
+ status: "readiness-failed",
399
+ error: describeReadinessFailure(declared, readiness.status, readiness.error)
400
+ };
401
+ }
402
+ }
403
+ return undefined;
404
+ }
405
+ function describeReadinessFailure(declared, status, error) {
406
+ const id = JSON.stringify(declared.id);
407
+ switch (status) {
408
+ case "timeout":
409
+ return `Managed process ${id} did not become ready before the readiness timeout (${declared.readiness.timeoutMs}ms) at ${declared.readiness.url}.`;
410
+ case "process-exited":
411
+ return `Managed process ${id} exited before it became ready at ${declared.readiness.url}.`;
412
+ default:
413
+ return `Managed process ${id} readiness probe failed at ${declared.readiness.url}: ${error ?? "unknown readiness error"}`;
414
+ }
415
+ }
416
+ function resolveProcessCwd(declared, contractRoot, paths) {
417
+ return declared.cwd === "target-root" ? paths.targetRoot : contractRoot;
418
+ }
419
+ /**
420
+ * Substitutes the single supported placeholder. Validation has already rejected
421
+ * every other `{{...}}` form, so this is a literal replacement and never a
422
+ * template evaluation.
423
+ */
424
+ export function expandPlaceholders(values, targetRoot) {
425
+ return values.map((value) => value.split(TARGET_ROOT_PLACEHOLDER).join(targetRoot));
426
+ }
427
+ export function expandEnvPlaceholders(env, targetRoot) {
428
+ if (!env) {
429
+ return undefined;
430
+ }
431
+ const expanded = {};
432
+ for (const [key, value] of Object.entries(env)) {
433
+ expanded[key] = value.split(TARGET_ROOT_PLACEHOLDER).join(targetRoot);
434
+ }
435
+ return expanded;
436
+ }
437
+ /**
438
+ * Stops managed processes in reverse startup order so a dependent process is
439
+ * always shut down before whatever it depends on.
440
+ */
441
+ async function stopProcessesInReverse(started) {
442
+ const errors = [];
443
+ for (const handle of [...started].reverse()) {
444
+ try {
445
+ await handle.stop();
446
+ }
447
+ catch (error) {
448
+ errors.push(`Managed process ${JSON.stringify(handle.id)} failed to stop: ${messageOf(error)}`);
449
+ }
450
+ }
451
+ started.length = 0;
452
+ return errors;
453
+ }
454
+ async function closeQuietly(close) {
455
+ try {
456
+ await close();
457
+ return undefined;
458
+ }
459
+ catch (error) {
460
+ return messageOf(error);
461
+ }
462
+ }
463
+ function messageOf(error) {
464
+ return error instanceof Error ? error.message : String(error);
465
+ }