pi-harness-runtime 1.1.395 → 1.1.397

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 (210) hide show
  1. package/AGENTS.md +64 -8
  2. package/package.json +1 -1
  3. package/packages/a2a-adapter/package.json +1 -1
  4. package/packages/agent-policy/package.json +1 -1
  5. package/packages/architecture-generator/package.json +1 -1
  6. package/packages/auth/package.json +1 -1
  7. package/packages/autonomous-refactor/package.json +1 -1
  8. package/packages/autonomous-runtime/package.json +1 -1
  9. package/packages/cache-strategy/package.json +1 -1
  10. package/packages/capability-registry/package.json +1 -1
  11. package/packages/checkpoint/package.json +1 -1
  12. package/packages/cli-plugin-sdk/package.json +1 -1
  13. package/packages/clipboard/package.json +1 -1
  14. package/packages/clipboard-plugin/package.json +1 -1
  15. package/packages/code-generation/package.json +1 -1
  16. package/packages/code-review/package.json +1 -1
  17. package/packages/codex-adapter/package.json +1 -1
  18. package/packages/codex-watcher/package.json +1 -1
  19. package/packages/config-capture/package.json +1 -1
  20. package/packages/connection-runtime/package.json +1 -1
  21. package/packages/context-compiler/package.json +1 -1
  22. package/packages/context-discovery/package.json +1 -1
  23. package/packages/context-manager/package.json +1 -1
  24. package/packages/contracts/dist/workspace-env-format.d.ts +24 -0
  25. package/packages/contracts/dist/workspace-env-format.js +41 -1
  26. package/packages/contracts/dist/workspace-env.js +7 -4
  27. package/packages/contracts/package.json +1 -1
  28. package/packages/contracts/src/workspace-env-format.ts +38 -1
  29. package/packages/contracts/src/workspace-env.ts +8 -3
  30. package/packages/contracts/test/workspace-env.test.ts +48 -0
  31. package/packages/cookie-sanitizer/package.json +1 -1
  32. package/packages/cost-optimizer/package.json +1 -1
  33. package/packages/dependency-analyzer/package.json +1 -1
  34. package/packages/django-plugin/package.json +1 -1
  35. package/packages/doc-generator/package.json +1 -1
  36. package/packages/durable-review/package.json +1 -1
  37. package/packages/e2e-tester/package.json +1 -1
  38. package/packages/evaluation-engine/package.json +1 -1
  39. package/packages/evaluation-runner/package.json +1 -1
  40. package/packages/event-bus/package.json +1 -1
  41. package/packages/event-sink/package.json +1 -1
  42. package/packages/event-store/package.json +1 -1
  43. package/packages/experience-replay/package.json +1 -1
  44. package/packages/feedback-collector/package.json +1 -1
  45. package/packages/file-copy-helper/package.json +1 -1
  46. package/packages/framework-detector/package.json +1 -1
  47. package/packages/framework-plugin-sdk/package.json +1 -1
  48. package/packages/frappe-plugin/package.json +1 -1
  49. package/packages/generic-web-plugin/package.json +1 -1
  50. package/packages/health-monitor/package.json +1 -1
  51. package/packages/intent-analyzer/package.json +1 -1
  52. package/packages/jev-judge/package.json +1 -1
  53. package/packages/knowledge-graph/package.json +1 -1
  54. package/packages/knowledge-retrieval/package.json +1 -1
  55. package/packages/laravel-plugin/package.json +1 -1
  56. package/packages/learning-engine/package.json +1 -1
  57. package/packages/logging/README.md +41 -6
  58. package/packages/logging/dist/classification.d.ts +65 -0
  59. package/packages/logging/dist/classification.d.ts.map +1 -0
  60. package/packages/logging/dist/classification.js +155 -0
  61. package/packages/logging/dist/classification.js.map +1 -0
  62. package/packages/logging/dist/config.d.ts +9 -0
  63. package/packages/logging/dist/config.d.ts.map +1 -1
  64. package/packages/logging/dist/config.js +40 -3
  65. package/packages/logging/dist/config.js.map +1 -1
  66. package/packages/logging/dist/index.d.ts +9 -1
  67. package/packages/logging/dist/index.d.ts.map +1 -1
  68. package/packages/logging/dist/index.js +10 -1
  69. package/packages/logging/dist/index.js.map +1 -1
  70. package/packages/logging/dist/ingest/schema.d.ts +60 -0
  71. package/packages/logging/dist/ingest/schema.d.ts.map +1 -0
  72. package/packages/logging/dist/ingest/schema.js +245 -0
  73. package/packages/logging/dist/ingest/schema.js.map +1 -0
  74. package/packages/logging/dist/installation.d.ts +32 -0
  75. package/packages/logging/dist/installation.d.ts.map +1 -0
  76. package/packages/logging/dist/installation.js +64 -0
  77. package/packages/logging/dist/installation.js.map +1 -0
  78. package/packages/logging/dist/sensitive-keys.d.ts +12 -0
  79. package/packages/logging/dist/sensitive-keys.d.ts.map +1 -0
  80. package/packages/logging/dist/sensitive-keys.js +39 -0
  81. package/packages/logging/dist/sensitive-keys.js.map +1 -0
  82. package/packages/logging/dist/server/credentials.d.ts +85 -0
  83. package/packages/logging/dist/server/credentials.d.ts.map +1 -0
  84. package/packages/logging/dist/server/credentials.js +147 -0
  85. package/packages/logging/dist/server/credentials.js.map +1 -0
  86. package/packages/logging/dist/server/http.d.ts +36 -0
  87. package/packages/logging/dist/server/http.d.ts.map +1 -0
  88. package/packages/logging/dist/server/http.js +139 -0
  89. package/packages/logging/dist/server/http.js.map +1 -0
  90. package/packages/logging/dist/server/index-store.d.ts +95 -0
  91. package/packages/logging/dist/server/index-store.d.ts.map +1 -0
  92. package/packages/logging/dist/server/index-store.js +190 -0
  93. package/packages/logging/dist/server/index-store.js.map +1 -0
  94. package/packages/logging/dist/server/index.d.ts +22 -0
  95. package/packages/logging/dist/server/index.d.ts.map +1 -0
  96. package/packages/logging/dist/server/index.js +15 -0
  97. package/packages/logging/dist/server/index.js.map +1 -0
  98. package/packages/logging/dist/server/keys.d.ts +22 -0
  99. package/packages/logging/dist/server/keys.d.ts.map +1 -0
  100. package/packages/logging/dist/server/keys.js +24 -0
  101. package/packages/logging/dist/server/keys.js.map +1 -0
  102. package/packages/logging/dist/server/outbox-worker.d.ts +55 -0
  103. package/packages/logging/dist/server/outbox-worker.d.ts.map +1 -0
  104. package/packages/logging/dist/server/outbox-worker.js +95 -0
  105. package/packages/logging/dist/server/outbox-worker.js.map +1 -0
  106. package/packages/logging/dist/server/outbox.d.ts +112 -0
  107. package/packages/logging/dist/server/outbox.d.ts.map +1 -0
  108. package/packages/logging/dist/server/outbox.js +247 -0
  109. package/packages/logging/dist/server/outbox.js.map +1 -0
  110. package/packages/logging/dist/server/service.d.ts +83 -0
  111. package/packages/logging/dist/server/service.d.ts.map +1 -0
  112. package/packages/logging/dist/server/service.js +144 -0
  113. package/packages/logging/dist/server/service.js.map +1 -0
  114. package/packages/logging/dist/shipper.d.ts +20 -4
  115. package/packages/logging/dist/shipper.d.ts.map +1 -1
  116. package/packages/logging/dist/shipper.js +31 -5
  117. package/packages/logging/dist/shipper.js.map +1 -1
  118. package/packages/logging/dist/singleton.d.ts.map +1 -1
  119. package/packages/logging/dist/singleton.js +3 -0
  120. package/packages/logging/dist/singleton.js.map +1 -1
  121. package/packages/logging/dist/types.d.ts +28 -1
  122. package/packages/logging/dist/types.d.ts.map +1 -1
  123. package/packages/logging/dist/types.js +8 -0
  124. package/packages/logging/dist/types.js.map +1 -1
  125. package/packages/logging/package.json +1 -1
  126. package/packages/logging/src/classification.ts +175 -0
  127. package/packages/logging/src/config.ts +60 -3
  128. package/packages/logging/src/index.ts +45 -1
  129. package/packages/logging/src/ingest/schema.ts +295 -0
  130. package/packages/logging/src/installation.ts +76 -0
  131. package/packages/logging/src/sensitive-keys.ts +40 -0
  132. package/packages/logging/src/server/credentials.ts +198 -0
  133. package/packages/logging/src/server/http.ts +170 -0
  134. package/packages/logging/src/server/index-store.ts +242 -0
  135. package/packages/logging/src/server/index.ts +56 -0
  136. package/packages/logging/src/server/keys.ts +32 -0
  137. package/packages/logging/src/server/outbox-worker.ts +124 -0
  138. package/packages/logging/src/server/outbox.ts +316 -0
  139. package/packages/logging/src/server/service.ts +196 -0
  140. package/packages/logging/src/shipper.ts +54 -8
  141. package/packages/logging/src/singleton.ts +3 -0
  142. package/packages/logging/src/types.ts +29 -1
  143. package/packages/logging/test/classification.test.ts +137 -0
  144. package/packages/logging/test/identity-transport.test.ts +197 -0
  145. package/packages/logging/test/ingest-schema.test.ts +184 -0
  146. package/packages/logging/test/integration.test.ts +9 -4
  147. package/packages/logging/test/log-http.test.ts +246 -0
  148. package/packages/logging/test/server.test.ts +444 -0
  149. package/packages/logging/test/shipper.test.ts +11 -11
  150. package/packages/logging/test/spool.test.ts +4 -1
  151. package/packages/mcp-adapter/package.json +1 -1
  152. package/packages/memory-engine/package.json +1 -1
  153. package/packages/milestone-manager/package.json +1 -1
  154. package/packages/model-registry/package.json +1 -1
  155. package/packages/nextjs-plugin/package.json +1 -1
  156. package/packages/notification/package.json +1 -1
  157. package/packages/observability/package.json +1 -1
  158. package/packages/okf-indexer/package.json +1 -1
  159. package/packages/paperclip-integration/package.json +1 -1
  160. package/packages/performance-optimizer/package.json +1 -1
  161. package/packages/permission-mode/package.json +1 -1
  162. package/packages/privilege-broker/package.json +1 -1
  163. package/packages/project-analyzer/package.json +1 -1
  164. package/packages/project-bootstrap/package.json +1 -1
  165. package/packages/projection-engine/package.json +1 -1
  166. package/packages/prompt-compiler/package.json +1 -1
  167. package/packages/prompt-versioning/package.json +1 -1
  168. package/packages/provider-adapter-sdk/package.json +1 -1
  169. package/packages/provider-router/package.json +1 -1
  170. package/packages/provider-selector/package.json +1 -1
  171. package/packages/providers/package.json +1 -1
  172. package/packages/qdrant-skills/package.json +1 -1
  173. package/packages/quota-manager/package.json +1 -1
  174. package/packages/rate-limiter/package.json +1 -1
  175. package/packages/react-vite-plugin/package.json +1 -1
  176. package/packages/relay/package.json +1 -1
  177. package/packages/release-manager/package.json +1 -1
  178. package/packages/requirement-compiler/package.json +1 -1
  179. package/packages/runtime/package.json +1 -1
  180. package/packages/scheduler/package.json +1 -1
  181. package/packages/scheduler-adapter/package.json +1 -1
  182. package/packages/session/package.json +1 -1
  183. package/packages/session-api/package.json +1 -1
  184. package/packages/session-export/package.json +1 -1
  185. package/packages/shared-context/package.json +1 -1
  186. package/packages/skill-mcp-client/package.json +1 -1
  187. package/packages/skill-registry/package.json +1 -1
  188. package/packages/skills/package.json +1 -1
  189. package/packages/sprint-planner/package.json +1 -1
  190. package/packages/subscription-engine/package.json +1 -1
  191. package/packages/task-compiler/package.json +1 -1
  192. package/packages/telegram/package.json +1 -1
  193. package/packages/tencentdb-memory/package.json +1 -1
  194. package/packages/tencentdb-sync/package.json +1 -1
  195. package/packages/test-data-generator/package.json +1 -1
  196. package/packages/test-generator/package.json +1 -1
  197. package/packages/todo-bd-sync/package.json +1 -1
  198. package/packages/token-estimation/package.json +1 -1
  199. package/packages/token-optimizer/package.json +1 -1
  200. package/packages/trajectory/package.json +1 -1
  201. package/packages/tui/package.json +1 -1
  202. package/packages/types/package.json +1 -1
  203. package/packages/voice-api/package.json +1 -1
  204. package/packages/webmcp-tester/package.json +1 -1
  205. package/packages/wiki/package.json +1 -1
  206. package/packages/workflow-events/package.json +1 -1
  207. package/packages/workspace-scanner/package.json +1 -1
  208. package/packages/worktree/package.json +1 -1
  209. package/packages/write-review/package.json +1 -1
  210. package/scripts/unified-webhook-server.ts +86 -81
