pi-harness-runtime 1.1.428 → 1.1.429

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 (115) hide show
  1. package/package.json +1 -1
  2. package/packages/a2a-adapter/package.json +1 -1
  3. package/packages/agent-policy/package.json +1 -1
  4. package/packages/architecture-generator/package.json +1 -1
  5. package/packages/auth/package.json +1 -1
  6. package/packages/autonomous-refactor/package.json +1 -1
  7. package/packages/autonomous-runtime/package.json +1 -1
  8. package/packages/cache-strategy/package.json +1 -1
  9. package/packages/capability-registry/package.json +1 -1
  10. package/packages/checkpoint/package.json +1 -1
  11. package/packages/cli-plugin-sdk/package.json +1 -1
  12. package/packages/clipboard/package.json +1 -1
  13. package/packages/clipboard-plugin/dist/index.js +1 -1
  14. package/packages/clipboard-plugin/dist/index.js.map +1 -1
  15. package/packages/clipboard-plugin/package.json +1 -2
  16. package/packages/clipboard-plugin/src/index.ts +1 -1
  17. package/packages/code-generation/package.json +1 -1
  18. package/packages/code-review/package.json +1 -1
  19. package/packages/codex-adapter/package.json +1 -1
  20. package/packages/codex-watcher/package.json +1 -1
  21. package/packages/config-capture/package.json +1 -1
  22. package/packages/connection-runtime/package.json +1 -1
  23. package/packages/context-compiler/package.json +1 -1
  24. package/packages/context-discovery/package.json +1 -1
  25. package/packages/context-manager/package.json +1 -1
  26. package/packages/contracts/package.json +1 -1
  27. package/packages/cookie-sanitizer/package.json +1 -1
  28. package/packages/cost-optimizer/package.json +1 -1
  29. package/packages/dependency-analyzer/package.json +1 -1
  30. package/packages/django-plugin/package.json +1 -1
  31. package/packages/doc-generator/package.json +1 -1
  32. package/packages/durable-review/package.json +1 -1
  33. package/packages/e2e-tester/package.json +1 -1
  34. package/packages/evaluation-engine/package.json +1 -1
  35. package/packages/evaluation-runner/package.json +1 -1
  36. package/packages/event-bus/package.json +1 -1
  37. package/packages/event-sink/package.json +1 -1
  38. package/packages/event-store/package.json +1 -1
  39. package/packages/experience-replay/package.json +1 -1
  40. package/packages/feedback-collector/package.json +1 -1
  41. package/packages/file-copy-helper/package.json +1 -1
  42. package/packages/framework-detector/package.json +1 -1
  43. package/packages/framework-plugin-sdk/package.json +1 -1
  44. package/packages/frappe-plugin/package.json +1 -1
  45. package/packages/generic-web-plugin/package.json +1 -1
  46. package/packages/health-monitor/package.json +1 -1
  47. package/packages/intent-analyzer/package.json +1 -1
  48. package/packages/jev-judge/package.json +1 -1
  49. package/packages/knowledge-graph/package.json +1 -1
  50. package/packages/knowledge-retrieval/package.json +1 -1
  51. package/packages/laravel-plugin/package.json +1 -1
  52. package/packages/learning-engine/package.json +1 -1
  53. package/packages/logging/package.json +1 -1
  54. package/packages/mcp-adapter/package.json +1 -1
  55. package/packages/memory-engine/package.json +1 -1
  56. package/packages/milestone-manager/package.json +1 -1
  57. package/packages/model-registry/package.json +1 -1
  58. package/packages/nextjs-plugin/package.json +1 -1
  59. package/packages/notification/package.json +1 -1
  60. package/packages/observability/package.json +1 -1
  61. package/packages/okf-indexer/package.json +1 -1
  62. package/packages/paperclip-integration/package.json +1 -1
  63. package/packages/performance-optimizer/package.json +1 -1
  64. package/packages/permission-mode/package.json +1 -1
  65. package/packages/privilege-broker/package.json +1 -1
  66. package/packages/project-analyzer/package.json +1 -1
  67. package/packages/project-bootstrap/package.json +1 -1
  68. package/packages/projection-engine/package.json +1 -1
  69. package/packages/prompt-compiler/package.json +1 -1
  70. package/packages/prompt-versioning/package.json +1 -1
  71. package/packages/provider-adapter-sdk/package.json +1 -1
  72. package/packages/provider-router/package.json +1 -1
  73. package/packages/provider-selector/package.json +1 -1
  74. package/packages/providers/package.json +1 -1
  75. package/packages/qdrant-skills/package.json +1 -1
  76. package/packages/quota-manager/package.json +1 -1
  77. package/packages/rate-limiter/package.json +1 -1
  78. package/packages/react-vite-plugin/package.json +1 -1
  79. package/packages/relay/package.json +1 -1
  80. package/packages/release-manager/package.json +1 -1
  81. package/packages/requirement-compiler/package.json +1 -1
  82. package/packages/runtime/package.json +1 -1
  83. package/packages/scheduler/package.json +1 -1
  84. package/packages/scheduler-adapter/package.json +1 -1
  85. package/packages/session/package.json +1 -1
  86. package/packages/session-api/package.json +1 -1
  87. package/packages/session-export/package.json +1 -1
  88. package/packages/shared-context/package.json +1 -1
  89. package/packages/skill-mcp-client/package.json +1 -1
  90. package/packages/skill-registry/package.json +1 -1
  91. package/packages/skills/package.json +1 -1
  92. package/packages/sprint-planner/package.json +1 -1
  93. package/packages/subscription-engine/package.json +1 -1
  94. package/packages/task-compiler/package.json +1 -1
  95. package/packages/tencentdb-memory/package.json +1 -1
  96. package/packages/tencentdb-sync/package.json +1 -1
  97. package/packages/test-data-generator/package.json +1 -1
  98. package/packages/test-generator/package.json +1 -1
  99. package/packages/todo-bd-sync/package.json +1 -1
  100. package/packages/token-estimation/package.json +1 -1
  101. package/packages/token-optimizer/package.json +1 -1
  102. package/packages/tooling-preference/package.json +1 -1
  103. package/packages/trajectory/package.json +1 -1
  104. package/packages/tui/package.json +1 -1
  105. package/packages/two-phase-review/package.json +1 -1
  106. package/packages/types/package.json +1 -1
  107. package/packages/voice-api/package.json +1 -1
  108. package/packages/webmcp-tester/package.json +1 -1
  109. package/packages/wiki/package.json +1 -1
  110. package/packages/workflow-events/package.json +1 -1
  111. package/packages/workspace-scanner/package.json +1 -1
  112. package/packages/worktree/package.json +1 -1
  113. package/packages/write-review/package.json +1 -1
  114. package/scripts/lib/runtime-imports.ts +90 -26
  115. package/scripts/verify-package-contents.ts +42 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/project-bootstrap",
