pi-harness-runtime 1.1.426 → 1.1.428

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 (153) hide show
  1. package/AGENTS.md +2 -2
  2. package/RULES.md +2 -3
  3. package/package.json +1 -1
  4. package/packages/a2a-adapter/package.json +1 -1
  5. package/packages/agent-policy/package.json +1 -1
  6. package/packages/architecture-generator/package.json +1 -1
  7. package/packages/auth/package.json +1 -1
  8. package/packages/autonomous-refactor/package.json +1 -1
  9. package/packages/autonomous-runtime/package.json +1 -1
  10. package/packages/cache-strategy/package.json +1 -1
  11. package/packages/capability-registry/package.json +1 -1
  12. package/packages/checkpoint/package.json +1 -1
  13. package/packages/cli-plugin-sdk/package.json +1 -1
  14. package/packages/clipboard/package.json +1 -1
  15. package/packages/clipboard-plugin/package.json +1 -1
  16. package/packages/code-generation/package.json +1 -1
  17. package/packages/code-review/package.json +1 -1
  18. package/packages/codex-adapter/package.json +1 -1
  19. package/packages/codex-watcher/package.json +1 -1
  20. package/packages/config-capture/package.json +1 -1
  21. package/packages/connection-runtime/package.json +1 -1
  22. package/packages/context-compiler/package.json +1 -1
  23. package/packages/context-discovery/package.json +1 -1
  24. package/packages/context-manager/package.json +1 -1
  25. package/packages/contracts/package.json +1 -1
  26. package/packages/cookie-sanitizer/package.json +1 -1
  27. package/packages/cost-optimizer/package.json +1 -1
  28. package/packages/dependency-analyzer/package.json +1 -1
  29. package/packages/django-plugin/package.json +1 -1
  30. package/packages/doc-generator/package.json +1 -1
  31. package/packages/durable-review/package.json +1 -1
  32. package/packages/e2e-tester/package.json +1 -1
  33. package/packages/evaluation-engine/package.json +1 -1
  34. package/packages/evaluation-runner/package.json +1 -1
  35. package/packages/event-bus/package.json +1 -1
  36. package/packages/event-sink/package.json +1 -1
  37. package/packages/event-store/package.json +1 -1
  38. package/packages/experience-replay/package.json +1 -1
  39. package/packages/feedback-collector/package.json +1 -1
  40. package/packages/file-copy-helper/package.json +1 -1
  41. package/packages/framework-detector/package.json +1 -1
  42. package/packages/framework-plugin-sdk/package.json +1 -1
  43. package/packages/frappe-plugin/package.json +1 -1
  44. package/packages/generic-web-plugin/package.json +1 -1
  45. package/packages/health-monitor/package.json +1 -1
  46. package/packages/intent-analyzer/package.json +1 -1
  47. package/packages/jev-judge/package.json +1 -1
  48. package/packages/knowledge-graph/package.json +1 -1
  49. package/packages/knowledge-retrieval/package.json +1 -1
  50. package/packages/laravel-plugin/package.json +1 -1
  51. package/packages/learning-engine/package.json +1 -1
  52. package/packages/logging/package.json +1 -1
  53. package/packages/mcp-adapter/package.json +1 -1
  54. package/packages/memory-engine/package.json +1 -1
  55. package/packages/milestone-manager/package.json +1 -1
  56. package/packages/model-registry/package.json +1 -1
  57. package/packages/nextjs-plugin/package.json +1 -1
  58. package/packages/notification/package.json +1 -1
  59. package/packages/observability/package.json +1 -1
  60. package/packages/okf-indexer/package.json +1 -1
  61. package/packages/paperclip-integration/package.json +1 -1
  62. package/packages/performance-optimizer/package.json +1 -1
  63. package/packages/permission-mode/package.json +1 -1
  64. package/packages/privilege-broker/package.json +1 -1
  65. package/packages/project-analyzer/package.json +1 -1
  66. package/packages/project-bootstrap/package.json +1 -1
  67. package/packages/projection-engine/package.json +1 -1
  68. package/packages/prompt-compiler/package.json +1 -1
  69. package/packages/prompt-versioning/package.json +1 -1
  70. package/packages/provider-adapter-sdk/package.json +1 -1
  71. package/packages/provider-router/package.json +1 -1
  72. package/packages/provider-selector/package.json +1 -1
  73. package/packages/providers/package.json +1 -1
  74. package/packages/qdrant-skills/package.json +1 -1
  75. package/packages/quota-manager/package.json +1 -1
  76. package/packages/rate-limiter/package.json +1 -1
  77. package/packages/react-vite-plugin/package.json +1 -1
  78. package/packages/relay/package.json +1 -1
  79. package/packages/release-manager/package.json +1 -1
  80. package/packages/requirement-compiler/package.json +1 -1
  81. package/packages/runtime/package.json +1 -1
  82. package/packages/scheduler/package.json +1 -1
  83. package/packages/scheduler-adapter/package.json +1 -1
  84. package/packages/session/package.json +1 -1
  85. package/packages/session-api/package.json +1 -1
  86. package/packages/session-export/package.json +1 -1
  87. package/packages/shared-context/package.json +1 -1
  88. package/packages/skill-mcp-client/package.json +1 -1
  89. package/packages/skill-registry/package.json +1 -1
  90. package/packages/skills/package.json +1 -1
  91. package/packages/sprint-planner/package.json +1 -1
  92. package/packages/subscription-engine/package.json +1 -1
  93. package/packages/task-compiler/package.json +1 -1
  94. package/packages/tencentdb-memory/package.json +1 -1
  95. package/packages/tencentdb-sync/package.json +1 -1
  96. package/packages/test-data-generator/package.json +1 -1
  97. package/packages/test-generator/package.json +1 -1
  98. package/packages/todo-bd-sync/package.json +1 -1
  99. package/packages/token-estimation/package.json +1 -1
  100. package/packages/token-optimizer/package.json +1 -1
  101. package/packages/tooling-preference/package.json +1 -1
  102. package/packages/trajectory/package.json +1 -1
  103. package/packages/tui/package.json +1 -1
  104. package/packages/two-phase-review/package.json +1 -1
  105. package/packages/types/package.json +1 -1
  106. package/packages/voice-api/package.json +1 -1
  107. package/packages/webmcp-tester/package.json +1 -1
  108. package/packages/wiki/package.json +1 -1
  109. package/packages/workflow-events/package.json +1 -1
  110. package/packages/workspace-scanner/package.json +1 -1
  111. package/packages/worktree/package.json +1 -1
  112. package/packages/write-review/package.json +1 -1
  113. package/scripts/lib/runtime-imports.ts +199 -0
  114. package/scripts/verify-package-contents.ts +70 -18
  115. package/packages/telegram/package.json +0 -22
  116. package/packages/telegram/src/agent-messages.d.ts +0 -28
  117. package/packages/telegram/src/agent-messages.js +0 -90
  118. package/packages/telegram/src/bindings.d.ts +0 -296
  119. package/packages/telegram/src/bindings.js +0 -1086
  120. package/packages/telegram/src/bus.d.ts +0 -759
  121. package/packages/telegram/src/bus.js +0 -2732
  122. package/packages/telegram/src/commands.d.ts +0 -761
  123. package/packages/telegram/src/commands.js +0 -2622
  124. package/packages/telegram/src/config.d.ts +0 -222
  125. package/packages/telegram/src/config.js +0 -844
  126. package/packages/telegram/src/delivery.d.ts +0 -161
  127. package/packages/telegram/src/delivery.js +0 -550
  128. package/packages/telegram/src/extension.d.ts +0 -7
  129. package/packages/telegram/src/extension.js +0 -2444
  130. package/packages/telegram/src/inbound.d.ts +0 -94
  131. package/packages/telegram/src/inbound.js +0 -478
  132. package/packages/telegram/src/index.d.ts +0 -6
  133. package/packages/telegram/src/index.js +0 -6
  134. package/packages/telegram/src/keyboard.d.ts +0 -21
  135. package/packages/telegram/src/keyboard.js +0 -37
  136. package/packages/telegram/src/lifecycle.d.ts +0 -210
  137. package/packages/telegram/src/lifecycle.js +0 -538
  138. package/packages/telegram/src/pi.d.ts +0 -76
  139. package/packages/telegram/src/pi.js +0 -130
  140. package/packages/telegram/src/polling.d.ts +0 -332
  141. package/packages/telegram/src/polling.js +0 -1219
  142. package/packages/telegram/src/replies.d.ts +0 -210
  143. package/packages/telegram/src/replies.js +0 -752
  144. package/packages/telegram/src/routing.d.ts +0 -388
  145. package/packages/telegram/src/routing.js +0 -7886
  146. package/packages/telegram/src/runtime.d.ts +0 -159
  147. package/packages/telegram/src/runtime.js +0 -351
  148. package/packages/telegram/src/telegram-api.d.ts +0 -564
  149. package/packages/telegram/src/telegram-api.js +0 -1332
  150. package/packages/telegram/src/turns.d.ts +0 -108
  151. package/packages/telegram/src/turns.js +0 -482
  152. package/packages/telegram/src/updates.d.ts +0 -1545
  153. package/packages/telegram/src/updates.js +0 -6420
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/projection-engine",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/prompt-compiler",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Deterministic prompt compiler for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/prompt-versioning",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Version control for prompts with rollback support (RFC-0019)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/provider-adapter-sdk",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "SDK for building, testing, and registering AI provider adapters",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/provider-router",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Enhanced Provider Router for pi-harness-runtime — intelligent routing with capabilities, costs, and quotas",
5
5
  "type": "module",