package/AGENTS.md CHANGED
@@ -555,7 +555,10 @@ bun run build && bun run start # Server deployment
555
555
  - The facts about the repository (only when NO variable names the environment
556
556
  at all) → a published source repository without a runtime of its own is a
557
557
  development checkout; a `develop`/`development` branch is the fallback
558
- - System RAM → Low RAM warning (<16GB total or <4GB available)
558
+ - System RAM → Low RAM warning (<4GB free, or a small machine (<16GB total)
559
+ with less than 6GB free). The warning is about the headroom that is
560
+ actually free, not about the size of the machine: a 15GB laptop with 6.5GB
561
+ free can build, a 32GB server with 3GB free cannot.
559
562
  - Running processes → dev/build server status
560
563
 
561
564
  The dotenv files are read from the WORKSPACE (not from the current working
@@ -616,6 +619,12 @@ command to use.
616
619
  | `Low RAM` | Never run parallel build + dev |
617
620
  | `Dev server running` | Reuse it, don't restart |
618
621
 
622
+ The status line states the build permission with its reason: `Build allowed:
623
+ yes`, `no - low memory` (not enough free memory) or `no - requires explicit
624
+ request` (the mode is unknown, so the environment has to be investigated
625
+ first). In development mode the permission follows the free memory (a build
626
+ needs ~2GB), not the size of the machine.
627
+
619
628
  **Decision flow:**
620
629
  ```text
621
630
  Check process.env.NODE_ENV first (it decides, also when it names no known mode)
@@ -639,20 +648,41 @@ Production detection ≠ deployment authorization
639
648
 
640
649
  ## Centralized Application Logging
641
650
 
642
- All application logs can be shipped to **Cloudflare R2** (durable archive) and to the
643
- **unified webhook server** (live path). The pipeline lives in `packages/logging`
644
- (`@pi-harness/logging`); the harness uses the process-wide singleton from it.
651
+ All application logs can be shipped to the **unified webhook server** (ingest path),
652
+ which is the only component that writes to **Cloudflare R2** (durable archive). The
653
+ pipeline lives in `packages/logging` (`@pi-harness/logging`); the harness uses the
654
+ process-wide singleton from it.
655
+
656
+ **Client side** (first success wins, the rest are skipped - a fallback chain, never
657
+ a broadcast):
658
+
659
+ ```text
660
+ producer -> classify -> redact -> sample -> buffer -> webhook -> local spool (~/.pi-harness-runtime/logs/spool)
661
+ ```
645
662
 
646
- **Delivery order** (first success wins, the rest are skipped):
663
+ **Server side** (durable hand-off, then an independent upload):
647
664
 
648
665
  ```text
649
- producer -> redact -> sample -> buffer -> R2 -> webhook -> local spool (~/.pi-harness-runtime/logs/spool)
666
+ POST /api/logs -> authenticate -> validate -> durable outbox -> 202
667
+ |
668
+ v
669
+ worker -> R2 -> done
650
670
  ```
651
671
 
652
672
  - The local spool is the fallback: if every transport fails the batch is written to
653
673
  disk as NDJSON and re-shipped on the next successful flush. Nothing is lost, only delayed.
654
674
  - The local log files (`~/.pi-harness-runtime/logs/*.jsonl`, `harness/*.log`) stay the
655
675
  source of truth. The centralized pipeline is a copy for the archive.
676
+ - **Only the server writes to R2.** In `auto` mode the webhook is preferred when
677
+ `PI_LOG_WEBHOOK_URL` is set, so client machines need no R2 credentials.
678
+
679
+ **What may leave the machine** (`classify`): an event allowlist decides, not a
680
+ denylist. Structured service/session/validation events are remote; the catch-all
681
+ `harness.log` mirror of a local log line, prompts, responses and command output stay
682
+ local. A message only travels when it looks sanitized (one line, short, no path, no
683
+ URL with a query string), and fields with a private key name (`prompt`, `output`,
684
+ `path`, `url`, `user`, ...) are dropped. `PI_LOG_DIAGNOSTIC=1` relaxes the message rule
685
+ for a user who explicitly asked for more - it never widens the event allowlist.
656
686
 
657
687
  **Configuration** (environment first, then `~/.pi-harness-runtime/keys/`):
658
688
 
@@ -667,6 +697,9 @@ producer -> redact -> sample -> buffer -> R2 -> webhook -> local spool (~/.pi-ha
667
697
  | `PI_LOG_FLUSH_INTERVAL_MS` | Automatic flush interval | `15000` |
668
698
  | `PI_LOG_WEBHOOK_URL` | Ingest URL of the webhook server | unset |
669
699
  | `PI_LOG_WEBHOOK_TOKEN` | Bearer token for the ingest endpoint | unset |
700
+ | `PI_LOG_APP_VERSION` | Version reported with every batch | unset |
701
+ | `PI_LOG_INSTALLATION_ID` | Stable id of this installation | generated once |
702
+ | `PI_LOG_DIAGNOSTIC` | `1` allows raw messages (events stay allowlisted) | unset |
670
703
  | `PI_LOG_R2_BUCKET` / `PI_LOG_R2_ENDPOINT` / `PI_LOG_R2_ACCESS_KEY_ID` / `PI_LOG_R2_SECRET_ACCESS_KEY` | R2 credentials | key files |
671
704
  | `PI_LOG_SPOOL_DIR` | Local spool directory | `~/.pi-harness-runtime/logs/spool` |
672
705
 
@@ -677,9 +710,32 @@ R2 credentials are read from the key files `r2-bucket-name.txt`, `r2-endpoint.tx
677
710
 
678
711
  - Emit through the singleton: `centralInfo/centralWarn/centralError(source, event, message?, fields?)`.
679
712
  The `source` identifies the component, the `event` is a dotted name.
713
+ - The event name decides whether a record may leave the machine. Use one of the
714
+ allowlisted shapes (`service.*`, `session.*`, `validation.*`, `harness.service-diagnostics.*`,
715
+ `harness.planner.decision`, `harness.glm-quota.quota`, ...) or a `warn`/`error` level.
716
+ An unknown event stays local.
680
717
  - Redaction is automatic (key names, credential patterns, truncation), but producers must
681
718
  not pass user content: prompts, raw model output and message bodies are dropped by the
682
719
  redactor, so shipping them is pointless.
683
720
  - Never put a credential in a log message. The redactor is a safety net, not a licence.
684
- - The webhook server exposes `POST /api/logs` for the ingest path. Set `LOG_INGEST_TOKEN`
685
- to require a bearer token; the server re-redacts every batch and relays it to R2.
721
+ - Prefer a structured event over mirroring a local log line. The `logToFile()` mirror
722
+ (`harness.log`) stays local on purpose - the local file is the source of truth.
723
+
724
+ **Server endpoints** (all require an ingest credential):
725
+
726
+ | Route | Method | Purpose |
727
+ |-------|--------|---------|
728
+ | `/api/logs` | POST | Accept a batch. `202` only after the durable write, `503` when the endpoint is not configured or the queue is unavailable (the client keeps its spool). |
729
+ | `/api/logs/query` | POST | Read-only, tenant-scoped metadata query (installation, session, time range, level, source, event). Bounded and paginated; never returns message text. |
730
+ | `/api/logs/health` | GET | Queue depth, oldest pending age, failure count, last error. |
731
+
732
+ **Ingest credentials** (server side):
733
+
734
+ - The endpoint **fails closed**: without a credential every write is refused with `503`.
735
+ - `LOG_INGEST_TOKEN` (or `keys/log-ingest-token.txt`) is a shared token for a
736
+ single-tenant deployment; `LOG_INGEST_TENANT` names its tenant.
737
+ - `keys/log-ingest-credentials.json` holds scoped credentials, one per installation:
738
+ `{ "id", "tenantId", "label", "scopes", "tokenHash", "createdAt", "revokedAt" }`.
739
+ Tokens are stored as SHA-256 hashes; the tenant is derived from the credential and
740
+ never from the request body.
741
+ - Rotate by adding an entry and revoking the old one (`revokedAt`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "[BETA] Codex-style /usage status + autonomous coding harness for pi. Not production ready — expect breaking changes.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/a2a-adapter",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "Google Agent-to-Agent (A2A) protocol adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/agent-policy",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Agent policy runtime for pi-harness - enforces mandatory rule delivery and mutation gating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/architecture-generator",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Generate ADR and Mermaid diagrams from project analysis",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/auth",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "pi-harness-runtime — auth",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-refactor",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "Autonomous refactoring engine",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-runtime",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Autonomous Operations Runtime — task inbox, lease management, and worker lifecycle (RFC-0101)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cache-strategy",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "Smart caching with TTL and invalidation strategies (RFC-0022)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/capability-registry",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/checkpoint",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Enhanced checkpoint system with incremental snapshots, diff-based storage, and recovery strategies",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cli-plugin-sdk",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "CLI Plugin SDK for pi-harness — install, list, remove, update, invoke plugins",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard-plugin",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-generation",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Code generation pipeline for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-review",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Automated code review engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/codex-adapter",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "OpenAI Codex provider adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/codex-watcher",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Watches Codex CLI sessions and emits visible messages for PING-PONG monitoring",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/config-capture",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Auto-capture API-fetched configuration values to AGENTS.md",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/connection-runtime",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "Connection management with jittered exponential backoff for pi-harness",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-compiler",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Bounded context selection engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-discovery",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/context-manager",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Context Window Manager — prevents model context overflow via compaction and resume prompts (RFC-0010)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -82,6 +82,30 @@ export interface WorkspaceEnvResult {
82
82
  * without the SQLite cache.
83
83
  */
84
84
  export declare function isLauncherCommand(cmdline: string): boolean;
85
+ /**
86
+ * The RAM rule behind the "low memory" warning.
87
+ *
88
+ * The warning exists to avoid running a build AND a dev server in parallel,
89
+ * so it is about the headroom that is actually available - not about the size
90
+ * of the machine. A 15 GB laptop with 6.5 GB free can build; a 32 GB server
91
+ * with 3 GB free cannot.
92
+ *
93
+ * - Below 4 GB free: always low.
94
+ * - Below 16 GB total: a small machine needs real headroom (6 GB) before a
95
+ * parallel build and dev server are safe.
96
+ */
97
+ export declare function isLowRamWarning(totalGb: number | null, availableGb: number | null): boolean;
98
+ /**
99
+ * The headroom a build needs before it is allowed in development mode.
100
+ */
101
+ export declare const MIN_BUILD_HEADROOM_GB = 2;
102
+ /**
103
+ * The reason the build permission is (not) given.
104
+ *
105
+ * The agent has to know WHY a build is not allowed: an unknown environment
106
+ * needs an explicit request, a memory shortage needs a lighter build.
107
+ */
108
+ export declare function buildAllowanceReason(env: WorkspaceEnvResult): string;
85
109
  export type ServerState = "running" | "not-detected" | "not-checked";
86
110
  /**
87
111
  * The name of the operating system the harness runs on.
@@ -31,6 +31,46 @@
31
31
  export function isLauncherCommand(cmdline) {
32
32
  return /^(npm|bun|yarn|pnpm)\b.*\b(run\s+)?(dev|start)\b/.test(cmdline.trim());
33
33
  }
34
+ /**
35
+ * The RAM rule behind the "low memory" warning.
36
+ *
37
+ * The warning exists to avoid running a build AND a dev server in parallel,
38
+ * so it is about the headroom that is actually available - not about the size
39
+ * of the machine. A 15 GB laptop with 6.5 GB free can build; a 32 GB server
40
+ * with 3 GB free cannot.
41
+ *
42
+ * - Below 4 GB free: always low.
43
+ * - Below 16 GB total: a small machine needs real headroom (6 GB) before a
44
+ * parallel build and dev server are safe.
45
+ */
46
+ export function isLowRamWarning(totalGb, availableGb) {
47
+ if (availableGb === null)
48
+ return false;
49
+ if (availableGb < 4)
50
+ return true;
51
+ if (totalGb === null)
52
+ return false;
53
+ return totalGb < 16 && availableGb < 6;
54
+ }
55
+ /**
56
+ * The headroom a build needs before it is allowed in development mode.
57
+ */
58
+ export const MIN_BUILD_HEADROOM_GB = 2;
59
+ /**
60
+ * The reason the build permission is (not) given.
61
+ *
62
+ * The agent has to know WHY a build is not allowed: an unknown environment
63
+ * needs an explicit request, a memory shortage needs a lighter build.
64
+ */
65
+ export function buildAllowanceReason(env) {
66
+ if (env.buildAllowed)
67
+ return "yes";
68
+ if (env.mode === "unknown")
69
+ return "no - requires explicit request";
70
+ if (env.lowRamWarning)
71
+ return "no - low memory";
72
+ return "no - requires explicit request";
73
+ }
34
74
  /**
35
75
  * The name of the operating system the harness runs on.
36
76
  *
@@ -609,7 +649,7 @@ export function formatEnvForAgentResult(env) {
609
649
  }
610
650
  }
611
651
  message += `\n`;
612
- message += `Build allowed: ${env.buildAllowed ? "yes" : "no - requires explicit request"}\n`;
652
+ message += `Build allowed: ${buildAllowanceReason(env)}\n`;
613
653
  if (env.mode === "unknown") {
614
654
  message += `\nNOTE: Environment unknown - a dev/build script only means a server CAN be started, it does not establish the workspace mode. Explicitly ask the user before build.\n`;
615
655
  }
@@ -16,7 +16,7 @@ import { execSync } from "child_process";
16
16
  import { existsSync, readFileSync, readdirSync, mkdirSync, readlinkSync, realpathSync } from "fs";
17
17
  import { join } from "path";
18
18
  import { platform, totalmem, freemem } from "os";
19
- import { canShowModeValue, collectDotenvVars, collectProcessEnvVars, describeCwdCommand, describeOs, describeServerState, describeWorkspaceMode, detectModeHint, DEPLOYMENT_MARKER_FILES, filterOwnPids, formatEnvForAgentResult, formatEnvStatusLine as formatStatusLine, formatWorkspacePath, isLauncherCommand, MASKED_MODE_VALUE, modeFromRepositoryFacts, modeFromValue, orderDotenvFileNames, parseDotenvVars, resolveWorkspaceMode, } from "./workspace-env-format.js";
19
+ import { canShowModeValue, collectDotenvVars, collectProcessEnvVars, describeCwdCommand, describeOs, describeServerState, describeWorkspaceMode, detectModeHint, DEPLOYMENT_MARKER_FILES, filterOwnPids, formatEnvForAgentResult, formatEnvStatusLine as formatStatusLine, formatWorkspacePath, isLauncherCommand, isLowRamWarning, MASKED_MODE_VALUE, MIN_BUILD_HEADROOM_GB, modeFromRepositoryFacts, modeFromValue, orderDotenvFileNames, parseDotenvVars, resolveWorkspaceMode, } from "./workspace-env-format.js";
20
20
  import { readDotenvFiles } from "./workspace-dotenv.js";
21
21
  const STORE_DIR = join(process.env.HOME || "/home/frappe", ".pi-harness-runtime");
22
22
  /**
@@ -95,11 +95,10 @@ function detectRamInfo() {
95
95
  const freeBytes = freemem();
96
96
  const totalGb = Math.round((totalBytes / (1024 ** 3)) * 10) / 10;
97
97
  const availableGb = Math.round((freeBytes / (1024 ** 3)) * 10) / 10;
98
- const LOW_RAM_GB = 16;
99
98
  return {
100
99
  total: totalGb,
101
100
  available: availableGb,
102
- lowWarning: totalGb < LOW_RAM_GB || availableGb < 4,
101
+ lowWarning: isLowRamWarning(totalGb, availableGb),
103
102
  };
104
103
  }
105
104
  catch {
@@ -709,7 +708,11 @@ export function detectWorkspaceEnv(workspacePath) {
709
708
  buildAllowed = true; // Production build is allowed
710
709
  }
711
710
  else if (mode === "development") {
712
- buildAllowed = !ramInfo.lowWarning; // Allow if not low RAM
711
+ // A build needs headroom, not a big machine. The low-memory warning is
712
+ // about running a build AND a dev server in parallel; a build on its
713
+ // own only needs enough free memory to finish.
714
+ buildAllowed =
715
+ ramInfo.available === null ? false : ramInfo.available >= MIN_BUILD_HEADROOM_GB;
713
716
  }
714
717
  else {
715
718
  buildAllowed = false; // Unknown requires investigation
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/contracts",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "description": "RPC schema definitions for pi-harness runtime",
6
6
  "main": "./dist/index.js",
@@ -90,6 +90,43 @@ export function isLauncherCommand(cmdline: string): boolean {
90
90
  return /^(npm|bun|yarn|pnpm)\b.*\b(run\s+)?(dev|start)\b/.test(cmdline.trim());
91
91
  }
92
92
 
93
+ /**
94
+ * The RAM rule behind the "low memory" warning.
95
+ *
96
+ * The warning exists to avoid running a build AND a dev server in parallel,
97
+ * so it is about the headroom that is actually available - not about the size
98
+ * of the machine. A 15 GB laptop with 6.5 GB free can build; a 32 GB server
99
+ * with 3 GB free cannot.
100
+ *
101
+ * - Below 4 GB free: always low.
102
+ * - Below 16 GB total: a small machine needs real headroom (6 GB) before a
103
+ * parallel build and dev server are safe.
104
+ */
105
+ export function isLowRamWarning(totalGb: number | null, availableGb: number | null): boolean {
106
+ if (availableGb === null) return false;
107
+ if (availableGb < 4) return true;
108
+ if (totalGb === null) return false;
109
+ return totalGb < 16 && availableGb < 6;
110
+ }
111
+
112
+ /**
113
+ * The headroom a build needs before it is allowed in development mode.
114
+ */
115
+ export const MIN_BUILD_HEADROOM_GB = 2;
116
+
117
+ /**
118
+ * The reason the build permission is (not) given.
119
+ *
120
+ * The agent has to know WHY a build is not allowed: an unknown environment
121
+ * needs an explicit request, a memory shortage needs a lighter build.
122
+ */
123
+ export function buildAllowanceReason(env: WorkspaceEnvResult): string {
124
+ if (env.buildAllowed) return "yes";
125
+ if (env.mode === "unknown") return "no - requires explicit request";
126
+ if (env.lowRamWarning) return "no - low memory";
127
+ return "no - requires explicit request";
128
+ }
129
+
93
130
  export type ServerState = "running" | "not-detected" | "not-checked";
94
131
 
95
132
  /**
@@ -756,7 +793,7 @@ export function formatEnvForAgentResult(env: WorkspaceEnvResult): string {
756
793
  }
757
794
 
758
795
  message += `\n`;
759
- message += `Build allowed: ${env.buildAllowed ? "yes" : "no - requires explicit request"}\n`;
796
+ message += `Build allowed: ${buildAllowanceReason(env)}\n`;
760
797
 
761
798
  if (env.mode === "unknown") {
762
799
  message += `\nNOTE: Environment unknown - a dev/build script only means a server CAN be started, it does not establish the workspace mode. Explicitly ask the user before build.\n`;
@@ -32,7 +32,9 @@ import {
32
32
  formatEnvStatusLine as formatStatusLine,
33
33
  formatWorkspacePath,
34
34
  isLauncherCommand,
35
+ isLowRamWarning,
35
36
  MASKED_MODE_VALUE,
37
+ MIN_BUILD_HEADROOM_GB,
36
38
  modeFromRepositoryFacts,
37
39
  modeFromValue,
38
40
  orderDotenvFileNames,
@@ -148,12 +150,11 @@ function detectRamInfo(): {
148
150
  const freeBytes = freemem();
149
151
  const totalGb = Math.round((totalBytes / (1024 ** 3)) * 10) / 10;
150
152
  const availableGb = Math.round((freeBytes / (1024 ** 3)) * 10) / 10;
151
- const LOW_RAM_GB = 16;
152
153
 
153
154
  return {
154
155
  total: totalGb,
155
156
  available: availableGb,
156
- lowWarning: totalGb < LOW_RAM_GB || availableGb < 4,
157
+ lowWarning: isLowRamWarning(totalGb, availableGb),
157
158
  };
158
159
  } catch {
159
160
  return { total: null, available: null, lowWarning: false };
@@ -778,7 +779,11 @@ export function detectWorkspaceEnv(workspacePath: string): WorkspaceEnvResult {
778
779
  if (mode === "production") {
779
780
  buildAllowed = true; // Production build is allowed
780
781
  } else if (mode === "development") {
781
- buildAllowed = !ramInfo.lowWarning; // Allow if not low RAM
782
+ // A build needs headroom, not a big machine. The low-memory warning is
783
+ // about running a build AND a dev server in parallel; a build on its
784
+ // own only needs enough free memory to finish.
785
+ buildAllowed =
786
+ ramInfo.available === null ? false : ramInfo.available >= MIN_BUILD_HEADROOM_GB;
782
787
  } else {
783
788
  buildAllowed = false; // Unknown requires investigation
784
789
  }
@@ -3,6 +3,7 @@ import { mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "n
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import {
6
+ buildAllowanceReason,
6
7
  canShowModeValue,
7
8
  collectDotenvVars,
8
9
  collectProcessEnvVars,
@@ -16,6 +17,7 @@ import {
16
17
  formatEnvStatusLine,
17
18
  formatWorkspacePath,
18
19
  isLauncherCommand,
20
+ isLowRamWarning,
19
21
  isSessionVariableKey,
20
22
  MASKED_MODE_VALUE,
21
23
  modeFromRepositoryFacts,
@@ -752,3 +754,49 @@ describe("the mode detection of a source repository", () => {
752
754
  expect(describeWorkspaceMode(env)).toBe("DEVELOPMENT (source-only repository)");
753
755
  });
754
756
  });
757
+
758
+ describe("the low memory rule", () => {
759
+ test("flags a machine with almost no free memory", () => {
760
+ expect(isLowRamWarning(64, 2)).toBe(true);
761
+ expect(isLowRamWarning(16, 3.9)).toBe(true);
762
+ });
763
+
764
+ test("does not flag a small machine with real headroom", () => {
765
+ expect(isLowRamWarning(15, 6.6)).toBe(false);
766
+ expect(isLowRamWarning(8, 8)).toBe(false);
767
+ });
768
+
769
+ test("flags a big machine that ran out of memory", () => {
770
+ expect(isLowRamWarning(64, 3)).toBe(true);
771
+ });
772
+
773
+ test("does not flag an unknown memory state", () => {
774
+ expect(isLowRamWarning(null, null)).toBe(false);
775
+ expect(isLowRamWarning(null, 12)).toBe(false);
776
+ });
777
+ });
778
+
779
+ describe("the build permission", () => {
780
+ test("allows a build when the environment allows it", () => {
781
+ expect(buildAllowanceReason(makeEnv({ mode: "development", buildAllowed: true }))).toBe("yes");
782
+ });
783
+
784
+ test("asks for an explicit request when the mode is unknown", () => {
785
+ expect(
786
+ buildAllowanceReason(makeEnv({ mode: "unknown", buildAllowed: false, lowRamWarning: false })),
787
+ ).toBe("no - requires explicit request");
788
+ });
789
+
790
+ test("names the memory shortage when the memory is the reason", () => {
791
+ expect(
792
+ buildAllowanceReason(makeEnv({ mode: "development", buildAllowed: false, lowRamWarning: true })),
793
+ ).toBe("no - low memory");
794
+ });
795
+
796
+ test("appears in the agent context", () => {
797
+ const message = formatEnvForAgentResult(
798
+ makeEnv({ mode: "development", buildAllowed: false, lowRamWarning: true }),
799
+ );
800
+ expect(message).toContain("Build allowed: no - low memory");
801
+ });
802
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cookie-sanitizer",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "pi-harness-runtime — cookie sanitizer (provider-quota cookie file normaliser)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cost-optimizer",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Cost Optimizer for pi-harness-runtime — budget tracking, forecasting, and model selection optimization",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/dependency-analyzer",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/django-plugin",
3
- "version": "1.1.395",
3
+ "version": "1.1.397",
4
4
  "description": "Django framework analysis — models, management commands, settings",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",