3
- "version": "1.1.428",
3
+ "version": "1.1.429",
4
4
  "description": "Project scaffolding from typed ProjectSpec",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/projection-engine",
3
- "version": "1.1.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
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.428",
3
+ "version": "1.1.429",
4
4
  "description": "Two-agent write-review loop with blackboard coordination",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -16,7 +16,9 @@
16
16
  * 1. A TYPE-only import is erased at runtime, so it does not need a
17
17
  * runtime target. It is skipped.
18
18
  * 2. Comments are removed before the scan, so a commented-out import is
19
- * not a broken import.
19
+ * not a broken import. The same holds for text inside a string or a
20
+ * template literal: documentation that shows an import is not an
21
+ * import.
20
22
  * 3. A relative import resolves when the target file exists:
21
23
  * - the specifier as written (`./x.js` -> `x.js`),
22
24
  * - the TypeScript source of a `.js` specifier (`./x.js` -> `x.ts`),
@@ -25,35 +27,59 @@
25
27
  * 4. A compiled file (`.js`) must reach a file that is PUBLISHED. A
26
28
  * TypeScript source (`.ts`) is resolved at compile time, so it may
27
29
  * reach a source file in the repository.
30
+ * 5. A bare import that names a WORKSPACE package cannot resolve: the
31
+ * workspace packages ship inside this one tarball and are never
32
+ * installed as separate packages, so the name does not exist at
33
+ * runtime. Such an import must point at the built artifact instead.
28
34
  */
29
35
 
30
36
  import { existsSync, statSync } from "node:fs";
31
37
  import { dirname, resolve } from "node:path";
32
38
 
33
- /** The quoting state of the comment scanner. */
39
+ /** The quoting state of the scanner. */
34
40
  type Quote = "" | '"' | "'" | "`";
35
41
 
42
+ /** A source with its comments removed and its string content marked. */
43
+ export interface ScannedSource {
44
+ /** The source without its comments. */
45
+ code: string;
46
+ /**
47
+ * Whether the character at the given index of {@link code} is code.
48
+ *
49
+ * The content of a string or a template literal is not code, so an
50
+ * import that only appears inside one is documentation, not an import.
51
+ */
52
+ isCodeAt: (index: number) => boolean;
53
+ }
54
+
36
55
  /**
37
- * Remove the comments from a source file.
56
+ * Remove the comments from a source file and mark its string content.
38
57
  *
39
58
  * A string or a template literal may contain something that looks like a
40
59
  * comment, so the scanner tracks the quoting state instead of using a
41
60
  * regular expression.
42
61
  */
