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.
- package/AGENTS.md +64 -8
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/dist/workspace-env-format.d.ts +24 -0
- package/packages/contracts/dist/workspace-env-format.js +41 -1
- package/packages/contracts/dist/workspace-env.js +7 -4
- package/packages/contracts/package.json +1 -1
- package/packages/contracts/src/workspace-env-format.ts +38 -1
- package/packages/contracts/src/workspace-env.ts +8 -3
- package/packages/contracts/test/workspace-env.test.ts +48 -0
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/logging/README.md +41 -6
- package/packages/logging/dist/classification.d.ts +65 -0
- package/packages/logging/dist/classification.d.ts.map +1 -0
- package/packages/logging/dist/classification.js +155 -0
- package/packages/logging/dist/classification.js.map +1 -0
- package/packages/logging/dist/config.d.ts +9 -0
- package/packages/logging/dist/config.d.ts.map +1 -1
- package/packages/logging/dist/config.js +40 -3
- package/packages/logging/dist/config.js.map +1 -1
- package/packages/logging/dist/index.d.ts +9 -1
- package/packages/logging/dist/index.d.ts.map +1 -1
- package/packages/logging/dist/index.js +10 -1
- package/packages/logging/dist/index.js.map +1 -1
- package/packages/logging/dist/ingest/schema.d.ts +60 -0
- package/packages/logging/dist/ingest/schema.d.ts.map +1 -0
- package/packages/logging/dist/ingest/schema.js +245 -0
- package/packages/logging/dist/ingest/schema.js.map +1 -0
- package/packages/logging/dist/installation.d.ts +32 -0
- package/packages/logging/dist/installation.d.ts.map +1 -0
- package/packages/logging/dist/installation.js +64 -0
- package/packages/logging/dist/installation.js.map +1 -0
- package/packages/logging/dist/sensitive-keys.d.ts +12 -0
- package/packages/logging/dist/sensitive-keys.d.ts.map +1 -0
- package/packages/logging/dist/sensitive-keys.js +39 -0
- package/packages/logging/dist/sensitive-keys.js.map +1 -0
- package/packages/logging/dist/server/credentials.d.ts +85 -0
- package/packages/logging/dist/server/credentials.d.ts.map +1 -0
- package/packages/logging/dist/server/credentials.js +147 -0
- package/packages/logging/dist/server/credentials.js.map +1 -0
- package/packages/logging/dist/server/http.d.ts +36 -0
- package/packages/logging/dist/server/http.d.ts.map +1 -0
- package/packages/logging/dist/server/http.js +139 -0
- package/packages/logging/dist/server/http.js.map +1 -0
- package/packages/logging/dist/server/index-store.d.ts +95 -0
- package/packages/logging/dist/server/index-store.d.ts.map +1 -0
- package/packages/logging/dist/server/index-store.js +190 -0
- package/packages/logging/dist/server/index-store.js.map +1 -0
- package/packages/logging/dist/server/index.d.ts +22 -0
- package/packages/logging/dist/server/index.d.ts.map +1 -0
- package/packages/logging/dist/server/index.js +15 -0
- package/packages/logging/dist/server/index.js.map +1 -0
- package/packages/logging/dist/server/keys.d.ts +22 -0
- package/packages/logging/dist/server/keys.d.ts.map +1 -0
- package/packages/logging/dist/server/keys.js +24 -0
- package/packages/logging/dist/server/keys.js.map +1 -0
- package/packages/logging/dist/server/outbox-worker.d.ts +55 -0
- package/packages/logging/dist/server/outbox-worker.d.ts.map +1 -0
- package/packages/logging/dist/server/outbox-worker.js +95 -0
- package/packages/logging/dist/server/outbox-worker.js.map +1 -0
- package/packages/logging/dist/server/outbox.d.ts +112 -0
- package/packages/logging/dist/server/outbox.d.ts.map +1 -0
- package/packages/logging/dist/server/outbox.js +247 -0
- package/packages/logging/dist/server/outbox.js.map +1 -0
- package/packages/logging/dist/server/service.d.ts +83 -0
- package/packages/logging/dist/server/service.d.ts.map +1 -0
- package/packages/logging/dist/server/service.js +144 -0
- package/packages/logging/dist/server/service.js.map +1 -0
- package/packages/logging/dist/shipper.d.ts +20 -4
- package/packages/logging/dist/shipper.d.ts.map +1 -1
- package/packages/logging/dist/shipper.js +31 -5
- package/packages/logging/dist/shipper.js.map +1 -1
- package/packages/logging/dist/singleton.d.ts.map +1 -1
- package/packages/logging/dist/singleton.js +3 -0
- package/packages/logging/dist/singleton.js.map +1 -1
- package/packages/logging/dist/types.d.ts +28 -1
- package/packages/logging/dist/types.d.ts.map +1 -1
- package/packages/logging/dist/types.js +8 -0
- package/packages/logging/dist/types.js.map +1 -1
- package/packages/logging/package.json +1 -1
- package/packages/logging/src/classification.ts +175 -0
- package/packages/logging/src/config.ts +60 -3
- package/packages/logging/src/index.ts +45 -1
- package/packages/logging/src/ingest/schema.ts +295 -0
- package/packages/logging/src/installation.ts +76 -0
- package/packages/logging/src/sensitive-keys.ts +40 -0
- package/packages/logging/src/server/credentials.ts +198 -0
- package/packages/logging/src/server/http.ts +170 -0
- package/packages/logging/src/server/index-store.ts +242 -0
- package/packages/logging/src/server/index.ts +56 -0
- package/packages/logging/src/server/keys.ts +32 -0
- package/packages/logging/src/server/outbox-worker.ts +124 -0
- package/packages/logging/src/server/outbox.ts +316 -0
- package/packages/logging/src/server/service.ts +196 -0
- package/packages/logging/src/shipper.ts +54 -8
- package/packages/logging/src/singleton.ts +3 -0
- package/packages/logging/src/types.ts +29 -1
- package/packages/logging/test/classification.test.ts +137 -0
- package/packages/logging/test/identity-transport.test.ts +197 -0
- package/packages/logging/test/ingest-schema.test.ts +184 -0
- package/packages/logging/test/integration.test.ts +9 -4
- package/packages/logging/test/log-http.test.ts +246 -0
- package/packages/logging/test/server.test.ts +444 -0
- package/packages/logging/test/shipper.test.ts +11 -11
- package/packages/logging/test/spool.test.ts +4 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
- 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 (<
|
|
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 **
|
|
643
|
-
|
|
644
|
-
(`@pi-harness/logging`); the harness uses the
|
|
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
|
-
**
|
|
663
|
+
**Server side** (durable hand-off, then an independent upload):
|
|
647
664
|
|
|
648
665
|
```text
|
|
649
|
-
|
|
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
|
-
-
|
|
685
|
-
|
|
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/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
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",
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
+
});
|