6
6
  "main": "./dist/provider-router.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/provider-selector",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Multi-Provider Selector — route requests by cost, quality, and latency (RFC-0012)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/providers",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — providers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/qdrant-skills",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Qdrant vector search integration for Hermes-style skill system",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/quota-manager",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — quota-manager",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/rate-limiter",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Rate limiting with token bucket algorithm (RFC-0023)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/react-vite-plugin",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "React/Vite framework analysis — components, config, TypeScript setup",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/relay",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Cloud relay for remote access - T3 Connect style for pi-harness",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/release-manager",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Release management for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/requirement-compiler",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Compiles raw requirements into validated CompiledRequirement with ambiguity detection and risk tagging",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/runtime",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/scheduler",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — scheduler",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/scheduler-adapter",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Scheduler Adapter — cron, systemd, launchd, internal adapters for autonomous runtime (RFC-0101 §6)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/session",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Session management system for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/session-api",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/session-export",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/shared-context",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — shared-context",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/skill-mcp-client",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "MCP client for Skills SaaS backend",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/skill-registry",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Skill Registry for pi-harness-runtime — dynamic skill discovery and invocation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/skills",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "File-based skill system with pi.dev compatibility and Hermes self-improvement",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/sprint-planner",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Sprint planning engine for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/subscription-engine",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/task-compiler",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Task Compiler for pi-harness-runtime — produces deterministic task DAG from CompiledRequirement",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/tencentdb-memory",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "TencentDB Agent Memory client - sync skills to centralized knowledge base",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tencentdb-sync",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Sync SKILL.md skills to TencentDB-Agent-Memory server (RFC-0105/0106)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/test-data-generator",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Test data generation for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/test-generator",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Auto-Test Generator — generate unit and E2E tests from source code (RFC-0013)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/todo-bd-sync",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Two-way sync between rpiv-todo overlay and bd issue tracker",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/token-estimation",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — token-estimation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/token-optimizer",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Token Budget Optimizer — maximize prompt value within token limits (RFC-0011)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tooling-preference",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — JS/TS tooling preference (Biome vs ESLint/Prettier) proposal",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/trajectory",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Trajectory capture for the write-review loop — persists cycle records for learning",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tui",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — tui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/two-phase-review",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — two-phase implementation and review workflow (queue review signals, gate the phase, scope the diff)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/types",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Shared TypeScript types for pi-harness-runtime packages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/voice-api",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "description": "Voice-to-text API using Whisper for Telegram and LINE integration",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/webmcp-tester",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "WebMCP-powered E2E testing for pi-harness - natural language test scenarios",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/wiki",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "LLM Wiki integration for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/workflow-events",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/workspace-scanner",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/worktree",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "pi-harness-runtime — worktree",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/write-review",