43
- export function stripComments(source: string): string {
44
- let out = "";
62
+ export function scanSource(source: string): ScannedSource {
63
+ let code = "";
64
+ const isCode: boolean[] = [];
45
65
  let i = 0;
46
66
  let quote: Quote = "";
47
67
 
68
+ const emit = (char: string, isCodeChar: boolean) => {
69
+ code += char;
70
+ isCode.push(isCodeChar);
71
+ };
72
+
48
73
  while (i < source.length) {
49
74
  const char = source[i];
50
75
  const next = source[i + 1];
51
76
 
52
77
  if (quote) {
53
- out += char;
78
+ // The content of a literal is not code. The quotes are.
79
+ emit(char, char === quote && source[i - 1] !== "\\");
54
80
  if (char === "\\") {
55
81
  // An escaped character cannot end the literal.
56
- out += next ?? "";
82
+ emit(next ?? "", false);
57
83
  i += 2;
58
84
  continue;
59
85
  }
@@ -64,7 +90,7 @@ export function stripComments(source: string): string {
64
90
 
65
91
  if (char === '"' || char === "'" || char === "`") {
66
92
  quote = char;
67
- out += char;
93
+ emit(char, true);
68
94
  i += 1;
69
95
  continue;
70
96
  }
@@ -84,45 +110,56 @@ export function stripComments(source: string): string {
84
110
  }
85
111
  // Keep the newlines, so a line number stays meaningful.
86
112
  for (let k = i; k < end; k += 1) {
87
- if (source[k] === "\n") out += "\n";
113
+ if (source[k] === "\n") emit("\n", false);
88
114
  }
89
115
  i = end + 2;
90
116
  continue;
91
117
  }
92
118
 
93
- out += char;
119
+ emit(char, true);
94
120
  i += 1;
95
121
  }
96
122
 
97
- return out;
123
+ return { code, isCodeAt: (index: number) => isCode[index] === true };
98
124
  }
99
125
 
100
126
  /**
101
- * Every RELATIVE value import of a source file.
127
+ * Remove the comments from a source file.
128
+ */
129
+ export function stripComments(source: string): string {
130
+ return scanSource(source).code;
131
+ }
132
+
133
+ /** The import forms that carry a specifier. */
134
+ const IMPORT_PATTERNS: RegExp[] = [
135
+ // import ... from "..." / export ... from "..."
136
+ /(?:^|[\n;])[ \t]*(import|export)\s+(type\s+)?[^;\n]*?from\s*["']([^"']+)["']/g,
137
+ // import "..." (side effect)
138
+ /(?:^|[\n;])[ \t]*import\s*["']([^"']+)["']/g,
139
+ // import("...") (dynamic)
140
+ /import\s*\(\s*["']([^"']+)["']\s*\)/g,
141
+ ];
142
+
143
+ /**
144
+ * Every VALUE import of a source file.
102
145
  *
103
146
  * A type-only import is skipped: `import type { X } from "..."` is erased
104
- * by the compiler and never reaches the runtime.
147
+ * by the compiler and never reaches the runtime. An import that only
148
+ * appears inside a string or a template literal is skipped as well: that
149
+ * is documentation, not an import.
105
150
  */
106
- export function extractRelativeValueImports(source: string): string[] {
107
- const code = stripComments(source);
151
+ export function extractValueImports(source: string): string[] {
152
+ const { code, isCodeAt } = scanSource(source);
108
153
  const specifiers: string[] = [];
109
154
 
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) {
155
+ for (const pattern of IMPORT_PATTERNS) {
120
156
  for (const match of code.matchAll(pattern)) {
157
+ // The match must start in code, not inside a literal.
158
+ if (match.index === undefined || !isCodeAt(match.index)) continue;
121
159
  // `type` marks an import that the compiler erases.
122
160
  if (match[2] && match[2].trim() === "type") continue;
123
161
  const specifier = match[3] ?? match[1];
124
162
  if (!specifier) continue;
125
- if (!specifier.startsWith(".")) continue;
126
163
  specifiers.push(specifier);
127
164
  }
128
165
  }
@@ -130,6 +167,33 @@ export function extractRelativeValueImports(source: string): string[] {
130
167
  return [...new Set(specifiers)];
131
168
  }
132
169
 
170
+ /**
171
+ * Every RELATIVE value import of a source file.
172
+ */
173
+ export function extractRelativeValueImports(source: string): string[] {
174
+ return extractValueImports(source).filter((specifier) => specifier.startsWith("."));
175
+ }
176
+
177
+ /**
178
+ * Every BARE value import of a source file.
179
+ *
180
+ * A bare import names a package, not a file in this repository.
181
+ */
182
+ export function extractBareImports(source: string): string[] {
183
+ return extractValueImports(source).filter((specifier) => !specifier.startsWith("."));
184
+ }
185
+
186
+ /**
187
+ * The package a specifier names.
188
+ *
189
+ * `@scope/name/sub/path` and `name/sub/path` both name `@scope/name` and
190
+ * `name`.
191
+ */
192
+ export function packageNameOf(specifier: string): string {
193
+ if (specifier.startsWith("@")) return specifier.split("/").slice(0, 2).join("/");
194
+ return specifier.split("/")[0];
195
+ }
196
+
133
197
  /**
134
198
  * The files a relative specifier may point at.
135
199
  *