3
- "version": "1.1.426",
3
+ "version": "1.1.428",
4
4
  "description": "Two-agent write-review loop with blackboard coordination",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Resolve the relative imports of a published file.
3
+ *
4
+ * The published package is a single app: every internal package lives in
5
+ * `packages/<name>/` and the runtime reaches it through relative paths. A
6
+ * relative import that does not resolve is a broken module graph, and a
7
+ * consumer finds out when the import runs - long after the release.
8
+ *
9
+ * The check that used to guard this only followed specifiers that contained
10
+ * "packages/", so an import inside a package (`./locks.js`) was never
11
+ * looked at, and the compiled output was never scanned at all. That gap
12
+ * let a package whose entry point could not be imported ship.
13
+ *
14
+ * The rules:
15
+ *
16
+ * 1. A TYPE-only import is erased at runtime, so it does not need a
17
+ * runtime target. It is skipped.
18
+ * 2. Comments are removed before the scan, so a commented-out import is
19
+ * not a broken import.
20
+ * 3. A relative import resolves when the target file exists:
21
+ * - the specifier as written (`./x.js` -> `x.js`),
22
+ * - the TypeScript source of a `.js` specifier (`./x.js` -> `x.ts`),
23
+ * because the compiler and the Bun runtime map it, or
24
+ * - a directory entry point (`./x` -> `x/index.js`).
25
+ * 4. A compiled file (`.js`) must reach a file that is PUBLISHED. A
26
+ * TypeScript source (`.ts`) is resolved at compile time, so it may
27
+ * reach a source file in the repository.
28
+ */
29
+
30
+ import { existsSync, statSync } from "node:fs";
31
+ import { dirname, resolve } from "node:path";
32
+
33
+ /** The quoting state of the comment scanner. */
34
+ type Quote = "" | '"' | "'" | "`";
35
+
36
+ /**
37
+ * Remove the comments from a source file.
38
+ *
39
+ * A string or a template literal may contain something that looks like a
40
+ * comment, so the scanner tracks the quoting state instead of using a
41
+ * regular expression.
42
+ */
43
+ export function stripComments(source: string): string {
44
+ let out = "";
45
+ let i = 0;
46
+ let quote: Quote = "";
47
+
48
+ while (i < source.length) {
49
+ const char = source[i];
50
+ const next = source[i + 1];
51
+
52
+ if (quote) {
53
+ out += char;
54
+ if (char === "\\") {
55
+ // An escaped character cannot end the literal.
56
+ out += next ?? "";
57
+ i += 2;
58
+ continue;
59
+ }
60
+ if (char === quote) quote = "";
61
+ i += 1;
62
+ continue;
63
+ }
64
+
65
+ if (char === '"' || char === "'" || char === "`") {
66
+ quote = char;
67
+ out += char;
68
+ i += 1;
69
+ continue;
70
+ }
71
+
72
+ if (char === "/" && next === "/") {
73
+ // A line comment runs to the end of the line.
74
+ while (i < source.length && source[i] !== "\n") i += 1;
75
+ continue;
76
+ }
77
+
78
+ if (char === "/" && next === "*") {
79
+ // A block comment runs to its closing marker.
80
+ const end = source.indexOf("*/", i + 2);
81
+ if (end === -1) {
82
+ i = source.length;
83
+ break;
84
+ }
85
+ // Keep the newlines, so a line number stays meaningful.
86
+ for (let k = i; k < end; k += 1) {
87
+ if (source[k] === "\n") out += "\n";
88
+ }
89
+ i = end + 2;
90
+ continue;
91
+ }
92
+
93
+ out += char;
94
+ i += 1;
95
+ }
96
+
97
+ return out;
98
+ }
99
+
100
+ /**
101
+ * Every RELATIVE value import of a source file.
102
+ *
103
+ * A type-only import is skipped: `import type { X } from "..."` is erased
104
+ * by the compiler and never reaches the runtime.
105
+ */
106
+ export function extractRelativeValueImports(source: string): string[] {
107
+ const code = stripComments(source);
108
+ const specifiers: string[] = [];
109
+
110
+ const patterns: RegExp[] = [
111
+ // import ... from "..." / export ... from "..."
112
+ /(?:^|[\n;])[ \t]*(import|export)\s+(type\s+)?[^;\n]*?from\s*["']([^"']+)["']/g,
113
+ // import "..." (side effect)
114
+ /(?:^|[\n;])[ \t]*import\s*["']([^"']+)["']/g,
115
+ // import("...") (dynamic)
116
+ /import\s*\(\s*["']([^"']+)["']\s*\)/g,
117
+ ];
118
+
119
+ for (const pattern of patterns) {
120
+ for (const match of code.matchAll(pattern)) {
121
+ // `type` marks an import that the compiler erases.
122
+ if (match[2] && match[2].trim() === "type") continue;
123
+ const specifier = match[3] ?? match[1];
124
+ if (!specifier) continue;
125
+ if (!specifier.startsWith(".")) continue;
126
+ specifiers.push(specifier);
127
+ }
128
+ }
129
+
130
+ return [...new Set(specifiers)];
131
+ }
132
+
133
+ /**
134
+ * The files a relative specifier may point at.
135
+ *
136
+ * The candidates are absolute paths, most specific first.
137
+ */
138
+ export function importTargetCandidates(
139
+ importer: string,
140
+ specifier: string,
141
+ ): string[] {
142
+ const base = resolve(dirname(importer), specifier);
143
+ const candidates = [base];
144
+ if (base.endsWith(".js")) candidates.push(`${base.slice(0, -3)}.ts`);
145
+ candidates.push(`${base}.js`, `${base}.ts`);
146
+ candidates.push(`${base}/index.js`, `${base}/index.ts`);
147
+ return [...new Set(candidates)];
148
+ }
149
+
150
+ /** The result of resolving one relative import. */
151
+ export interface ResolvedImport {
152
+ ok: boolean;
153
+ /** The file the import points at, when one was found. */
154
+ target?: string;
155
+ /** Why the import does not resolve. */
156
+ reason?: string;
157
+ }
158
+
159
+ /** The options of {@link resolveRelativeImport}. */
160
+ export interface ResolveOptions {
161
+ /** Absolute path of the importing file. */
162
+ importer: string;
163
+ /** The relative specifier. */
164
+ specifier: string;
165
+ /** Existence test, overridable for a test. */
166
+ exists?: (path: string) => boolean;
167
+ /** Publication test, overridable for a test. */
168
+ isPublished?: (path: string) => boolean;
169
+ }
170
+
171
+ /**
172
+ * Resolve one relative import.
173
+ */
174
+ export function resolveRelativeImport({
175
+ importer,
176
+ specifier,
177
+ exists = existsSync,
178
+ isPublished = () => true,
179
+ }: ResolveOptions): ResolvedImport {
180
+ const candidates = importTargetCandidates(importer, specifier);
181
+ const found = candidates.find((candidate) => {
182
+ try {
183
+ return exists(candidate) && statSync(candidate).isFile();
184
+ } catch {
185
+ return false;
186
+ }
187
+ });
188
+ if (!found) {
189
+ return { ok: false, reason: "the target does not exist" };
190
+ }
191
+ // A compiled file has to reach a published file: a consumer never sees
192
+ // the repository. A TypeScript source is resolved by the compiler, so it
193
+ // may point at a source file in the repository.
194
+ const isCompiled = /\.(js|mjs|cjs)$/.test(importer);
195
+ if (isCompiled && !isPublished(found)) {
196
+ return { ok: false, target: found, reason: "the target is not published" };
197
+ }
198
+ return { ok: true, target: found };
199
+ }